UNPKG

lexical-vue

Version:

An extensible Vue 3 web text-editor based on Lexical.

215 lines (214 loc) 10.4 kB
import { computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, ref, toDisplayString, useTemplateRef, watchEffect } from "vue"; const LARGE_EDITOR_STATE_SIZE = 1000; const TreeViewCore = (()=>{ const _hoisted_1 = { key: 0, style: { padding: "20px" } }; const _hoisted_2 = [ "max" ]; const __vine = defineComponent({ name: 'TreeViewCore', props: { editorState: { required: true }, treeTypeButtonClassName: {}, timeTravelButtonClassName: {}, timeTravelPanelButtonClassName: {}, timeTravelPanelClassName: {}, timeTravelPanelSliderClassName: {}, viewClassName: {}, generateContent: { required: true }, setEditorState: { required: true }, setEditorReadOnly: { required: true }, commandsLog: {} }, setup (__props, param) { let { expose: __expose } = param; const props = __props; const preRef = useTemplateRef('preRef'); const timeStampedEditorStates = ref([]); const content = ref(''); const timeTravelEnabled = ref(false); const showExportDOM = ref(false); let playingIndexRef = 0; const inputRef = useTemplateRef('inputRef'); const isPlaying = ref(false); const isLimited = ref(false); const showLimited = ref(false); let lastEditorStateRef = null; let lastCommandsLogRef = []; let lastGenerationID = 0; const totalEditorStates = computed(()=>timeStampedEditorStates.value.length); const generateTree = async (exportDOM)=>{ const myID = ++lastGenerationID; try { const treeText = await props.generateContent(exportDOM); if (myID === lastGenerationID) content.value = treeText; } catch (err) { if (myID === lastGenerationID) content.value = "Error rendering tree: ".concat(err instanceof Error ? err.message : String(err), "\n\nStack:\n").concat(err instanceof Error ? err.stack : 'No stack trace'); } }; watchEffect(()=>{ if (!showLimited.value && props.editorState._nodeMap.size > LARGE_EDITOR_STATE_SIZE) { isLimited.value = true; if (!showLimited) return; } const shouldUpdate = lastEditorStateRef !== props.editorState || lastCommandsLogRef !== props.commandsLog; if (shouldUpdate) { const isEditorStateChange = lastEditorStateRef !== props.editorState; lastEditorStateRef = props.editorState; lastCommandsLogRef = props.commandsLog || []; generateTree(showExportDOM.value); if (!timeTravelEnabled.value && isEditorStateChange) timeStampedEditorStates.value = [ ...timeStampedEditorStates.value, [ Date.now(), props.editorState ] ]; } }); watchEffect((onInvalidate)=>{ if (isPlaying.value) { let timeoutId; const play = ()=>{ const currentIndex = playingIndexRef; if (currentIndex === totalEditorStates.value - 1) { isPlaying.value = false; return; } const currentTime = timeStampedEditorStates.value[currentIndex][0]; const nextTime = timeStampedEditorStates.value[currentIndex + 1][0]; const timeDiff = nextTime - currentTime; timeoutId = setTimeout(()=>{ playingIndexRef++; const index = playingIndexRef; const input = inputRef.value; if (null !== input) input.value = String(index); props.setEditorState(timeStampedEditorStates.value[index][1]); play(); }, timeDiff); }; play(); onInvalidate(()=>{ clearTimeout(timeoutId); }); } }); const handleExportModeToggleClick = ()=>{ generateTree(!showExportDOM.value); showExportDOM.value = !showExportDOM.value; }; const handleTimeTravelClick = ()=>{ props.setEditorReadOnly(true); playingIndexRef = totalEditorStates.value - 1; timeTravelEnabled.value = true; }; const handlePlayPauseClick = ()=>{ if (playingIndexRef === totalEditorStates.value - 1) playingIndexRef = 1; isPlaying.value = !isPlaying.value; }; const handleSliderChange = (event)=>{ const target = event.target; const editorStateIndex = Number(target.value); const timeStampedEditorState = timeStampedEditorStates.value[editorStateIndex]; if (timeStampedEditorState) { playingIndexRef = editorStateIndex; props.setEditorState(timeStampedEditorState[1]); } }; const handleExitTimeTravel = ()=>{ props.setEditorReadOnly(false); const index = timeStampedEditorStates.value.length - 1; const timeStampedEditorState = timeStampedEditorStates.value[index]; props.setEditorState(timeStampedEditorState[1]); const input = inputRef.value; if (null !== input) input.value = String(index); timeTravelEnabled.value = false; isPlaying.value = false; }; const handleShowFullTree = ()=>{ showLimited.value = true; }; __expose({ preRef }); return (_ctx, _cache)=>(openBlock(), createElementBlock("div", { class: normalizeClass(_ctx.viewClassName) }, [ !showLimited.value && isLimited.value ? (openBlock(), createElementBlock("div", _hoisted_1, [ _cache[0] || (_cache[0] = createElementVNode("span", { style: { "margin-right": "20px" } }, " Detected large EditorState, this can impact debugging performance. ", -1)), createElementVNode("button", { onClick: handleShowFullTree, style: { background: "transparent", border: "1px solid white", color: "white", cursor: "pointer", padding: "5px" } }, " Show full tree ") ])) : createCommentVNode("", true), showLimited.value ? createCommentVNode("", true) : (openBlock(), createElementBlock("button", { key: 1, onClick: handleExportModeToggleClick, class: normalizeClass(_ctx.treeTypeButtonClassName), type: "button" }, toDisplayString(showExportDOM.value ? 'Tree' : 'Export DOM'), 3)), !timeTravelEnabled.value && (showLimited.value || !isLimited.value) && totalEditorStates.value > 2 ? (openBlock(), createElementBlock("button", { key: 2, onClick: handleTimeTravelClick, class: normalizeClass(_ctx.timeTravelButtonClassName), type: "button" }, " Time Travel ", 2)) : createCommentVNode("", true), showLimited.value || !isLimited.value ? (openBlock(), createElementBlock("pre", { key: 3, ref_key: "preRef", ref: preRef }, toDisplayString(content.value), 513)) : createCommentVNode("", true), timeTravelEnabled.value && (showLimited.value || !isLimited.value) ? (openBlock(), createElementBlock("div", { key: 4, class: normalizeClass(_ctx.timeTravelPanelClassName) }, [ createElementVNode("button", { class: normalizeClass(_ctx.timeTravelPanelButtonClassName), onClick: handlePlayPauseClick, type: "button" }, toDisplayString(isPlaying.value ? 'Pause' : 'Play'), 3), createElementVNode("input", { class: normalizeClass(_ctx.timeTravelPanelSliderClassName), ref_key: "inputRef", ref: inputRef, onChange: handleSliderChange, type: "range", min: "1", max: totalEditorStates.value - 1 }, null, 42, _hoisted_2), createElementVNode("button", { class: normalizeClass(_ctx.timeTravelPanelButtonClassName), onClick: handleExitTimeTravel, type: "button" }, " Exit ", 2) ], 2)) : createCommentVNode("", true) ], 2)); } }); __vine.__vue_vine = true; return __vine; })(); export { TreeViewCore };