5392320Interactive illustration of Floater-Hormann barycentric rational interpolationJeremy Magland 1import { useEffect, useRef } from 'react'
2import { EditorView, basicSetup } from 'codemirror'
3import { EditorState } from '@codemirror/state'
4import { keymap } from '@codemirror/view'
5import { indentUnit, StreamLanguage } from '@codemirror/language'
6import { octave } from '@codemirror/legacy-modes/mode/octave'
7import { oneDark } from '@codemirror/theme-one-dark'
9export interface ScriptEditorProps {
10 value: string
11 onChange: (value: string) => void
12 /** Ctrl/Cmd+Enter */
13 onRun: () => void
14}
16export default function ScriptEditor({ value, onChange, onRun }: ScriptEditorProps) {
17 const hostRef = useRef<HTMLDivElement>(null)
18 const viewRef = useRef<EditorView | null>(null)
19 const onChangeRef = useRef(onChange)
20 onChangeRef.current = onChange
21 const onRunRef = useRef(onRun)
22 onRunRef.current = onRun
24 useEffect(() => {
25 if (!hostRef.current) return
26 const view = new EditorView({
27 parent: hostRef.current,
28 state: EditorState.create({
29 doc: value,
30 extensions: [
31 basicSetup,
32 keymap.of([
33 {
34 key: 'Mod-Enter',
35 run: () => {
36 onRunRef.current()
37 return true
38 },
39 },
40 ]),
41 StreamLanguage.define(octave),
42 oneDark,
43 indentUnit.of(' '),
44 EditorView.updateListener.of((update) => {
45 if (update.docChanged) onChangeRef.current(update.state.doc.toString())
46 }),
47 ],
48 }),
49 })
50 viewRef.current = view
51 return () => {
52 view.destroy()
53 viewRef.current = null
54 }
55 // created once; external value changes are synced below
56 // eslint-disable-next-line react-hooks/exhaustive-deps
57 }, [])
59 // sync an externally loaded script (a different method picked) into the editor
60 useEffect(() => {
61 const view = viewRef.current
62 if (!view) return
63 const current = view.state.doc.toString()
64 if (current !== value) {
65 view.dispatch({ changes: { from: 0, to: current.length, insert: value } })
66 }
67 }, [value])
69 return <div className="editor-host" ref={hostRef} />
70}