UNPKG

@kaspersky/components

Version:

Kaspersky Design System UI Kit

184 lines (173 loc) 7.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useCodeViewer = useCodeViewer; var _react = require("react"); var _commands = require("@codemirror/commands"); var _gutter = require("@codemirror/gutter"); var _lint = require("@codemirror/lint"); var _state = require("@codemirror/state"); var _view = require("@codemirror/view"); var _constants = require("./constants.js"); var _hightlightingStyles = require("./hightlightingStyles.js"); function useCodeViewer(props, forwardedRef) { const containerRef = (0, _react.useRef)(null); const editorStateRef = (0, _react.useRef)(null); const editorViewRef = (0, _react.useRef)(null); const highlightingExtensionRef = (0, _react.useRef)(new _state.Compartment()); const languageExtensionRef = (0, _react.useRef)(new _state.Compartment()); const readOnlyExtensionRef = (0, _react.useRef)(new _state.Compartment()); const valueChangeListenerExtensionRef = (0, _react.useRef)(new _state.Compartment()); const linesChangeListenerExtensionRef = (0, _react.useRef)(new _state.Compartment()); const hasTextListenerExtensionRef = (0, _react.useRef)(new _state.Compartment()); const focusListenerExtensionRef = (0, _react.useRef)(new _state.Compartment()); const keymapExtensionRef = (0, _react.useRef)(new _state.Compartment()); /** Defines editor view and state */ (0, _react.useEffect)(() => { if (!containerRef.current) return; editorStateRef.current = _state.EditorState.create({ doc: '', extensions: [languageExtensionRef.current.of([]), readOnlyExtensionRef.current.of([]), valueChangeListenerExtensionRef.current.of([]), highlightingExtensionRef.current.of([]), linesChangeListenerExtensionRef.current.of([]), hasTextListenerExtensionRef.current.of([]), keymapExtensionRef.current.of([]), focusListenerExtensionRef.current.of([]), (0, _gutter.lineNumbers)(), (0, _view.highlightActiveLine)(), (0, _gutter.highlightActiveLineGutter)(), ...(props.linter ? [(0, _lint.linter)(props.linter)] : []), ...(props.linter ? [(0, _lint.lintGutter)()] : [])] }); editorViewRef.current = new _view.EditorView({ state: editorStateRef.current, parent: containerRef.current }); return () => { var _editorViewRef$curren; (_editorViewRef$curren = editorViewRef.current) === null || _editorViewRef$curren === void 0 ? void 0 : _editorViewRef$curren.destroy(); }; }, []); /** Controls readonly state */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; const readOnlyExtension = _state.EditorState.readOnly.of(!!props.readonly); editorViewRef.current.dispatch({ effects: readOnlyExtensionRef.current.reconfigure(readOnlyExtension) }); }, [props.readonly]); /** Updates text passed through «initialValue» prop */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; const currentValue = editorViewRef.current.state.doc.toString(); const transaction = editorViewRef.current.state.update({ changes: { from: 0, to: currentValue.length, insert: props.initialValue || '' } }); editorViewRef.current.dispatch(transaction); }, [props.initialValue]); /** Defines and updates «onChange» listener */ (0, _react.useEffect)(() => { if (!editorViewRef.current || !props.onChange) return; const valueChangeListenerExtension = _view.EditorView.updateListener.of(update => { if (update.docChanged && props.onChange) { props.onChange(update.state.doc.toString()); } }); const effects = valueChangeListenerExtensionRef.current.reconfigure(valueChangeListenerExtension); editorViewRef.current.dispatch({ effects }); }, [props.onChange]); /** Controls highlighting styles */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; const tagsColors = (0, _hightlightingStyles.createTagsColors)(props.cssConfig); const effects = highlightingExtensionRef.current.reconfigure(tagsColors); if (effects) { editorViewRef.current.dispatch({ effects }); } }, [props.language, props.cssConfig]); /** Defines editor keymap */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; const keymapExtension = _view.keymap.of([..._commands.defaultKeymap, { key: 'Tab', preventDefault: true, run: _commands.insertTab }, { key: 'Shift-Tab', preventDefault: true, run: _commands.indentLess }]); editorViewRef.current.dispatch({ effects: keymapExtensionRef.current.reconfigure([keymapExtension]) }); }, []); /** Controls languages state */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; const selectedLang = _constants.DEFAULT_LANGUAGES[props.language] || props.customLanguages && props.customLanguages[props.language]; const effects = languageExtensionRef.current.reconfigure(selectedLang); if (effects) { editorViewRef.current.dispatch({ effects }); } }, [props.language, props.customLanguages]); const [linesNum, setLinesNum] = (0, _react.useState)(1); /** Controls lines number state */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; setLinesNum(editorViewRef.current.state.doc.lines); const linesChangeListenerExtension = _view.EditorView.updateListener.of(update => { if (update.docChanged) { setLinesNum(update.state.doc.lines); } }); const effects = linesChangeListenerExtensionRef.current.reconfigure(linesChangeListenerExtension); editorViewRef.current.dispatch({ effects }); }, []); const [hasText, setHasText] = (0, _react.useState)((props.initialValue || '').trim().length > 0); /** Controls «hasText» state */ (0, _react.useEffect)(() => { if (!editorViewRef.current) return; const hasTextListenerExtension = _view.EditorView.updateListener.of(update => { if (update.docChanged) { const text = update.state.doc.toString().trim(); setHasText(text.length > 0); } }); const effects = hasTextListenerExtensionRef.current.reconfigure(hasTextListenerExtension); editorViewRef.current.dispatch({ effects }); }, []); /** Defines a ref to use the CodeMirror API outside of the component */ (0, _react.useEffect)(() => { if (!forwardedRef) return; const isOldRef = typeof forwardedRef === 'function'; const isEditorDefined = !!editorStateRef.current && !!editorViewRef.current; if (isOldRef && isEditorDefined) { forwardedRef({ editorState: editorStateRef.current, editorView: editorViewRef.current }); } if (isOldRef && !isEditorDefined) { forwardedRef(null); } if (!isOldRef && isEditorDefined) { forwardedRef.current = { editorState: editorStateRef.current, editorView: editorViewRef.current }; } if (!isOldRef && !isEditorDefined) { forwardedRef.current = null; } }, [forwardedRef]); return { containerRef, linesNum, hasText }; }