UNPKG

@tiptap/core

Version:

headless rich text editor

1,566 lines (1,483 loc) 215 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; 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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { CommandManager: () => CommandManager, Editor: () => Editor, Extendable: () => Extendable, Extension: () => Extension, Fragment: () => Fragment6, InputRule: () => InputRule, Mark: () => Mark, MarkView: () => MarkView, Node: () => Node3, NodePos: () => NodePos, NodeView: () => NodeView, PasteRule: () => PasteRule, ResizableNodeview: () => ResizableNodeview, Tracker: () => Tracker, callOrReturn: () => callOrReturn, canInsertNode: () => canInsertNode, combineTransactionSteps: () => combineTransactionSteps, commands: () => commands_exports, createAtomBlockMarkdownSpec: () => createAtomBlockMarkdownSpec, createBlockMarkdownSpec: () => createBlockMarkdownSpec, createChainableState: () => createChainableState, createDocument: () => createDocument, createElement: () => h, createInlineMarkdownSpec: () => createInlineMarkdownSpec, createNodeFromContent: () => createNodeFromContent, createStyleTag: () => createStyleTag, defaultBlockAt: () => defaultBlockAt, deleteProps: () => deleteProps, elementFromString: () => elementFromString, escapeForRegEx: () => escapeForRegEx, extensions: () => extensions_exports, findChildren: () => findChildren, findChildrenInRange: () => findChildrenInRange, findDuplicates: () => findDuplicates, findParentNode: () => findParentNode, findParentNodeClosestToPos: () => findParentNodeClosestToPos, flattenExtensions: () => flattenExtensions, fromString: () => fromString, generateHTML: () => generateHTML, generateJSON: () => generateJSON, generateText: () => generateText, getAttributes: () => getAttributes, getAttributesFromExtensions: () => getAttributesFromExtensions, getChangedRanges: () => getChangedRanges, getDebugJSON: () => getDebugJSON, getExtensionField: () => getExtensionField, getHTMLFromFragment: () => getHTMLFromFragment, getMarkAttributes: () => getMarkAttributes, getMarkRange: () => getMarkRange, getMarkType: () => getMarkType, getMarksBetween: () => getMarksBetween, getNodeAtPosition: () => getNodeAtPosition, getNodeAttributes: () => getNodeAttributes, getNodeType: () => getNodeType, getRenderedAttributes: () => getRenderedAttributes, getSchema: () => getSchema, getSchemaByResolvedExtensions: () => getSchemaByResolvedExtensions, getSchemaTypeByName: () => getSchemaTypeByName, getSchemaTypeNameByName: () => getSchemaTypeNameByName, getSplittedAttributes: () => getSplittedAttributes, getText: () => getText, getTextBetween: () => getTextBetween, getTextContentFromNodes: () => getTextContentFromNodes, getTextSerializersFromSchema: () => getTextSerializersFromSchema, h: () => h, injectExtensionAttributesToParseRule: () => injectExtensionAttributesToParseRule, inputRulesPlugin: () => inputRulesPlugin, isActive: () => isActive, isAndroid: () => isAndroid, isAtEndOfNode: () => isAtEndOfNode, isAtStartOfNode: () => isAtStartOfNode, isEmptyObject: () => isEmptyObject, isExtensionRulesEnabled: () => isExtensionRulesEnabled, isFunction: () => isFunction, isList: () => isList, isMacOS: () => isMacOS, isMarkActive: () => isMarkActive, isNodeActive: () => isNodeActive, isNodeEmpty: () => isNodeEmpty, isNodeSelection: () => isNodeSelection, isNumber: () => isNumber, isPlainObject: () => isPlainObject, isRegExp: () => isRegExp, isString: () => isString, isTextSelection: () => isTextSelection, isiOS: () => isiOS, markInputRule: () => markInputRule, markPasteRule: () => markPasteRule, markdown: () => markdown_exports, mergeAttributes: () => mergeAttributes, mergeDeep: () => mergeDeep, minMax: () => minMax, nodeInputRule: () => nodeInputRule, nodePasteRule: () => nodePasteRule, objectIncludes: () => objectIncludes, parseAttributes: () => parseAttributes, parseIndentedBlocks: () => parseIndentedBlocks, pasteRulesPlugin: () => pasteRulesPlugin, posToDOMRect: () => posToDOMRect, removeDuplicates: () => removeDuplicates, renderNestedMarkdownContent: () => renderNestedMarkdownContent, resolveExtensions: () => resolveExtensions, resolveFocusPosition: () => resolveFocusPosition, rewriteUnknownContent: () => rewriteUnknownContent, selectionToInsertionEnd: () => selectionToInsertionEnd, serializeAttributes: () => serializeAttributes, sortExtensions: () => sortExtensions, splitExtensions: () => splitExtensions, textInputRule: () => textInputRule, textPasteRule: () => textPasteRule, textblockTypeInputRule: () => textblockTypeInputRule, updateMarkViewAttributes: () => updateMarkViewAttributes, wrappingInputRule: () => wrappingInputRule }); module.exports = __toCommonJS(index_exports); // src/helpers/createChainableState.ts function createChainableState(config) { const { state, transaction } = config; let { selection } = transaction; let { doc } = transaction; let { storedMarks } = transaction; return { ...state, apply: state.apply.bind(state), applyTransaction: state.applyTransaction.bind(state), plugins: state.plugins, schema: state.schema, reconfigure: state.reconfigure.bind(state), toJSON: state.toJSON.bind(state), get storedMarks() { return storedMarks; }, get selection() { return selection; }, get doc() { return doc; }, get tr() { selection = transaction.selection; doc = transaction.doc; storedMarks = transaction.storedMarks; return transaction; } }; } // src/CommandManager.ts var CommandManager = class { constructor(props) { this.editor = props.editor; this.rawCommands = this.editor.extensionManager.commands; this.customState = props.state; } get hasCustomState() { return !!this.customState; } get state() { return this.customState || this.editor.state; } get commands() { const { rawCommands, editor, state } = this; const { view } = editor; const { tr } = state; const props = this.buildProps(tr); return Object.fromEntries( Object.entries(rawCommands).map(([name, command2]) => { const method = (...args) => { const callback = command2(...args)(props); if (!tr.getMeta("preventDispatch") && !this.hasCustomState) { view.dispatch(tr); } return callback; }; return [name, method]; }) ); } get chain() { return () => this.createChain(); } get can() { return () => this.createCan(); } createChain(startTr, shouldDispatch = true) { const { rawCommands, editor, state } = this; const { view } = editor; const callbacks = []; const hasStartTransaction = !!startTr; const tr = startTr || state.tr; const run3 = () => { if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) { view.dispatch(tr); } return callbacks.every((callback) => callback === true); }; const chain = { ...Object.fromEntries( Object.entries(rawCommands).map(([name, command2]) => { const chainedCommand = (...args) => { const props = this.buildProps(tr, shouldDispatch); const callback = command2(...args)(props); callbacks.push(callback); return chain; }; return [name, chainedCommand]; }) ), run: run3 }; return chain; } createCan(startTr) { const { rawCommands, state } = this; const dispatch = false; const tr = startTr || state.tr; const props = this.buildProps(tr, dispatch); const formattedCommands = Object.fromEntries( Object.entries(rawCommands).map(([name, command2]) => { return [name, (...args) => command2(...args)({ ...props, dispatch: void 0 })]; }) ); return { ...formattedCommands, chain: () => this.createChain(tr, dispatch) }; } buildProps(tr, shouldDispatch = true) { const { rawCommands, editor, state } = this; const { view } = editor; const props = { tr, editor, view, state: createChainableState({ state, transaction: tr }), dispatch: shouldDispatch ? () => void 0 : void 0, chain: () => this.createChain(tr, shouldDispatch), can: () => this.createCan(tr), get commands() { return Object.fromEntries( Object.entries(rawCommands).map(([name, command2]) => { return [name, (...args) => command2(...args)(props)]; }) ); } }; return props; } }; // src/commands/index.ts var commands_exports = {}; __export(commands_exports, { blur: () => blur, clearContent: () => clearContent, clearNodes: () => clearNodes, command: () => command, createParagraphNear: () => createParagraphNear, cut: () => cut, deleteCurrentNode: () => deleteCurrentNode, deleteNode: () => deleteNode, deleteRange: () => deleteRange, deleteSelection: () => deleteSelection, enter: () => enter, exitCode: () => exitCode, extendMarkRange: () => extendMarkRange, first: () => first, focus: () => focus, forEach: () => forEach, insertContent: () => insertContent, insertContentAt: () => insertContentAt, joinBackward: () => joinBackward, joinDown: () => joinDown, joinForward: () => joinForward, joinItemBackward: () => joinItemBackward, joinItemForward: () => joinItemForward, joinTextblockBackward: () => joinTextblockBackward, joinTextblockForward: () => joinTextblockForward, joinUp: () => joinUp, keyboardShortcut: () => keyboardShortcut, lift: () => lift, liftEmptyBlock: () => liftEmptyBlock, liftListItem: () => liftListItem, newlineInCode: () => newlineInCode, resetAttributes: () => resetAttributes, scrollIntoView: () => scrollIntoView, selectAll: () => selectAll, selectNodeBackward: () => selectNodeBackward, selectNodeForward: () => selectNodeForward, selectParentNode: () => selectParentNode, selectTextblockEnd: () => selectTextblockEnd, selectTextblockStart: () => selectTextblockStart, setContent: () => setContent, setMark: () => setMark, setMeta: () => setMeta, setNode: () => setNode, setNodeSelection: () => setNodeSelection, setTextSelection: () => setTextSelection, sinkListItem: () => sinkListItem, splitBlock: () => splitBlock, splitListItem: () => splitListItem, toggleList: () => toggleList, toggleMark: () => toggleMark, toggleNode: () => toggleNode, toggleWrap: () => toggleWrap, undoInputRule: () => undoInputRule, unsetAllMarks: () => unsetAllMarks, unsetMark: () => unsetMark, updateAttributes: () => updateAttributes, wrapIn: () => wrapIn, wrapInList: () => wrapInList }); // src/commands/blur.ts var blur = () => ({ editor, view }) => { requestAnimationFrame(() => { var _a; if (!editor.isDestroyed) { ; view.dom.blur(); (_a = window == null ? void 0 : window.getSelection()) == null ? void 0 : _a.removeAllRanges(); } }); return true; }; // src/commands/clearContent.ts var clearContent = (emitUpdate = true) => ({ commands }) => { return commands.setContent("", { emitUpdate }); }; // src/commands/clearNodes.ts var import_transform = require("@tiptap/pm/transform"); var clearNodes = () => ({ state, tr, dispatch }) => { const { selection } = tr; const { ranges } = selection; if (!dispatch) { return true; } ranges.forEach(({ $from, $to }) => { state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => { if (node.type.isText) { return; } const { doc, mapping } = tr; const $mappedFrom = doc.resolve(mapping.map(pos)); const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize)); const nodeRange = $mappedFrom.blockRange($mappedTo); if (!nodeRange) { return; } const targetLiftDepth = (0, import_transform.liftTarget)(nodeRange); if (node.type.isTextblock) { const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index()); tr.setNodeMarkup(nodeRange.start, defaultType); } if (targetLiftDepth || targetLiftDepth === 0) { tr.lift(nodeRange, targetLiftDepth); } }); }); return true; }; // src/commands/command.ts var command = (fn) => (props) => { return fn(props); }; // src/commands/createParagraphNear.ts var import_commands = require("@tiptap/pm/commands"); var createParagraphNear = () => ({ state, dispatch }) => { return (0, import_commands.createParagraphNear)(state, dispatch); }; // src/commands/cut.ts var import_state = require("@tiptap/pm/state"); var cut = (originRange, targetPos) => ({ editor, tr }) => { const { state } = editor; const contentSlice = state.doc.slice(originRange.from, originRange.to); tr.deleteRange(originRange.from, originRange.to); const newPos = tr.mapping.map(targetPos); tr.insert(newPos, contentSlice.content); tr.setSelection(new import_state.TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0)))); return true; }; // src/commands/deleteCurrentNode.ts var deleteCurrentNode = () => ({ tr, dispatch }) => { const { selection } = tr; const currentNode = selection.$anchor.node(); if (currentNode.content.size > 0) { return false; } const $pos = tr.selection.$anchor; for (let depth = $pos.depth; depth > 0; depth -= 1) { const node = $pos.node(depth); if (node.type === currentNode.type) { if (dispatch) { const from = $pos.before(depth); const to = $pos.after(depth); tr.delete(from, to).scrollIntoView(); } return true; } } return false; }; // src/helpers/getNodeType.ts function getNodeType(nameOrType, schema) { if (typeof nameOrType === "string") { if (!schema.nodes[nameOrType]) { throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`); } return schema.nodes[nameOrType]; } return nameOrType; } // src/commands/deleteNode.ts var deleteNode = (typeOrName) => ({ tr, state, dispatch }) => { const type = getNodeType(typeOrName, state.schema); const $pos = tr.selection.$anchor; for (let depth = $pos.depth; depth > 0; depth -= 1) { const node = $pos.node(depth); if (node.type === type) { if (dispatch) { const from = $pos.before(depth); const to = $pos.after(depth); tr.delete(from, to).scrollIntoView(); } return true; } } return false; }; // src/commands/deleteRange.ts var deleteRange = (range) => ({ tr, dispatch }) => { const { from, to } = range; if (dispatch) { tr.delete(from, to); } return true; }; // src/commands/deleteSelection.ts var import_commands2 = require("@tiptap/pm/commands"); var deleteSelection = () => ({ state, dispatch }) => { return (0, import_commands2.deleteSelection)(state, dispatch); }; // src/commands/enter.ts var enter = () => ({ commands }) => { return commands.keyboardShortcut("Enter"); }; // src/commands/exitCode.ts var import_commands3 = require("@tiptap/pm/commands"); var exitCode = () => ({ state, dispatch }) => { return (0, import_commands3.exitCode)(state, dispatch); }; // src/commands/extendMarkRange.ts var import_state2 = require("@tiptap/pm/state"); // src/utilities/isRegExp.ts function isRegExp(value) { return Object.prototype.toString.call(value) === "[object RegExp]"; } // src/utilities/objectIncludes.ts function objectIncludes(object1, object2, options = { strict: true }) { const keys = Object.keys(object2); if (!keys.length) { return true; } return keys.every((key) => { if (options.strict) { return object2[key] === object1[key]; } if (isRegExp(object2[key])) { return object2[key].test(object1[key]); } return object2[key] === object1[key]; }); } // src/helpers/getMarkRange.ts function findMarkInSet(marks, type, attributes = {}) { return marks.find((item) => { return item.type === type && objectIncludes( // Only check equality for the attributes that are provided Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes ); }); } function isMarkInSet(marks, type, attributes = {}) { return !!findMarkInSet(marks, type, attributes); } function getMarkRange($pos, type, attributes) { var _a; if (!$pos || !type) { return; } let start = $pos.parent.childAfter($pos.parentOffset); if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) { start = $pos.parent.childBefore($pos.parentOffset); } if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) { return; } attributes = attributes || ((_a = start.node.marks[0]) == null ? void 0 : _a.attrs); const mark = findMarkInSet([...start.node.marks], type, attributes); if (!mark) { return; } let startIndex = start.index; let startPos = $pos.start() + start.offset; let endIndex = startIndex + 1; let endPos = startPos + start.node.nodeSize; while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) { startIndex -= 1; startPos -= $pos.parent.child(startIndex).nodeSize; } while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) { endPos += $pos.parent.child(endIndex).nodeSize; endIndex += 1; } return { from: startPos, to: endPos }; } // src/helpers/getMarkType.ts function getMarkType(nameOrType, schema) { if (typeof nameOrType === "string") { if (!schema.marks[nameOrType]) { throw Error(`There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`); } return schema.marks[nameOrType]; } return nameOrType; } // src/commands/extendMarkRange.ts var extendMarkRange = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => { const type = getMarkType(typeOrName, state.schema); const { doc, selection } = tr; const { $from, from, to } = selection; if (dispatch) { const range = getMarkRange($from, type, attributes); if (range && range.from <= from && range.to >= to) { const newSelection = import_state2.TextSelection.create(doc, range.from, range.to); tr.setSelection(newSelection); } } return true; }; // src/commands/first.ts var first = (commands) => (props) => { const items = typeof commands === "function" ? commands(props) : commands; for (let i = 0; i < items.length; i += 1) { if (items[i](props)) { return true; } } return false; }; // src/helpers/isTextSelection.ts var import_state3 = require("@tiptap/pm/state"); function isTextSelection(value) { return value instanceof import_state3.TextSelection; } // src/helpers/resolveFocusPosition.ts var import_state4 = require("@tiptap/pm/state"); // src/utilities/minMax.ts function minMax(value = 0, min = 0, max = 0) { return Math.min(Math.max(value, min), max); } // src/helpers/resolveFocusPosition.ts function resolveFocusPosition(doc, position = null) { if (!position) { return null; } const selectionAtStart = import_state4.Selection.atStart(doc); const selectionAtEnd = import_state4.Selection.atEnd(doc); if (position === "start" || position === true) { return selectionAtStart; } if (position === "end") { return selectionAtEnd; } const minPos = selectionAtStart.from; const maxPos = selectionAtEnd.to; if (position === "all") { return import_state4.TextSelection.create(doc, minMax(0, minPos, maxPos), minMax(doc.content.size, minPos, maxPos)); } return import_state4.TextSelection.create(doc, minMax(position, minPos, maxPos), minMax(position, minPos, maxPos)); } // src/utilities/isAndroid.ts function isAndroid() { return navigator.platform === "Android" || /android/i.test(navigator.userAgent); } // src/utilities/isiOS.ts function isiOS() { return ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"].includes(navigator.platform) || // iPad on iOS 13 detection navigator.userAgent.includes("Mac") && "ontouchend" in document; } // src/commands/focus.ts var focus = (position = null, options = {}) => ({ editor, view, tr, dispatch }) => { options = { scrollIntoView: true, ...options }; const delayedFocus = () => { if (isiOS() || isAndroid()) { ; view.dom.focus(); } requestAnimationFrame(() => { if (!editor.isDestroyed) { view.focus(); if (options == null ? void 0 : options.scrollIntoView) { editor.commands.scrollIntoView(); } } }); }; if (view.hasFocus() && position === null || position === false) { return true; } if (dispatch && position === null && !isTextSelection(editor.state.selection)) { delayedFocus(); return true; } const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection; const isSameSelection = editor.state.selection.eq(selection); if (dispatch) { if (!isSameSelection) { tr.setSelection(selection); } if (isSameSelection && tr.storedMarks) { tr.setStoredMarks(tr.storedMarks); } delayedFocus(); } return true; }; // src/commands/forEach.ts var forEach = (items, fn) => (props) => { return items.every((item, index) => fn(item, { ...props, index })); }; // src/commands/insertContent.ts var insertContent = (value, options) => ({ tr, commands }) => { return commands.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options); }; // src/commands/insertContentAt.ts var import_model2 = require("@tiptap/pm/model"); // src/helpers/createNodeFromContent.ts var import_model = require("@tiptap/pm/model"); // src/utilities/elementFromString.ts var removeWhitespaces = (node) => { const children = node.childNodes; for (let i = children.length - 1; i >= 0; i -= 1) { const child = children[i]; if (child.nodeType === 3 && child.nodeValue && /^(\n\s\s|\n)$/.test(child.nodeValue)) { node.removeChild(child); } else if (child.nodeType === 1) { removeWhitespaces(child); } } return node; }; function elementFromString(value) { if (typeof window === "undefined") { throw new Error("[tiptap error]: there is no window object available, so this function cannot be used"); } const wrappedValue = `<body>${value}</body>`; const html = new window.DOMParser().parseFromString(wrappedValue, "text/html").body; return removeWhitespaces(html); } // src/helpers/createNodeFromContent.ts function createNodeFromContent(content, schema, options) { if (content instanceof import_model.Node || content instanceof import_model.Fragment) { return content; } options = { slice: true, parseOptions: {}, ...options }; const isJSONContent = typeof content === "object" && content !== null; const isTextContent = typeof content === "string"; if (isJSONContent) { try { const isArrayContent = Array.isArray(content) && content.length > 0; if (isArrayContent) { return import_model.Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item))); } const node = schema.nodeFromJSON(content); if (options.errorOnInvalidContent) { node.check(); } return node; } catch (error) { if (options.errorOnInvalidContent) { throw new Error("[tiptap error]: Invalid JSON content", { cause: error }); } console.warn("[tiptap warn]: Invalid content.", "Passed value:", content, "Error:", error); return createNodeFromContent("", schema, options); } } if (isTextContent) { if (options.errorOnInvalidContent) { let hasInvalidContent = false; let invalidContent = ""; const contentCheckSchema = new import_model.Schema({ topNode: schema.spec.topNode, marks: schema.spec.marks, // Prosemirror's schemas are executed such that: the last to execute, matches last // This means that we can add a catch-all node at the end of the schema to catch any content that we don't know how to handle nodes: schema.spec.nodes.append({ __tiptap__private__unknown__catch__all__node: { content: "inline*", group: "block", parseDOM: [ { tag: "*", getAttrs: (e) => { hasInvalidContent = true; invalidContent = typeof e === "string" ? e : e.outerHTML; return null; } } ] } }) }); if (options.slice) { import_model.DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions); } else { import_model.DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions); } if (options.errorOnInvalidContent && hasInvalidContent) { throw new Error("[tiptap error]: Invalid HTML content", { cause: new Error(`Invalid element found: ${invalidContent}`) }); } } const parser = import_model.DOMParser.fromSchema(schema); if (options.slice) { return parser.parseSlice(elementFromString(content), options.parseOptions).content; } return parser.parse(elementFromString(content), options.parseOptions); } return createNodeFromContent("", schema, options); } // src/helpers/selectionToInsertionEnd.ts var import_state5 = require("@tiptap/pm/state"); var import_transform2 = require("@tiptap/pm/transform"); function selectionToInsertionEnd(tr, startLen, bias) { const last = tr.steps.length - 1; if (last < startLen) { return; } const step = tr.steps[last]; if (!(step instanceof import_transform2.ReplaceStep || step instanceof import_transform2.ReplaceAroundStep)) { return; } const map = tr.mapping.maps[last]; let end = 0; map.forEach((_from, _to, _newFrom, newTo) => { if (end === 0) { end = newTo; } }); tr.setSelection(import_state5.Selection.near(tr.doc.resolve(end), bias)); } // src/commands/insertContentAt.ts var isFragment = (nodeOrFragment) => { return !("type" in nodeOrFragment); }; var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) => { var _a; if (dispatch) { options = { parseOptions: editor.options.parseOptions, updateSelection: true, applyInputRules: false, applyPasteRules: false, ...options }; let content; const emitContentError = (error) => { editor.emit("contentError", { editor, error, disableCollaboration: () => { if ("collaboration" in editor.storage && typeof editor.storage.collaboration === "object" && editor.storage.collaboration) { ; editor.storage.collaboration.isDisabled = true; } } }); }; const parseOptions = { preserveWhitespace: "full", ...options.parseOptions }; if (!options.errorOnInvalidContent && !editor.options.enableContentCheck && editor.options.emitContentError) { try { createNodeFromContent(value, editor.schema, { parseOptions, errorOnInvalidContent: true }); } catch (e) { emitContentError(e); } } try { content = createNodeFromContent(value, editor.schema, { parseOptions, errorOnInvalidContent: (_a = options.errorOnInvalidContent) != null ? _a : editor.options.enableContentCheck }); } catch (e) { emitContentError(e); return false; } let { from, to } = typeof position === "number" ? { from: position, to: position } : { from: position.from, to: position.to }; let isOnlyTextContent = true; let isOnlyBlockContent = true; const nodes = isFragment(content) ? content : [content]; nodes.forEach((node) => { node.check(); isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false; isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false; }); if (from === to && isOnlyBlockContent) { const { parent } = tr.doc.resolve(from); const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount; if (isEmptyTextBlock) { from -= 1; to += 1; } } let newContent; if (isOnlyTextContent) { if (Array.isArray(value)) { newContent = value.map((v) => v.text || "").join(""); } else if (value instanceof import_model2.Fragment) { let text = ""; value.forEach((node) => { if (node.text) { text += node.text; } }); newContent = text; } else if (typeof value === "object" && !!value && !!value.text) { newContent = value.text; } else { newContent = value; } tr.insertText(newContent, from, to); } else { newContent = content; const $from = tr.doc.resolve(from); const $fromNode = $from.node(); const fromSelectionAtStart = $from.parentOffset === 0; const isTextSelection2 = $fromNode.isText || $fromNode.isTextblock; const hasContent = $fromNode.content.size > 0; if (fromSelectionAtStart && isTextSelection2 && hasContent) { from = Math.max(0, from - 1); } tr.replaceWith(from, to, newContent); } if (options.updateSelection) { selectionToInsertionEnd(tr, tr.steps.length - 1, -1); } if (options.applyInputRules) { tr.setMeta("applyInputRules", { from, text: newContent }); } if (options.applyPasteRules) { tr.setMeta("applyPasteRules", { from, text: newContent }); } } return true; }; // src/commands/join.ts var import_commands4 = require("@tiptap/pm/commands"); var joinUp = () => ({ state, dispatch }) => { return (0, import_commands4.joinUp)(state, dispatch); }; var joinDown = () => ({ state, dispatch }) => { return (0, import_commands4.joinDown)(state, dispatch); }; var joinBackward = () => ({ state, dispatch }) => { return (0, import_commands4.joinBackward)(state, dispatch); }; var joinForward = () => ({ state, dispatch }) => { return (0, import_commands4.joinForward)(state, dispatch); }; // src/commands/joinItemBackward.ts var import_transform3 = require("@tiptap/pm/transform"); var joinItemBackward = () => ({ state, dispatch, tr }) => { try { const point = (0, import_transform3.joinPoint)(state.doc, state.selection.$from.pos, -1); if (point === null || point === void 0) { return false; } tr.join(point, 2); if (dispatch) { dispatch(tr); } return true; } catch { return false; } }; // src/commands/joinItemForward.ts var import_transform4 = require("@tiptap/pm/transform"); var joinItemForward = () => ({ state, dispatch, tr }) => { try { const point = (0, import_transform4.joinPoint)(state.doc, state.selection.$from.pos, 1); if (point === null || point === void 0) { return false; } tr.join(point, 2); if (dispatch) { dispatch(tr); } return true; } catch { return false; } }; // src/commands/joinTextblockBackward.ts var import_commands5 = require("@tiptap/pm/commands"); var joinTextblockBackward = () => ({ state, dispatch }) => { return (0, import_commands5.joinTextblockBackward)(state, dispatch); }; // src/commands/joinTextblockForward.ts var import_commands6 = require("@tiptap/pm/commands"); var joinTextblockForward = () => ({ state, dispatch }) => { return (0, import_commands6.joinTextblockForward)(state, dispatch); }; // src/utilities/isMacOS.ts function isMacOS() { return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false; } // src/commands/keyboardShortcut.ts function normalizeKeyName(name) { const parts = name.split(/-(?!$)/); let result = parts[parts.length - 1]; if (result === "Space") { result = " "; } let alt; let ctrl; let shift; let meta; for (let i = 0; i < parts.length - 1; i += 1) { const mod = parts[i]; if (/^(cmd|meta|m)$/i.test(mod)) { meta = true; } else if (/^a(lt)?$/i.test(mod)) { alt = true; } else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; } else if (/^s(hift)?$/i.test(mod)) { shift = true; } else if (/^mod$/i.test(mod)) { if (isiOS() || isMacOS()) { meta = true; } else { ctrl = true; } } else { throw new Error(`Unrecognized modifier name: ${mod}`); } } if (alt) { result = `Alt-${result}`; } if (ctrl) { result = `Ctrl-${result}`; } if (meta) { result = `Meta-${result}`; } if (shift) { result = `Shift-${result}`; } return result; } var keyboardShortcut = (name) => ({ editor, view, tr, dispatch }) => { const keys = normalizeKeyName(name).split(/-(?!$)/); const key = keys.find((item) => !["Alt", "Ctrl", "Meta", "Shift"].includes(item)); const event = new KeyboardEvent("keydown", { key: key === "Space" ? " " : key, altKey: keys.includes("Alt"), ctrlKey: keys.includes("Ctrl"), metaKey: keys.includes("Meta"), shiftKey: keys.includes("Shift"), bubbles: true, cancelable: true }); const capturedTransaction = editor.captureTransaction(() => { view.someProp("handleKeyDown", (f) => f(view, event)); }); capturedTransaction == null ? void 0 : capturedTransaction.steps.forEach((step) => { const newStep = step.map(tr.mapping); if (newStep && dispatch) { tr.maybeStep(newStep); } }); return true; }; // src/commands/lift.ts var import_commands7 = require("@tiptap/pm/commands"); // src/helpers/isNodeActive.ts function isNodeActive(state, typeOrName, attributes = {}) { const { from, to, empty } = state.selection; const type = typeOrName ? getNodeType(typeOrName, state.schema) : null; const nodeRanges = []; state.doc.nodesBetween(from, to, (node, pos) => { if (node.isText) { return; } const relativeFrom = Math.max(from, pos); const relativeTo = Math.min(to, pos + node.nodeSize); nodeRanges.push({ node, from: relativeFrom, to: relativeTo }); }); const selectionRange = to - from; const matchedNodeRanges = nodeRanges.filter((nodeRange) => { if (!type) { return true; } return type.name === nodeRange.node.type.name; }).filter((nodeRange) => objectIncludes(nodeRange.node.attrs, attributes, { strict: false })); if (empty) { return !!matchedNodeRanges.length; } const range = matchedNodeRanges.reduce((sum, nodeRange) => sum + nodeRange.to - nodeRange.from, 0); return range >= selectionRange; } // src/commands/lift.ts var lift = (typeOrName, attributes = {}) => ({ state, dispatch }) => { const type = getNodeType(typeOrName, state.schema); const isActive2 = isNodeActive(state, type, attributes); if (!isActive2) { return false; } return (0, import_commands7.lift)(state, dispatch); }; // src/commands/liftEmptyBlock.ts var import_commands8 = require("@tiptap/pm/commands"); var liftEmptyBlock = () => ({ state, dispatch }) => { return (0, import_commands8.liftEmptyBlock)(state, dispatch); }; // src/commands/liftListItem.ts var import_schema_list = require("@tiptap/pm/schema-list"); var liftListItem = (typeOrName) => ({ state, dispatch }) => { const type = getNodeType(typeOrName, state.schema); return (0, import_schema_list.liftListItem)(type)(state, dispatch); }; // src/commands/newlineInCode.ts var import_commands9 = require("@tiptap/pm/commands"); var newlineInCode = () => ({ state, dispatch }) => { return (0, import_commands9.newlineInCode)(state, dispatch); }; // src/helpers/getSchemaTypeNameByName.ts function getSchemaTypeNameByName(name, schema) { if (schema.nodes[name]) { return "node"; } if (schema.marks[name]) { return "mark"; } return null; } // src/utilities/deleteProps.ts function deleteProps(obj, propOrProps) { const props = typeof propOrProps === "string" ? [propOrProps] : propOrProps; return Object.keys(obj).reduce((newObj, prop) => { if (!props.includes(prop)) { newObj[prop] = obj[prop]; } return newObj; }, {}); } // src/commands/resetAttributes.ts var resetAttributes = (typeOrName, attributes) => ({ tr, state, dispatch }) => { let nodeType = null; let markType = null; const schemaType = getSchemaTypeNameByName( typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema ); if (!schemaType) { return false; } if (schemaType === "node") { nodeType = getNodeType(typeOrName, state.schema); } if (schemaType === "mark") { markType = getMarkType(typeOrName, state.schema); } if (dispatch) { tr.selection.ranges.forEach((range) => { state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => { if (nodeType && nodeType === node.type) { tr.setNodeMarkup(pos, void 0, deleteProps(node.attrs, attributes)); } if (markType && node.marks.length) { node.marks.forEach((mark) => { if (markType === mark.type) { tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes))); } }); } }); }); } return true; }; // src/commands/scrollIntoView.ts var scrollIntoView = () => ({ tr, dispatch }) => { if (dispatch) { tr.scrollIntoView(); } return true; }; // src/commands/selectAll.ts var import_state6 = require("@tiptap/pm/state"); var selectAll = () => ({ tr, dispatch }) => { if (dispatch) { const selection = new import_state6.AllSelection(tr.doc); tr.setSelection(selection); } return true; }; // src/commands/selectNodeBackward.ts var import_commands10 = require("@tiptap/pm/commands"); var selectNodeBackward = () => ({ state, dispatch }) => { return (0, import_commands10.selectNodeBackward)(state, dispatch); }; // src/commands/selectNodeForward.ts var import_commands11 = require("@tiptap/pm/commands"); var selectNodeForward = () => ({ state, dispatch }) => { return (0, import_commands11.selectNodeForward)(state, dispatch); }; // src/commands/selectParentNode.ts var import_commands12 = require("@tiptap/pm/commands"); var selectParentNode = () => ({ state, dispatch }) => { return (0, import_commands12.selectParentNode)(state, dispatch); }; // src/commands/selectTextblockEnd.ts var import_commands13 = require("@tiptap/pm/commands"); var selectTextblockEnd = () => ({ state, dispatch }) => { return (0, import_commands13.selectTextblockEnd)(state, dispatch); }; // src/commands/selectTextblockStart.ts var import_commands14 = require("@tiptap/pm/commands"); var selectTextblockStart = () => ({ state, dispatch }) => { return (0, import_commands14.selectTextblockStart)(state, dispatch); }; // src/helpers/createDocument.ts function createDocument(content, schema, parseOptions = {}, options = {}) { return createNodeFromContent(content, schema, { slice: false, parseOptions, errorOnInvalidContent: options.errorOnInvalidContent }); } // src/commands/setContent.ts var setContent = (content, { errorOnInvalidContent, emitUpdate = true, parseOptions = {} } = {}) => ({ editor, tr, dispatch, commands }) => { const { doc } = tr; if (parseOptions.preserveWhitespace !== "full") { const document2 = createDocument(content, editor.schema, parseOptions, { errorOnInvalidContent: errorOnInvalidContent != null ? errorOnInvalidContent : editor.options.enableContentCheck }); if (dispatch) { tr.replaceWith(0, doc.content.size, document2).setMeta("preventUpdate", !emitUpdate); } return true; } if (dispatch) { tr.setMeta("preventUpdate", !emitUpdate); } return commands.insertContentAt({ from: 0, to: doc.content.size }, content, { parseOptions, errorOnInvalidContent: errorOnInvalidContent != null ? errorOnInvalidContent : editor.options.enableContentCheck }); }; // src/helpers/getMarkAttributes.ts function getMarkAttributes(state, typeOrName) { const type = getMarkType(typeOrName, state.schema); const { from, to, empty } = state.selection; const marks = []; if (empty) { if (state.storedMarks) { marks.push(...state.storedMarks); } marks.push(...state.selection.$head.marks()); } else { state.doc.nodesBetween(from, to, (node) => { marks.push(...node.marks); }); } const mark = marks.find((markItem) => markItem.type.name === type.name); if (!mark) { return {}; } return { ...mark.attrs }; } // src/helpers/combineTransactionSteps.ts var import_transform5 = require("@tiptap/pm/transform"); function combineTransactionSteps(oldDoc, transactions) { const transform = new import_transform5.Transform(oldDoc); transactions.forEach((transaction) => { transaction.steps.forEach((step) => { transform.step(step); }); }); return transform; } // src/helpers/defaultBlockAt.ts function defaultBlockAt(match) { for (let i = 0; i < match.edgeCount; i += 1) { const { type } = match.edge(i); if (type.isTextblock && !type.hasRequiredAttrs()) { return type; } } return null; } // src/helpers/findChildren.ts function findChildren(node, predicate) { const nodesWithPos = []; node.descendants((child, pos) => { if (predicate(child)) { nodesWithPos.push({ node: child, pos }); } }); return nodesWithPos; } // src/helpers/findChildrenInRange.ts function findChildrenInRange(node, range, predicate) { const nodesWithPos = []; node.nodesBetween(range.from, range.to, (child, pos) => { if (predicate(child)) { nodesWithPos.push({ node: child, pos }); } }); return nodesWithPos; } // src/helpers/findParentNodeClosestToPos.ts function findParentNodeClosestToPos($pos, predicate) { for (let i = $pos.depth; i > 0; i -= 1) { const node = $pos.node(i); if (predicate(node)) { return { pos: i > 0 ? $pos.before(i) : 0, start: $pos.start(i), depth: i, node }; } } } // src/helpers/findParentNode.ts function findParentNode(predicate) { return (selection) => findParentNodeClosestToPos(selection.$from, predicate); } // src/helpers/getExtensionField.ts function getExtensionField(extension, field, context) { if (extension.config[field] === void 0 && extension.parent) { return getExtensionField(extension.parent, field, context); } if (typeof extension.config[field] === "function") { const value = extension.config[field].bind({ ...context, parent: extension.parent ? getExtensionField(extension.parent, field, context) : null }); return value; } return extension.config[field]; } // src/helpers/flattenExtensions.ts function flattenExtensions(extensions) { return extensions.map((extension) => { const context = { name: extension.name, options: extension.options, storage: extension.storage }; const addExtensions = getExtensionField(extension, "addExtensions", context); if (addExtensions) { return [extension, ...flattenExtensions(addExtensions())]; } return extension; }).flat(10); } // src/helpers/generateHTML.ts var import_model5 = require("@tiptap/pm/model"); // src/helpers/getHTMLFromFragment.ts var import_model3 = require("@tiptap/pm/model"); function getHTMLFromFragment(fragment, schema) { const documentFragment = import_model3.DOMSerializer.fromSchema(schema).serializeFragment(fragment); const temporaryDocument = document.implementation.createHTMLDocument(); const container = temporaryDocument.createElement("div"); container.appendChild(documentFragment); return container.innerHTML; } // src/helpers/getSchemaByResolvedExtensions.ts var import_model4 = require("@tiptap/pm/model"); // src/utilities/isFunction.ts function isFunction(value) { return typeof value === "function"; } // src/utilities/callOrReturn.ts function callOrReturn(value, context = void 0, ...props) { if (isFunction(value)) { if (context) { return value.bind(context)(...props); } return value(...props); } return value; } // src/utilities/isEmptyObject.ts function isEmptyObject(value = {}) { return Object.keys(value).length === 0 && value.constructor === Object; } // src/helpers/splitExtensions.ts function splitExtensions(extensions) { const baseExtensions = extensions.filter((extension) => extension.type === "extension"); const nodeExtensions = extensions.filter((extension) => extension.type === "node"); const markExtensions = extensions.filter((extension) => extension.type === "mark"); return { baseExtensions, nodeExtensions, markExtensions }; } // src/helpers/getAttributesFromExtensions.ts function getAttributesFromExtensions(extensions) { const extensionAttributes = []; const { nodeExtensions, markExtensions } = splitExtensions(extensions); const nodeAndMarkExtensions = [...nodeExtensions, ...markExtensions]; const defaultAttribute = { default: null, validate: void 0, rendered: true, renderHTML: null, parseHTML: null, keepOnSplit: true, isRequired: false }; extensions.forEach((extension) => { const context = { name: extension.name, options: extension.options, storage: extension.storage, extensions: nodeAndMarkExtensions }; const addGlobalAttributes = getExtensionField( extension, "addGlobalAttributes", context ); if (!addGlobalAttributes) { return; } const globalAttributes = addGlobalAttributes(); globalAttributes.forEach((globalAttribute) => { globalAttribute.types.forEach((type) => { Object.entries(globalAttribute.attributes).forEach(([name, attribute]) => { extensionAttributes.push({ type, name, attribute: { ...defaultAttribute, ...attribute } }); }); }); }); }); nodeAndMarkExtensions.forEach((extension) => { const context = { name: extension.name, options: extension.options, storage: extension.storage }; const addAttributes = getExtensionField( extension, "addAttributes", context ); if (!addAttributes) { return; } const attributes = addAttributes(); Object.entries(attributes).forEach(([name, attribute]) => { const mergedAttr = { ...defaultAttribute, ...attribute }; if (typeof (mergedAttr == null ? void 0 : mergedAttr.default) === "function") { mergedAttr.default = mergedAttr.default(); } if ((mergedAttr == null ? void 0 : mergedAttr.isRequired) && (mergedAttr == null ? void 0 : mergedAttr.default) === void 0) { delete mergedAttr.default; } extensionAttributes.push({ type: extension.name, name, attribute: mergedAttr }); }); }); return extensionAttributes; } // src/utilities/mergeAttributes.ts function mergeAttributes(...objects) { return objects.filter((item) => !!item).reduce((items, item) => { const mergedAttributes = { ...items }; Object.entries(item).forEach(([key, value]) => { const exists = mergedAttributes[key]; if (!exists) { mergedAttributes[key] = value; return; } if (key === "class") { const valueClasses = value ? String(value).split(" ") : []; const existingClasses = mergedAttributes[key] ? mergedAttributes[key].split(" ") : []; const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass)); mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" "); } else if (key === "style") { const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : []; const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : []; const styleMap = /* @__PURE__ */ new Map(); existingStyles.forEach((style2) => { const [property, val] = style2.split(":").map((part) => part.trim()); styleMap.set(property, val); }); newStyles.forEach((style2) => { const [property, val] = style2.split(":").map((part) => part.trim()); styleMap.set(property, val); }); mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; "); } else { mergedAttributes[key] = value; } }); return mergedAttributes; }, {}); } // src/helpers/getRenderedAttributes.ts function getRenderedAttributes(nodeOrMark, extensionAttributes) { return extensionAttributes.filter((attribute) => attribute.type === nodeOrMark.type.name).filter((item) => item.attribute.rendered).map((item) => { if (!item.attribute.renderHTML) { return { [item.name]: nodeOrMark.attrs[item.name