fix: CodeMirror cursor placement at non-100% zoom levels
Root cause: CSS zoom on document.documentElement caused stale CodeMirror measurements. Two issues: 1. Race condition: zoom was applied in useEffect (parent), but CodeMirror was created in useEffect (child) — child effects run first, so CM measured at zoom=1 before zoom was actually applied. 2. No re-measure on zoom change: CSS zoom changes don't trigger ResizeObserver on descendant elements, so CodeMirror never updated its cached scaleX/scaleY, line heights, or character widths. Fix: - Apply zoom synchronously during useState init (before child effects) - Dispatch 'laputa-zoom-change' event when zoom changes - Listen for this event in useCodeMirror and call view.requestMeasure() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -111,7 +111,19 @@ export function useCodeMirror(
|
||||
|
||||
const view = new EditorView({ state, parent })
|
||||
viewRef.current = view
|
||||
return () => { view.destroy(); viewRef.current = null }
|
||||
|
||||
// When CSS zoom changes on the document, CodeMirror's cached measurements
|
||||
// (scaleX/scaleY, line heights, character widths) become stale because
|
||||
// ResizeObserver doesn't fire for ancestor zoom changes. Force a re-measure
|
||||
// so cursor placement stays accurate at any zoom level.
|
||||
const handleZoomChange = () => { view.requestMeasure() }
|
||||
window.addEventListener('laputa-zoom-change', handleZoomChange)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('laputa-zoom-change', handleZoomChange)
|
||||
view.destroy()
|
||||
viewRef.current = null
|
||||
}
|
||||
// Re-create editor when isDark changes (theme is baked into extensions)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isDark])
|
||||
|
||||
Reference in New Issue
Block a user