UNPKG

lexical-vue

Version:

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

1,418 lines (1,392 loc) 170 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { $createDecoratorBlockNode: () => $createDecoratorBlockNode, $createHorizontalRuleNode: () => $createHorizontalRuleNode, $isDecoratorBlockNode: () => $isDecoratorBlockNode, $isHorizontalRuleNode: () => $isHorizontalRuleNode, AutoEmbedOption: () => AutoEmbedOption, DecoratorBlockNode: () => DecoratorBlockNode, HR: () => HR, HorizontalRuleNode: () => HorizontalRuleNode, INSERT_EMBED_COMMAND: () => INSERT_EMBED_COMMAND, INSERT_HORIZONTAL_RULE_COMMAND: () => INSERT_HORIZONTAL_RULE_COMMAND, LexicalAutoEmbedPlugin: () => LexicalAutoEmbedPlugin_default, LexicalAutoFocusPlugin: () => LexicalAutoFocusPlugin_default, LexicalAutoLinkPlugin: () => LexicalAutoLinkPlugin_default, LexicalAutoScrollPlugin: () => LexicalAutoScrollPlugin_default, LexicalBlockWithAlignableContents: () => LexicalBlockWithAlignableContents_default, LexicalCharacterLimitPlugin: () => LexicalCharacterLimitPlugin_default, LexicalCheckListPlugin: () => LexicalCheckListPlugin_default, LexicalClearEditorPlugin: () => LexicalClearEditorPlugin_default, LexicalClickableLinkPlugin: () => LexicalClickableLinkPlugin_default, LexicalCollaborationPlugin: () => LexicalCollaborationPlugin_default, LexicalComposer: () => LexicalComposer_default, LexicalContentEditable: () => LexicalContentEditable_default, LexicalContextMenuPlugin: () => LexicalContextMenuPlugin_default, LexicalDecoratedTeleports: () => LexicalDecoratedTeleports_default, LexicalHashtagPlugin: () => LexicalHashtagPlugin_default, LexicalHistoryPlugin: () => LexicalHistoryPlugin_default, LexicalLinkPlugin: () => LexicalLinkPlugin_default, LexicalListPlugin: () => LexicalListPlugin_default, LexicalMarkdownShortcutPlugin: () => LexicalMarkdownShortcutPlugin_default, LexicalNodeMenuPlugin: () => LexicalNodeMenuPlugin_default, LexicalOnChangePlugin: () => LexicalOnChangePlugin_default, LexicalPlainTextPlugin: () => LexicalPlainTextPlugin_default, LexicalRichTextPlugin: () => LexicalRichTextPlugin_default, LexicalTabIndentationPlugin: () => LexicalTabIndentationPlugin_default, LexicalTablePlugin: () => LexicalTablePlugin_default, LexicalTreeViewPlugin: () => LexicalTreeViewPlugin_default, LexicalTypeaheadMenuPlugin: () => LexicalTypeaheadMenuPlugin_default, MenuOption: () => MenuOption2, URL_MATCHER: () => URL_MATCHER, createLinkMatcherWithRegExp: () => createLinkMatcherWithRegExp, mergePrevious: () => mergePrevious, useBasicTypeaheadTriggerMatch: () => useBasicTypeaheadTriggerMatch, useCanShowPlaceholder: () => useCanShowPlaceholder, useCharacterLimit: () => useCharacterLimit, useDecorators: () => useDecorators, useEffect: () => useEffect, useHistory: () => useHistory, useLexicalCommandsLog: () => useLexicalCommandsLog, useLexicalComposer: () => useLexicalComposer, useLexicalIsTextContentEmpty: () => useLexicalIsTextContentEmpty, useLexicalNodeSelection: () => useLexicalNodeSelection, useLexicalTextEntity: () => useLexicalTextEntity, useList: () => useList, useMounted: () => useMounted, usePlainTextSetup: () => usePlainTextSetup, useRichTextSetup: () => useRichTextSetup, useTableOfContents: () => useTableOfContents, useYjsCollaboration: () => useYjsCollaboration, useYjsFocusTracking: () => useYjsFocusTracking, useYjsHistory: () => useYjsHistory }); module.exports = __toCommonJS(index_exports); // src/composables/useCanShowPlaceholder.ts var import_vue2 = require("vue"); var import_text = require("@lexical/text"); var import_utils = require("@lexical/utils"); // src/composables/useMounted.ts var import_vue = require("vue"); function useMounted(cb) { let unregister; (0, import_vue.onMounted)(() => { unregister = cb(); }); (0, import_vue.onUnmounted)(() => { unregister?.(); }); } // src/composables/useCanShowPlaceholder.ts function canShowPlaceholderFromCurrentEditorState(editor) { const currentCanShowPlaceholder = editor.getEditorState().read((0, import_text.$canShowPlaceholderCurry)(editor.isComposing())); return currentCanShowPlaceholder; } function useCanShowPlaceholder(editor) { const initialState = editor.getEditorState().read((0, import_text.$canShowPlaceholderCurry)(editor.isComposing())); const canShowPlaceholder = (0, import_vue2.ref)(initialState); function resetCanShowPlaceholder() { const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor); canShowPlaceholder.value = currentCanShowPlaceholder; } useMounted(() => { return (0, import_utils.mergeRegister)( editor.registerUpdateListener(() => { resetCanShowPlaceholder(); }), editor.registerEditableListener(() => { resetCanShowPlaceholder(); }) ); }); return (0, import_vue2.readonly)(canShowPlaceholder); } // src/composables/useCharacterLimit.ts var import_overflow = require("@lexical/overflow"); var import_text2 = require("@lexical/text"); var import_utils2 = require("@lexical/utils"); var import_lexical = require("lexical"); var import_tiny_invariant = __toESM(require("tiny-invariant"), 1); var import_vue3 = require("vue"); function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({})) { (0, import_vue3.watchEffect)((onInvalidate) => { if (!editor.hasNodes([import_overflow.OverflowNode])) { (0, import_tiny_invariant.default)( false, "useCharacterLimit: OverflowNode not registered on editor" ); } const { strlen = (input) => input.length, // UTF-16 remainingCharacters = (_characters) => { } } = (0, import_vue3.toValue)(optional); let text = editor.getEditorState().read(import_text2.$rootTextContent); let lastComputedTextLength = 0; const fn = (0, import_utils2.mergeRegister)( editor.registerTextContentListener((currentText) => { text = currentText; }), editor.registerUpdateListener(({ dirtyLeaves }) => { const isComposing = editor.isComposing(); const hasDirtyLeaves = dirtyLeaves.size > 0; if (isComposing || !hasDirtyLeaves) return; const textLength = strlen(text); const textLengthAboveThreshold = textLength > (0, import_vue3.toValue)(maxCharacters) || lastComputedTextLength !== null && lastComputedTextLength > (0, import_vue3.toValue)(maxCharacters); const diff = (0, import_vue3.toValue)(maxCharacters) - textLength; remainingCharacters(diff); if (lastComputedTextLength === null || textLengthAboveThreshold) { const offset = findOffset(text, (0, import_vue3.toValue)(maxCharacters), strlen); editor.update( () => { $wrapOverflowedNodes(offset); }, { tag: "history-merge" } ); } lastComputedTextLength = textLength; }) ); onInvalidate(() => { fn(); }); }); } function findOffset(text, maxCharacters, strlen) { const Segmenter = Intl.Segmenter; let offsetUtf16 = 0; let offset = 0; if (typeof Segmenter === "function") { const segmenter = new Segmenter(); const graphemes = segmenter.segment(text); for (const { segment: grapheme } of graphemes) { const nextOffset = offset + strlen(grapheme); if (nextOffset > maxCharacters) break; offset = nextOffset; offsetUtf16 += grapheme.length; } } else { const codepoints = Array.from(text); const codepointsLength = codepoints.length; for (let i = 0; i < codepointsLength; i++) { const codepoint = codepoints[i]; const nextOffset = offset + strlen(codepoint); if (nextOffset > maxCharacters) break; offset = nextOffset; offsetUtf16 += codepoint.length; } } return offsetUtf16; } function $wrapOverflowedNodes(offset) { const dfsNodes = (0, import_utils2.$dfs)(); const dfsNodesLength = dfsNodes.length; let accumulatedLength = 0; for (let i = 0; i < dfsNodesLength; i += 1) { const { node } = dfsNodes[i]; if ((0, import_overflow.$isOverflowNode)(node)) { const previousLength = accumulatedLength; const nextLength = accumulatedLength + node.getTextContentSize(); if (nextLength <= offset) { const parent = node.getParent(); const previousSibling = node.getPreviousSibling(); const nextSibling = node.getNextSibling(); $unwrapNode(node); const selection = (0, import_lexical.$getSelection)(); if ((0, import_lexical.$isRangeSelection)(selection) && (!selection.anchor.getNode().isAttached() || !selection.focus.getNode().isAttached())) { if ((0, import_lexical.$isTextNode)(previousSibling)) previousSibling.select(); else if ((0, import_lexical.$isTextNode)(nextSibling)) nextSibling.select(); else if (parent !== null) parent.select(); } } else if (previousLength < offset) { const descendant = node.getFirstDescendant(); const descendantLength = descendant !== null ? descendant.getTextContentSize() : 0; const previousPlusDescendantLength = previousLength + descendantLength; const firstDescendantIsSimpleText = (0, import_lexical.$isTextNode)(descendant) && descendant.isSimpleText(); const firstDescendantDoesNotOverflow = previousPlusDescendantLength <= offset; if (firstDescendantIsSimpleText || firstDescendantDoesNotOverflow) $unwrapNode(node); } } else if ((0, import_lexical.$isLeafNode)(node)) { const previousAccumulatedLength = accumulatedLength; accumulatedLength += node.getTextContentSize(); if (accumulatedLength > offset && !(0, import_overflow.$isOverflowNode)(node.getParent())) { const previousSelection = (0, import_lexical.$getSelection)(); let overflowNode; if (previousAccumulatedLength < offset && (0, import_lexical.$isTextNode)(node) && node.isSimpleText()) { const [, overflowedText] = node.splitText( offset - previousAccumulatedLength ); overflowNode = $wrapNode(overflowedText); } else { overflowNode = $wrapNode(node); } if (previousSelection !== null) (0, import_lexical.$setSelection)(previousSelection); mergePrevious(overflowNode); } } } } function $wrapNode(node) { const overflowNode = (0, import_overflow.$createOverflowNode)(); node.insertBefore(overflowNode); overflowNode.append(node); return overflowNode; } function $unwrapNode(node) { const children = node.getChildren(); const childrenLength = children.length; for (let i = 0; i < childrenLength; i++) node.insertBefore(children[i]); node.remove(); return childrenLength > 0 ? children[childrenLength - 1] : null; } function mergePrevious(overflowNode) { const previousNode = overflowNode.getPreviousSibling(); if (!(0, import_overflow.$isOverflowNode)(previousNode)) return; const firstChild = overflowNode.getFirstChild(); const previousNodeChildren = previousNode.getChildren(); const previousNodeChildrenLength = previousNodeChildren.length; if (firstChild === null) { overflowNode.append(...previousNodeChildren); } else { for (let i = 0; i < previousNodeChildrenLength; i++) firstChild.insertBefore(previousNodeChildren[i]); } const selection = (0, import_lexical.$getSelection)(); if ((0, import_lexical.$isRangeSelection)(selection)) { const anchor = selection.anchor; const anchorNode = anchor.getNode(); const focus = selection.focus; const focusNode = anchor.getNode(); if (anchorNode.is(previousNode)) { anchor.set(overflowNode.getKey(), anchor.offset, "element"); } else if (anchorNode.is(overflowNode)) { anchor.set( overflowNode.getKey(), previousNodeChildrenLength + anchor.offset, "element" ); } if (focusNode.is(previousNode)) { focus.set(overflowNode.getKey(), focus.offset, "element"); } else if (focusNode.is(overflowNode)) { focus.set( overflowNode.getKey(), previousNodeChildrenLength + focus.offset, "element" ); } } previousNode.remove(); } // src/composables/useDecorators.ts var import_vue4 = require("vue"); function useDecorators(editor) { const decorators = (0, import_vue4.shallowRef)(editor.getDecorators()); useMounted(() => { return editor.registerDecoratorListener((nextDecorators) => { decorators.value = nextDecorators; }); }); return (0, import_vue4.computed)(() => { const decoratedTeleports = []; const decoratorKeys = Object.keys((0, import_vue4.unref)(decorators)); for (let i = 0; i < decoratorKeys.length; i++) { const nodeKey = decoratorKeys[i]; const vueDecorator = decorators.value[nodeKey]; const element = editor.getElementByKey(nodeKey); if (element !== null) { decoratedTeleports.push( (0, import_vue4.h)(import_vue4.Teleport, { to: element }, vueDecorator) ); } } return decoratedTeleports; }); } // src/composables/useEffect.ts var import_vue5 = require("vue"); function useEffect(cb, options) { (0, import_vue5.watchEffect)((onInvalidate) => { const unregister = cb(); onInvalidate(() => unregister?.()); }, { ...options }); } // src/composables/useHistory.ts var import_vue6 = require("vue"); var import_history = require("@lexical/history"); function useHistory(editor, externalHistoryState, delay) { const historyState = (0, import_vue6.computed)( () => (0, import_vue6.toValue)(externalHistoryState) || (0, import_history.createEmptyHistoryState)() ); (0, import_vue6.watchEffect)((onInvalidate) => { const unregisterListener = (0, import_history.registerHistory)((0, import_vue6.toValue)(editor), historyState.value, (0, import_vue6.toValue)(delay) || 1e3); onInvalidate(unregisterListener); }); } // src/composables/useLexicalCommandsLog.ts var import_lexical2 = require("lexical"); var import_vue7 = require("vue"); function useLexicalCommandsLog(editor) { const loggedCommands = (0, import_vue7.ref)([]); useMounted(() => { const unregisterCommandListeners = /* @__PURE__ */ new Set(); for (const [command] of editor._commands) { unregisterCommandListeners.add( editor.registerCommand( command, (payload) => { loggedCommands.value = [ ...loggedCommands.value, { payload, type: command.type ? command.type : "UNKNOWN" } ]; if (loggedCommands.value.length > 10) loggedCommands.value.shift(); return false; }, import_lexical2.COMMAND_PRIORITY_HIGH ) ); } return () => { unregisterCommandListeners.forEach((unregister) => unregister()); }; }); return (0, import_vue7.readonly)(loggedCommands); } // src/composables/useLexicalComposer.ts var import_vue8 = require("vue"); var import_tiny_invariant2 = __toESM(require("tiny-invariant"), 1); // src/composables/inject.ts var LexicalEditorProviderKey = "LexicalEditorProviderKey"; // src/composables/useLexicalComposer.ts function useLexicalComposer() { const editor = (0, import_vue8.inject)(LexicalEditorProviderKey); if (!editor) { (0, import_tiny_invariant2.default)( false, "useLexicalComposer: cannot find a LexicalComposer" ); } return editor; } // src/composables/useLexicalIsTextContentEmpty.ts var import_vue9 = require("vue"); var import_text3 = require("@lexical/text"); function useLexicalIsTextContentEmpty(editor, trim) { const isEmpty = (0, import_vue9.ref)( editor.getEditorState().read((0, import_text3.$isRootTextContentEmptyCurry)(editor.isComposing(), trim)) ); useMounted(() => { return editor.registerUpdateListener(({ editorState }) => { const isComposing = editor.isComposing(); isEmpty.value = editorState.read( (0, import_text3.$isRootTextContentEmptyCurry)(isComposing, trim) ); }); }); return (0, import_vue9.readonly)(isEmpty); } // src/composables/useLexicalNodeSelection.ts var import_lexical3 = require("lexical"); var import_vue10 = require("vue"); function isNodeSelected(editor, key) { return editor.getEditorState().read(() => { const node = (0, import_lexical3.$getNodeByKey)(key); if (node === null) return false; return node.isSelected(); }); } function useLexicalNodeSelection(key) { const editor = useLexicalComposer(); const isSelected = (0, import_vue10.ref)(isNodeSelected(editor, (0, import_vue10.toValue)(key))); (0, import_vue10.watchEffect)((onInvalidate) => { const unregisterListener = editor.registerUpdateListener(() => { isSelected.value = isNodeSelected(editor, (0, import_vue10.toValue)(key)); }); onInvalidate(() => { unregisterListener(); }); }); const setSelected = (selected) => { editor.update(() => { let selection = (0, import_lexical3.$getSelection)(); if (!(0, import_lexical3.$isNodeSelection)(selection)) { selection = (0, import_lexical3.$createNodeSelection)(); (0, import_lexical3.$setSelection)(selection); } if ((0, import_lexical3.$isNodeSelection)(selection)) { if (selected) selection.add((0, import_vue10.toValue)(key)); else selection.delete((0, import_vue10.toValue)(key)); } }); }; const clearSelection = () => { editor.update(() => { const selection = (0, import_lexical3.$getSelection)(); if ((0, import_lexical3.$isNodeSelection)(selection)) selection.clear(); }); }; return { isSelected: (0, import_vue10.readonly)(isSelected), setSelected, clearSelection }; } // src/composables/useLexicalTextEntity.ts var import_text4 = require("@lexical/text"); var import_utils3 = require("@lexical/utils"); function useLexicalTextEntity(getMatch, targetNode, createNode) { const editor = useLexicalComposer(); useMounted(() => { return (0, import_utils3.mergeRegister)( ...(0, import_text4.registerLexicalTextEntity)(editor, getMatch, targetNode, createNode) ); }); } // src/composables/useList.ts var import_list = require("@lexical/list"); var import_utils4 = require("@lexical/utils"); var import_lexical4 = require("lexical"); function useList(editor) { useMounted(() => { return (0, import_utils4.mergeRegister)( editor.registerCommand( import_list.INSERT_ORDERED_LIST_COMMAND, () => { (0, import_list.insertList)(editor, "number"); return true; }, import_lexical4.COMMAND_PRIORITY_LOW ), editor.registerCommand( import_list.INSERT_UNORDERED_LIST_COMMAND, () => { (0, import_list.insertList)(editor, "bullet"); return true; }, import_lexical4.COMMAND_PRIORITY_LOW ), editor.registerCommand( import_list.REMOVE_LIST_COMMAND, () => { (0, import_list.removeList)(editor); return true; }, import_lexical4.COMMAND_PRIORITY_LOW ), editor.registerCommand( import_lexical4.INSERT_PARAGRAPH_COMMAND, () => { const hasHandledInsertParagraph = (0, import_list.$handleListInsertParagraph)(); if (hasHandledInsertParagraph) return true; return false; }, import_lexical4.COMMAND_PRIORITY_LOW ) ); }); } // src/composables/usePlainTextSetup.ts var import_dragon = require("@lexical/dragon"); var import_plain_text = require("@lexical/plain-text"); var import_utils5 = require("@lexical/utils"); function usePlainTextSetup(editor) { useMounted(() => { return (0, import_utils5.mergeRegister)( (0, import_plain_text.registerPlainText)(editor), (0, import_dragon.registerDragonSupport)(editor) ); }); } // src/composables/useRichTextSetup.ts var import_dragon2 = require("@lexical/dragon"); var import_rich_text = require("@lexical/rich-text"); var import_utils6 = require("@lexical/utils"); function useRichTextSetup(editor) { useMounted(() => { return (0, import_utils6.mergeRegister)( (0, import_rich_text.registerRichText)(editor), (0, import_dragon2.registerDragonSupport)(editor) ); }); } // src/composables/useTableOfContents.ts var import_rich_text2 = require("@lexical/rich-text"); var import_utils7 = require("@lexical/utils"); var import_lexical5 = require("lexical"); var import_vue11 = require("vue"); function toEntry(heading) { return [heading.getKey(), heading.getTextContent(), heading.getTag()]; } function $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents) { if (newHeading === null) return currentTableOfContents; const newEntry = toEntry(newHeading); let newTableOfContents = []; if (prevHeading === null) { if (currentTableOfContents.length > 0 && currentTableOfContents[0][0] === newHeading.__key) { return currentTableOfContents; } newTableOfContents = [newEntry, ...currentTableOfContents]; } else { for (let i = 0; i < currentTableOfContents.length; i++) { const key = currentTableOfContents[i][0]; newTableOfContents.push(currentTableOfContents[i]); if (key === prevHeading.getKey() && key !== newHeading.getKey()) { if (i + 1 < currentTableOfContents.length && currentTableOfContents[i + 1][0] === newHeading.__key) { return currentTableOfContents; } newTableOfContents.push(newEntry); } } } return newTableOfContents; } function $deleteHeadingFromTableOfContents(key, currentTableOfContents) { const newTableOfContents = []; for (const heading of currentTableOfContents) { if (heading[0] !== key) newTableOfContents.push(heading); } return newTableOfContents; } function $updateHeadingInTableOfContents(heading, currentTableOfContents) { const newTableOfContents = []; for (const oldHeading of currentTableOfContents) { if (oldHeading[0] === heading.getKey()) newTableOfContents.push(toEntry(heading)); else newTableOfContents.push(oldHeading); } return newTableOfContents; } function $updateHeadingPosition(prevHeading, heading, currentTableOfContents) { const newTableOfContents = []; const newEntry = toEntry(heading); if (!prevHeading) newTableOfContents.push(newEntry); for (const oldHeading of currentTableOfContents) { if (oldHeading[0] === heading.getKey()) continue; newTableOfContents.push(oldHeading); if (prevHeading && oldHeading[0] === prevHeading.getKey()) newTableOfContents.push(newEntry); } return newTableOfContents; } function $getPreviousHeading(node) { let prevHeading = (0, import_utils7.$getNextRightPreorderNode)(node); while (prevHeading !== null && !(0, import_rich_text2.$isHeadingNode)(prevHeading)) prevHeading = (0, import_utils7.$getNextRightPreorderNode)(prevHeading); return prevHeading; } function useTableOfContents(editor) { const tableOfContents = (0, import_vue11.ref)([]); editor.getEditorState().read(() => { const root = (0, import_lexical5.$getRoot)(); const rootChildren = root.getChildren(); for (const child of rootChildren) { if ((0, import_rich_text2.$isHeadingNode)(child)) { tableOfContents.value.push([ child.getKey(), child.getTextContent(), child.getTag() ]); } } }); const removeRootUpdateListener = editor.registerUpdateListener( ({ editorState, dirtyElements }) => { editorState.read(() => { const updateChildHeadings = (node) => { for (const child of node.getChildren()) { if ((0, import_rich_text2.$isHeadingNode)(child)) { const prevHeading = $getPreviousHeading(child); tableOfContents.value = $updateHeadingPosition( prevHeading, child, tableOfContents.value ); } else if ((0, import_lexical5.$isElementNode)(child)) { updateChildHeadings(child); } } }; (0, import_lexical5.$getRoot)().getChildren().forEach((node) => { if ((0, import_lexical5.$isElementNode)(node) && dirtyElements.get(node.__key)) updateChildHeadings(node); }); }); } ); const removeHeaderMutationListener = editor.registerMutationListener( import_rich_text2.HeadingNode, (mutatedNodes) => { editor.getEditorState().read(() => { for (const [nodeKey, mutation] of mutatedNodes) { if (mutation === "created") { const newHeading = (0, import_lexical5.$getNodeByKey)(nodeKey); if (newHeading !== null) { const prevHeading = $getPreviousHeading(newHeading); tableOfContents.value = $insertHeadingIntoTableOfContents( prevHeading, newHeading, tableOfContents.value ); } } else if (mutation === "destroyed") { tableOfContents.value = $deleteHeadingFromTableOfContents( nodeKey, tableOfContents.value ); } else if (mutation === "updated") { const newHeading = (0, import_lexical5.$getNodeByKey)(nodeKey); if (newHeading !== null) { const prevHeading = $getPreviousHeading(newHeading); tableOfContents.value = $updateHeadingPosition( prevHeading, newHeading, tableOfContents.value ); } } } }); } ); const removeTextNodeMutationListener = editor.registerMutationListener( import_lexical5.TextNode, (mutatedNodes) => { editor.getEditorState().read(() => { for (const [nodeKey, mutation] of mutatedNodes) { if (mutation === "updated") { const currNode = (0, import_lexical5.$getNodeByKey)(nodeKey); if (currNode !== null) { const parentNode = currNode.getParentOrThrow(); if ((0, import_rich_text2.$isHeadingNode)(parentNode)) { tableOfContents.value = $updateHeadingInTableOfContents( parentNode, tableOfContents.value ); } } } } }); } ); useMounted(() => (0, import_utils7.mergeRegister)( removeRootUpdateListener, removeHeaderMutationListener, removeTextNodeMutationListener )); return tableOfContents; } // src/composables/useYjsCollaboration.ts var import_utils8 = require("@lexical/utils"); var import_yjs = require("@lexical/yjs"); var import_lexical6 = require("lexical"); var import_yjs2 = require("yjs"); var import_vue12 = require("vue"); function useYjsCollaboration(editor, id, provider, docMap, name, color, shouldBootstrap, initialEditorState, excludedProperties, awarenessData) { const isReloadingDoc = (0, import_vue12.ref)(false); const doc = (0, import_vue12.ref)(docMap.get(id)); const binding = (0, import_vue12.computed)(() => (0, import_yjs.createBinding)(editor, provider, id, (0, import_vue12.toRaw)(doc.value), docMap, excludedProperties)); const connect = () => { provider.connect(); }; const disconnect = () => { try { provider.disconnect(); } catch { } }; useEffect(() => { const { root } = binding.value; const { awareness } = provider; const onStatus = ({ status }) => { editor.dispatchCommand(import_yjs.CONNECTED_COMMAND, status === "connected"); }; const onSync = (isSynced) => { if (shouldBootstrap && isSynced && root.isEmpty() && root._xmlText._length === 0 && isReloadingDoc.value === false) { initializeEditor(editor, initialEditorState); } isReloadingDoc.value = false; }; const onAwarenessUpdate = () => { (0, import_yjs.syncCursorPositions)(binding.value, provider); }; const onYjsTreeChanges = (events, transaction) => { const origin = transaction.origin; if ((0, import_vue12.toRaw)(origin) !== binding.value) { const isFromUndoManger = origin instanceof import_yjs2.UndoManager; (0, import_yjs.syncYjsChangesToLexical)(binding.value, provider, events, isFromUndoManger); } }; (0, import_yjs.initLocalState)( provider, name, color, document.activeElement === editor.getRootElement(), awarenessData || {} ); const onProviderDocReload = (ydoc) => { clearEditorSkipCollab(editor, binding.value); doc.value = ydoc; docMap.set(id, ydoc); isReloadingDoc.value = true; }; provider.on("reload", onProviderDocReload); provider.on("status", onStatus); provider.on("sync", onSync); awareness.on("update", onAwarenessUpdate); root.getSharedType().observeDeep(onYjsTreeChanges); const removeListener = editor.registerUpdateListener( ({ prevEditorState, editorState, dirtyLeaves, dirtyElements, normalizedNodes, tags }) => { if (tags.has("skip-collab") === false) { (0, import_yjs.syncLexicalUpdateToYjs)( binding.value, provider, prevEditorState, editorState, dirtyElements, dirtyLeaves, normalizedNodes, tags ); } } ); connect(); return () => { if (isReloadingDoc.value === false) disconnect(); provider.off("sync", onSync); provider.off("status", onStatus); provider.off("reload", onProviderDocReload); awareness.off("update", onAwarenessUpdate); root.getSharedType().unobserveDeep(onYjsTreeChanges); docMap.delete(id); removeListener(); }; }); useEffect(() => { return editor.registerCommand( import_yjs.TOGGLE_CONNECT_COMMAND, (payload) => { if (connect !== void 0 && disconnect !== void 0) { const shouldConnect = payload; if (shouldConnect) { console.log("Collaboration connected!"); connect(); } else { console.log("Collaboration disconnected!"); disconnect(); } } return true; }, import_lexical6.COMMAND_PRIORITY_EDITOR ); }); return binding; } function useYjsFocusTracking(editor, provider, name, color, awarenessData) { useEffect(() => { return (0, import_utils8.mergeRegister)( editor.registerCommand( import_lexical6.FOCUS_COMMAND, () => { (0, import_yjs.setLocalStateFocus)(provider, name, color, true, awarenessData || {}); return false; }, import_lexical6.COMMAND_PRIORITY_EDITOR ), editor.registerCommand( import_lexical6.BLUR_COMMAND, () => { (0, import_yjs.setLocalStateFocus)(provider, name, color, false, awarenessData || {}); return false; }, import_lexical6.COMMAND_PRIORITY_EDITOR ) ); }); } function useYjsHistory(editor, binding) { const undoManager = (0, import_vue12.computed)(() => (0, import_yjs.createUndoManager)(binding, binding.root.getSharedType())); useEffect(() => { const undo = () => { undoManager.value.undo(); }; const redo = () => { undoManager.value.redo(); }; return (0, import_utils8.mergeRegister)( editor.registerCommand( import_lexical6.UNDO_COMMAND, () => { undo(); return true; }, import_lexical6.COMMAND_PRIORITY_EDITOR ), editor.registerCommand( import_lexical6.REDO_COMMAND, () => { redo(); return true; }, import_lexical6.COMMAND_PRIORITY_EDITOR ) ); }); const clearHistory = () => { undoManager.value.clear(); }; return clearHistory; } function initializeEditor(editor, initialEditorState) { editor.update( () => { const root = (0, import_lexical6.$getRoot)(); if (root.isEmpty()) { if (initialEditorState) { switch (typeof initialEditorState) { case "string": { const parsedEditorState = editor.parseEditorState(initialEditorState); editor.setEditorState(parsedEditorState, { tag: "history-merge" }); break; } case "object": { editor.setEditorState(initialEditorState, { tag: "history-merge" }); break; } case "function": { editor.update( () => { const root1 = (0, import_lexical6.$getRoot)(); if (root1.isEmpty()) initialEditorState(editor); }, { tag: "history-merge" } ); break; } } } else { const paragraph = (0, import_lexical6.$createParagraphNode)(); root.append(paragraph); const { activeElement } = document; if ((0, import_lexical6.$getSelection)() !== null || activeElement !== null && activeElement === editor.getRootElement()) { paragraph.select(); } } } }, { tag: "history-merge" } ); } function clearEditorSkipCollab(editor, binding) { editor.update( () => { const root = (0, import_lexical6.$getRoot)(); root.clear(); root.select(); }, { tag: "skip-collab" } ); if (binding.cursors == null) return; const cursors = binding.cursors; if (cursors == null) return; const cursorsContainer = binding.cursorsContainer; if (cursorsContainer == null) return; const cursorsArr = Array.from(cursors.values()); for (let i = 0; i < cursorsArr.length; i++) { const cursor = cursorsArr[i]; const selection = cursor.selection; if (selection && selection.selections !== null) { const selections = selection.selections; for (let j = 0; j < selections.length; j++) cursorsContainer.removeChild(selections[i]); } } } // src/components/LexicalDecoratedTeleports.ts var import_vue13 = require("vue"); var LexicalDecoratedTeleports_default = (0, import_vue13.defineComponent)({ name: "LexicalDecoratedTeleports", setup() { const editor = useLexicalComposer(); const decorators = useDecorators(editor); return () => decorators.value; } }); // src/components/LexicalContentEditable.vue var import_vue17 = require("vue"); var import_vue18 = require("vue"); var import_vue19 = require("vue"); // src/components/LexicalContentEditableElement.vue var import_vue14 = require("vue"); var import_vue15 = require("vue"); var import_vue16 = require("vue"); var _hoisted_1 = ["aria-activedescendant", "aria-autocomplete", "aria-controls", "aria-describedby", "aria-expanded", "aria-label", "aria-labelledby", "aria-multiline", "aria-owns", "aria-readonly", "aria-required", "autocapitalize", "contenteditable", "data-testid", "role", "spellcheck", "tabindex"]; var _sfc_main = /* @__PURE__ */ (0, import_vue14.defineComponent)({ __name: "LexicalContentEditableElement", props: { editor: {}, ariaActiveDescendant: {}, ariaAutoComplete: {}, ariaControls: {}, ariaDescribedBy: {}, ariaErrorMessage: {}, ariaExpanded: { type: [Boolean, String] }, ariaInvalid: { type: [Boolean, String] }, ariaLabel: {}, ariaLabelledBy: {}, ariaMultiline: { type: [Boolean, String] }, ariaOwns: {}, ariaRequired: { type: [Boolean, String] }, dataTestid: {}, innerHTML: {}, class: {}, style: { type: [Boolean, null, String, Object, Array] }, accesskey: {}, contenteditable: { type: [Boolean, String] }, contextmenu: {}, dir: {}, draggable: { type: [Boolean, String] }, hidden: { type: [Boolean, String] }, id: {}, inert: { type: [Boolean, String] }, lang: {}, spellcheck: { type: [Boolean, String], default: true }, tabindex: {}, title: {}, translate: {}, radiogroup: {}, role: { default: "textbox" }, about: {}, datatype: {}, inlist: {}, property: {}, resource: {}, typeof: {}, vocab: {}, autocapitalize: {}, autocorrect: {}, autosave: {}, color: {}, itemprop: {}, itemscope: { type: [Boolean, String] }, itemtype: {}, itemid: {}, itemref: {}, results: {}, security: {}, unselectable: {}, inputmode: {}, is: {}, "aria-activedescendant": {}, "aria-atomic": { type: [Boolean, String] }, "aria-autocomplete": {}, "aria-busy": { type: [Boolean, String] }, "aria-checked": { type: [Boolean, String] }, "aria-colcount": {}, "aria-colindex": {}, "aria-colspan": {}, "aria-controls": {}, "aria-current": { type: [Boolean, String] }, "aria-describedby": {}, "aria-details": {}, "aria-disabled": { type: [Boolean, String] }, "aria-dropeffect": {}, "aria-errormessage": {}, "aria-expanded": { type: [Boolean, String] }, "aria-flowto": {}, "aria-grabbed": { type: [Boolean, String] }, "aria-haspopup": { type: [Boolean, String] }, "aria-hidden": { type: [Boolean, String] }, "aria-invalid": { type: [Boolean, String] }, "aria-keyshortcuts": {}, "aria-label": {}, "aria-labelledby": {}, "aria-level": {}, "aria-live": {}, "aria-modal": { type: [Boolean, String] }, "aria-multiline": { type: [Boolean, String] }, "aria-multiselectable": { type: [Boolean, String] }, "aria-orientation": {}, "aria-owns": {}, "aria-placeholder": {}, "aria-posinset": {}, "aria-pressed": { type: [Boolean, String] }, "aria-readonly": { type: [Boolean, String] }, "aria-relevant": {}, "aria-required": { type: [Boolean, String] }, "aria-roledescription": {}, "aria-rowcount": {}, "aria-rowindex": {}, "aria-rowspan": {}, "aria-selected": { type: [Boolean, String] }, "aria-setsize": {}, "aria-sort": {}, "aria-valuemax": {}, "aria-valuemin": {}, "aria-valuenow": {}, "aria-valuetext": {} }, setup(__props) { const props = __props; const root = (0, import_vue16.ref)(null); const isEditable = (0, import_vue16.ref)(props.editor.isEditable()); const otherAttrs = (0, import_vue16.computed)(() => { const ariaAttrs = {}; if (props.ariaInvalid != null) ariaAttrs["aria-invalid"] = props.ariaInvalid; if (props.ariaErrorMessage != null) ariaAttrs["aria-errormessage"] = props.ariaErrorMessage; return { ...props, ...ariaAttrs }; }); useMounted(() => { function handleRef(rootElement) { if (rootElement && rootElement.ownerDocument && rootElement.ownerDocument.defaultView) { props.editor.setRootElement(rootElement); } else { props.editor.setRootElement(null); } } handleRef(root.value); isEditable.value = props.editor.isEditable(); return props.editor.registerEditableListener((currentIsEditable) => { isEditable.value = currentIsEditable; }); }); return (_ctx, _cache) => { return (0, import_vue15.openBlock)(), (0, import_vue15.createElementBlock)("div", (0, import_vue15.mergeProps)({ ref_key: "root", ref: root }, otherAttrs.value, { "aria-activedescendant": isEditable.value ? _ctx.ariaActiveDescendant : void 0, "aria-autocomplete": isEditable.value ? _ctx.ariaAutoComplete : "none", "aria-controls": isEditable.value ? _ctx.ariaControls : void 0, "aria-describedby": _ctx.ariaDescribedBy, "aria-expanded": isEditable.value && _ctx.role === "combobox" ? !!_ctx.ariaExpanded : void 0, "aria-label": _ctx.ariaLabel, "aria-labelledby": _ctx.ariaLabelledBy, "aria-multiline": _ctx.ariaMultiline, "aria-owns": isEditable.value ? _ctx.ariaOwns : void 0, "aria-readonly": isEditable.value ? void 0 : true, "aria-required": _ctx.ariaRequired, autocapitalize: _ctx.autocapitalize, contenteditable: isEditable.value, "data-testid": _ctx.dataTestid, role: isEditable.value ? _ctx.role : void 0, spellcheck: _ctx.spellcheck, style: _ctx.style, tabindex: _ctx.tabindex }), null, 16, _hoisted_1); }; } }); var LexicalContentEditableElement_default = _sfc_main; // src/components/LexicalContentEditable.vue var _hoisted_12 = { key: 0, "aria-hidden": "true" }; var _sfc_main2 = /* @__PURE__ */ (0, import_vue17.defineComponent)({ __name: "LexicalContentEditable", props: { ariaActiveDescendant: {}, ariaAutoComplete: {}, ariaControls: {}, ariaDescribedBy: {}, ariaErrorMessage: {}, ariaExpanded: {}, ariaInvalid: {}, ariaLabel: {}, ariaLabelledBy: {}, ariaMultiline: {}, ariaOwns: {}, ariaRequired: {}, dataTestid: {}, innerHTML: {}, class: {}, style: { type: [Boolean, null, String, Object, Array] }, accesskey: {}, contenteditable: { type: [Boolean, String] }, contextmenu: {}, dir: {}, draggable: { type: [Boolean, String] }, hidden: { type: [Boolean, String] }, id: {}, inert: { type: [Boolean, String] }, lang: {}, spellcheck: { type: [Boolean, String], default: true }, tabindex: {}, title: {}, translate: {}, radiogroup: {}, role: { default: "textbox" }, about: {}, datatype: {}, inlist: {}, property: {}, resource: {}, typeof: {}, vocab: {}, autocapitalize: {}, autocorrect: {}, autosave: {}, color: {}, itemprop: {}, itemscope: { type: [Boolean, String] }, itemtype: {}, itemid: {}, itemref: {}, results: {}, security: {}, unselectable: {}, inputmode: {}, is: {}, "aria-activedescendant": {}, "aria-atomic": { type: [Boolean, String] }, "aria-autocomplete": {}, "aria-busy": { type: [Boolean, String] }, "aria-checked": { type: [Boolean, String] }, "aria-colcount": {}, "aria-colindex": {}, "aria-colspan": {}, "aria-controls": {}, "aria-current": { type: [Boolean, String] }, "aria-describedby": {}, "aria-details": {}, "aria-disabled": { type: [Boolean, String] }, "aria-dropeffect": {}, "aria-errormessage": {}, "aria-expanded": { type: [Boolean, String] }, "aria-flowto": {}, "aria-grabbed": { type: [Boolean, String] }, "aria-haspopup": { type: [Boolean, String] }, "aria-hidden": { type: [Boolean, String] }, "aria-invalid": { type: [Boolean, String] }, "aria-keyshortcuts": {}, "aria-label": {}, "aria-labelledby": {}, "aria-level": {}, "aria-live": {}, "aria-modal": { type: [Boolean, String] }, "aria-multiline": { type: [Boolean, String] }, "aria-multiselectable": { type: [Boolean, String] }, "aria-orientation": {}, "aria-owns": {}, "aria-placeholder": {}, "aria-posinset": {}, "aria-pressed": { type: [Boolean, String] }, "aria-readonly": { type: [Boolean, String] }, "aria-relevant": {}, "aria-required": { type: [Boolean, String] }, "aria-roledescription": {}, "aria-rowcount": {}, "aria-rowindex": {}, "aria-rowspan": {}, "aria-selected": { type: [Boolean, String] }, "aria-setsize": {}, "aria-sort": {}, "aria-valuemax": {}, "aria-valuemin": {}, "aria-valuenow": {}, "aria-valuetext": {} }, setup(__props) { const editor = useLexicalComposer(); const isEditable = (0, import_vue19.ref)(false); const showPlaceholder = useCanShowPlaceholder(editor); useMounted(() => { isEditable.value = editor.isEditable(); return editor.registerEditableListener((currentIsEditable) => { isEditable.value = currentIsEditable; }); }); return (_ctx, _cache) => { return (0, import_vue18.openBlock)(), (0, import_vue18.createElementBlock)( import_vue18.Fragment, null, [ (0, import_vue18.createVNode)(LexicalContentEditableElement_default, (0, import_vue18.mergeProps)({ editor: (0, import_vue18.unref)(editor) }, _ctx.$props), null, 16, ["editor"]), (0, import_vue18.unref)(showPlaceholder) ? ((0, import_vue18.openBlock)(), (0, import_vue18.createElementBlock)("div", _hoisted_12, [ (0, import_vue18.renderSlot)(_ctx.$slots, "placeholder") ])) : (0, import_vue18.createCommentVNode)("v-if", true) ], 64 /* STABLE_FRAGMENT */ ); }; } }); var LexicalContentEditable_default = _sfc_main2; // src/components/LexicalPlainTextPlugin.vue var import_vue20 = require("vue"); var import_vue21 = require("vue"); var _sfc_main3 = /* @__PURE__ */ (0, import_vue20.defineComponent)({ __name: "LexicalPlainTextPlugin", setup(__props) { const editor = useLexicalComposer(); const showPlaceholder = useCanShowPlaceholder(editor); usePlainTextSetup(editor); return (_ctx, _cache) => { return (0, import_vue21.openBlock)(), (0, import_vue21.createElementBlock)( import_vue21.Fragment, null, [ (0, import_vue21.unref)(showPlaceholder) ? (0, import_vue21.renderSlot)(_ctx.$slots, "placeholder", { key: 0 }) : (0, import_vue21.createCommentVNode)("v-if", true), (0, import_vue21.renderSlot)(_ctx.$slots, "contentEditable"), (0, import_vue21.createVNode)((0, import_vue21.unref)(LexicalDecoratedTeleports_default)) ], 64 /* STABLE_FRAGMENT */ ); }; } }); var LexicalPlainTextPlugin_default = _sfc_main3; // src/components/LexicalComposer.vue var import_vue22 = require("vue"); var import_vue23 = require("vue"); var import_vue24 = require("vue"); var import_lexical7 = require("lexical"); var _sfc_main4 = /* @__PURE__ */ (0, import_vue22.defineComponent)({ __name: "LexicalComposer", props: { initialConfig: {} }, emits: ["error"], setup(__props, { emit: __emit }) { const props = __props; const emit = __emit; const HISTORY_MERGE_OPTIONS = { tag: "history-merge" }; const { theme, namespace, nodes, onError, editorState: initialEditorState, html } = props.initialConfig; const editor = (0, import_lexical7.createEditor)({ editable: props.initialConfig.editable, html, namespace, nodes, theme, onError(error) { emit("error", error, editor); onError?.(error, editor); } }); initializeEditor2(editor, initialEditorState); function initializeEditor2(editor2, initialEditorState2) { if (initialEditorState2 === null) return; if (initialEditorState2 === void 0) { editor2.update(() => { const root = (0, import_lexical7.$getRoot)(); if (root.isEmpty()) { const paragraph = (0, import_lexical7.$createParagraphNode)(); root.append(paragraph); const activeElement = document.activeElement; if ((0, import_lexical7.$getSelection)() !== null || activeElement !== null && activeElement === editor2.getRootElement()) { paragraph.select(); } } }, HISTORY_MERGE_OPTIONS); } else if (initialEditorState2 !== null) { switch (typeof initialEditorState2) { case "string": { const parsedEditorState = editor2.parseEditorState(initialEditorState2); editor2.setEditorState(parsedEditorState, HISTORY_MERGE_OPTIONS); break; } case "object": { editor2.setEditorState(initialEditorState2, HISTORY_MERGE_OPTIONS); break; } case "function": { editor2.update(() => { const root = (0, import_lexical7.$getRoot)(); if (root.isEmpty()) initialEditorState2(editor2); }, HISTORY_MERGE_OPTIONS); break; } } } } (0, import_vue24.provide)(LexicalEditorProviderKey, editor); (0, import_vue24.onMounted)(() => { const isEditable = props.initialConfig.editable; editor.setEditable(isEditab