UNPKG

reactjs-tiptap-editor

Version:

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

260 lines (259 loc) 10.5 kB
import { N as j, m as $ } from "./index-CXIIg9Sq.js"; import { N as x, c as y, R as D, g as s } from "./dom-dataset-2RXYq9wp.js"; import { X as P, Y as R, Z as I, _ as Z, $ as O, a0 as W, a1 as C, A as N } from "./RichTextEditor-iSPxjLdO.js"; import { jsx as e, Fragment as A, jsxs as p } from "react/jsx-runtime"; import { LucideTableProperties as U, LucideSheet as X, LucideImage as Y, LucideFile as q, LucideVideo as G, LucideAudioLines as J } from "lucide-react"; import { useRef as K, useState as Q, useCallback as k, useEffect as ee } from "react"; import { u as te } from "./index-D-DR0FPY.js"; const re = { audio: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-audio-lines"><path d="M2 10v3"/><path d="M6 6v11"/><path d="M10 3v18"/><path d="M14 8v7"/><path d="M18 5v13"/><path d="M22 10v3"/></svg>', video: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-video"><path d="m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5"/><rect x="2" y="6" width="14" height="12" rx="2"/></svg>', file: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg>', image: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-image"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>', pdf: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32"> <path fill="currentColor" d="M30 18v-2h-6v10h2v-4h3v-2h-3v-2zm-11 8h-4V16h4a3.003 3.003 0 0 1 3 3v4a3.003 3.003 0 0 1-3 3m-2-2h2a1 1 0 0 0 1-1v-4a1 1 0 0 0-1-1h-2zm-6-8H6v10h2v-3h3a2.003 2.003 0 0 0 2-2v-3a2 2 0 0 0-2-2m-3 5v-3h3l.001 3z"></path> <path fill="currentColor" d="M22 14v-4a.91.91 0 0 0-.3-.7l-7-7A.9.9 0 0 0 14 2H4a2.006 2.006 0 0 0-2 2v24a2 2 0 0 0 2 2h16v-2H4V4h8v6a2.006 2.006 0 0 0 2 2h6v2Zm-8-4V4.4l5.6 5.6Z"></path> </svg>`, word: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" className="icon" viewBox="0 0 1024 1024" > <path fill="currentColor" d="M679.253 402.364 618.77 561.015l-60.348-158.651a30.04 30.04 0 0 0-30.447-18.637 29.76 29.76 0 0 0-30.447 18.637l-60.416 158.651-60.416-158.651a30.515 30.515 0 0 0-38.843-17.272 28.945 28.945 0 0 0-17.954 37.547l88.815 233.267c4.369 11.469 15.7 19.115 28.398 19.115a30.31 30.31 0 0 0 28.468-19.115l62.395-163.908 62.396 163.84c4.437 11.605 15.701 19.183 28.4 19.183a30.31 30.31 0 0 0 28.466-19.115l88.747-233.267a28.945 28.945 0 0 0-17.886-37.547 30.447 30.447 0 0 0-38.912 17.272zm219.478 395.605-51.883-29.218c-28.672-16.18-52.224-3.072-52.224 29.082v.273H643.209a29.833 29.833 0 0 0-30.31 29.354c0 16.18 13.584 29.218 30.31 29.218h151.825c1.092 30.516 24.03 43.077 52.224 27.648l51.063-27.989c29.013-15.906 29.15-42.189.41-58.368" /> <path fill="currentColor" d="m810.667 913.135-.478.068H201.796c-19.865 0-36.727-11.673-36.727-25.6v-618.36h154.965c51.268 0 92.911-39.39 92.911-87.858v-87.86H810.19c19.797 0 36.522 11.742 36.522 25.669V739.26h61.987V119.262c0-46.421-44.169-84.241-98.51-84.241H328.364l-225.28 194.56v658.09c0 46.285 44.236 84.105 98.713 84.105H810.19c43.759 0 80.554-24.713 93.32-58.573h-92.842zM350.89 94.89v86.562c0 16.11-13.858 29.286-30.925 29.286H216.815L350.959 94.891z" /> </svg>`, excel: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sheet"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><line x1="3" x2="21" y1="9" y2="9"/><line x1="3" x2="21" y1="15" y2="15"/><line x1="9" x2="9" y1="9" y2="21"/><line x1="15" x2="15" y1="9" y2="21"/></svg>', ppt: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-table-properties"><path d="M15 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M21 9H3"/><path d="M21 15H3"/></svg>' }; function ie(t) { const n = re[t], a = new DOMParser().parseFromString(n, "image/svg+xml").documentElement, o = [ "svg", { ...Array.from(a.attributes).reduce((r, l) => (r[l.name] = l.value, r), {}) } ]; return Array.from(a.childNodes).forEach((r) => { if (r.nodeType === 1) { const l = [ r.tagName.toLowerCase(), Array.from(r.attributes).reduce((m, f) => (m[f.name] = f.value, m), {}) ]; r.textContent && l.push(r.textContent), o.push(l); } }), o; } const ne = { audio: /* @__PURE__ */ e(J, {}), video: /* @__PURE__ */ e(G, {}), file: /* @__PURE__ */ e(q, {}), image: /* @__PURE__ */ e(Y, {}), pdf: /* @__PURE__ */ e(I, {}), word: /* @__PURE__ */ e(R, {}), excel: /* @__PURE__ */ e(X, {}), ppt: /* @__PURE__ */ e(U, {}) }; function z(t, n = !1) { const i = P(t), c = ne[i] || /* @__PURE__ */ e(A, {}); return n ? ie(i) : c; } const ae = "_wrap_1x1ms_2", M = { wrap: ae }; function oe({ editor: t, node: n, updateAttributes: i, deleteNode: c, extension: a }) { var L; const o = K(null), r = Z(), { hasTrigger: l, fileName: m, fileSize: f, fileExt: E, fileType: b, url: d, error: T } = n.attrs, [F, g] = Q(!1), { t: w } = te(), V = (L = a == null ? void 0 : a.options) == null ? void 0 : L.upload, u = k(() => { !r || d || r && o.current.click(); }, [r, d]), _ = k( async (H) => { const h = H.target.files && H.target.files[0]; if (!h) return; const B = { fileName: W(h.name), fileSize: h.size, fileType: h.type, fileExt: O(h.name) }; g(!0); try { const v = await V(h); i({ ...B, url: v }), g(!1); } catch (v) { i({ error: `File upload fail: ${v && v.message}` || "Unknown error" }), g(!1), o.current.value = ""; } }, [g, i] ); ee(() => { !d && !l && (u(), i({ hasTrigger: !0 })); }, [d, l, u, i]); const S = k(() => c(), [t]); return r && !d ? /* @__PURE__ */ e(x, { children: /* @__PURE__ */ p("div", { className: y(M.wrap, "render-wrapper"), children: [ /* @__PURE__ */ e( "p", { onClick: u, style: { cursor: "pointer" }, children: F ? /* @__PURE__ */ e("span", { children: w("editor.attachment.uploading") }) : /* @__PURE__ */ e("span", { children: w("editor.attachment.please_upload") }) } ), /* @__PURE__ */ e( "input", { hidden: !0, onChange: _, ref: o, type: "file" } ) ] }) }) : d ? /* @__PURE__ */ e(x, { children: /* @__PURE__ */ p( "div", { className: y(M.wrap, "render-wrapper"), onClick: u, children: [ /* @__PURE__ */ p("div", { className: "richtext-flex richtext-items-center richtext-gap-[4px]", children: [ /* @__PURE__ */ e("span", { children: z(b) }), /* @__PURE__ */ p("span", { children: [ m, ".", E ] }), /* @__PURE__ */ p("span", { children: [ "(", C(f), ")" ] }) ] }), /* @__PURE__ */ e( N, { action: S, icon: "Trash2", tooltip: w("editor.delete") } ) ] } ) }) : T !== "null" ? /* @__PURE__ */ e(x, { children: /* @__PURE__ */ e( "div", { className: y(M.wrap, "render-wrapper"), onClick: u, children: /* @__PURE__ */ e("p", { children: T }) } ) }) : /* @__PURE__ */ e(A, {}); } const me = /* @__PURE__ */ j.create({ name: "attachment", content: "", marks: "", group: "block", selectable: !0, atom: !0, draggable: !0, addOptions() { var t; return { ...(t = this.parent) == null ? void 0 : t.call(this), HTMLAttributes: { class: "attachment" }, button: ({ editor: n, t: i }) => ({ component: N, componentProps: { action: () => n.chain().focus().setAttachment().run(), isActive: () => !1, disabled: !1, icon: "Attachment", tooltip: i("editor.attachment.tooltip") } }) }; }, parseHTML() { return [{ tag: "div[class=attachment]" }]; }, renderHTML({ HTMLAttributes: t }) { const { url: n = "", fileName: i = "", fileSize: c = "", fileType: a = "", fileExt: o = "" } = t || {}; return [ "div", $( // @ts-expect-error this.options.HTMLAttributes || {}, t || {} ), n ? [ "a", { href: n || "#" }, [ "span", { class: "attachment__icon" }, z(a, !0) ], [ "span", { class: "attachment__text" }, `${i}.${o} (${C(c)})` ] ] : ["div", { class: "attachment__placeholder" }] ]; }, addAttributes() { return { fileName: { default: null, parseHTML: s("filename") }, fileSize: { default: null, parseHTML: s("filesize") }, fileType: { default: null, parseHTML: s("filetype") }, fileExt: { default: null, parseHTML: s("fileext") }, url: { default: null, parseHTML: s("url") }, hasTrigger: { default: !1, parseHTML: (t) => s("hastrigger")(t) === "true" }, error: { default: null, parseHTML: s("error") } }; }, addCommands() { return { setAttachment: (t = {}) => ({ chain: n }) => n().insertContent({ type: this.name, attrs: t }).run() }; }, addNodeView() { return D(oe); } }); export { me as Attachment };