UNPKG

velaris-richtext-editor

Version:

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

624 lines (623 loc) 21.2 kB
import { jsxs as b, jsx as t, Fragment as w } from "react/jsx-runtime"; import { useState as y, useRef as L, useCallback as v, useEffect as T, useMemo as W, Fragment as G } from "react"; import { B as z } from "./dom-dataset-CJ7GyQ2E.js"; import { w as Z, x as J, A as S, y as Q, z as X, F as Y, B as H, G as ee, O as D, a3 as ce, a4 as te, a5 as R, a6 as se, a7 as le } from "./RichTextEditor-BbtoCmQU.js"; import { Mermaid as j } from "./Mermaid.js"; import { s as re, i as ne } from "./shortId-WJVkrvml.js"; import { T as ie } from "./textarea-BF1CwOFt.js"; import { u as O } from "./index-D9llIWB5.js"; import { E as I, t as de } from "./Excalidraw-DQRfiUsg.js"; import { T as K, F as he } from "./Twitter-CQ-B6ltR.js"; import ue from "katex"; import { HelpCircle as me, Pencil as xe, Trash2 as fe } from "lucide-react"; import { Katex as P } from "./Katex.js"; import { C as pe, D as _ } from "./Drawer-DRectDEu.js"; import { Editor as ge, makeDropdownToolbar as be } from "easydrawer"; const q = `graph TB a-->b`, we = ({ editor: e, attrs: s, extension: o }) => { const { alt: a, align: n } = s, [r, i] = y(decodeURIComponent(a ?? q)), [l, h] = y(""), [m, x] = y(!1), p = L(null), [f, M] = y(null), k = o == null ? void 0 : o.options.upload, A = v( (g) => { g && import("mermaid").then((B) => { M(B.default); }); }, [] ), E = async (g) => { try { const { svg: B } = await f.render("mermaid-svg", g); h(B); } catch { h(""); } }, $ = () => { f.initialize({ darkMode: !1, startOnLoad: !1, // fontFamily:'', fontSize: 12, theme: "base" }), E(r); }; return T(() => { f && m && $(); }, [f, m]), T(() => { f && m && E(r); }, [f, r]), /* @__PURE__ */ b( Z, { onOpenChange: x, open: m, children: [ /* @__PURE__ */ t(J, { asChild: !0, children: /* @__PURE__ */ t( S, { action: () => x(!0), icon: "Pencil", tooltip: "Edit Mermaid" } ) }), /* @__PURE__ */ b(Q, { className: "richtext-z-[99999] !richtext-max-w-[1300px]", children: [ /* @__PURE__ */ t(X, { children: "Edit Mermaid" }), /* @__PURE__ */ t( "div", { ref: A, style: { height: "100%", border: "1px solid hsl(var(--border))" }, children: /* @__PURE__ */ b("div", { className: "richtext-flex richtext-gap-[10px] richtext-rounded-[10px] richtext-p-[10px]", children: [ /* @__PURE__ */ t( ie, { autoFocus: !0, className: "richtext-flex-1", defaultValue: q, onChange: (g) => i(g.target.value), placeholder: "Text", required: !0, rows: 10, value: r, style: { color: "hsl(var(--richtext-foreground))" } } ), /* @__PURE__ */ t( "div", { className: "richtext-flex richtext-flex-1 richtext-items-center richtext-justify-center richtext-rounded-[10px] richtext-p-[10px]", dangerouslySetInnerHTML: { __html: l }, ref: p, style: { height: "100%", border: "1px solid hsl(var(--border))", minHeight: 500, background: "#fff" } } ) ] }) } ), /* @__PURE__ */ t(Y, { children: /* @__PURE__ */ t( H, { onClick: async () => { if (r !== "") { if (r) { const g = p.current.querySelector("svg"), { width: B, height: V } = g.getBoundingClientRect(), u = `mermaid-${re()}.svg`; let c = ne(g.outerHTML); if (k) { const d = ee(c, u); c = await k(d); } e == null || e.chain().focus().setMermaid( { type: "mermaid", src: c, alt: encodeURIComponent(r), width: B, height: V }, !!r ).run(), e == null || e.commands.setAlignImageMermaid(n); } x(!1); } }, type: "button", children: "Save changes" } ) }) ] }) ] } ); }; function oe(e, s) { const [o, a] = y(void 0); return T(() => { const n = () => { const r = e.extensionManager.extensions.find((i) => i.name === s); r && a(r); }; return e.on("selectionUpdate", n), e.on("transaction", n), () => { e.off("selectionUpdate", n), e.off("transaction", n); }; }, [e, s]), o; } const ve = { maxWidth: "auto", zIndex: 20, appendTo: "parent", moveTransition: "transform 0.1s ease-out" }; function ye({ item: e, disabled: s, editor: o }) { var n; const a = e.component; return a ? /* @__PURE__ */ t(G, { children: e.type === "divider" ? /* @__PURE__ */ t( te, { className: "!richtext-mx-1 !richtext-my-2 !richtext-h-[16px]", orientation: "vertical" } ) : /* @__PURE__ */ t( a, { ...e.componentProps, disabled: s || ((n = e == null ? void 0 : e.componentProps) == null ? void 0 : n.disabled), editor: o } ) }) : /* @__PURE__ */ t(w, {}); } function Se(e) { return e.type.name === "mermaid"; } function Ve(e) { const { lang: s } = O(), o = D(e.editor, j.name), a = oe(e.editor, j.name), n = ({ editor: i }) => { const { selection: l } = i.view.state, { $from: h, to: m } = l; let x = !1; return i.view.state.doc.nodesBetween(h.pos, m, (p) => { if (Se(p)) return x = !0, !1; }), x; }, r = W(() => e.disabled ? [] : ce(e.editor), [e.disabled, e.editor, s]); return /* @__PURE__ */ t(w, { children: /* @__PURE__ */ t( z, { editor: e == null ? void 0 : e.editor, shouldShow: n, tippyOptions: ve, children: r != null && r.length ? /* @__PURE__ */ t("div", { className: "richtext-pointer-events-auto richtext-w-auto richtext-select-none richtext-rounded-sm !richtext-border richtext-border-neutral-200 richtext-bg-background richtext-px-3 richtext-py-2 richtext-shadow-sm richtext-transition-all dark:richtext-border-neutral-800", children: /* @__PURE__ */ t("div", { className: "richtext-relative richtext-flex richtext-h-[26px] richtext-flex-nowrap richtext-items-center richtext-justify-start richtext-whitespace-nowrap", children: r == null ? void 0 : r.map((i, l) => i.type === "edit" && (o != null && o.src) ? /* @__PURE__ */ t( we, { attrs: o, editor: e.editor, extension: a }, `bubbleMenu-mermaid-${l}` ) : /* @__PURE__ */ t( ye, { disabled: e.disabled, editor: e.editor, item: i }, `bubbleMenu-mermaid-${l}` )) }) }) : /* @__PURE__ */ t(w, {}) } ) }); } const C = /* @__PURE__ */ new Map(); function Ce(e) { const s = e.options.element; C.has("width") || C.set("width", s.clientWidth), C.has("width") && C.get("width") <= 0 && C.set("width", s.clientWidth); const o = { attributes: !0, childList: !0, subtree: !0 }, a = function() { C.set("width", s.clientWidth); }, n = new MutationObserver(a); return n.observe(s, o), e.on("destroy", () => { n.disconnect(); }), { width: C.get("width") }; } function je({ editor: e }) { const { t: s } = O(), { width: o } = Ce(e), a = D(e, I.name, { defaultShowPicker: !1, createUser: "", width: 0, height: 0 }), { defaultShowPicker: n, createUser: r, width: i, height: l } = a, h = v( (f) => { e.chain().updateAttributes(I.name, f).setNodeSelection(e.state.selection.from).focus().run(); }, [e] ), m = v(() => { de(a); }, [e, a]), x = v(() => e.isActive(I.name), [e]), p = v(() => R(I.name, e), [e]); return T(() => { n && (m(), e.chain().updateAttributes(I.name, { defaultShowPicker: !1 }).focus().run()); }, [r, n, e, m]), /* @__PURE__ */ t( z, { className: "bubble-menu", editor: e, pluginKey: "excalidraw-bubble-menu", shouldShow: x, tippyOptions: { popperOptions: { modifiers: [{ name: "flip", enabled: !1 }] }, placement: "bottom-start", offset: [-2, 16], zIndex: 9999 // onHidden: () => { // toggleVisible(false) // }, }, children: /* @__PURE__ */ b("div", { className: "richtext-w-auto richtext-px-3 richtext-py-2 richtext-transition-all !richtext-border richtext-rounded-sm richtext-shadow-sm richtext-pointer-events-auto richtext-select-none richtext-border-neutral-200 dark:richtext-border-neutral-800 richtext-bg-background", children: [ /* @__PURE__ */ t( S, { icon: "Pencil", action: m, tooltip: s("editor.edit") } ), /* @__PURE__ */ t(se, { width: i, maxWidth: o, height: l, onOk: h, children: /* @__PURE__ */ t( S, { icon: "Settings", tooltip: s("editor.settings") } ) }), /* @__PURE__ */ t( S, { icon: "Trash2", action: p, tooltip: s("editor.delete") } ) ] }) } ); } function Ke({ editor: e, disabled: s }) { const [o, a] = y(!1), { t: n } = O(), r = v(({ editor: h }) => h.isActive(K.name), []), i = (h) => { e.commands.updateTweet({ src: h }), a(!1); }, l = v(() => R(K.name, e), [e]); return /* @__PURE__ */ t(w, { children: /* @__PURE__ */ t( z, { editor: e, shouldShow: r, tippyOptions: { popperOptions: { modifiers: [{ name: "flip", enabled: !1 }] }, placement: "bottom-start", offset: [-2, 16], zIndex: 9999, onHidden: () => { a(!1); } }, children: s ? /* @__PURE__ */ t(w, {}) : /* @__PURE__ */ t(w, { children: o ? /* @__PURE__ */ t( he, { editor: e, onSetLink: i } ) : /* @__PURE__ */ t("div", { className: "richtext-flex richtext-items-center richtext-gap-2 richtext-rounded-lg !richtext-border richtext-border-neutral-200 richtext-bg-white richtext-p-2 richtext-shadow-sm dark:richtext-border-neutral-800 dark:richtext-bg-black", children: /* @__PURE__ */ b("div", { className: "richtext-flex richtext-flex-nowrap", children: [ /* @__PURE__ */ t( S, { icon: "Pencil", tooltip: n("editor.link.edit.tooltip"), tooltipOptions: { sideOffset: 15 }, action: () => { a(!0); } } ), /* @__PURE__ */ t( S, { action: l, icon: "Trash", tooltip: n("editor.delete"), tooltipOptions: { sideOffset: 15 } } ) ] }) }) }) } ) }); } function _e({ editor: e, ...s }) { const o = D(e, P.name, { text: "", defaultShowPicker: !1 }), { text: a, defaultShowPicker: n } = o, [r, i] = y(""), [l, h] = y(!1), m = v(() => e.isActive(P.name), [e]), x = v(() => R(P.name, e), [e]), p = v(() => { e.chain().focus().setKatex({ text: r }).run(), h(!1); }, [e, r]); T(() => { n && (h(!0), e.chain().updateAttributes(P.name, { defaultShowPicker: !1 }).focus().run()); }, [e, n, h]), T(() => { l && i(a || ""); }, [l]); const f = W(() => { try { return ue.renderToString(`${r}`); } catch { return r; } }, [r]), M = W( () => `${r}`.trim() ? /* @__PURE__ */ t( "span", { contentEditable: !1, dangerouslySetInnerHTML: { __html: f || "" } } ) : null, [r, f] ); return /* @__PURE__ */ t( z, { editor: e, pluginKey: "Katex-bubble-menu", shouldShow: m, tippyOptions: { popperOptions: { modifiers: [{ name: "flip", enabled: !1 }] }, placement: "bottom-start", offset: [-2, 16], zIndex: 9999, onHidden: () => { h(!1); } }, children: s != null && s.disabled ? /* @__PURE__ */ t(w, {}) : /* @__PURE__ */ t("div", { className: "richtext-rounded-lg !richtext-border richtext-border-neutral-200 richtext-bg-white richtext-p-2 richtext-shadow-sm dark:richtext-border-neutral-800 dark:richtext-bg-black", children: l ? /* @__PURE__ */ b(w, { children: [ /* @__PURE__ */ t( ie, { autoFocus: !0, defaultValue: a, onChange: (k) => i(k.target.value), placeholder: "Formula text", rows: 3, style: { marginBottom: 8 }, value: r } ), M && /* @__PURE__ */ t("div", { className: "richtext-my-[10px] richtext-overflow-auto richtext-whitespace-nowrap richtext-rounded-[6px] !richtext-border richtext-p-[10px]", children: M }), /* @__PURE__ */ b("div", { className: "richtext-flex richtext-items-center richtext-justify-between richtext-gap-[6px]", children: [ /* @__PURE__ */ t( H, { className: "richtext-flex-1", onClick: p, children: "Submit" } ), /* @__PURE__ */ t( "a", { href: "https://katex.org/docs/supported", rel: "noreferrer noopener", target: "_blank", children: /* @__PURE__ */ t(me, { size: 16 }) } ) ] }) ] }) : /* @__PURE__ */ b("div", { className: "richtext-flex richtext-items-center richtext-justify-center richtext-gap-[6px]", children: [ /* @__PURE__ */ t( S, { action: () => h(!l), tooltip: "Edit", children: /* @__PURE__ */ t(xe, { size: 16 }) } ), /* @__PURE__ */ t( S, { action: x, tooltip: "Delete", children: /* @__PURE__ */ t(fe, { size: 16 }) } ) ] }) }) } ); } let N = !1; function Te({ editor: e, attrs: s, extension: o }) { const [a, n] = y(!1), r = L(null), i = L(null), { alt: l, align: h } = s, m = o == null ? void 0 : o.options.upload, x = () => { (async () => { const c = document.querySelector("#easydrawer"); c && (r.current = new ge(c, { wheelEventsEnabled: !1, disableZoom: !0 }), i.current = be(r.current), i.current.addDefaultToolWidgets(), r.current.loadFromSVG(decodeURIComponent(l))); })(); }; T(() => { a && setTimeout(() => { x(); }, 200); }, [a]); const p = async () => { if (r.current) { const u = r.current.toSVG(), c = u.outerHTML, d = `drawer-${re()}.svg`; let F = ne(u.outerHTML); if (m) { const ae = ee(F, d); F = await m(ae); } e == null || e.chain().focus().setDrawer( { type: "drawer", src: F, alt: encodeURIComponent(c), width: 426, height: 212 }, !!c ).run(), e == null || e.commands.setAlignImageDrawer(h); } n(!1); }, f = (u) => { const c = r.current.toolController.getPrimaryTools()[2], d = i.current.getWidgetById("pen-1"); c && d && (c.setColor(u), d.serializeState()); }, M = (u) => { const c = r.current.toolController.getPrimaryTools()[2], d = i.current.getWidgetById("pen-1"); c && d && (c.setThickness(u), d.serializeState()); }, k = (u) => { const c = r.current.toolController.getPrimaryTools()[3], d = i.current.getWidgetById("pen-2"); c && d && (c.setColor(u), d.serializeState()); }, A = (u) => { const c = i.current.getWidgetById("shape"); c && c.setShapeType(u); }, E = (u) => { const c = r.current.toolController.getPrimaryTools()[5], d = i.current.getWidgetById("shape"); c && d && (c.setColor(u), d.serializeState()); }, $ = (u) => { const c = r.current.toolController.getPrimaryTools()[5], d = i.current.getWidgetById("shape"); c && d && (c.setThickness(u), d.serializeState()); }, U = (u) => { const c = r.current.toolController.getPrimaryTools()[5], d = i.current.getWidgetById("shape"); c && d && (c.setBorderColor(u), d.serializeState()); }, g = () => { if (N) { for (; r.current.history.redoStackSize > 0; ) r.current.history.redo(); N = !1; return; } r.current.history.undo(); }; return /* @__PURE__ */ b( Z, { onOpenChange: n, open: a, children: [ /* @__PURE__ */ t(J, { asChild: !0, children: /* @__PURE__ */ t( S, { action: () => n(!0), icon: "Pencil", tooltip: "Edit Drawer" } ) }), /* @__PURE__ */ b(Q, { className: "richtext-z-[99999] !richtext-max-w-[1300px]", children: [ /* @__PURE__ */ t(X, { children: "Edit Drawer" }), /* @__PURE__ */ b("div", { style: { height: "100%", borderWidth: 1, background: "white", position: "relative" }, children: [ /* @__PURE__ */ t( "div", { className: "richtext-size-full", id: "easydrawer" } ), /* @__PURE__ */ t( pe, { changeBorderColorShape: U, changeColorShape: E, changeShape: A, onClear: () => { if (!N) { for (; r.current.history.undoStackSize > 0; ) g(); N = !0; } }, onRedo: () => { N || r.current.history.redo(); }, onThicknessChange: $, onUndo: g, refEditor: r, setColorHighlight: k, setColorPen: f, setThicknessPen: M } ) ] }), /* @__PURE__ */ t(Y, { children: /* @__PURE__ */ t( H, { onClick: p, type: "button", children: "Save changes" } ) }) ] }) ] } ); } const Me = { maxWidth: "auto", zIndex: 20, appendTo: "parent", moveTransition: "transform 0.1s ease-out" }; function ke({ item: e, disabled: s, editor: o }) { var n; const a = e.component; return a ? /* @__PURE__ */ t(G, { children: e.type === "divider" ? /* @__PURE__ */ t( te, { className: "!richtext-mx-1 !richtext-my-2 !richtext-h-[16px]", orientation: "vertical" } ) : /* @__PURE__ */ t( a, { ...e.componentProps, disabled: s || ((n = e == null ? void 0 : e.componentProps) == null ? void 0 : n.disabled), editor: o } ) }) : /* @__PURE__ */ t(w, {}); } function Be(e) { return e.type.name === "drawer"; } function qe(e) { const { lang: s } = O(), o = D(e.editor, _.name), a = oe(e.editor, _.name), n = ({ editor: i }) => { const { selection: l } = i.view.state, { $from: h, to: m } = l; let x = !1; return i.view.state.doc.nodesBetween(h.pos, m, (p) => { if (Be(p)) return x = !0, !1; }), x; }, r = W(() => e.disabled ? [] : le(e.editor), [e.disabled, e.editor, s]); return /* @__PURE__ */ t(w, { children: /* @__PURE__ */ t( z, { editor: e == null ? void 0 : e.editor, shouldShow: n, tippyOptions: Me, children: r != null && r.length ? /* @__PURE__ */ t("div", { className: "richtext-pointer-events-auto richtext-w-auto richtext-select-none richtext-rounded-sm !richtext-border richtext-border-neutral-200 richtext-bg-background richtext-px-3 richtext-py-2 richtext-shadow-sm richtext-transition-all dark:richtext-border-neutral-800", children: /* @__PURE__ */ t("div", { className: "richtext-relative richtext-flex richtext-h-[26px] richtext-flex-nowrap richtext-items-center richtext-justify-start richtext-whitespace-nowrap", children: r == null ? void 0 : r.map((i, l) => i.type === "edit" && (o != null && o.src) ? /* @__PURE__ */ t( Te, { attrs: o, editor: e.editor, extension: a }, `bubbleMenu-drawer-${l}` ) : /* @__PURE__ */ t( ke, { disabled: e.disabled, editor: e.editor, item: i }, `bubbleMenu-drawer-${l}` )) }) }) : /* @__PURE__ */ t(w, {}) } ) }); } export { qe as BubbleMenuDrawer, je as BubbleMenuExcalidraw, _e as BubbleMenuKatex, Ve as BubbleMenuMermaid, Ke as BubbleMenuTwitter };