UNPKG

@yuntijs/ui

Version:

☁️ Yunti UI - an open-source UI component library for building Cloud Native web apps

357 lines (349 loc) 13.6 kB
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* eslint-disable no-empty */ import { shikiToMonaco } from '@shikijs/monaco'; import { useEffect, useRef, useState } from 'react'; import { createHighlighter } from 'shiki'; import { languageMap } from "../../hooks/languageMap"; import { themeMap } from "../../hooks/themeMap"; import { isBrowser } from "../../utils/tools"; import { getMonaco } from "./monaco"; // @todo fill type def for monaco editor without refering monaco editor /** * @see https://microsoft.github.io/monaco-editor/api/index.html */ var CURRENT_LANGUAGE = isBrowser ? (window.locale || window.localStorage.getItem('vdev-locale') || '').replace(/_/, '-') || 'zh-CN' : 'zh-CN'; export var WORD_EDITOR_INITIALIZING = CURRENT_LANGUAGE === 'en-US' ? 'Initializing Editor' : '编辑器初始化中'; export var INITIAL_OPTIONS = { fontSize: 12, tabSize: 2, fontFamily: 'Menlo, Monaco, Courier New, monospace', folding: true, minimap: { enabled: false }, autoIndent: 'advanced', contextmenu: true, useTabStops: true, // wordBasedSuggestions: true, formatOnPaste: true, automaticLayout: true, lineNumbers: 'on', wordWrap: 'off', scrollBeyondLastLine: false, fixedOverflowWidgets: false, snippetSuggestions: 'top', scrollbar: { vertical: 'auto', horizontal: 'auto', verticalScrollbarSize: 10, horizontalScrollbarSize: 10 } }; var DIFF_EDITOR_INITIAL_OPTIONS = { fontSize: 12, fontFamily: 'Menlo, Monaco, Courier New, monospace', folding: true, minimap: { enabled: false }, autoIndent: 'advanced', contextmenu: true, useTabStops: true, formatOnPaste: true, automaticLayout: true, lineNumbers: 'on', wordWrap: 'off', scrollBeyondLastLine: false, fixedOverflowWidgets: false, snippetSuggestions: 'top', scrollbar: { vertical: 'auto', horizontal: 'auto', verticalScrollbarSize: 10, horizontalScrollbarSize: 10 } }; function usePrevious(value) { var ref = useRef(null); useEffect(function () { ref.current = value; }, [value]); return ref.current; } function getOrCreateModel(monaco, value, language, path) { if (path) { var prevModel = monaco.editor.getModel(monaco.Uri.parse(path)); if (prevModel) { return prevModel; } } return monaco.editor.createModel(value, language, path ? monaco.Uri.parse(path) : undefined); } function setHighlight(monaco, language, theme) { var themes = themeMap.filter(function (t) { return !!t; }); if (!theme) return; var matchedLanguage = languageMap.includes(language) ? language : 'txt'; createHighlighter({ langs: [matchedLanguage], themes: [theme].concat(_toConsumableArray(themes)) }).then(function (highlighter) { monaco === null || monaco === void 0 || monaco.languages.register({ id: matchedLanguage }); shikiToMonaco(highlighter, monaco); }); } export var useEditor = function useEditor(type, props) { var editorDidMount = props.editorDidMount, editorWillMount = props.editorWillMount, theme = props.theme, value = props.value, path = props.path, language = props.language, saveViewState = props.saveViewState, defaultValue = props.defaultValue, enhancers = props.enhancers, placeholder = props.placeholder; var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), isEditorReady = _useState2[0], setIsEditorReady = _useState2[1]; var _useState3 = useState(false), _useState4 = _slicedToArray(_useState3, 2), focused = _useState4[0], setFocused = _useState4[1]; var _useState5 = useState(false), _useState6 = _slicedToArray(_useState5, 2), loading = _useState6[0], setLoading = _useState6[1]; var defaultValueRef = useRef(defaultValue); var valueRef = useRef(value); var languageRef = useRef(language || 'text'); var pathRef = useRef(path); var previousPath = usePrevious(path); var requireConfigRef = useRef(props.requireConfig); var optionRef = useRef(props.options); var monacoRef = useRef(null); var editorRef = useRef(null); var containerRef = useRef(null); var typeRef = useRef(type); var editorDidMountRef = useRef(null); var editorWillMountRef = useRef(null); var decomposeRef = useRef(false); var viewStatusRef = useRef(new Map()); var enhancersRef = useRef({}); useEffect(function () { enhancersRef.current.enhancers = enhancers; }, [enhancers]); useEffect(function () { editorDidMountRef.current = editorDidMount; }, [editorDidMount]); useEffect(function () { editorWillMountRef.current = editorWillMount; }, [editorWillMount]); useEffect(function () { valueRef.current = value; }, [value]); useEffect(function () { languageRef.current = language; }, [language]); useEffect(function () { defaultValueRef.current = defaultValue; }, [defaultValue]); // make sure loader / editor only init once useEffect(function () { setLoading(true); getMonaco(requireConfigRef.current).then(function (monaco) { var _enhancersRef$current; // 兼容旧版本 monaco-editor 写死 MonacoEnvironment 的问题 window.MonacoEnvironment = undefined; if (typeof window.define === 'function' && window.define.amd) { // make monaco-editor's loader work with webpack's umd loader // @see https://github.com/microsoft/monaco-editor/issues/2283 delete window.define.amd; } monacoRef.current = monaco; try { var _editorWillMountRef$c; setHighlight(monaco, languageRef.current, theme); (_editorWillMountRef$c = editorWillMountRef.current) === null || _editorWillMountRef$c === void 0 || _editorWillMountRef$c.call(editorWillMountRef, monaco); } catch (_unused) {} if (!containerRef.current) { return; } if (editorRef.current) { editorRef.current.dispose(); decomposeRef.current = false; } var editor; if (typeRef.current === 'single') { var _ref, _valueRef$current; var model = getOrCreateModel(monaco, (_ref = (_valueRef$current = valueRef.current) !== null && _valueRef$current !== void 0 ? _valueRef$current : defaultValueRef.current) !== null && _ref !== void 0 ? _ref : '', languageRef.current, pathRef.current); editor = monaco.editor.create(containerRef.current, _objectSpread(_objectSpread({ automaticLayout: true }, INITIAL_OPTIONS), {}, { placeholder: placeholder }, optionRef.current)); editor.setModel(model); } else { var originalModel = monaco.editor.createModel(valueRef.current, languageRef.current); var modifiedModel = monaco.editor.createModel(valueRef.current, languageRef.current); editor = monaco.editor.createDiffEditor(containerRef.current, _objectSpread(_objectSpread({ automaticLayout: true }, DIFF_EDITOR_INITIAL_OPTIONS), {}, { placeholder: placeholder }, optionRef.current)); editor.setModel({ original: originalModel, modified: modifiedModel }); } editorRef.current = editor; (_enhancersRef$current = enhancersRef.current.enhancers) === null || _enhancersRef$current === void 0 || _enhancersRef$current.forEach(function (en) { return en(monaco, editor); }); try { var _editorDidMountRef$cu; (_editorDidMountRef$cu = editorDidMountRef.current) === null || _editorDidMountRef$cu === void 0 || _editorDidMountRef$cu.call(editorDidMountRef, monaco, editor); } catch (_unused2) {} if (!decomposeRef.current) { setIsEditorReady(true); } }).catch(function (error) { // eslint-disable-next-line no-console console.error('Monaco Editor Load Error!', error); }).then(function () { if (!decomposeRef.current) { setLoading(false); } }); }, [placeholder, theme]); useEffect(function () { if (!isEditorReady) { return; } try { var _monacoRef$current; (_monacoRef$current = monacoRef.current) === null || _monacoRef$current === void 0 || _monacoRef$current.editor.setTheme(theme); } catch (_unused3) {} }, [isEditorReady, theme]); // focus status useEffect(function () { if (!isEditorReady) { return; } var editor = type === 'diff' ? editorRef.current.getModifiedEditor() : editorRef.current; editor === null || editor === void 0 || editor.onDidFocusEditorText(function () { if (!decomposeRef.current) { setFocused(true); } }); editor === null || editor === void 0 || editor.onDidBlurEditorText(function () { if (!decomposeRef.current) { setFocused(false); } }); }, [isEditorReady, type]); // decomposing status useEffect(function () { return function () { decomposeRef.current = true; }; }, []); // controlled value -- diff mode / without path only useEffect(function () { var _ref2, _monacoRef$current2, _editor$getOption; if (!isEditorReady) { return; } if (type !== 'diff' && !!path) { return; } var editor = type === 'diff' ? editorRef.current.getModifiedEditor() : editorRef.current; var nextValue = (_ref2 = value !== null && value !== void 0 ? value : defaultValueRef.current) !== null && _ref2 !== void 0 ? _ref2 : ''; var readOnly = (_monacoRef$current2 = monacoRef.current) === null || _monacoRef$current2 === void 0 ? void 0 : _monacoRef$current2.editor.EditorOption.readOnly; if (readOnly && editor !== null && editor !== void 0 && (_editor$getOption = editor.getOption) !== null && _editor$getOption !== void 0 && _editor$getOption.call(editor, readOnly)) { editor === null || editor === void 0 || editor.setValue(nextValue); } else if (value !== (editor === null || editor === void 0 ? void 0 : editor.getValue())) { editor === null || editor === void 0 || editor.executeEdits('', [{ range: editor === null || editor === void 0 ? void 0 : editor.getModel().getFullModelRange(), text: nextValue, forceMoveMarkers: true }]); editor === null || editor === void 0 || editor.pushUndoStop(); } }, [isEditorReady, path, type, value]); // multi-model && controlled value (shouldn't be diff mode) useEffect(function () { var _valueRef$current2, _editorRef$current; if (!isEditorReady) { return; } if (type === 'diff') { return; } if (path === previousPath) { return; } var model = getOrCreateModel(monacoRef.current, (_valueRef$current2 = valueRef.current) !== null && _valueRef$current2 !== void 0 ? _valueRef$current2 : defaultValueRef.current, languageRef.current, path); var editor = editorRef.current; if (valueRef.current !== null && valueRef.current !== undefined && model.getValue() !== valueRef.current) { model.setValue(valueRef.current); } if (model !== ((_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current.getModel())) { if (saveViewState) { viewStatusRef.current.set(previousPath, editor.saveViewState()); } editor.setModel(model); if (saveViewState) { editor.restoreViewState(viewStatusRef.current.get(path)); } } }, [isEditorReady, value, path, previousPath, type, saveViewState]); var retEditorRef = editorRef; return { isEditorReady: isEditorReady, focused: focused, loading: loading, containerRef: containerRef, monacoRef: monacoRef, editorRef: retEditorRef, valueRef: valueRef }; }; export var useFullScreen = function useFullScreen(editor) { var _useState7 = useState(false), _useState8 = _slicedToArray(_useState7, 2), isFullScreen = _useState8[0], setIsFullScreen = _useState8[1]; var fullScreen = function fullScreen() { if (isFullScreen) { setIsFullScreen(false); editor === null || editor === void 0 || editor.updateOptions(_objectSpread(_objectSpread({}, editor === null || editor === void 0 ? void 0 : editor.getOptions()), {}, { minimap: { enabled: false } })); editor === null || editor === void 0 || editor.layout(); return; } setIsFullScreen(true); // 更新小地图配置 editor === null || editor === void 0 || editor.updateOptions(_objectSpread(_objectSpread({}, editor === null || editor === void 0 ? void 0 : editor.getOptions()), {}, { minimap: { enabled: true } })); editor === null || editor === void 0 || editor.layout(); }; return { isFullScreen: isFullScreen, fullScreen: fullScreen }; };