rhino-editor
Version:
A custom element wrapped rich text editor
1,686 lines (1,670 loc) • 72.9 kB
JavaScript
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