UNPKG

@varlet/schema-repl

Version:

Lightweight Schema repl component based on Vue3

240 lines (235 loc) 8.27 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); // src/index.ts export * from "@varlet/schema-renderer"; // src/repl.tsx import { withDirectives as _withDirectives, vShow as _vShow, createVNode as _createVNode } from "vue"; import * as monaco from "monaco-editor"; import { defineComponent, onMounted, ref, onUnmounted, watch, shallowRef, computed } from "vue"; import { SchemaRenderer } from "@varlet/schema-renderer"; import { useVModel, useWindowSize } from "@varlet/use"; import { call, classes } from "@varlet/shared"; // src/monacoWorkers.ts import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"; import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker"; import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker"; import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker"; import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker"; self.MonacoEnvironment = { getWorker(_, label) { if (label === "json") { return new jsonWorker(); } if (label === "css" || label === "scss" || label === "less") { return new cssWorker(); } if (label === "html" || label === "handlebars" || label === "razor") { return new htmlWorker(); } if (label === "typescript" || label === "javascript") { return new tsWorker(); } return new editorWorker(); } }; // src/repl.tsx var DESKTOP_BREAKPOINT = 720; var INTERNAL_INJECTS_KEYS = ["h", "ref", "reactive", "computed", "readonly", "watch", "watchEffect", "watchSyncEffect", "watchPostEffect", "isRef", "unref", "toRefs", "isProxy", "isReactive", "isReadonly", "onBeforeMount", "onMounted", "onBeforeUpdate", "onUpdated", "onBeforeUnmount", "onUnmounted", "axle"]; var SchemaRepl = defineComponent({ props: { schema: { type: Object, default: () => ({}) }, components: { type: Object, default: () => ({}) }, injects: { type: Object, default: () => ({}) }, theme: { type: String, default: "vs" }, activeTab: { type: String, default: "JSON" }, editorFontSize: { type: Number, default: 13 }, onChange: { type: [Function, Array] }, "onUpdate:activeTab": { type: [Function, Array] } }, setup(props) { const schema = shallowRef(props.schema); const editorContainer = ref(null); const activeTab = useVModel(props, "activeTab"); const showEditor = ref(true); const tabs = ref(["JSON", "SCRIPT", "CSS"]); const { width: windowWidth } = useWindowSize(); const isDesktop = computed(() => windowWidth.value > DESKTOP_BREAKPOINT); let editor2; let completionProvider; onMounted(setupMonaco); onUnmounted(() => { editor2.dispose(); completionProvider.dispose(); }); watch(() => [props.theme, props.schema], refreshEditor); function setupMonaco() { editor2 = monaco.editor.create(editorContainer.value, getOptions()); editor2.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, updateSchema); monaco.languages.registerCompletionItemProvider("javascript", { provideCompletionItems(model, position) { const word = model.getWordUntilPosition(position); const range = { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: word.startColumn, endColumn: word.endColumn }; return { suggestions: [...INTERNAL_INJECTS_KEYS, ...Object.keys(props.injects)].map((name) => ({ label: name, kind: monaco.languages.CompletionItemKind.Variable, insertText: name, range })) }; } }); } function refreshEditor() { const options = getOptions(); editor2.updateOptions(options); editor2.setValue(options.value); monaco.editor.setModelLanguage(editor2.getModel(), options.language); schema.value = props.schema; } function getOptions() { var _a, _b; const defaultOptions = { scrollBeyondLastLine: false, fontSize: props.editorFontSize, theme: props.theme, automaticLayout: true, minimap: { enabled: false } }; if (activeTab.value === "JSON") { return __spreadProps(__spreadValues({}, defaultOptions), { value: JSON.stringify(props.schema, null, 2), language: "json" }); } if (activeTab.value === "SCRIPT") { return __spreadProps(__spreadValues({}, defaultOptions), { value: (_a = props.schema.code) != null ? _a : "function setup() {}", language: "javascript" }); } return __spreadProps(__spreadValues({}, defaultOptions), { value: (_b = props.schema.css) != null ? _b : "", language: "css" }); } function clone(value) { return JSON.parse(JSON.stringify(value)); } function updateSchema() { const editorValue = editor2.getValue(); let value = ""; if (activeTab.value === "JSON") { value = editorValue; } if (activeTab.value === "SCRIPT") { const clonedSchema = clone(schema.value); clonedSchema.code = editorValue; value = JSON.stringify(clonedSchema); } if (activeTab.value === "CSS") { const clonedSchema = clone(schema.value); clonedSchema.css = editorValue; value = JSON.stringify(clonedSchema); } try { const newValue = JSON.parse(value); if (value !== JSON.stringify(schema.value)) { call(props.onChange, newValue); } schema.value = newValue; } catch (e) { alert("JSON parse error"); } } function handleTabClick(tab) { activeTab.value = tab; refreshEditor(); } function handleTransferClick() { showEditor.value = !showEditor.value; } function renderTabs() { return tabs.value.map((tab) => _createVNode("div", { "class": classes("var-schema-repl-tab", [tab === activeTab.value, "var-schema-repl-tab-active"]), "onClick": () => handleTabClick(tab) }, [tab])); } return () => { return _createVNode("div", { "class": classes("var-schema-repl", [props.theme === "vs-dark", "var-schema-repl-vs-dark"]) }, [_createVNode("div", { "class": "var-schema-repl-tab-container" }, [renderTabs()]), _createVNode("div", { "class": "var-schema-repl-editor-container" }, [_withDirectives(_createVNode("div", { "class": "var-schema-repl-editor", "style": { width: isDesktop.value ? "50%" : "100%" }, "ref": editorContainer }, null), [[_vShow, isDesktop.value || showEditor.value]]), _withDirectives(_createVNode(SchemaRenderer, { "style": { width: isDesktop.value ? "50%" : "100%" }, "schema": schema.value, "components": props.components, "injects": props.injects }, null), [[_vShow, isDesktop.value || !showEditor.value]]), !isDesktop.value && _createVNode("button", { "class": "var-schema-repl-transfer", "onClick": handleTransferClick }, [showEditor.value ? "SHOW PREVIEW" : "SHOW EDITOR"])])]); }; } }); export { SchemaRepl };