import { useEffect, useRef } from 'react' import { EditorState } from '@codemirror/state' import { EditorView, drawSelection, keymap } from '@codemirror/view' import { defaultKeymap, history, historyKeymap } from '@codemirror/commands' import type { useDocumentSync } from '../sync/use-document-sync' type Binding = Pick, 'bindView' | 'onDocumentUpdate'> /** Ordinary .base text uses the same Automerge/CM6 document binding as other editors. */ export function BaseSourceEditor({ source, binding, onTextChange, onView }: { source: string; binding: Binding; onTextChange: (text: string) => void; onView?: (view: EditorView | null) => void }) { const parent = useRef(null) const initialSource = useRef(source) const bindView = binding.bindView const onUpdate = useRef(binding.onDocumentUpdate) const onText = useRef(onTextChange) const onViewRef = useRef(onView) onUpdate.current = binding.onDocumentUpdate onText.current = onTextChange onViewRef.current = onView useEffect(() => { if (!parent.current) return const view = new EditorView({ parent: parent.current, state: EditorState.create({ doc: initialSource.current, extensions: [ history(), drawSelection(), EditorView.lineWrapping, keymap.of([...defaultKeymap, ...historyKeymap]), EditorView.contentAttributes.of({ 'aria-label': 'Query definition' }), EditorView.updateListener.of(update => { if (!update.docChanged) return onText.current(update.state.doc.toString()) onUpdate.current(update) }), ] }), }) bindView(view) onViewRef.current?.(view) return () => { onViewRef.current?.(null); bindView(null, undefined, view); view.destroy() } }, [bindView]) return
}