@varlet/schema-repl
Version:
Lightweight Schema repl component based on Vue3
240 lines (235 loc) • 8.27 kB
JavaScript
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
};