UNPKG

reactjs-tiptap-editor

Version:

A modern WYSIWYG rich text editor based on tiptap and shadcn ui for React

708 lines (707 loc) 20.8 kB
import { N as L, w as k, m, r as E, E as H, p as M, i as g, a as B, b as j, g as $, c as K } from "./clsx-DaPvp9ji.js"; var V = Object.defineProperty, X = (t, e) => { for (var s in e) V(t, s, { get: e[s], enumerable: !0 }); }, z = "listItem", x = "textStyle", w = /^\s*([-+*])\s$/, F = L.create({ name: "bulletList", addOptions() { return { itemTypeName: "listItem", HTMLAttributes: {}, keepMarks: !1, keepAttributes: !1 }; }, group: "block list", content() { return `${this.options.itemTypeName}+`; }, parseHTML() { return [{ tag: "ul" }]; }, renderHTML({ HTMLAttributes: t }) { return ["ul", m(this.options.HTMLAttributes, t), 0]; }, markdownTokenName: "list", parseMarkdown: (t, e) => t.type !== "list" || t.ordered ? [] : { type: "bulletList", content: t.items ? e.parseChildren(t.items) : [] }, renderMarkdown: (t, e) => t.content ? e.renderChildren(t.content, ` `) : "", markdownOptions: { indentsContent: !0 }, addCommands() { return { toggleBulletList: () => ({ commands: t, chain: e }) => this.options.keepAttributes ? e().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(z, this.editor.getAttributes(x)).run() : t.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks) }; }, addKeyboardShortcuts() { return { "Mod-Shift-8": () => this.editor.commands.toggleBulletList() }; }, addInputRules() { let t = k({ find: w, type: this.type }); return (this.options.keepMarks || this.options.keepAttributes) && (t = k({ find: w, type: this.type, keepMarks: this.options.keepMarks, keepAttributes: this.options.keepAttributes, getAttributes: () => this.editor.getAttributes(x), editor: this.editor })), [t]; } }), G = L.create({ name: "listItem", addOptions() { return { HTMLAttributes: {}, bulletListTypeName: "bulletList", orderedListTypeName: "orderedList" }; }, content: "paragraph block*", defining: !0, parseHTML() { return [ { tag: "li" } ]; }, renderHTML({ HTMLAttributes: t }) { return ["li", m(this.options.HTMLAttributes, t), 0]; }, markdownTokenName: "list_item", parseMarkdown: (t, e) => { if (t.type !== "list_item") return []; let s = []; if (t.tokens && t.tokens.length > 0) if (t.tokens.some((r) => r.type === "paragraph")) s = e.parseChildren(t.tokens); else { const r = t.tokens[0]; if (r && r.type === "text" && r.tokens && r.tokens.length > 0) { if (s = [ { type: "paragraph", content: e.parseInline(r.tokens) } ], t.tokens.length > 1) { const c = t.tokens.slice(1), a = e.parseChildren(c); s.push(...a); } } else s = e.parseChildren(t.tokens); } return s.length === 0 && (s = [ { type: "paragraph", content: [] } ]), { type: "listItem", content: s }; }, renderMarkdown: (t, e, s) => E( t, e, (n) => n.parentType === "bulletList" ? "- " : n.parentType === "orderedList" ? `${n.index + 1}. ` : "- ", s ), addKeyboardShortcuts() { return { Enter: () => this.editor.commands.splitListItem(this.name), Tab: () => this.editor.commands.sinkListItem(this.name), "Shift-Tab": () => this.editor.commands.liftListItem(this.name) }; } }), W = {}; X(W, { findListItemPos: () => b, getNextListDepth: () => T, handleBackspace: () => v, handleDelete: () => I, hasListBefore: () => S, hasListItemAfter: () => q, hasListItemBefore: () => O, listItemHasSubList: () => P, nextListIsDeeper: () => _, nextListIsHigher: () => D }); var b = (t, e) => { const { $from: s } = e.selection, n = $(t, e.schema); let r = null, i = s.depth, c = s.pos, a = null; for (; i > 0 && a === null; ) r = s.node(i), r.type === n ? a = i : (i -= 1, c -= 1); return a === null ? null : { $pos: e.doc.resolve(c), depth: a }; }, T = (t, e) => { const s = b(t, e); if (!s) return !1; const [, n] = K(e, t, s.$pos.pos + 4); return n; }, S = (t, e, s) => { const { $anchor: n } = t.selection, r = Math.max(0, n.pos - 2), i = t.doc.resolve(r).node(); return !(!i || !s.includes(i.type.name)); }, O = (t, e) => { var s; const { $anchor: n } = e.selection, r = e.doc.resolve(n.pos - 2); return !(r.index() === 0 || ((s = r.nodeBefore) == null ? void 0 : s.type.name) !== t); }, P = (t, e, s) => { if (!s) return !1; const n = $(t, e.schema); let r = !1; return s.descendants((i) => { i.type === n && (r = !0); }), r; }, v = (t, e, s) => { if (t.commands.undoInputRule()) return !0; if (t.state.selection.from !== t.state.selection.to) return !1; if (!g(t.state, e) && S(t.state, e, s)) { const { $anchor: a } = t.state.selection, p = t.state.doc.resolve(a.before() - 1), h = []; p.node().descendants((l, u) => { l.type.name === e && h.push({ node: l, pos: u }); }); const o = h.at(-1); if (!o) return !1; const d = t.state.doc.resolve(p.start() + o.pos + 1); return t.chain().cut({ from: a.start() - 1, to: a.end() + 1 }, d.end()).joinForward().run(); } if (!g(t.state, e) || !B(t.state)) return !1; const n = b(e, t.state); if (!n) return !1; const i = t.state.doc.resolve(n.$pos.pos - 2).node(n.depth), c = P(e, t.state, i); return O(e, t.state) && !c ? t.commands.joinItemBackward() : t.chain().liftListItem(e).run(); }, _ = (t, e) => { const s = T(t, e), n = b(t, e); return !n || !s ? !1 : s > n.depth; }, D = (t, e) => { const s = T(t, e), n = b(t, e); return !n || !s ? !1 : s < n.depth; }, I = (t, e) => { if (!g(t.state, e) || !j(t.state, e)) return !1; const { selection: s } = t.state, { $from: n, $to: r } = s; return !s.empty && n.sameParent(r) ? !1 : _(e, t.state) ? t.chain().focus(t.state.selection.from + 4).lift(e).joinBackward().run() : D(e, t.state) ? t.chain().joinForward().joinBackward().run() : t.commands.joinItemForward(); }, q = (t, e) => { var s; const { $anchor: n } = e.selection, r = e.doc.resolve(n.pos - n.parentOffset - 2); return !(r.index() === r.parent.childCount - 1 || ((s = r.nodeAfter) == null ? void 0 : s.type.name) !== t); }, Y = H.create({ name: "listKeymap", addOptions() { return { listTypes: [ { itemName: "listItem", wrapperNames: ["bulletList", "orderedList"] }, { itemName: "taskItem", wrapperNames: ["taskList"] } ] }; }, addKeyboardShortcuts() { return { Delete: ({ editor: t }) => { let e = !1; return this.options.listTypes.forEach(({ itemName: s }) => { t.state.schema.nodes[s] !== void 0 && I(t, s) && (e = !0); }), e; }, "Mod-Delete": ({ editor: t }) => { let e = !1; return this.options.listTypes.forEach(({ itemName: s }) => { t.state.schema.nodes[s] !== void 0 && I(t, s) && (e = !0); }), e; }, Backspace: ({ editor: t }) => { let e = !1; return this.options.listTypes.forEach(({ itemName: s, wrapperNames: n }) => { t.state.schema.nodes[s] !== void 0 && v(t, s, n) && (e = !0); }), e; }, "Mod-Backspace": ({ editor: t }) => { let e = !1; return this.options.listTypes.forEach(({ itemName: s, wrapperNames: n }) => { t.state.schema.nodes[s] !== void 0 && v(t, s, n) && (e = !0); }), e; } }; } }), A = /^(\s*)(\d+)\.\s+(.*)$/, J = /^\s/; function Q(t) { const e = []; let s = 0, n = 0; for (; s < t.length; ) { const r = t[s], i = r.match(A); if (!i) break; const [, c, a, p] = i, h = c.length; let o = p, d = s + 1; const l = [r]; for (; d < t.length; ) { const u = t[d]; if (u.match(A)) break; if (u.trim() === "") l.push(u), o += ` `, d += 1; else if (u.match(J)) l.push(u), o += ` ${u.slice(h + 2)}`, d += 1; else break; } e.push({ indent: h, number: parseInt(a, 10), content: o.trim(), raw: l.join(` `) }), n = d, s = d; } return [e, n]; } function R(t, e, s) { var n; const r = []; let i = 0; for (; i < t.length; ) { const c = t[i]; if (c.indent === e) { const a = c.content.split(` `), p = ((n = a[0]) == null ? void 0 : n.trim()) || "", h = []; p && h.push({ type: "paragraph", raw: p, tokens: s.inlineTokens(p) }); const o = a.slice(1).join(` `).trim(); if (o) { const u = s.blockTokens(o); h.push(...u); } let d = i + 1; const l = []; for (; d < t.length && t[d].indent > e; ) l.push(t[d]), d += 1; if (l.length > 0) { const u = Math.min(...l.map((y) => y.indent)), f = R(l, u, s); h.push({ type: "list", ordered: !0, start: l[0].number, items: f, raw: l.map((y) => y.raw).join(` `) }); } r.push({ type: "list_item", raw: c.raw, tokens: h }), i = d; } else i += 1; } return r; } function U(t, e) { return t.map((s) => { if (s.type !== "list_item") return e.parseChildren([s])[0]; const n = []; return s.tokens && s.tokens.length > 0 && s.tokens.forEach((r) => { if (r.type === "paragraph" || r.type === "list" || r.type === "blockquote" || r.type === "code") n.push(...e.parseChildren([r])); else if (r.type === "text" && r.tokens) { const i = e.parseChildren([r]); n.push({ type: "paragraph", content: i }); } else { const i = e.parseChildren([r]); i.length > 0 && n.push(...i); } }), { type: "listItem", content: n }; }); } var Z = "listItem", C = "textStyle", N = /^(\d+)\.\s$/, tt = L.create({ name: "orderedList", addOptions() { return { itemTypeName: "listItem", HTMLAttributes: {}, keepMarks: !1, keepAttributes: !1 }; }, group: "block list", content() { return `${this.options.itemTypeName}+`; }, addAttributes() { return { start: { default: 1, parseHTML: (t) => t.hasAttribute("start") ? parseInt(t.getAttribute("start") || "", 10) : 1 }, type: { default: null, parseHTML: (t) => t.getAttribute("type") } }; }, parseHTML() { return [ { tag: "ol" } ]; }, renderHTML({ HTMLAttributes: t }) { const { start: e, ...s } = t; return e === 1 ? ["ol", m(this.options.HTMLAttributes, s), 0] : ["ol", m(this.options.HTMLAttributes, t), 0]; }, markdownTokenName: "list", parseMarkdown: (t, e) => { if (t.type !== "list" || !t.ordered) return []; const s = t.start || 1, n = t.items ? U(t.items, e) : []; return s !== 1 ? { type: "orderedList", attrs: { start: s }, content: n } : { type: "orderedList", content: n }; }, renderMarkdown: (t, e) => t.content ? e.renderChildren(t.content, ` `) : "", markdownTokenizer: { name: "orderedList", level: "block", start: (t) => { const e = t.match(/^(\s*)(\d+)\.\s+/), s = e == null ? void 0 : e.index; return s !== void 0 ? s : -1; }, tokenize: (t, e, s) => { var n; const r = t.split(` `), [i, c] = Q(r); if (i.length === 0) return; const a = R(i, 0, s); return a.length === 0 ? void 0 : { type: "list", ordered: !0, start: ((n = i[0]) == null ? void 0 : n.number) || 1, items: a, raw: r.slice(0, c).join(` `) }; } }, markdownOptions: { indentsContent: !0 }, addCommands() { return { toggleOrderedList: () => ({ commands: t, chain: e }) => this.options.keepAttributes ? e().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(Z, this.editor.getAttributes(C)).run() : t.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks) }; }, addKeyboardShortcuts() { return { "Mod-Shift-7": () => this.editor.commands.toggleOrderedList() }; }, addInputRules() { let t = k({ find: N, type: this.type, getAttributes: (e) => ({ start: +e[1] }), joinPredicate: (e, s) => s.childCount + s.attrs.start === +e[1] }); return (this.options.keepMarks || this.options.keepAttributes) && (t = k({ find: N, type: this.type, keepMarks: this.options.keepMarks, keepAttributes: this.options.keepAttributes, getAttributes: (e) => ({ start: +e[1], ...this.editor.getAttributes(C) }), joinPredicate: (e, s) => s.childCount + s.attrs.start === +e[1], editor: this.editor })), [t]; } }), et = /^\s*(\[([( |x])?\])\s$/, st = L.create({ name: "taskItem", addOptions() { return { nested: !1, HTMLAttributes: {}, taskListTypeName: "taskList", a11y: void 0 }; }, content() { return this.options.nested ? "paragraph block*" : "paragraph+"; }, defining: !0, addAttributes() { return { checked: { default: !1, keepOnSplit: !1, parseHTML: (t) => { const e = t.getAttribute("data-checked"); return e === "" || e === "true"; }, renderHTML: (t) => ({ "data-checked": t.checked }) } }; }, parseHTML() { return [ { tag: `li[data-type="${this.name}"]`, priority: 51 } ]; }, renderHTML({ node: t, HTMLAttributes: e }) { return [ "li", m(this.options.HTMLAttributes, e, { "data-type": this.name }), [ "label", [ "input", { type: "checkbox", checked: t.attrs.checked ? "checked" : null } ], ["span"] ], ["div", 0] ]; }, parseMarkdown: (t, e) => { const s = []; if (t.tokens && t.tokens.length > 0 ? s.push(e.createNode("paragraph", {}, e.parseInline(t.tokens))) : t.text ? s.push(e.createNode("paragraph", {}, [e.createNode("text", { text: t.text })])) : s.push(e.createNode("paragraph", {}, [])), t.nestedTokens && t.nestedTokens.length > 0) { const n = e.parseChildren(t.nestedTokens); s.push(...n); } return e.createNode("taskItem", { checked: t.checked || !1 }, s); }, renderMarkdown: (t, e) => { var s; const r = `- [${(s = t.attrs) != null && s.checked ? "x" : " "}] `; return E(t, e, r); }, addKeyboardShortcuts() { const t = { Enter: () => this.editor.commands.splitListItem(this.name), "Shift-Tab": () => this.editor.commands.liftListItem(this.name) }; return this.options.nested ? { ...t, Tab: () => this.editor.commands.sinkListItem(this.name) } : t; }, addNodeView() { return ({ node: t, HTMLAttributes: e, getPos: s, editor: n }) => { const r = document.createElement("li"), i = document.createElement("label"), c = document.createElement("span"), a = document.createElement("input"), p = document.createElement("div"), h = (o) => { var d, l; a.ariaLabel = ((l = (d = this.options.a11y) == null ? void 0 : d.checkboxLabel) == null ? void 0 : l.call(d, o, a.checked)) || `Task item checkbox for ${o.textContent || "empty task item"}`; }; return h(t), i.contentEditable = "false", a.type = "checkbox", a.addEventListener("mousedown", (o) => o.preventDefault()), a.addEventListener("change", (o) => { if (!n.isEditable && !this.options.onReadOnlyChecked) { a.checked = !a.checked; return; } const { checked: d } = o.target; n.isEditable && typeof s == "function" && n.chain().focus(void 0, { scrollIntoView: !1 }).command(({ tr: l }) => { const u = s(); if (typeof u != "number") return !1; const f = l.doc.nodeAt(u); return l.setNodeMarkup(u, void 0, { ...f == null ? void 0 : f.attrs, checked: d }), !0; }).run(), !n.isEditable && this.options.onReadOnlyChecked && (this.options.onReadOnlyChecked(t, d) || (a.checked = !a.checked)); }), Object.entries(this.options.HTMLAttributes).forEach(([o, d]) => { r.setAttribute(o, d); }), r.dataset.checked = t.attrs.checked, a.checked = t.attrs.checked, i.append(a, c), r.append(i, p), Object.entries(e).forEach(([o, d]) => { r.setAttribute(o, d); }), { dom: r, contentDOM: p, update: (o) => o.type !== this.type ? !1 : (r.dataset.checked = o.attrs.checked, a.checked = o.attrs.checked, h(o), !0) }; }; }, addInputRules() { return [ k({ find: et, type: this.type, getAttributes: (t) => ({ checked: t[t.length - 1] === "x" }) }) ]; } }), nt = L.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: t }) { return ["ul", m(this.options.HTMLAttributes, t, { "data-type": this.name }), 0]; }, parseMarkdown: (t, e) => e.createNode("taskList", {}, e.parseChildren(t.items || [])), renderMarkdown: (t, e) => t.content ? e.renderChildren(t.content, ` `) : "", markdownTokenizer: { name: "taskList", level: "block", start(t) { var e; const s = (e = t.match(/^\s*[-+*]\s+\[([ xX])\]\s+/)) == null ? void 0 : e.index; return s !== void 0 ? s : -1; }, tokenize(t, e, s) { const n = (i) => { const c = M( i, { itemPattern: /^(\s*)([-+*])\s+\[([ xX])\]\s+(.*)$/, extractItemData: (a) => ({ indentLevel: a[1].length, mainContent: a[4], checked: a[3].toLowerCase() === "x" }), createToken: (a, p) => ({ type: "taskItem", raw: "", mainContent: a.mainContent, indentLevel: a.indentLevel, checked: a.checked, text: a.mainContent, tokens: s.inlineTokens(a.mainContent), nestedTokens: p }), // Allow recursive nesting customNestedParser: n }, s ); return c ? [ { type: "taskList", raw: c.raw, items: c.items } ] : s.blockTokens(i); }, r = M( t, { itemPattern: /^(\s*)([-+*])\s+\[([ xX])\]\s+(.*)$/, extractItemData: (i) => ({ indentLevel: i[1].length, mainContent: i[4], checked: i[3].toLowerCase() === "x" }), createToken: (i, c) => ({ type: "taskItem", raw: "", mainContent: i.mainContent, indentLevel: i.indentLevel, checked: i.checked, text: i.mainContent, tokens: s.inlineTokens(i.mainContent), nestedTokens: c }), // Use the recursive parser for nested content customNestedParser: n }, s ); if (r) return { type: "taskList", raw: r.raw, items: r.items }; } }, markdownOptions: { indentsContent: !0 }, addCommands() { return { toggleTaskList: () => ({ commands: t }) => t.toggleList(this.name, this.options.itemTypeName) }; }, addKeyboardShortcuts() { return { "Mod-Shift-9": () => this.editor.commands.toggleTaskList() }; } }); H.create({ name: "listKit", addExtensions() { const t = []; return this.options.bulletList !== !1 && t.push(F.configure(this.options.bulletList)), this.options.listItem !== !1 && t.push(G.configure(this.options.listItem)), this.options.listKeymap !== !1 && t.push(Y.configure(this.options.listKeymap)), this.options.orderedList !== !1 && t.push(tt.configure(this.options.orderedList)), this.options.taskItem !== !1 && t.push(st.configure(this.options.taskItem)), this.options.taskList !== !1 && t.push(nt.configure(this.options.taskList)), t; } }); export { F as B, tt as O, nt as T, st as a };