@kaspersky/components
Version:
Kaspersky Design System UI Kit
184 lines (173 loc) • 7.13 kB
JavaScript
"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
};
}