import { Extension } from '@codemirror/state'; import { tags } from '@lezer/highlight'; import { createTheme } from '@uiw/codemirror-themes'; import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror'; import { EditorView } from 'codemirror'; import { RefObject, useCallback, useMemo, useRef } from 'react'; import { useRSForm } from '../../context/RSFormContext'; import { useConceptTheme } from '../../context/ThemeContext'; import { TokenID } from '../../models/rslang'; import Label from '../Common/Label'; import { ccBracketMatching } from './bracketMatching'; import { RSLanguage } from './rslang'; import { getSymbolSubstitute,TextWrapper } from './textEditing'; import { rshoverTooltip as rsHoverTooltip } from './tooltip'; const editorSetup: BasicSetupOptions = { highlightSpecialChars: false, history: true, drawSelection: false, syntaxHighlighting: false, defaultKeymap: true, historyKeymap: true, lineNumbers: false, highlightActiveLineGutter: false, foldGutter: false, dropCursor: false, allowMultipleSelections: false, indentOnInput: false, bracketMatching: false, closeBrackets: false, autocompletion: false, rectangularSelection: false, crosshairCursor: false, highlightActiveLine: false, highlightSelectionMatches: false, closeBracketsKeymap: false, searchKeymap: false, foldKeymap: false, completionKeymap: false, lintKeymap: false }; interface RSInputProps extends Pick { label?: string innerref?: RefObject | undefined onChange?: (newValue: string) => void } function RSInput({ id, label, innerref, onChange, editable, ...props }: RSInputProps) { const { darkMode, colors } = useConceptTheme(); const { schema } = useRSForm(); const internalRef = useRef(null); const thisRef = useMemo( () => { return innerref ?? internalRef; }, [internalRef, innerref]); const cursor = useMemo(() => editable ? 'cursor-text': 'cursor-default', [editable]); const customTheme: Extension = useMemo( () => createTheme({ theme: darkMode ? 'dark' : 'light', settings: { fontFamily: 'inherit', background: editable ? colors.bgInput : colors.bgDefault, foreground: colors.fgDefault, selection: colors.bgHover }, styles: [ { tag: tags.name, color: colors.fgPurple, cursor: 'default' }, // GlobalID { tag: tags.variableName, color: colors.fgGreen }, // LocalID { tag: tags.propertyName, color: colors.fgTeal }, // Radical { tag: tags.keyword, color: colors.fgBlue }, // keywords { tag: tags.literal, color: colors.fgBlue }, // literals { tag: tags.controlKeyword, fontWeight: '500'}, // R | I | D { tag: tags.unit, fontSize: '0.75rem' }, // indicies ] }), [editable, colors, darkMode]); const editorExtensions = useMemo( () => [ EditorView.lineWrapping, RSLanguage, ccBracketMatching(darkMode), rsHoverTooltip(schema?.items || []), ], [darkMode, schema?.items]); const handleInput = useCallback( (event: React.KeyboardEvent) => { if (!thisRef.current) { return; } const text = new TextWrapper(thisRef.current as Required); if (event.shiftKey && event.key === '*' && !event.altKey) { text.insertToken(TokenID.DECART); } else if (event.altKey) { if (!text.processAltKey(event.code, event.shiftKey)) { return; } } else if (!event.ctrlKey) { const newSymbol = getSymbolSubstitute(event.code, event.shiftKey); if (!newSymbol) { return; } text.replaceWith(newSymbol); } else { return; } event.preventDefault(); }, [thisRef]); return (
{label &&
); } export default RSInput;