UNPKG

rhino-editor

Version:

A custom element wrapped rich text editor

1,686 lines (1,670 loc) 72.9 kB
import { RhinoChangeEvent } from "./chunk-BYRYOV3A.js"; import { RhinoBlurEvent } from "./chunk-RXTNV3CH.js"; import { InitializeEvent } from "./chunk-TUFYCG5K.js"; import { FileAcceptEvent } from "./chunk-CVO5J527.js"; import { BeforeInitializeEvent } from "./chunk-PBNR35P2.js"; import { AddAttachmentEvent } from "./chunk-CZRGOOEV.js"; import { SelectionChangeEvent } from "./chunk-OVNNLQEY.js"; import { RhinoFocusEvent } from "./chunk-CO3NBTSN.js"; import { editor_default } from "./chunk-6LK3B3JM.js"; import { Dropcursor, Gapcursor, Link, RhinoStarterKit, TrailingNode, UndoRedo } from "./chunk-KMWW23PU.js"; import { Strike } from "./chunk-2PXEVWXN.js"; import { AttachmentRemoveEvent } from "./chunk-3PWTYHXV.js"; import { Editor, Extension, Mark, Node3, canInsertNode, getNodeAtPosition, getNodeType, isAtEndOfNode, isAtStartOfNode, isNodeActive, isNodeSelection, markInputRule, markPasteRule, mergeAttributes, nodeInputRule, textblockTypeInputRule, wrappingInputRule } from "./chunk-4CJ3F2XK.js"; import { DOMSerializer, NodeSelection, Plugin, PluginKey, Selection, TextSelection } from "./chunk-XG3W5CFT.js"; import { AttachmentManager } from "./chunk-TVEIGRY7.js"; import { AttachmentUpload, AttachmentUploadCompleteEvent, AttachmentUploadStartEvent } from "./chunk-QZ4YCGG4.js"; import { AttachmentEditor, BaseElement } from "./chunk-IXVACZYD.js"; import { normalize } from "./chunk-KS2J443B.js"; import { tipTapCoreStyles } from "./chunk-TYRYT5SD.js"; import { x } from "./chunk-6JX5B4GC.js"; // node_modules/.pnpm/@tiptap+core@3.4.4_@tiptap+pm@3.4.4/node_modules/@tiptap/core/dist/jsx-runtime/jsx-runtime.js var h = (tag, attributes) => { if (tag === "slot") { return 0; } if (tag instanceof Function) { return tag(attributes); } const { children, ...rest } = attributes != null ? attributes : {}; if (tag === "svg") { throw new Error("SVG elements are not supported in the JSX syntax, use the array syntax instead"); } return [tag, rest, children]; }; // node_modules/.pnpm/@tiptap+extension-blockquote@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-blockquote/dist/index.js var inputRegex = /^\s*>\s$/; var Blockquote = Node3.create({ name: "blockquote", addOptions() { return { HTMLAttributes: {} }; }, content: "block+", group: "block", defining: true, parseHTML() { return [{ tag: "blockquote" }]; }, renderHTML({ HTMLAttributes }) { return /* @__PURE__ */ h("blockquote", { ...mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), children: /* @__PURE__ */ h("slot", {}) }); }, addCommands() { return { setBlockquote: () => ({ commands }) => { return commands.wrapIn(this.name); }, toggleBlockquote: () => ({ commands }) => { return commands.toggleWrap(this.name); }, unsetBlockquote: () => ({ commands }) => { return commands.lift(this.name); } }; }, addKeyboardShortcuts() { return { "Mod-Shift-b": () => this.editor.commands.toggleBlockquote() }; }, addInputRules() { return [ wrappingInputRule({ find: inputRegex, type: this.type }) ]; } }); // node_modules/.pnpm/@tiptap+extension-bold@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-bold/dist/index.js var starInputRegex = /(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))$/; var starPasteRegex = /(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))/g; var underscoreInputRegex = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))$/; var underscorePasteRegex = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))/g; var Bold = Mark.create({ name: "bold", addOptions() { return { HTMLAttributes: {} }; }, parseHTML() { return [ { tag: "strong" }, { tag: "b", getAttrs: (node) => node.style.fontWeight !== "normal" && null }, { style: "font-weight=400", clearMark: (mark) => mark.type.name === this.name }, { style: "font-weight", getAttrs: (value) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null } ]; }, renderHTML({ HTMLAttributes }) { return /* @__PURE__ */ h("strong", { ...mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), children: /* @__PURE__ */ h("slot", {}) }); }, addCommands() { return { setBold: () => ({ commands }) => { return commands.setMark(this.name); }, toggleBold: () => ({ commands }) => { return commands.toggleMark(this.name); }, unsetBold: () => ({ commands }) => { return commands.unsetMark(this.name); } }; }, addKeyboardShortcuts() { return { "Mod-b": () => this.editor.commands.toggleBold(), "Mod-B": () => this.editor.commands.toggleBold() }; }, addInputRules() { return [ markInputRule({ find: starInputRegex, type: this.type }), markInputRule({ find: underscoreInputRegex, type: this.type }) ]; }, addPasteRules() { return [ markPasteRule({ find: starPasteRegex, type: this.type }), markPasteRule({ find: underscorePasteRegex, type: this.type }) ]; } }); // node_modules/.pnpm/@tiptap+extension-code@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-code/dist/index.js var inputRegex2 = /(^|[^`])`([^`]+)`(?!`)$/; var pasteRegex = /(^|[^`])`([^`]+)`(?!`)/g; var Code = Mark.create({ name: "code", addOptions() { return { HTMLAttributes: {} }; }, excludes: "_", code: true, exitable: true, parseHTML() { return [{ tag: "code" }]; }, renderHTML({ HTMLAttributes }) { return ["code", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { setCode: () => ({ commands }) => { return commands.setMark(this.name); }, toggleCode: () => ({ commands }) => { return commands.toggleMark(this.name); }, unsetCode: () => ({ commands }) => { return commands.unsetMark(this.name); } }; }, addKeyboardShortcuts() { return { "Mod-e": () => this.editor.commands.toggleCode() }; }, addInputRules() { return [ markInputRule({ find: inputRegex2, type: this.type }) ]; }, addPasteRules() { return [ markPasteRule({ find: pasteRegex, type: this.type }) ]; } }); // node_modules/.pnpm/@tiptap+extension-code-block@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4__@tiptap+pm@3.4.4/node_modules/@tiptap/extension-code-block/dist/index.js var backtickInputRegex = /^```([a-z]+)?[\s\n]$/; var tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/; var CodeBlock = Node3.create({ name: "codeBlock", addOptions() { return { languageClassPrefix: "language-", exitOnTripleEnter: true, exitOnArrowDown: true, defaultLanguage: null, enableTabIndentation: false, tabSize: 4, HTMLAttributes: {} }; }, content: "text*", marks: "", group: "block", code: true, defining: true, addAttributes() { return { language: { default: this.options.defaultLanguage, parseHTML: (element) => { var _a; const { languageClassPrefix } = this.options; const classNames = [...((_a = element.firstElementChild) == null ? void 0 : _a.classList) || []]; const languages = classNames.filter((className) => className.startsWith(languageClassPrefix)).map((className) => className.replace(languageClassPrefix, "")); const language = languages[0]; if (!language) { return null; } return language; }, rendered: false } }; }, parseHTML() { return [ { tag: "pre", preserveWhitespace: "full" } ]; }, renderHTML({ node, HTMLAttributes }) { return [ "pre", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), [ "code", { class: node.attrs.language ? this.options.languageClassPrefix + node.attrs.language : null }, 0 ] ]; }, addCommands() { return { setCodeBlock: (attributes) => ({ commands }) => { return commands.setNode(this.name, attributes); }, toggleCodeBlock: (attributes) => ({ commands }) => { return commands.toggleNode(this.name, "paragraph", attributes); } }; }, addKeyboardShortcuts() { return { "Mod-Alt-c": () => this.editor.commands.toggleCodeBlock(), // remove code block when at start of document or code block is empty Backspace: () => { const { empty, $anchor } = this.editor.state.selection; const isAtStart = $anchor.pos === 1; if (!empty || $anchor.parent.type.name !== this.name) { return false; } if (isAtStart || !$anchor.parent.textContent.length) { return this.editor.commands.clearNodes(); } return false; }, // handle tab indentation Tab: ({ editor }) => { if (!this.options.enableTabIndentation) { return false; } const { state } = editor; const { selection } = state; const { $from, empty } = selection; if ($from.parent.type !== this.type) { return false; } const indent = " ".repeat(this.options.tabSize); if (empty) { return editor.commands.insertContent(indent); } return editor.commands.command(({ tr }) => { const { from, to } = selection; const text = state.doc.textBetween(from, to, "\n", "\n"); const lines = text.split("\n"); const indentedText = lines.map((line) => indent + line).join("\n"); tr.replaceWith(from, to, state.schema.text(indentedText)); return true; }); }, // handle shift+tab reverse indentation "Shift-Tab": ({ editor }) => { if (!this.options.enableTabIndentation) { return false; } const { state } = editor; const { selection } = state; const { $from, empty } = selection; if ($from.parent.type !== this.type) { return false; } if (empty) { return editor.commands.command(({ tr }) => { var _a; const { pos } = $from; const codeBlockStart = $from.start(); const codeBlockEnd = $from.end(); const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, "\n", "\n"); const lines = allText.split("\n"); let currentLineIndex = 0; let charCount = 0; const relativeCursorPos = pos - codeBlockStart; for (let i = 0; i < lines.length; i += 1) { if (charCount + lines[i].length >= relativeCursorPos) { currentLineIndex = i; break; } charCount += lines[i].length + 1; } const currentLine = lines[currentLineIndex]; const leadingSpaces = ((_a = currentLine.match(/^ */)) == null ? void 0 : _a[0]) || ""; const spacesToRemove = Math.min(leadingSpaces.length, this.options.tabSize); if (spacesToRemove === 0) { return true; } let lineStartPos = codeBlockStart; for (let i = 0; i < currentLineIndex; i += 1) { lineStartPos += lines[i].length + 1; } tr.delete(lineStartPos, lineStartPos + spacesToRemove); const cursorPosInLine = pos - lineStartPos; if (cursorPosInLine <= spacesToRemove) { tr.setSelection(TextSelection.create(tr.doc, lineStartPos)); } return true; }); } return editor.commands.command(({ tr }) => { const { from, to } = selection; const text = state.doc.textBetween(from, to, "\n", "\n"); const lines = text.split("\n"); const reverseIndentText = lines.map((line) => { var _a; const leadingSpaces = ((_a = line.match(/^ */)) == null ? void 0 : _a[0]) || ""; const spacesToRemove = Math.min(leadingSpaces.length, this.options.tabSize); return line.slice(spacesToRemove); }).join("\n"); tr.replaceWith(from, to, state.schema.text(reverseIndentText)); return true; }); }, // exit node on triple enter Enter: ({ editor }) => { if (!this.options.exitOnTripleEnter) { return false; } const { state } = editor; const { selection } = state; const { $from, empty } = selection; if (!empty || $from.parent.type !== this.type) { return false; } const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; const endsWithDoubleNewline = $from.parent.textContent.endsWith("\n\n"); if (!isAtEnd || !endsWithDoubleNewline) { return false; } return editor.chain().command(({ tr }) => { tr.delete($from.pos - 2, $from.pos); return true; }).exitCode().run(); }, // exit node on arrow down ArrowDown: ({ editor }) => { if (!this.options.exitOnArrowDown) { return false; } const { state } = editor; const { selection, doc } = state; const { $from, empty } = selection; if (!empty || $from.parent.type !== this.type) { return false; } const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; if (!isAtEnd) { return false; } const after = $from.after(); if (after === void 0) { return false; } const nodeAfter = doc.nodeAt(after); if (nodeAfter) { return editor.commands.command(({ tr }) => { tr.setSelection(Selection.near(doc.resolve(after))); return true; }); } return editor.commands.exitCode(); } }; }, addInputRules() { return [ textblockTypeInputRule({ find: backtickInputRegex, type: this.type, getAttributes: (match) => ({ language: match[1] }) }), textblockTypeInputRule({ find: tildeInputRegex, type: this.type, getAttributes: (match) => ({ language: match[1] }) }) ]; }, addProseMirrorPlugins() { return [ // this plugin creates a code block for pasted content from VS Code // we can also detect the copied code language new Plugin({ key: new PluginKey("codeBlockVSCodeHandler"), props: { handlePaste: (view, event) => { if (!event.clipboardData) { return false; } if (this.editor.isActive(this.type.name)) { return false; } const text = event.clipboardData.getData("text/plain"); const vscode = event.clipboardData.getData("vscode-editor-data"); const vscodeData = vscode ? JSON.parse(vscode) : void 0; const language = vscodeData == null ? void 0 : vscodeData.mode; if (!text || !language) { return false; } const { tr, schema } = view.state; const textNode = schema.text(text.replace(/\r\n?/g, "\n")); tr.replaceSelectionWith(this.type.create({ language }, textNode)); if (tr.selection.$from.parent.type !== this.type) { tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2)))); } tr.setMeta("paste", true); view.dispatch(tr); return true; } } }) ]; } }); // node_modules/.pnpm/@tiptap+extension-document@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-document/dist/index.js var Document = Node3.create({ name: "doc", topNode: true, content: "block+" }); // node_modules/.pnpm/@tiptap+extension-hard-break@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-hard-break/dist/index.js var HardBreak = Node3.create({ name: "hardBreak", addOptions() { return { keepMarks: true, HTMLAttributes: {} }; }, inline: true, group: "inline", selectable: false, linebreakReplacement: true, parseHTML() { return [{ tag: "br" }]; }, renderHTML({ HTMLAttributes }) { return ["br", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]; }, renderText() { return "\n"; }, addCommands() { return { setHardBreak: () => ({ commands, chain, state, editor }) => { return commands.first([ () => commands.exitCode(), () => commands.command(() => { const { selection, storedMarks } = state; if (selection.$from.parent.type.spec.isolating) { return false; } const { keepMarks } = this.options; const { splittableMarks } = editor.extensionManager; const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks(); return chain().insertContent({ type: this.name }).command(({ tr, dispatch }) => { if (dispatch && marks && keepMarks) { const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name)); tr.ensureMarks(filteredMarks); } return true; }).run(); }) ]); } }; }, addKeyboardShortcuts() { return { "Mod-Enter": () => this.editor.commands.setHardBreak(), "Shift-Enter": () => this.editor.commands.setHardBreak() }; } }); // node_modules/.pnpm/@tiptap+extension-heading@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-heading/dist/index.js var Heading = Node3.create({ name: "heading", addOptions() { return { levels: [1, 2, 3, 4, 5, 6], HTMLAttributes: {} }; }, content: "inline*", group: "block", defining: true, addAttributes() { return { level: { default: 1, rendered: false } }; }, parseHTML() { return this.options.levels.map((level) => ({ tag: `h${level}`, attrs: { level } })); }, renderHTML({ node, HTMLAttributes }) { const hasLevel = this.options.levels.includes(node.attrs.level); const level = hasLevel ? node.attrs.level : this.options.levels[0]; return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { setHeading: (attributes) => ({ commands }) => { if (!this.options.levels.includes(attributes.level)) { return false; } return commands.setNode(this.name, attributes); }, toggleHeading: (attributes) => ({ commands }) => { if (!this.options.levels.includes(attributes.level)) { return false; } return commands.toggleNode(this.name, "paragraph", attributes); } }; }, addKeyboardShortcuts() { return this.options.levels.reduce( (items, level) => ({ ...items, ...{ [`Mod-Alt-${level}`]: () => this.editor.commands.toggleHeading({ level }) } }), {} ); }, addInputRules() { return this.options.levels.map((level) => { return textblockTypeInputRule({ find: new RegExp(`^(#{${Math.min(...this.options.levels)},${level}})\\s$`), type: this.type, getAttributes: { level } }); }); } }); // node_modules/.pnpm/@tiptap+extension-horizontal-rule@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4__@tiptap+pm@3.4.4/node_modules/@tiptap/extension-horizontal-rule/dist/index.js var HorizontalRule = Node3.create({ name: "horizontalRule", addOptions() { return { HTMLAttributes: {} }; }, group: "block", parseHTML() { return [{ tag: "hr" }]; }, renderHTML({ HTMLAttributes }) { return ["hr", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]; }, addCommands() { return { setHorizontalRule: () => ({ chain, state }) => { if (!canInsertNode(state, state.schema.nodes[this.name])) { return false; } const { selection } = state; const { $to: $originTo } = selection; const currentChain = chain(); if (isNodeSelection(selection)) { currentChain.insertContentAt($originTo.pos, { type: this.name }); } else { currentChain.insertContent({ type: this.name }); } return currentChain.command(({ tr, dispatch }) => { var _a; if (dispatch) { const { $to } = tr.selection; const posAfter = $to.end(); if ($to.nodeAfter) { if ($to.nodeAfter.isTextblock) { tr.setSelection(TextSelection.create(tr.doc, $to.pos + 1)); } else if ($to.nodeAfter.isBlock) { tr.setSelection(NodeSelection.create(tr.doc, $to.pos)); } else { tr.setSelection(TextSelection.create(tr.doc, $to.pos)); } } else { const node = (_a = $to.parent.type.contentMatch.defaultType) == null ? void 0 : _a.create(); if (node) { tr.insert(posAfter, node); tr.setSelection(TextSelection.create(tr.doc, posAfter + 1)); } } tr.scrollIntoView(); } return true; }).run(); } }; }, addInputRules() { return [ nodeInputRule({ find: /^(?:---|—-|___\s|\*\*\*\s)$/, type: this.type }) ]; } }); // node_modules/.pnpm/@tiptap+extension-italic@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-italic/dist/index.js var starInputRegex2 = /(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))$/; var starPasteRegex2 = /(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))/g; var underscoreInputRegex2 = /(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))$/; var underscorePasteRegex2 = /(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))/g; var Italic = Mark.create({ name: "italic", addOptions() { return { HTMLAttributes: {} }; }, parseHTML() { return [ { tag: "em" }, { tag: "i", getAttrs: (node) => node.style.fontStyle !== "normal" && null }, { style: "font-style=normal", clearMark: (mark) => mark.type.name === this.name }, { style: "font-style=italic" } ]; }, renderHTML({ HTMLAttributes }) { return ["em", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { setItalic: () => ({ commands }) => { return commands.setMark(this.name); }, toggleItalic: () => ({ commands }) => { return commands.toggleMark(this.name); }, unsetItalic: () => ({ commands }) => { return commands.unsetMark(this.name); } }; }, addKeyboardShortcuts() { return { "Mod-i": () => this.editor.commands.toggleItalic(), "Mod-I": () => this.editor.commands.toggleItalic() }; }, addInputRules() { return [ markInputRule({ find: starInputRegex2, type: this.type }), markInputRule({ find: underscoreInputRegex2, type: this.type }) ]; }, addPasteRules() { return [ markPasteRule({ find: starPasteRegex2, type: this.type }), markPasteRule({ find: underscorePasteRegex2, type: this.type }) ]; } }); // node_modules/.pnpm/@tiptap+extension-list@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4__@tiptap+pm@3.4.4/node_modules/@tiptap/extension-list/dist/index.js var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var ListItemName = "listItem"; var TextStyleName = "textStyle"; var bulletListInputRegex = /^\s*([-+*])\s$/; var BulletList = Node3.create({ name: "bulletList", addOptions() { return { itemTypeName: "listItem", HTMLAttributes: {}, keepMarks: false, keepAttributes: false }; }, group: "block list", content() { return `${this.options.itemTypeName}+`; }, parseHTML() { return [{ tag: "ul" }]; }, renderHTML({ HTMLAttributes }) { return ["ul", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { toggleBulletList: () => ({ commands, chain }) => { if (this.options.keepAttributes) { return chain().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName)).run(); } return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks); } }; }, addKeyboardShortcuts() { return { "Mod-Shift-8": () => this.editor.commands.toggleBulletList() }; }, addInputRules() { let inputRule = wrappingInputRule({ find: bulletListInputRegex, type: this.type }); if (this.options.keepMarks || this.options.keepAttributes) { inputRule = wrappingInputRule({ find: bulletListInputRegex, type: this.type, keepMarks: this.options.keepMarks, keepAttributes: this.options.keepAttributes, getAttributes: () => { return this.editor.getAttributes(TextStyleName); }, editor: this.editor }); } return [inputRule]; } }); var ListItem = Node3.create({ name: "listItem", addOptions() { return { HTMLAttributes: {}, bulletListTypeName: "bulletList", orderedListTypeName: "orderedList" }; }, content: "paragraph block*", defining: true, parseHTML() { return [ { tag: "li" } ]; }, renderHTML({ HTMLAttributes }) { return ["li", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addKeyboardShortcuts() { return { Enter: () => this.editor.commands.splitListItem(this.name), Tab: () => this.editor.commands.sinkListItem(this.name), "Shift-Tab": () => this.editor.commands.liftListItem(this.name) }; } }); var listHelpers_exports = {}; __export(listHelpers_exports, { findListItemPos: () => findListItemPos, getNextListDepth: () => getNextListDepth, handleBackspace: () => handleBackspace, handleDelete: () => handleDelete, hasListBefore: () => hasListBefore, hasListItemAfter: () => hasListItemAfter, hasListItemBefore: () => hasListItemBefore, listItemHasSubList: () => listItemHasSubList, nextListIsDeeper: () => nextListIsDeeper, nextListIsHigher: () => nextListIsHigher }); var findListItemPos = (typeOrName, state) => { const { $from } = state.selection; const nodeType = getNodeType(typeOrName, state.schema); let currentNode = null; let currentDepth = $from.depth; let currentPos = $from.pos; let targetDepth = null; while (currentDepth > 0 && targetDepth === null) { currentNode = $from.node(currentDepth); if (currentNode.type === nodeType) { targetDepth = currentDepth; } else { currentDepth -= 1; currentPos -= 1; } } if (targetDepth === null) { return null; } return { $pos: state.doc.resolve(currentPos), depth: targetDepth }; }; var getNextListDepth = (typeOrName, state) => { const listItemPos = findListItemPos(typeOrName, state); if (!listItemPos) { return false; } const [, depth] = getNodeAtPosition(state, typeOrName, listItemPos.$pos.pos + 4); return depth; }; var hasListBefore = (editorState, name, parentListTypes) => { const { $anchor } = editorState.selection; const previousNodePos = Math.max(0, $anchor.pos - 2); const previousNode = editorState.doc.resolve(previousNodePos).node(); if (!previousNode || !parentListTypes.includes(previousNode.type.name)) { return false; } return true; }; var hasListItemBefore = (typeOrName, state) => { var _a; const { $anchor } = state.selection; const $targetPos = state.doc.resolve($anchor.pos - 2); if ($targetPos.index() === 0) { return false; } if (((_a = $targetPos.nodeBefore) == null ? void 0 : _a.type.name) !== typeOrName) { return false; } return true; }; var listItemHasSubList = (typeOrName, state, node) => { if (!node) { return false; } const nodeType = getNodeType(typeOrName, state.schema); let hasSubList = false; node.descendants((child) => { if (child.type === nodeType) { hasSubList = true; } }); return hasSubList; }; var handleBackspace = (editor, name, parentListTypes) => { if (editor.commands.undoInputRule()) { return true; } if (editor.state.selection.from !== editor.state.selection.to) { return false; } if (!isNodeActive(editor.state, name) && hasListBefore(editor.state, name, parentListTypes)) { const { $anchor } = editor.state.selection; const $listPos = editor.state.doc.resolve($anchor.before() - 1); const listDescendants = []; $listPos.node().descendants((node, pos) => { if (node.type.name === name) { listDescendants.push({ node, pos }); } }); const lastItem = listDescendants.at(-1); if (!lastItem) { return false; } const $lastItemPos = editor.state.doc.resolve($listPos.start() + lastItem.pos + 1); return editor.chain().cut({ from: $anchor.start() - 1, to: $anchor.end() + 1 }, $lastItemPos.end()).joinForward().run(); } if (!isNodeActive(editor.state, name)) { return false; } if (!isAtStartOfNode(editor.state)) { return false; } const listItemPos = findListItemPos(name, editor.state); if (!listItemPos) { return false; } const $prev = editor.state.doc.resolve(listItemPos.$pos.pos - 2); const prevNode = $prev.node(listItemPos.depth); const previousListItemHasSubList = listItemHasSubList(name, editor.state, prevNode); if (hasListItemBefore(name, editor.state) && !previousListItemHasSubList) { return editor.commands.joinItemBackward(); } return editor.chain().liftListItem(name).run(); }; var nextListIsDeeper = (typeOrName, state) => { const listDepth = getNextListDepth(typeOrName, state); const listItemPos = findListItemPos(typeOrName, state); if (!listItemPos || !listDepth) { return false; } if (listDepth > listItemPos.depth) { return true; } return false; }; var nextListIsHigher = (typeOrName, state) => { const listDepth = getNextListDepth(typeOrName, state); const listItemPos = findListItemPos(typeOrName, state); if (!listItemPos || !listDepth) { return false; } if (listDepth < listItemPos.depth) { return true; } return false; }; var handleDelete = (editor, name) => { if (!isNodeActive(editor.state, name)) { return false; } if (!isAtEndOfNode(editor.state, name)) { return false; } const { selection } = editor.state; const { $from, $to } = selection; if (!selection.empty && $from.sameParent($to)) { return false; } if (nextListIsDeeper(name, editor.state)) { return editor.chain().focus(editor.state.selection.from + 4).lift(name).joinBackward().run(); } if (nextListIsHigher(name, editor.state)) { return editor.chain().joinForward().joinBackward().run(); } return editor.commands.joinItemForward(); }; var hasListItemAfter = (typeOrName, state) => { var _a; const { $anchor } = state.selection; const $targetPos = state.doc.resolve($anchor.pos - $anchor.parentOffset - 2); if ($targetPos.index() === $targetPos.parent.childCount - 1) { return false; } if (((_a = $targetPos.nodeAfter) == null ? void 0 : _a.type.name) !== typeOrName) { return false; } return true; }; var ListKeymap = Extension.create({ name: "listKeymap", addOptions() { return { listTypes: [ { itemName: "listItem", wrapperNames: ["bulletList", "orderedList"] }, { itemName: "taskItem", wrapperNames: ["taskList"] } ] }; }, addKeyboardShortcuts() { return { Delete: ({ editor }) => { let handled = false; this.options.listTypes.forEach(({ itemName }) => { if (editor.state.schema.nodes[itemName] === void 0) { return; } if (handleDelete(editor, itemName)) { handled = true; } }); return handled; }, "Mod-Delete": ({ editor }) => { let handled = false; this.options.listTypes.forEach(({ itemName }) => { if (editor.state.schema.nodes[itemName] === void 0) { return; } if (handleDelete(editor, itemName)) { handled = true; } }); return handled; }, Backspace: ({ editor }) => { let handled = false; this.options.listTypes.forEach(({ itemName, wrapperNames }) => { if (editor.state.schema.nodes[itemName] === void 0) { return; } if (handleBackspace(editor, itemName, wrapperNames)) { handled = true; } }); return handled; }, "Mod-Backspace": ({ editor }) => { let handled = false; this.options.listTypes.forEach(({ itemName, wrapperNames }) => { if (editor.state.schema.nodes[itemName] === void 0) { return; } if (handleBackspace(editor, itemName, wrapperNames)) { handled = true; } }); return handled; } }; } }); var ListItemName2 = "listItem"; var TextStyleName2 = "textStyle"; var orderedListInputRegex = /^(\d+)\.\s$/; var OrderedList = Node3.create({ name: "orderedList", addOptions() { return { itemTypeName: "listItem", HTMLAttributes: {}, keepMarks: false, keepAttributes: false }; }, group: "block list", content() { return `${this.options.itemTypeName}+`; }, addAttributes() { return { start: { default: 1, parseHTML: (element) => { return element.hasAttribute("start") ? parseInt(element.getAttribute("start") || "", 10) : 1; } }, type: { default: null, parseHTML: (element) => element.getAttribute("type") } }; }, parseHTML() { return [ { tag: "ol" } ]; }, renderHTML({ HTMLAttributes }) { const { start, ...attributesWithoutStart } = HTMLAttributes; return start === 1 ? ["ol", mergeAttributes(this.options.HTMLAttributes, attributesWithoutStart), 0] : ["ol", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { toggleOrderedList: () => ({ commands, chain }) => { if (this.options.keepAttributes) { return chain().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(ListItemName2, this.editor.getAttributes(TextStyleName2)).run(); } return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks); } }; }, addKeyboardShortcuts() { return { "Mod-Shift-7": () => this.editor.commands.toggleOrderedList() }; }, addInputRules() { let inputRule = wrappingInputRule({ find: orderedListInputRegex, type: this.type, getAttributes: (match) => ({ start: +match[1] }), joinPredicate: (match, node) => node.childCount + node.attrs.start === +match[1] }); if (this.options.keepMarks || this.options.keepAttributes) { inputRule = wrappingInputRule({ find: orderedListInputRegex, type: this.type, keepMarks: this.options.keepMarks, keepAttributes: this.options.keepAttributes, getAttributes: (match) => ({ start: +match[1], ...this.editor.getAttributes(TextStyleName2) }), joinPredicate: (match, node) => node.childCount + node.attrs.start === +match[1], editor: this.editor }); } return [inputRule]; } }); var inputRegex3 = /^\s*(\[([( |x])?\])\s$/; var TaskItem = Node3.create({ name: "taskItem", addOptions() { return { nested: false, HTMLAttributes: {}, taskListTypeName: "taskList", a11y: void 0 }; }, content() { return this.options.nested ? "paragraph block*" : "paragraph+"; }, defining: true, addAttributes() { return { checked: { default: false, keepOnSplit: false, parseHTML: (element) => { const dataChecked = element.getAttribute("data-checked"); return dataChecked === "" || dataChecked === "true"; }, renderHTML: (attributes) => ({ "data-checked": attributes.checked }) } }; }, parseHTML() { return [ { tag: `li[data-type="${this.name}"]`, priority: 51 } ]; }, renderHTML({ node, HTMLAttributes }) { return [ "li", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }), [ "label", [ "input", { type: "checkbox", checked: node.attrs.checked ? "checked" : null } ], ["span"] ], ["div", 0] ]; }, addKeyboardShortcuts() { const shortcuts = { Enter: () => this.editor.commands.splitListItem(this.name), "Shift-Tab": () => this.editor.commands.liftListItem(this.name) }; if (!this.options.nested) { return shortcuts; } return { ...shortcuts, Tab: () => this.editor.commands.sinkListItem(this.name) }; }, addNodeView() { return ({ node, HTMLAttributes, getPos, editor }) => { const listItem = document.createElement("li"); const checkboxWrapper = document.createElement("label"); const checkboxStyler = document.createElement("span"); const checkbox = document.createElement("input"); const content = document.createElement("div"); const updateA11Y = (currentNode) => { var _a, _b; checkbox.ariaLabel = ((_b = (_a = this.options.a11y) == null ? void 0 : _a.checkboxLabel) == null ? void 0 : _b.call(_a, currentNode, checkbox.checked)) || `Task item checkbox for ${currentNode.textContent || "empty task item"}`; }; updateA11Y(node); checkboxWrapper.contentEditable = "false"; checkbox.type = "checkbox"; checkbox.addEventListener("mousedown", (event) => event.preventDefault()); checkbox.addEventListener("change", (event) => { if (!editor.isEditable && !this.options.onReadOnlyChecked) { checkbox.checked = !checkbox.checked; return; } const { checked } = event.target; if (editor.isEditable && typeof getPos === "function") { editor.chain().focus(void 0, { scrollIntoView: false }).command(({ tr }) => { const position = getPos(); if (typeof position !== "number") { return false; } const currentNode = tr.doc.nodeAt(position); tr.setNodeMarkup(position, void 0, { ...currentNode == null ? void 0 : currentNode.attrs, checked }); return true; }).run(); } if (!editor.isEditable && this.options.onReadOnlyChecked) { if (!this.options.onReadOnlyChecked(node, checked)) { checkbox.checked = !checkbox.checked; } } }); Object.entries(this.options.HTMLAttributes).forEach(([key, value]) => { listItem.setAttribute(key, value); }); listItem.dataset.checked = node.attrs.checked; checkbox.checked = node.attrs.checked; checkboxWrapper.append(checkbox, checkboxStyler); listItem.append(checkboxWrapper, content); Object.entries(HTMLAttributes).forEach(([key, value]) => { listItem.setAttribute(key, value); }); return { dom: listItem, contentDOM: content, update: (updatedNode) => { if (updatedNode.type !== this.type) { return false; } listItem.dataset.checked = updatedNode.attrs.checked; checkbox.checked = updatedNode.attrs.checked; updateA11Y(updatedNode); return true; } }; }; }, addInputRules() { return [ wrappingInputRule({ find: inputRegex3, type: this.type, getAttributes: (match) => ({ checked: match[match.length - 1] === "x" }) }) ]; } }); var TaskList = Node3.create({ name: "taskList", addOptions() { return { itemTypeName: "taskItem", HTMLAttributes: {} }; }, group: "block list", content() { return `${this.options.itemTypeName}+`; }, parseHTML() { return [ { tag: `ul[data-type="${this.name}"]`, priority: 51 } ]; }, renderHTML({ HTMLAttributes }) { return ["ul", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }), 0]; }, addCommands() { return { toggleTaskList: () => ({ commands }) => { return commands.toggleList(this.name, this.options.itemTypeName); } }; }, addKeyboardShortcuts() { return { "Mod-Shift-9": () => this.editor.commands.toggleTaskList() }; } }); var ListKit = Extension.create({ name: "listKit", addExtensions() { const extensions = []; if (this.options.bulletList !== false) { extensions.push(BulletList.configure(this.options.bulletList)); } if (this.options.listItem !== false) { extensions.push(ListItem.configure(this.options.listItem)); } if (this.options.listKeymap !== false) { extensions.push(ListKeymap.configure(this.options.listKeymap)); } if (this.options.orderedList !== false) { extensions.push(OrderedList.configure(this.options.orderedList)); } if (this.options.taskItem !== false) { extensions.push(TaskItem.configure(this.options.taskItem)); } if (this.options.taskList !== false) { extensions.push(TaskList.configure(this.options.taskList)); } return extensions; } }); // node_modules/.pnpm/@tiptap+extension-paragraph@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-paragraph/dist/index.js var Paragraph = Node3.create({ name: "paragraph", priority: 1e3, addOptions() { return { HTMLAttributes: {} }; }, group: "block", content: "inline*", parseHTML() { return [{ tag: "p" }]; }, renderHTML({ HTMLAttributes }) { return ["p", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { setParagraph: () => ({ commands }) => { return commands.setNode(this.name); } }; }, addKeyboardShortcuts() { return { "Mod-Alt-0": () => this.editor.commands.setParagraph() }; } }); // node_modules/.pnpm/@tiptap+extension-text@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-text/dist/index.js var Text = Node3.create({ name: "text", group: "inline" }); // node_modules/.pnpm/@tiptap+extension-underline@3.4.4_@tiptap+core@3.4.4_@tiptap+pm@3.4.4_/node_modules/@tiptap/extension-underline/dist/index.js var Underline = Mark.create({ name: "underline", addOptions() { return { HTMLAttributes: {} }; }, parseHTML() { return [ { tag: "u" }, { style: "text-decoration", consuming: false, getAttrs: (style) => style.includes("underline") ? {} : false } ]; }, renderHTML({ HTMLAttributes }) { return ["u", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addCommands() { return { setUnderline: () => ({ commands }) => { return commands.setMark(this.name); }, toggleUnderline: () => ({ commands }) => { return commands.toggleMark(this.name); }, unsetUnderline: () => ({ commands }) => { return commands.unsetMark(this.name); } }; }, addKeyboardShortcuts() { return { "Mod-u": () => this.editor.commands.toggleUnderline(), "Mod-U": () => this.editor.commands.toggleUnderline() }; } }); // node_modules/.pnpm/@tiptap+starter-kit@3.4.4/node_modules/@tiptap/starter-kit/dist/index.js var StarterKit = Extension.create({ name: "starterKit", addExtensions() { var _a, _b, _c, _d; const extensions = []; if (this.options.bold !== false) { extensions.push(Bold.configure(this.options.bold)); } if (this.options.blockquote !== false) { extensions.push(Blockquote.configure(this.options.blockquote)); } if (this.options.bulletList !== false) { extensions.push(BulletList.configure(this.options.bulletList)); } if (this.options.code !== false) { extensions.push(Code.configure(this.options.code)); } if (this.options.codeBlock !== false) { extensions.push(CodeBlock.configure(this.options.codeBlock)); } if (this.options.document !== false) { extensions.push(Document.configure(this.options.document)); } if (this.options.dropcursor !== false) { extensions.push(Dropcursor.configure(this.options.dropcursor)); } if (this.options.gapcursor !== false) { extensions.push(Gapcursor.configure(this.options.gapcursor)); } if (this.options.hardBreak !== false) { extensions.push(HardBreak.configure(this.options.hardBreak)); } if (this.options.heading !== false) { extensions.push(Heading.configure(this.options.heading)); } if (this.options.undoRedo !== false) { extensions.push(UndoRedo.configure(this.options.undoRedo)); } if (this.options.horizontalRule !== false) { extensions.push(HorizontalRule.configure(this.options.horizontalRule)); } if (this.options.italic !== false) { extensions.push(Italic.configure(this.options.italic)); } if (this.options.listItem !== false) { extensions.push(ListItem.configure(this.options.listItem)); } if (this.options.listKeymap !== false) { extensions.push(ListKeymap.configure((_a = this.options) == null ? void 0 : _a.listKeymap)); } if (this.options.link !== false) { extensions.push(Link.configure((_b = this.options) == null ? void 0 : _b.link)); } if (this.options.orderedList !== false) { extensions.push(OrderedList.configure(this.options.orderedList)); } if (this.options.paragraph !== false) { extensions.push(Paragraph.configure(this.options.paragraph)); } if (this.options.strike !== false) { extensions.push(Strike.configure(this.options.strike)); } if (this.options.text !== false) { extensions.push(Text.configure(this.options.text)); } if (this.options.underline !== false) { extensions.push(Underline.configure((_c = this.options) == null ? void 0 : _c.underline)); } if (this.options.trailingNode !== false) { extensions.push(TrailingNode.configure((_d = this.options) == null ? void 0 : _d.trailingNode)); } return extensions; } }); var index_default = StarterKit; // src/exports/elements/tip-tap-editor-base.ts var NON_BREAKING_SPACE = "\xA0"; var TipTapEditorBase = class extends BaseElement { constructor() { super(); // Instance /** * Whether or not the editor should be editable. * * NOTE: a user can change this in the browser dev tools, don't rely on this to prevent * users from editing and attempting to save the document. */ this.readonly = false; /** * Prevents premature rebuilds. */ this.hasInitialized = false; /** * An array of "AttachmentUploads" added via direct upload. Check this for any attachment uploads that have not completed. */ this.pendingAttachments = []; /** * JSON or HTML serializer used for determining the string to write to the hidden input. */ this.serializer = "html"; /** Comma separated string passed to the attach-files input. */ this.accept = "*"; this.starterKitOptions = { // We don't use the native strike since it requires configuring ActionText. strike: false, link: false, rhinoLink: { openOnClick: false } }; /** * This will be concatenated onto RhinoStarterKit and StarterKit extensions. */ this.extensions = []; /** * When the `defer-initialize` attribute is present, it will wait to start the TipTap editor until the attribute has been removed. */ this.deferInitialize = false; /** * @internal */ this.__initialAttributes = {}; /** * @internal */ this.__hasRendered = false; this.__initializationPromise__ = null; this.__initializationResolver__ = null; /** * Used for determining how to handle uploads. * Override this for substituting your own * direct upload functionality. */ this.handleAttachment = (event) => { setTimeout(() => { if (event.defaultPrevented) { return; } const { attachment, target } = event; if (ta