Auto-check after every word; disable browser spellcheck
- spellCheck={false} on EditorContent — LanguageTool's wavy marks
take over entirely, no double-squiggle confusion
- onUpdate schedules runLint() 1.5 s after the last keystroke via
lintDebounce ref; typing resets the timer so it only fires when
the writer pauses (naturally after finishing a word or sentence)
- runLintRef kept in sync with useEffect so the stale onUpdate
closure always calls the latest runLint
- Timer cleaned up on unmount
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bdafd3f2c3
commit
91071270a4
@ -111,6 +111,8 @@ const Editor = forwardRef(function Editor(
|
|||||||
const [lintCount, setLintCount] = useState(0)
|
const [lintCount, setLintCount] = useState(0)
|
||||||
const [lintPopover, setLintPopover] = useState(null) // { top, left, message, replacements, from, to }
|
const [lintPopover, setLintPopover] = useState(null) // { top, left, message, replacements, from, to }
|
||||||
const lintStatusRef = useRef('idle')
|
const lintStatusRef = useRef('idle')
|
||||||
|
const lintDebounce = useRef(null)
|
||||||
|
const runLintRef = useRef(null) // always holds latest runLint, safe to call from onUpdate closure
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
extensions: [
|
extensions: [
|
||||||
@ -126,11 +128,9 @@ const Editor = forwardRef(function Editor(
|
|||||||
content: '',
|
content: '',
|
||||||
onUpdate({ editor }) {
|
onUpdate({ editor }) {
|
||||||
onChange(stripLintMarks(editor.getJSON()))
|
onChange(stripLintMarks(editor.getJSON()))
|
||||||
// Mark results as stale when the user edits so they know to re-check
|
// Debounced auto-check: fire 1.5 s after the last keystroke
|
||||||
if (lintStatusRef.current === 'done') {
|
clearTimeout(lintDebounce.current)
|
||||||
lintStatusRef.current = 'stale'
|
lintDebounce.current = setTimeout(() => runLintRef.current?.(), 1500)
|
||||||
setLintStatus('stale')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -153,6 +153,11 @@ const Editor = forwardRef(function Editor(
|
|||||||
}, [editor, content])
|
}, [editor, content])
|
||||||
|
|
||||||
// ── Lint check ───────────────────────────────────────────────────────────
|
// ── Lint check ───────────────────────────────────────────────────────────
|
||||||
|
// Keep ref in sync so the onUpdate closure (which never re-captures) always
|
||||||
|
// calls the latest version of runLint.
|
||||||
|
useEffect(() => { runLintRef.current = runLint }, [runLint])
|
||||||
|
useEffect(() => () => clearTimeout(lintDebounce.current), [])
|
||||||
|
|
||||||
const runLint = useCallback(async () => {
|
const runLint = useCallback(async () => {
|
||||||
if (!editor || lintStatusRef.current === 'checking') return
|
if (!editor || lintStatusRef.current === 'checking') return
|
||||||
lintStatusRef.current = 'checking'
|
lintStatusRef.current = 'checking'
|
||||||
@ -265,7 +270,7 @@ const Editor = forwardRef(function Editor(
|
|||||||
lintCount={lintCount}
|
lintCount={lintCount}
|
||||||
/>
|
/>
|
||||||
<div className="editor-wrap" onClick={handleEditorClick}>
|
<div className="editor-wrap" onClick={handleEditorClick}>
|
||||||
<EditorContent editor={editor} className="editor-body" />
|
<EditorContent editor={editor} className="editor-body" spellCheck={false} />
|
||||||
<div className="word-count">{wordCount.toLocaleString()} {wordCount === 1 ? 'word' : 'words'}</div>
|
<div className="word-count">{wordCount.toLocaleString()} {wordCount === 1 ? 'word' : 'words'}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user