@firecms/editor 3.0.0-canary.25 → 3.0.0-canary.251

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,973 +1,2011 @@
1
- import { jsx as s, jsxs as b } from "react/jsx-runtime";
2
- import L, { forwardRef as T, useRef as D, useEffect as C, useMemo as Z, useState as v } from "react";
3
- import me from "@tiptap/extension-underline";
4
- import ge from "@tiptap/extension-text-style";
5
- import { Color as pe } from "@tiptap/extension-color";
6
- import { Markdown as fe } from "tiptap-markdown";
7
- import he from "@tiptap/extension-highlight";
8
- import { useCurrentEditor as y, BubbleMenu as be, isNodeSelection as ke, ReactRenderer as xe, EditorProvider as ye } from "@tiptap/react";
9
- import { createStore as ve, Provider as Ce, atom as _, useAtom as we, useSetAtom as U, useAtomValue as Ae } from "jotai";
10
- import { Slot as Le } from "@radix-ui/react-slot";
11
- import Te from "tunnel-rat";
12
- import { Command as S, CommandItem as Ee, CommandEmpty as Me } from "cmdk";
13
- import Ne from "@tiptap/starter-kit";
14
- import Se from "@tiptap/extension-horizontal-rule";
15
- import Re from "@tiptap/extension-link";
16
- import Ie from "@tiptap/extension-image";
17
- import Pe from "@tiptap/extension-placeholder";
18
- import { TaskItem as He } from "@tiptap/extension-task-item";
19
- import { TaskList as De } from "@tiptap/extension-task-list";
20
- import { Extension as B, InputRule as Be } from "@tiptap/core";
21
- import ze from "@tiptap/suggestion";
22
- import Fe from "tippy.js";
23
- import { Popover as Q, Button as w, ExpandMoreIcon as Ue, CheckIcon as V, TextFieldsIcon as X, LooksOneIcon as Y, LooksTwoIcon as J, Looks3Icon as G, CheckBoxIcon as j, FormatListBulletedIcon as ee, FormatListNumberedIcon as te, FormatQuoteIcon as oe, CodeIcon as z, cn as g, DeleteIcon as Ke, FormatBoldIcon as $e, FormatItalicIcon as qe, FormatUnderlinedIcon as We, FormatStrikethroughIcon as Oe, defaultBorderMixin as x, useInjectStyles as Ze, Separator as K, ImageIcon as _e } from "@firecms/ui";
24
- import { Plugin as Qe } from "prosemirror-state";
25
- import { DecorationSet as Ve, Decoration as Xe, __serializeForClipboard as Ye } from "@tiptap/pm/view";
26
- import { Plugin as Je, NodeSelection as $ } from "@tiptap/pm/state";
27
- const P = ve(), Ge = ({ children: e }) => /* @__PURE__ */ s(Ce, { store: P, children: e }), je = T(
28
- ({ children: e, tippyOptions: o, ...t }, r) => {
29
- const { editor: a } = y(), c = D(null);
30
- C(() => {
31
- !c.current || !o?.placement || (c.current.setProps({ placement: o.placement }), c.current.popperInstance?.update());
32
- }, [o?.placement]);
33
- const n = Z(() => ({
34
- shouldShow: ({ editor: d, state: u }) => {
35
- const { selection: p } = u, { empty: h } = p;
36
- return !(d.isActive("image") || h || ke(p));
37
- },
38
- tippyOptions: {
39
- onCreate: (d) => {
40
- c.current = d;
41
- },
42
- moveTransition: "transform 0.15s ease-out",
43
- ...o
44
- },
45
- ...t
46
- }), [t, o]);
47
- return a ? (
48
- //We need to add this because of https://github.com/ueberdosis/tiptap/issues/2658
49
- /* @__PURE__ */ s("div", { ref: r, children: /* @__PURE__ */ s(be, { editor: a, ...n, children: e }) })
50
- ) : null;
51
- }
52
- ), F = T(({ children: e, asChild: o, onSelect: t, ...r }, a) => {
53
- const { editor: c } = y(), n = o ? Le : "div";
54
- return c ? /* @__PURE__ */ s(n, { ref: a, ...r, onClick: () => t?.(c), children: e }) : null;
55
- });
56
- F.displayName = "EditorBubbleItem";
57
- const re = Te(), ne = _(""), ae = _(null), et = ({
58
- query: e,
59
- range: o
60
- }) => {
61
- const t = U(ne, { store: P }), r = U(ae, { store: P });
62
- return C(() => {
63
- t(e);
64
- }, [e, t]), C(() => {
65
- r(o);
66
- }, [o, r]), C(() => {
67
- const a = ["ArrowUp", "ArrowDown", "Enter"], c = (n) => {
68
- if (a.includes(n.key)) {
69
- n.preventDefault();
70
- const i = document.querySelector("#slash-command");
71
- i && i.dispatchEvent(
72
- new KeyboardEvent("keydown", { key: n.key, cancelable: !0, bubbles: !0 })
73
- );
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import React, { forwardRef, useRef, useEffect, useState, useImperativeHandle, useMemo, useDeferredValue } from "react";
3
+ import { CheckIcon, TextFieldsIcon, LooksOneIcon, LooksTwoIcon, Looks3Icon, CheckBoxIcon, FormatListBulletedIcon, FormatListNumberedIcon, FormatQuoteIcon, CodeIcon, KeyboardArrowDownIcon, Button, Popover, cls, focusedDisabled, DeleteIcon, FormatBoldIcon, FormatItalicIcon, FormatUnderlinedIcon, FormatStrikethroughIcon, defaultBorderMixin, AutoFixHighIcon, ImageIcon, useInjectStyles, Separator } from "@firecms/ui";
4
+ import { useCurrentEditor, BubbleMenu, isNodeSelection, Node, mergeAttributes, ReactRenderer, EditorProvider } from "@tiptap/react";
5
+ import Document from "@tiptap/extension-document";
6
+ import { Markdown } from "tiptap-markdown";
7
+ import Underline from "@tiptap/extension-underline";
8
+ import Heading from "@tiptap/extension-heading";
9
+ import TextStyle from "@tiptap/extension-text-style";
10
+ import Color from "@tiptap/extension-color";
11
+ import Highlight from "@tiptap/extension-highlight";
12
+ import Bold from "@tiptap/extension-bold";
13
+ import Italic from "@tiptap/extension-italic";
14
+ import Strike from "@tiptap/extension-strike";
15
+ import { c } from "react-compiler-runtime";
16
+ import { Slot } from "@radix-ui/react-slot";
17
+ import StarterKit from "@tiptap/starter-kit";
18
+ import HorizontalRule from "@tiptap/extension-horizontal-rule";
19
+ import TiptapLink from "@tiptap/extension-link";
20
+ import TiptapImage from "@tiptap/extension-image";
21
+ import Placeholder from "@tiptap/extension-placeholder";
22
+ import { TaskItem } from "@tiptap/extension-task-item";
23
+ import { TaskList } from "@tiptap/extension-task-list";
24
+ import { Extension, InputRule } from "@tiptap/core";
25
+ import { PluginKey, Plugin } from "prosemirror-state";
26
+ import { DecorationSet, Decoration } from "prosemirror-view";
27
+ import OrderedList from "@tiptap/extension-ordered-list";
28
+ import BulletList from "@tiptap/extension-bullet-list";
29
+ import ListItem from "@tiptap/extension-list-item";
30
+ import CodeBlock from "@tiptap/extension-code-block";
31
+ import Blockquote from "@tiptap/extension-blockquote";
32
+ import Code from "@tiptap/extension-code";
33
+ import { DecorationSet as DecorationSet$1, Decoration as Decoration$1 } from "@tiptap/pm/view";
34
+ import { PluginKey as PluginKey$1, Plugin as Plugin$1, NodeSelection } from "@tiptap/pm/state";
35
+ import { DOMSerializer } from "prosemirror-model";
36
+ import Suggestion from "@tiptap/suggestion";
37
+ import tippy from "tippy.js";
38
+ const EditorBubble = forwardRef((t0, ref) => {
39
+ const $ = c(21);
40
+ let children;
41
+ let rest;
42
+ let tippyOptions;
43
+ if ($[0] !== t0) {
44
+ ({
45
+ children,
46
+ tippyOptions,
47
+ ...rest
48
+ } = t0);
49
+ $[0] = t0;
50
+ $[1] = children;
51
+ $[2] = rest;
52
+ $[3] = tippyOptions;
53
+ } else {
54
+ children = $[1];
55
+ rest = $[2];
56
+ tippyOptions = $[3];
57
+ }
58
+ const {
59
+ editor
60
+ } = useCurrentEditor();
61
+ const instanceRef = useRef(null);
62
+ let t1;
63
+ if ($[4] !== tippyOptions) {
64
+ t1 = () => {
65
+ if (!instanceRef.current || !tippyOptions?.placement) {
66
+ return;
74
67
  }
68
+ instanceRef.current.setProps({
69
+ placement: tippyOptions.placement
70
+ });
71
+ instanceRef.current.popperInstance?.update();
75
72
  };
76
- return document.addEventListener("keydown", c), () => {
77
- document.removeEventListener("keydown", c);
73
+ $[4] = tippyOptions;
74
+ $[5] = t1;
75
+ } else {
76
+ t1 = $[5];
77
+ }
78
+ const t2 = tippyOptions?.placement;
79
+ let t3;
80
+ if ($[6] !== t2) {
81
+ t3 = [t2];
82
+ $[6] = t2;
83
+ $[7] = t3;
84
+ } else {
85
+ t3 = $[7];
86
+ }
87
+ useEffect(t1, t3);
88
+ let t4;
89
+ const shouldShow = _temp$1;
90
+ let t5;
91
+ if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
92
+ t5 = (val) => {
93
+ instanceRef.current = val;
78
94
  };
79
- }, []), /* @__PURE__ */ s(re.Out, {});
80
- }, tt = T(
81
- ({ children: e, className: o, ...t }, r) => {
82
- const a = D(null), [c, n] = we(ne);
83
- return /* @__PURE__ */ s(re.In, { children: /* @__PURE__ */ b(
84
- S,
85
- {
86
- ref: r,
87
- onKeyDown: (i) => {
88
- i.stopPropagation();
89
- },
90
- id: "slash-command",
91
- className: o,
92
- ...t,
93
- children: [
94
- /* @__PURE__ */ s(S.Input, { value: c, onValueChange: n, style: { display: "none" } }),
95
- /* @__PURE__ */ s(S.List, { ref: a, children: e })
96
- ]
97
- }
98
- ) });
95
+ $[8] = t5;
96
+ } else {
97
+ t5 = $[8];
99
98
  }
100
- ), se = T(({ children: e, onCommand: o, ...t }, r) => {
101
- const { editor: a } = y(), c = Ae(ae);
102
- return !a || !c ? null : /* @__PURE__ */ s(Ee, { ref: r, ...t, onSelect: () => o({ editor: a, range: c }), children: e });
103
- });
104
- se.displayName = "EditorCommandItem";
105
- const ot = Me, rt = B.create({
106
- name: "slash-command",
107
- addOptions() {
108
- return {
109
- suggestion: {
110
- char: "/",
111
- command: ({ editor: e, range: o, props: t }) => {
112
- t.command({ editor: e, range: o });
113
- }
114
- }
99
+ let t6;
100
+ if ($[9] !== tippyOptions) {
101
+ t6 = {
102
+ onCreate: t5,
103
+ moveTransition: "transform 0.15s ease-out",
104
+ ...tippyOptions
115
105
  };
116
- },
117
- addProseMirrorPlugins() {
118
- return [
119
- ze({
120
- editor: this.editor,
121
- ...this.options.suggestion
122
- })
123
- ];
106
+ $[9] = tippyOptions;
107
+ $[10] = t6;
108
+ } else {
109
+ t6 = $[10];
124
110
  }
125
- }), nt = () => {
126
- let e = null, o = null;
127
- return {
128
- onStart: (t) => {
129
- e = new xe(et, {
130
- props: t,
131
- editor: t.editor
132
- }), o = Fe("body", {
133
- getReferenceClientRect: t.clientRect,
134
- appendTo: () => document.body,
135
- content: e.element,
136
- showOnCreate: !0,
137
- interactive: !0,
138
- trigger: "manual",
139
- placement: "bottom-start"
140
- });
141
- },
142
- onUpdate: (t) => {
143
- e?.updateProps(t), o && o[0].setProps({
144
- getReferenceClientRect: t.clientRect
145
- });
146
- },
147
- onKeyDown: (t) => t.event.key === "Escape" ? (o?.[0].hide(), !0) : e?.ref?.onKeyDown(t),
148
- onExit: () => {
149
- o?.[0].destroy(), e?.destroy();
150
- }
151
- };
152
- }, at = (e) => e, st = Pe.configure({
153
- placeholder: ({ node: e }) => e.type.name === "heading" ? `Heading ${e.attrs.level}` : "Press '/' for commands",
154
- includeChildren: !0
155
- }), it = Se.extend({
156
- addInputRules() {
157
- return [
158
- new Be({
159
- find: /^(?:---|—-|___\s|\*\*\*\s)$/,
160
- handler: ({ state: e, range: o }) => {
161
- const t = {}, { tr: r } = e, a = o.from, c = o.to;
162
- r.insert(a - 1, this.type.create(t)).delete(
163
- r.mapping.map(a),
164
- r.mapping.map(c)
165
- );
166
- }
167
- })
168
- ];
169
- }
170
- }), q = [
171
- {
172
- name: "Text",
173
- icon: X,
174
- command: (e) => e?.chain().focus().toggleNode("paragraph", "paragraph").run(),
175
- // I feel like there has to be a more efficient way to do this – feel free to PR if you know how!
176
- isActive: (e) => (e?.isActive("paragraph") && !e?.isActive("bulletList") && !e?.isActive("orderedList")) ?? !1
177
- },
178
- {
179
- name: "Heading 1",
180
- icon: Y,
181
- command: (e) => e?.chain().focus().toggleHeading({ level: 1 }).run(),
182
- isActive: (e) => e?.isActive("heading", { level: 1 }) ?? !1
183
- },
184
- {
185
- name: "Heading 2",
186
- icon: J,
187
- command: (e) => e?.chain().focus().toggleHeading({ level: 2 }).run(),
188
- isActive: (e) => e?.isActive("heading", { level: 2 }) ?? !1
189
- },
190
- {
191
- name: "Heading 3",
192
- icon: G,
193
- command: (e) => e?.chain().focus().toggleHeading({ level: 3 }).run(),
194
- isActive: (e) => e?.isActive("heading", { level: 3 }) ?? !1
195
- },
196
- {
197
- name: "To-do List",
198
- icon: j,
199
- command: (e) => e?.chain().focus().toggleTaskList().run(),
200
- isActive: (e) => e?.isActive("taskItem") ?? !1
201
- },
202
- {
203
- name: "Bullet List",
204
- icon: ee,
205
- command: (e) => e?.chain().focus().toggleBulletList().run(),
206
- isActive: (e) => e?.isActive("bulletList") ?? !1
207
- },
208
- {
209
- name: "Numbered List",
210
- icon: te,
211
- command: (e) => e?.chain().focus().toggleOrderedList().run(),
212
- isActive: (e) => e?.isActive("orderedList") ?? !1
213
- },
214
- {
215
- name: "Quote",
216
- icon: oe,
217
- command: (e) => e?.chain().focus().toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
218
- isActive: (e) => e?.isActive("blockquote") ?? !1
219
- },
220
- {
221
- name: "Code",
222
- icon: z,
223
- command: (e) => e?.chain().focus().toggleCodeBlock().run(),
224
- isActive: (e) => e?.isActive("codeBlock") ?? !1
225
- }
226
- ], ct = ({
227
- open: e,
228
- onOpenChange: o
229
- }) => {
230
- const { editor: t } = y();
231
- if (!t)
111
+ let t7;
112
+ if ($[11] !== rest || $[12] !== t6) {
113
+ t7 = {
114
+ shouldShow,
115
+ tippyOptions: t6,
116
+ ...rest
117
+ };
118
+ $[11] = rest;
119
+ $[12] = t6;
120
+ $[13] = t7;
121
+ } else {
122
+ t7 = $[13];
123
+ }
124
+ t4 = t7;
125
+ const bubbleMenuProps = t4;
126
+ if (!editor) {
232
127
  return null;
233
- const r = q.filter((a) => a.isActive(t)).pop() ?? {
234
- name: "Multiple"
235
- };
236
- return /* @__PURE__ */ s(
237
- Q,
238
- {
239
- sideOffset: 5,
240
- align: "start",
241
- className: "w-48 p-1",
242
- trigger: /* @__PURE__ */ b(
243
- w,
244
- {
245
- variant: "text",
246
- className: "gap-2 rounded-none",
247
- color: "text",
248
- children: [
249
- /* @__PURE__ */ s("span", { className: "whitespace-nowrap text-sm", children: r.name }),
250
- /* @__PURE__ */ s(Ue, { size: "small" })
251
- ]
252
- }
253
- ),
254
- modal: !0,
255
- open: e,
256
- onOpenChange: o,
257
- children: q.map((a, c) => /* @__PURE__ */ b(
258
- F,
259
- {
260
- onSelect: (n) => {
261
- a.command(n), o(!1);
262
- },
263
- className: "flex cursor-pointer items-center justify-between rounded px-2 py-1 text-sm hover:bg-blue-50 hover:dark:bg-gray-700 text-gray-900 dark:text-white",
264
- children: [
265
- /* @__PURE__ */ b("div", { className: "flex items-center space-x-2", children: [
266
- /* @__PURE__ */ s(a.icon, { size: "smallest" }),
267
- /* @__PURE__ */ s("span", { children: a.name })
268
- ] }),
269
- r.name === a.name && /* @__PURE__ */ s(V, { size: "smallest" })
270
- ]
271
- },
272
- c
273
- ))
274
- }
275
- );
128
+ }
129
+ let t8;
130
+ if ($[14] !== bubbleMenuProps || $[15] !== children || $[16] !== editor) {
131
+ t8 = /* @__PURE__ */ jsx(BubbleMenu, { editor, ...bubbleMenuProps, children });
132
+ $[14] = bubbleMenuProps;
133
+ $[15] = children;
134
+ $[16] = editor;
135
+ $[17] = t8;
136
+ } else {
137
+ t8 = $[17];
138
+ }
139
+ let t9;
140
+ if ($[18] !== ref || $[19] !== t8) {
141
+ t9 = /* @__PURE__ */ jsx("div", { ref, children: t8 });
142
+ $[18] = ref;
143
+ $[19] = t8;
144
+ $[20] = t9;
145
+ } else {
146
+ t9 = $[20];
147
+ }
148
+ return t9;
149
+ });
150
+ function _temp$1(t0) {
151
+ const {
152
+ editor: editor_0,
153
+ state
154
+ } = t0;
155
+ const {
156
+ selection
157
+ } = state;
158
+ const {
159
+ empty
160
+ } = selection;
161
+ if (editor_0.isActive("image") || empty || isNodeSelection(selection)) {
162
+ return false;
163
+ }
164
+ return true;
165
+ }
166
+ const EditorBubbleItem = forwardRef((t0, ref) => {
167
+ const $ = c(14);
168
+ let asChild;
169
+ let children;
170
+ let onSelect;
171
+ let rest;
172
+ if ($[0] !== t0) {
173
+ ({
174
+ children,
175
+ asChild,
176
+ onSelect,
177
+ ...rest
178
+ } = t0);
179
+ $[0] = t0;
180
+ $[1] = asChild;
181
+ $[2] = children;
182
+ $[3] = onSelect;
183
+ $[4] = rest;
184
+ } else {
185
+ asChild = $[1];
186
+ children = $[2];
187
+ onSelect = $[3];
188
+ rest = $[4];
189
+ }
190
+ const {
191
+ editor
192
+ } = useCurrentEditor();
193
+ const Comp = asChild ? Slot : "div";
194
+ if (!editor) {
195
+ return null;
196
+ }
197
+ let t1;
198
+ if ($[5] !== editor || $[6] !== onSelect) {
199
+ t1 = () => onSelect?.(editor);
200
+ $[5] = editor;
201
+ $[6] = onSelect;
202
+ $[7] = t1;
203
+ } else {
204
+ t1 = $[7];
205
+ }
206
+ let t2;
207
+ if ($[8] !== Comp || $[9] !== children || $[10] !== ref || $[11] !== rest || $[12] !== t1) {
208
+ t2 = /* @__PURE__ */ jsx(Comp, { ref, ...rest, onClick: t1, children });
209
+ $[8] = Comp;
210
+ $[9] = children;
211
+ $[10] = ref;
212
+ $[11] = rest;
213
+ $[12] = t1;
214
+ $[13] = t2;
215
+ } else {
216
+ t2 = $[13];
217
+ }
218
+ return t2;
219
+ });
220
+ EditorBubbleItem.displayName = "EditorBubbleItem";
221
+ const items = [{
222
+ name: "Text",
223
+ icon: TextFieldsIcon,
224
+ command: (editor) => editor?.chain().focus().toggleNode("paragraph", "paragraph").run(),
225
+ // I feel like there has to be a more efficient way to do this – feel free to PR if you know how!
226
+ isActive: (editor) => (editor?.isActive("paragraph") && !editor?.isActive("bulletList") && !editor?.isActive("orderedList")) ?? false
227
+ }, {
228
+ name: "Heading 1",
229
+ icon: LooksOneIcon,
230
+ command: (editor) => editor?.chain().focus().toggleHeading({
231
+ level: 1
232
+ }).run(),
233
+ isActive: (editor) => editor?.isActive("heading", {
234
+ level: 1
235
+ }) ?? false
236
+ }, {
237
+ name: "Heading 2",
238
+ icon: LooksTwoIcon,
239
+ command: (editor) => editor?.chain().focus().toggleHeading({
240
+ level: 2
241
+ }).run(),
242
+ isActive: (editor) => editor?.isActive("heading", {
243
+ level: 2
244
+ }) ?? false
245
+ }, {
246
+ name: "Heading 3",
247
+ icon: Looks3Icon,
248
+ command: (editor) => editor?.chain().focus().toggleHeading({
249
+ level: 3
250
+ }).run(),
251
+ isActive: (editor) => editor?.isActive("heading", {
252
+ level: 3
253
+ }) ?? false
254
+ }, {
255
+ name: "To-do List",
256
+ icon: CheckBoxIcon,
257
+ command: (editor) => editor?.chain().focus().toggleTaskList().run(),
258
+ isActive: (editor) => editor?.isActive("taskItem") ?? false
259
+ }, {
260
+ name: "Bullet List",
261
+ icon: FormatListBulletedIcon,
262
+ command: (editor) => editor?.chain().focus().toggleBulletList().run(),
263
+ isActive: (editor) => editor?.isActive("bulletList") ?? false
264
+ }, {
265
+ name: "Numbered List",
266
+ icon: FormatListNumberedIcon,
267
+ command: (editor) => editor?.chain().focus().toggleOrderedList().run(),
268
+ isActive: (editor) => editor?.isActive("orderedList") ?? false
269
+ }, {
270
+ name: "Quote",
271
+ icon: FormatQuoteIcon,
272
+ command: (editor) => editor?.chain().focus().toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
273
+ isActive: (editor) => editor?.isActive("blockquote") ?? false
274
+ }, {
275
+ name: "Code",
276
+ icon: CodeIcon,
277
+ command: (editor) => editor?.chain().focus().toggleCodeBlock().run(),
278
+ isActive: (editor) => editor?.isActive("codeBlock") ?? false
279
+ }];
280
+ const NodeSelector = (t0) => {
281
+ const $ = c(16);
282
+ const {
283
+ open,
284
+ onOpenChange,
285
+ portalContainer
286
+ } = t0;
287
+ const {
288
+ editor
289
+ } = useCurrentEditor();
290
+ if (!editor) {
291
+ return null;
292
+ }
293
+ let t1;
294
+ if ($[0] !== editor) {
295
+ t1 = items.filter((item) => item.isActive(editor)).pop() ?? {
296
+ name: "Multiple"
297
+ };
298
+ $[0] = editor;
299
+ $[1] = t1;
300
+ } else {
301
+ t1 = $[1];
302
+ }
303
+ const activeItem = t1;
304
+ let t2;
305
+ if ($[2] !== activeItem.name) {
306
+ t2 = /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-sm", children: activeItem.name });
307
+ $[2] = activeItem.name;
308
+ $[3] = t2;
309
+ } else {
310
+ t2 = $[3];
311
+ }
312
+ let t3;
313
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
314
+ t3 = /* @__PURE__ */ jsx(KeyboardArrowDownIcon, { size: "small" });
315
+ $[4] = t3;
316
+ } else {
317
+ t3 = $[4];
318
+ }
319
+ let t4;
320
+ if ($[5] !== t2) {
321
+ t4 = /* @__PURE__ */ jsxs(Button, { variant: "text", className: "gap-2 rounded-none", color: "text", children: [
322
+ t2,
323
+ t3
324
+ ] });
325
+ $[5] = t2;
326
+ $[6] = t4;
327
+ } else {
328
+ t4 = $[6];
329
+ }
330
+ let t5;
331
+ if ($[7] !== activeItem.name || $[8] !== onOpenChange) {
332
+ t5 = items.map((item_0, index) => /* @__PURE__ */ jsxs(EditorBubbleItem, { onSelect: (editor_0) => {
333
+ item_0.command(editor_0);
334
+ onOpenChange(false);
335
+ }, className: "flex cursor-pointer items-center justify-between rounded px-2 py-1 text-sm hover:bg-blue-50 hover:dark:bg-surface-700 text-surface-900 dark:text-white", children: [
336
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
337
+ /* @__PURE__ */ jsx(item_0.icon, { size: "smallest" }),
338
+ /* @__PURE__ */ jsx("span", { children: item_0.name })
339
+ ] }),
340
+ activeItem.name === item_0.name && /* @__PURE__ */ jsx(CheckIcon, { size: "smallest" })
341
+ ] }, index));
342
+ $[7] = activeItem.name;
343
+ $[8] = onOpenChange;
344
+ $[9] = t5;
345
+ } else {
346
+ t5 = $[9];
347
+ }
348
+ let t6;
349
+ if ($[10] !== onOpenChange || $[11] !== open || $[12] !== portalContainer || $[13] !== t4 || $[14] !== t5) {
350
+ t6 = /* @__PURE__ */ jsx(Popover, { sideOffset: 5, align: "start", portalContainer, className: "w-48 p-1", trigger: t4, modal: true, open, onOpenChange, children: t5 });
351
+ $[10] = onOpenChange;
352
+ $[11] = open;
353
+ $[12] = portalContainer;
354
+ $[13] = t4;
355
+ $[14] = t5;
356
+ $[15] = t6;
357
+ } else {
358
+ t6 = $[15];
359
+ }
360
+ return t6;
276
361
  };
277
- function lt(e) {
362
+ function isValidUrl(url) {
278
363
  try {
279
- return new URL(e), !0;
280
- } catch {
281
- return !1;
364
+ new URL(url);
365
+ return true;
366
+ } catch (e) {
367
+ return false;
282
368
  }
283
369
  }
284
- function dt(e) {
285
- if (lt(e))
286
- return e;
370
+ function getUrlFromString(str) {
371
+ if (isValidUrl(str)) return str;
287
372
  try {
288
- return e.includes(".") && !e.includes(" ") ? new URL(`https://${e}`).toString() : null;
289
- } catch {
373
+ if (str.includes(".") && !str.includes(" ")) {
374
+ return new URL(`https://${str}`).toString();
375
+ }
376
+ return null;
377
+ } catch (e) {
290
378
  return null;
291
379
  }
292
380
  }
293
- const ut = ({
294
- open: e,
295
- onOpenChange: o
296
- }) => {
297
- const t = D(null), { editor: r } = y();
298
- return C(() => {
299
- t.current && t.current?.focus();
300
- }), r ? /* @__PURE__ */ s(
301
- Q,
302
- {
303
- modal: !0,
304
- open: e,
305
- onOpenChange: o,
306
- trigger: /* @__PURE__ */ s(
307
- w,
308
- {
309
- variant: "text",
310
- className: "gap-2 rounded-none",
311
- color: "text",
312
- children: /* @__PURE__ */ s("p", { className: g("underline decoration-stone-400 underline-offset-4", {
313
- "text-blue-500": r.isActive("link")
314
- }), children: "Link" })
315
- }
316
- ),
317
- children: /* @__PURE__ */ b(
318
- "form",
319
- {
320
- onSubmit: (a) => {
321
- const c = a.currentTarget;
322
- a.preventDefault();
323
- const n = c[0], i = dt(n.value);
324
- i && r.chain().focus().setLink({ href: i }).run();
325
- },
326
- className: "flex p-1",
327
- children: [
328
- /* @__PURE__ */ s(
329
- "input",
330
- {
331
- ref: t,
332
- autoFocus: e,
333
- placeholder: "Paste a link",
334
- defaultValue: r.getAttributes("link").href || "",
335
- className: "text-gray-900 dark:text-white flex-grow bg-transparent p-1 text-sm outline-none"
336
- }
337
- ),
338
- r.getAttributes("link").href ? /* @__PURE__ */ s(
339
- w,
340
- {
341
- size: "small",
342
- variant: "text",
343
- type: "button",
344
- color: "text",
345
- className: "flex items-center",
346
- onClick: () => {
347
- r.chain().focus().unsetLink().run();
348
- },
349
- children: /* @__PURE__ */ s(Ke, { size: "small" })
350
- }
351
- ) : /* @__PURE__ */ s(
352
- w,
353
- {
354
- size: "small",
355
- variant: "text",
356
- children: /* @__PURE__ */ s(V, { size: "small" })
357
- }
358
- )
359
- ]
360
- }
361
- )
362
- }
363
- ) : null;
364
- }, mt = () => {
365
- const { editor: e } = y();
366
- return e ? /* @__PURE__ */ s("div", { className: "flex", children: [
367
- {
381
+ const LinkSelector = (t0) => {
382
+ const $ = c(24);
383
+ const {
384
+ open,
385
+ onOpenChange
386
+ } = t0;
387
+ const inputRef = useRef(null);
388
+ const {
389
+ editor
390
+ } = useCurrentEditor();
391
+ let t1;
392
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
393
+ t1 = () => {
394
+ inputRef.current && inputRef.current?.focus();
395
+ };
396
+ $[0] = t1;
397
+ } else {
398
+ t1 = $[0];
399
+ }
400
+ useEffect(t1);
401
+ if (!editor) {
402
+ return null;
403
+ }
404
+ let t2;
405
+ if ($[1] !== editor) {
406
+ t2 = cls("underline decoration-stone-400 underline-offset-4", {
407
+ "text-blue-500": editor.isActive("link")
408
+ });
409
+ $[1] = editor;
410
+ $[2] = t2;
411
+ } else {
412
+ t2 = $[2];
413
+ }
414
+ let t3;
415
+ if ($[3] !== t2) {
416
+ t3 = /* @__PURE__ */ jsx(Button, { variant: "text", className: "gap-2 rounded-none", color: "text", children: /* @__PURE__ */ jsx("p", { className: t2, children: "Link" }) });
417
+ $[3] = t2;
418
+ $[4] = t3;
419
+ } else {
420
+ t3 = $[4];
421
+ }
422
+ let t4;
423
+ if ($[5] !== editor) {
424
+ t4 = (e) => {
425
+ const target = e.currentTarget;
426
+ e.preventDefault();
427
+ const input = target[0];
428
+ const url = getUrlFromString(input.value);
429
+ url && editor.chain().focus().setLink({
430
+ href: url
431
+ }).run();
432
+ };
433
+ $[5] = editor;
434
+ $[6] = t4;
435
+ } else {
436
+ t4 = $[6];
437
+ }
438
+ let t5;
439
+ if ($[7] !== editor) {
440
+ t5 = editor.getAttributes("link").href || "";
441
+ $[7] = editor;
442
+ $[8] = t5;
443
+ } else {
444
+ t5 = $[8];
445
+ }
446
+ let t6;
447
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
448
+ t6 = cls("text-surface-900 dark:text-white flex-grow bg-transparent p-1 text-sm outline-none", focusedDisabled);
449
+ $[9] = t6;
450
+ } else {
451
+ t6 = $[9];
452
+ }
453
+ let t7;
454
+ if ($[10] !== open || $[11] !== t5) {
455
+ t7 = /* @__PURE__ */ jsx("input", { ref: inputRef, autoFocus: open, placeholder: "Paste a link", defaultValue: t5, className: t6 });
456
+ $[10] = open;
457
+ $[11] = t5;
458
+ $[12] = t7;
459
+ } else {
460
+ t7 = $[12];
461
+ }
462
+ let t8;
463
+ if ($[13] !== editor) {
464
+ t8 = editor.getAttributes("link").href ? /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", type: "button", color: "text", className: "flex items-center", onClick: () => {
465
+ editor.chain().focus().unsetLink().run();
466
+ }, children: /* @__PURE__ */ jsx(DeleteIcon, { size: "small" }) }) : /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", children: /* @__PURE__ */ jsx(CheckIcon, { size: "small" }) });
467
+ $[13] = editor;
468
+ $[14] = t8;
469
+ } else {
470
+ t8 = $[14];
471
+ }
472
+ let t9;
473
+ if ($[15] !== t4 || $[16] !== t7 || $[17] !== t8) {
474
+ t9 = /* @__PURE__ */ jsxs("form", { onSubmit: t4, className: "flex p-1", children: [
475
+ t7,
476
+ t8
477
+ ] });
478
+ $[15] = t4;
479
+ $[16] = t7;
480
+ $[17] = t8;
481
+ $[18] = t9;
482
+ } else {
483
+ t9 = $[18];
484
+ }
485
+ let t10;
486
+ if ($[19] !== onOpenChange || $[20] !== open || $[21] !== t3 || $[22] !== t9) {
487
+ t10 = /* @__PURE__ */ jsx(Popover, { modal: true, open, onOpenChange, trigger: t3, children: t9 });
488
+ $[19] = onOpenChange;
489
+ $[20] = open;
490
+ $[21] = t3;
491
+ $[22] = t9;
492
+ $[23] = t10;
493
+ } else {
494
+ t10 = $[23];
495
+ }
496
+ return t10;
497
+ };
498
+ const TextButtons = () => {
499
+ const $ = c(2);
500
+ const {
501
+ editor
502
+ } = useCurrentEditor();
503
+ if (!editor) {
504
+ return null;
505
+ }
506
+ let t0;
507
+ if ($[0] !== editor) {
508
+ const items2 = [{
368
509
  name: "bold",
369
- isActive: (t) => t?.isActive("bold") ?? !1,
370
- command: (t) => t?.chain().focus().toggleBold().run(),
371
- icon: $e
372
- },
373
- {
510
+ isActive: _temp,
511
+ command: _temp2,
512
+ icon: FormatBoldIcon
513
+ }, {
374
514
  name: "italic",
375
- isActive: (t) => t?.isActive("italic") ?? !1,
376
- command: (t) => t?.chain().focus().toggleItalic().run(),
377
- icon: qe
378
- },
379
- {
515
+ isActive: _temp3,
516
+ command: _temp4,
517
+ icon: FormatItalicIcon
518
+ }, {
380
519
  name: "underline",
381
- isActive: (t) => t?.isActive("underline") ?? !1,
382
- command: (t) => t?.chain().focus().toggleUnderline().run(),
383
- icon: We
384
- },
385
- {
520
+ isActive: _temp5,
521
+ command: _temp6,
522
+ icon: FormatUnderlinedIcon
523
+ }, {
386
524
  name: "strike",
387
- isActive: (t) => t?.isActive("strike") ?? !1,
388
- command: (t) => t?.chain().focus().toggleStrike().run(),
389
- icon: Oe
390
- },
391
- {
525
+ isActive: _temp7,
526
+ command: _temp8,
527
+ icon: FormatStrikethroughIcon
528
+ }, {
392
529
  name: "code",
393
- isActive: (t) => t?.isActive("code") ?? !1,
394
- command: (t) => t?.chain().focus().toggleCode().run(),
395
- icon: z
396
- }
397
- ].map((t, r) => /* @__PURE__ */ s(
398
- F,
399
- {
400
- onSelect: (a) => {
401
- t.command(a);
402
- },
403
- children: /* @__PURE__ */ s(
404
- w,
405
- {
406
- size: "small",
407
- color: "text",
408
- className: "gap-2 rounded-none h-full",
409
- variant: "text",
410
- children: /* @__PURE__ */ s(
411
- t.icon,
412
- {
413
- className: g({
414
- "text-inherit": !t.isActive(e),
415
- "text-blue-500": t.isActive(e)
416
- })
417
- }
418
- )
419
- }
420
- )
421
- },
422
- r
423
- )) }) : null;
530
+ isActive: _temp9,
531
+ command: _temp10,
532
+ icon: CodeIcon
533
+ }];
534
+ t0 = /* @__PURE__ */ jsx("div", { className: "flex", children: items2.map((item, index) => /* @__PURE__ */ jsx(EditorBubbleItem, { onSelect: (editor_10) => {
535
+ item.command(editor_10);
536
+ }, children: /* @__PURE__ */ jsx(Button, { size: "small", color: "text", className: "gap-2 rounded-none h-full", variant: "text", children: /* @__PURE__ */ jsx(item.icon, { className: cls({
537
+ "text-inherit": !item.isActive(editor),
538
+ "text-blue-500": item.isActive(editor)
539
+ }) }) }) }, index)) });
540
+ $[0] = editor;
541
+ $[1] = t0;
542
+ } else {
543
+ t0 = $[1];
544
+ }
545
+ return t0;
424
546
  };
425
- function R(e, o, t, r = 300) {
426
- const a = L.useRef(!1), c = () => {
427
- o(), a.current = !1;
428
- }, n = L.useRef(void 0);
429
- L.useEffect(
430
- () => (a.current = !0, clearTimeout(n.current), n.current = setTimeout(c, r), () => {
431
- t && c();
432
- }),
433
- [t, e]
434
- );
547
+ function _temp(editor_0) {
548
+ return editor_0?.isActive("bold") ?? false;
435
549
  }
436
- function H(e) {
437
- return Array.isArray(e) ? e.map((o) => H(o)) : (typeof e == "object" && e !== null && (e.attrs && typeof e.attrs == "object" && "class" in e.attrs && delete e.attrs.class, Object.keys(e).forEach((o) => {
438
- e[o] = H(e[o]);
439
- })), e);
550
+ function _temp2(editor_1) {
551
+ return editor_1?.chain().focus().toggleBold().run();
440
552
  }
441
- const gt = st, pt = Re.configure({
442
- HTMLAttributes: {
443
- class: g(
444
- "text-gray-600 dark:text-slate-300 underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer"
445
- )
446
- }
447
- }), ft = De.configure({
448
- HTMLAttributes: {
449
- class: g("not-prose")
553
+ function _temp3(editor_2) {
554
+ return editor_2?.isActive("italic") ?? false;
555
+ }
556
+ function _temp4(editor_3) {
557
+ return editor_3?.chain().focus().toggleItalic().run();
558
+ }
559
+ function _temp5(editor_4) {
560
+ return editor_4?.isActive("underline") ?? false;
561
+ }
562
+ function _temp6(editor_5) {
563
+ return editor_5?.chain().focus().toggleUnderline().run();
564
+ }
565
+ function _temp7(editor_6) {
566
+ return editor_6?.isActive("strike") ?? false;
567
+ }
568
+ function _temp8(editor_7) {
569
+ return editor_7?.chain().focus().toggleStrike().run();
570
+ }
571
+ function _temp9(editor_8) {
572
+ return editor_8?.isActive("code") ?? false;
573
+ }
574
+ function _temp10(editor_9) {
575
+ return editor_9?.chain().focus().toggleCode().run();
576
+ }
577
+ function removeClassesFromJson(jsonObj) {
578
+ if (Array.isArray(jsonObj)) {
579
+ return jsonObj.map((item) => removeClassesFromJson(item));
580
+ } else if (typeof jsonObj === "object" && jsonObj !== null) {
581
+ if (jsonObj.attrs && typeof jsonObj.attrs === "object" && "class" in jsonObj.attrs) {
582
+ delete jsonObj.attrs.class;
583
+ }
584
+ Object.keys(jsonObj).forEach((key) => {
585
+ jsonObj[key] = removeClassesFromJson(jsonObj[key]);
586
+ });
450
587
  }
451
- }), ht = He.configure({
452
- HTMLAttributes: {
453
- class: g("flex items-start my-4")
588
+ return jsonObj;
589
+ }
590
+ const loadingDecorationKey = new PluginKey("loadingDecoration");
591
+ const TextLoadingDecorationExtension = Extension.create({
592
+ name: "loadingDecoration",
593
+ addOptions() {
594
+ return {
595
+ pluginKey: loadingDecorationKey
596
+ };
454
597
  },
455
- nested: !0
456
- }), bt = it.configure({
457
- HTMLAttributes: {
458
- class: g("mt-4 mb-6 border-t", x)
459
- }
460
- }), kt = Ne.configure({
461
- bulletList: {
462
- HTMLAttributes: {
463
- class: g("list-disc list-outside leading-3 -mt-2")
464
- }
598
+ addProseMirrorPlugins() {
599
+ const pluginKey = this.options.pluginKey;
600
+ return [new Plugin({
601
+ key: pluginKey,
602
+ state: {
603
+ init() {
604
+ return {
605
+ decorationSet: DecorationSet.empty,
606
+ hasDecoration: false
607
+ };
608
+ },
609
+ apply(tr, oldState) {
610
+ const action = tr.getMeta(pluginKey);
611
+ if (action?.type === "loadingDecoration") {
612
+ const {
613
+ pos,
614
+ remove,
615
+ loadingHtml
616
+ } = action;
617
+ if (remove) {
618
+ return {
619
+ decorationSet: DecorationSet.empty,
620
+ hasDecoration: false
621
+ };
622
+ }
623
+ const decoration = Decoration.widget(pos, () => {
624
+ const container = document.createElement("span");
625
+ container.className = "loading-decoration";
626
+ if (loadingHtml) {
627
+ container.innerHTML = loadingHtml;
628
+ } else {
629
+ const span = document.createElement("span");
630
+ span.innerText = "loading...";
631
+ container.appendChild(span);
632
+ }
633
+ return container;
634
+ });
635
+ return {
636
+ decorationSet: DecorationSet.empty.add(tr.doc, [decoration]),
637
+ hasDecoration: true
638
+ };
639
+ }
640
+ return {
641
+ decorationSet: oldState.decorationSet.map(tr.mapping, tr.doc),
642
+ hasDecoration: oldState.hasDecoration
643
+ };
644
+ }
645
+ },
646
+ props: {
647
+ decorations(state) {
648
+ return this.getState(state)?.decorationSet || DecorationSet.empty;
649
+ }
650
+ }
651
+ })];
465
652
  },
466
- orderedList: {
467
- HTMLAttributes: {
468
- class: g("list-decimal list-outside leading-3 -mt-2")
653
+ addCommands() {
654
+ return {
655
+ toggleLoadingDecoration: (loadingHtml) => ({
656
+ state,
657
+ dispatch
658
+ }) => {
659
+ const {
660
+ selection
661
+ } = state;
662
+ const pos = selection.from;
663
+ if (!dispatch) return false;
664
+ const pluginKey = this.options.pluginKey;
665
+ const tr = state.tr.setMeta(pluginKey, {
666
+ pos,
667
+ type: "loadingDecoration",
668
+ remove: false,
669
+ loadingHtml
670
+ });
671
+ dispatch(tr);
672
+ return true;
673
+ },
674
+ removeLoadingDecoration: () => ({
675
+ state,
676
+ dispatch
677
+ }) => {
678
+ if (!dispatch) return false;
679
+ const pluginKey = this.options.pluginKey;
680
+ const tr = state.tr.setMeta(pluginKey, {
681
+ pos: 0,
682
+ // We can pass any position as it will remove the entire decoration set
683
+ type: "loadingDecoration",
684
+ remove: true
685
+ });
686
+ dispatch(tr);
687
+ return true;
688
+ }
689
+ };
690
+ }
691
+ });
692
+ const PlaceholderExtension = Placeholder.configure({
693
+ placeholder: ({
694
+ node,
695
+ editor
696
+ }) => {
697
+ editor.state.selection;
698
+ function hasLoadingDecoration(editor2) {
699
+ const pluginState = loadingDecorationKey.get(editor2.state);
700
+ return pluginState?.getState(editor2.state)?.hasDecoration ?? false;
469
701
  }
470
- },
471
- listItem: {
472
- HTMLAttributes: {
473
- class: g("leading-normal -mb-2")
702
+ const hasDecoration = hasLoadingDecoration(editor);
703
+ if (hasDecoration) {
704
+ return "";
474
705
  }
475
- },
476
- blockquote: {
477
- HTMLAttributes: {
478
- class: g("border-l-4 border-primary")
706
+ if (node.type.name === "heading") {
707
+ return `Heading ${node.attrs.level}`;
479
708
  }
480
- },
481
- codeBlock: {
482
- HTMLAttributes: {
483
- class: g("rounded bg-blue-50 dark:bg-gray-700 border p-5 font-mono font-medium", x)
709
+ if (node.type.name === "paragraph") {
710
+ return "Press '/' for commands";
484
711
  }
712
+ return "";
485
713
  },
486
- code: {
487
- HTMLAttributes: {
488
- class: g("rounded-md bg-slate-50 dark:bg-gray-700 px-1.5 py-1 font-mono font-medium"),
489
- spellcheck: "false"
490
- }
714
+ includeChildren: true
715
+ });
716
+ const Horizontal = HorizontalRule.extend({
717
+ addInputRules() {
718
+ return [new InputRule({
719
+ find: /^(?:---|—-|___\s|\*\*\*\s)$/,
720
+ handler: ({
721
+ state,
722
+ range
723
+ }) => {
724
+ const attributes = {};
725
+ const {
726
+ tr
727
+ } = state;
728
+ const start = range.from;
729
+ const end = range.to;
730
+ tr.insert(start - 1, this.type.create(attributes)).delete(tr.mapping.map(start), tr.mapping.map(end));
731
+ }
732
+ })];
733
+ }
734
+ });
735
+ const placeholder = PlaceholderExtension;
736
+ const tiptapLink = TiptapLink.configure({
737
+ HTMLAttributes: {
738
+ class: cls("text-surface-700 dark:text-surface-accent-200 underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer")
739
+ }
740
+ });
741
+ const taskList = TaskList.configure({
742
+ HTMLAttributes: {
743
+ class: cls("not-prose")
744
+ }
745
+ });
746
+ const taskItem = TaskItem.configure({
747
+ HTMLAttributes: {
748
+ class: cls("flex items-start my-4")
491
749
  },
492
- horizontalRule: !1,
750
+ nested: true
751
+ });
752
+ const horizontalRule = Horizontal.configure({
753
+ HTMLAttributes: {
754
+ class: cls("mt-4 mb-6 border-t", defaultBorderMixin)
755
+ }
756
+ });
757
+ const bulletList = BulletList.configure({
758
+ HTMLAttributes: {
759
+ class: cls("list-disc list-outside leading-3 -mt-2")
760
+ }
761
+ });
762
+ const orderedList = OrderedList.configure({
763
+ HTMLAttributes: {
764
+ class: cls("list-decimal list-outside leading-3 -mt-2")
765
+ }
766
+ });
767
+ const listItem = ListItem.configure({
768
+ HTMLAttributes: {
769
+ class: cls("leading-normal -mb-2")
770
+ }
771
+ });
772
+ const blockquote = Blockquote.configure({
773
+ HTMLAttributes: {
774
+ class: cls("border-l-4 border-primary")
775
+ }
776
+ });
777
+ const codeBlock = CodeBlock.configure({
778
+ HTMLAttributes: {
779
+ class: cls("rounded bg-blue-50 dark:bg-surface-700 border p-5 font-mono font-medium", defaultBorderMixin)
780
+ }
781
+ });
782
+ const code = Code.configure({
783
+ HTMLAttributes: {
784
+ class: cls("rounded-md bg-surface-accent-50 dark:bg-surface-700 px-1.5 py-1 font-mono font-medium"),
785
+ spellcheck: "false"
786
+ }
787
+ });
788
+ const starterKit = StarterKit.configure({
789
+ document: false,
790
+ horizontalRule: false,
493
791
  dropcursor: {
494
792
  color: "#DBEAFE",
495
793
  width: 4
496
794
  },
497
- gapcursor: !1
795
+ gapcursor: false
498
796
  });
499
- async function W(e, o, t, r, a, c) {
500
- const { schema: n } = o.state;
501
- let i = e.getState(o.state);
502
- const d = document.createElement("div"), u = document.createElement("img");
503
- u.setAttribute("class", "opacity-40 rounded-lg border border-stone-200"), u.src = t.target?.result, d.appendChild(u);
504
- const p = Xe.widget(r, d);
505
- i = i?.add(o.state.doc, [p]), o.dispatch(o.state.tr.setMeta(e, { decorationSet: i }));
506
- const h = await a(c);
507
- console.log("uploaded image", h);
508
- const f = n.nodes.image.create({ src: h }), A = o.state.tr.replaceWith(r, r, f);
509
- i = i?.remove([p]), A.setMeta(e, { decorationSet: i }), o.dispatch(A);
797
+ async function onFileRead(view, readerEvent, pos, upload, image) {
798
+ const {
799
+ schema
800
+ } = view.state;
801
+ const plugin = view.state.plugins.find((p) => p.key === ImagePluginKey.key);
802
+ if (!plugin) {
803
+ console.error("Image plugin not found");
804
+ return;
805
+ }
806
+ let decorationSet = plugin.getState(view.state);
807
+ const placeholder2 = document.createElement("div");
808
+ const imageElement = document.createElement("img");
809
+ imageElement.setAttribute("class", "opacity-40 rounded-lg border " + defaultBorderMixin);
810
+ imageElement.src = readerEvent.target?.result;
811
+ placeholder2.appendChild(imageElement);
812
+ const deco = Decoration$1.widget(pos, placeholder2);
813
+ decorationSet = decorationSet?.add(view.state.doc, [deco]);
814
+ view.dispatch(view.state.tr.setMeta(plugin, {
815
+ decorationSet
816
+ }));
817
+ const src = await upload(image);
818
+ console.debug("Uploaded image", src);
819
+ const imageNode = schema.nodes.image.create({
820
+ src
821
+ });
822
+ const tr = view.state.tr.replaceWith(pos, pos, imageNode);
823
+ decorationSet = decorationSet?.remove([deco]);
824
+ tr.setMeta(plugin, {
825
+ decorationSet
826
+ });
827
+ view.dispatch(tr);
510
828
  }
511
- const xt = (e) => {
512
- const o = new Qe({
829
+ const ImagePluginKey = new PluginKey$1("imagePlugin");
830
+ const createDropImagePlugin = (upload) => {
831
+ const plugin = new Plugin$1({
832
+ key: ImagePluginKey,
513
833
  state: {
514
834
  // Initialize the plugin state with an empty DecorationSet
515
- init: () => Ve.empty,
835
+ init: () => DecorationSet$1.empty,
516
836
  // Apply transactions to update the state
517
- apply: (t, r) => {
518
- const a = t.getMeta(o);
519
- return a && a.decorationSet ? a.decorationSet : r.map(t.mapping, t.doc);
837
+ apply: (tr, old) => {
838
+ const meta = tr.getMeta(plugin);
839
+ if (meta && meta.decorationSet) {
840
+ return meta.decorationSet;
841
+ }
842
+ return old.map(tr.mapping, tr.doc);
520
843
  }
521
844
  },
522
845
  props: {
523
846
  handleDOMEvents: {
524
- drop: (t, r) => {
525
- if (console.log("drop event", r), !r.dataTransfer?.files || r.dataTransfer?.files.length === 0)
526
- return !1;
527
- r.preventDefault();
528
- const c = Array.from(r.dataTransfer.files).filter((n) => /image/i.test(n.type));
529
- return c.length === 0 ? !1 : (c.forEach((n) => {
530
- const i = t.posAtCoords({ left: r.clientX, top: r.clientY });
531
- if (!i)
532
- return;
533
- const d = new FileReader();
534
- d.onload = async (u) => {
535
- await W(o, t, u, i.pos, e, n);
536
- }, d.readAsDataURL(n);
537
- }), !0);
847
+ drop: (view, event) => {
848
+ if (!event.dataTransfer?.files || event.dataTransfer?.files.length === 0) {
849
+ return false;
850
+ }
851
+ event.preventDefault();
852
+ const files = Array.from(event.dataTransfer.files);
853
+ const images = files.filter((file) => /image/i.test(file.type));
854
+ if (images.length === 0) {
855
+ console.log("No images found in dropped files");
856
+ return false;
857
+ }
858
+ images.forEach((image) => {
859
+ const position = view.posAtCoords({
860
+ left: event.clientX,
861
+ top: event.clientY
862
+ });
863
+ if (!position) return;
864
+ const reader = new FileReader();
865
+ reader.onload = async (readerEvent) => {
866
+ await onFileRead(view, readerEvent, position.pos, upload, image);
867
+ };
868
+ reader.readAsDataURL(image);
869
+ });
870
+ return true;
538
871
  }
539
872
  },
540
- handlePaste(t, r, a) {
541
- const c = Array.from(r.clipboardData?.items || []), n = t.state.selection.from;
542
- console.log("pos", n);
543
- let i = !1;
544
- return c.forEach((d) => {
545
- const u = d.getAsFile();
546
- if (console.log("image", u), u) {
547
- i = !0;
548
- const p = new FileReader();
549
- p.onload = async (h) => {
550
- await W(o, t, h, n, e, u);
551
- }, p.readAsDataURL(u);
873
+ handlePaste(view, event, slice) {
874
+ const items2 = Array.from(event.clipboardData?.items || []);
875
+ const pos = view.state.selection.from;
876
+ let anyImageFound = false;
877
+ items2.forEach((item) => {
878
+ const image = item.getAsFile();
879
+ if (image) {
880
+ anyImageFound = true;
881
+ const reader = new FileReader();
882
+ reader.onload = async (readerEvent) => {
883
+ await onFileRead(view, readerEvent, pos, upload, image);
884
+ };
885
+ reader.readAsDataURL(image);
552
886
  }
553
- }), i;
887
+ });
888
+ return anyImageFound;
554
889
  },
555
- decorations(t) {
556
- return o.getState(t);
890
+ decorations(state) {
891
+ return plugin.getState(state);
557
892
  }
558
893
  },
559
- view(t) {
894
+ view(editorView) {
560
895
  return {
561
- update(r, a) {
562
- const c = o.getState(a), n = o.getState(r.state);
563
- c !== n && r.updateState(r.state);
896
+ update(view, prevState) {
897
+ const prevDecos = plugin.getState(prevState);
898
+ const newDecos = plugin.getState(view.state);
899
+ if (prevDecos !== newDecos) {
900
+ view.updateState(view.state);
901
+ }
564
902
  }
565
903
  };
566
904
  }
567
905
  });
568
- return o;
569
- }, yt = (e) => Ie.extend({
570
- addProseMirrorPlugins() {
571
- return [xt(e)];
572
- }
573
- }).configure({
574
- allowBase64: !0,
575
- HTMLAttributes: {
576
- class: g("rounded-lg border", x)
577
- }
578
- }), vt = B.create({
906
+ return plugin;
907
+ };
908
+ const createImageExtension = (dropImagePlugin) => {
909
+ return TiptapImage.extend({
910
+ addProseMirrorPlugins() {
911
+ return [dropImagePlugin];
912
+ }
913
+ }).configure({
914
+ allowBase64: true,
915
+ HTMLAttributes: {
916
+ class: cls("rounded-lg border", defaultBorderMixin)
917
+ }
918
+ });
919
+ };
920
+ const CustomKeymap = Extension.create({
579
921
  name: "CustomKeymap",
580
922
  addCommands() {
581
923
  return {
582
- selectTextWithinNodeBoundaries: () => ({ editor: e, commands: o }) => {
583
- const { state: t } = e, { tr: r } = t, a = r.selection.$from.start(), c = r.selection.$to.end();
584
- return o.setTextSelection({
585
- from: a,
586
- to: c
924
+ selectTextWithinNodeBoundaries: () => ({
925
+ editor,
926
+ commands
927
+ }) => {
928
+ const {
929
+ state
930
+ } = editor;
931
+ const {
932
+ tr
933
+ } = state;
934
+ const startNodePos = tr.selection.$from.start();
935
+ const endNodePos = tr.selection.$to.end();
936
+ return commands.setTextSelection({
937
+ from: startNodePos,
938
+ to: endNodePos
587
939
  });
588
940
  }
589
941
  };
590
942
  },
591
943
  addKeyboardShortcuts() {
592
944
  return {
593
- "Mod-a": ({ editor: e }) => {
594
- const { state: o } = e, { tr: t } = o, r = t.selection.from, a = t.selection.to, c = t.selection.$from.start(), n = t.selection.$to.end();
595
- return r > c || a < n ? (e.chain().selectTextWithinNodeBoundaries().run(), !0) : !1;
945
+ "Mod-a": ({
946
+ editor
947
+ }) => {
948
+ const {
949
+ state
950
+ } = editor;
951
+ const {
952
+ tr
953
+ } = state;
954
+ const startSelectionPos = tr.selection.from;
955
+ const endSelectionPos = tr.selection.to;
956
+ const startNodePos = tr.selection.$from.start();
957
+ const endNodePos = tr.selection.$to.end();
958
+ const isCurrentTextSelectionNotExtendedToNodeBoundaries = startSelectionPos > startNodePos || endSelectionPos < endNodePos;
959
+ if (isCurrentTextSelectionNotExtendedToNodeBoundaries) {
960
+ editor.chain().selectTextWithinNodeBoundaries().run();
961
+ return true;
962
+ }
963
+ return false;
596
964
  }
597
965
  };
598
966
  }
599
967
  });
600
- function Ct(e) {
601
- const o = e.getBoundingClientRect();
968
+ function serializeForClipboard(view, slice) {
969
+ view.someProp("transformCopied", (f) => {
970
+ slice = f(slice, view);
971
+ });
972
+ const context = [];
973
+ let {
974
+ content,
975
+ openStart,
976
+ openEnd
977
+ } = slice;
978
+ while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {
979
+ openStart--;
980
+ openEnd--;
981
+ const node = content.firstChild;
982
+ context.push(node.type.name, node.attrs != node.type.defaultAttrs ? node.attrs : null);
983
+ content = node.content;
984
+ }
985
+ const serializer = view.someProp("clipboardSerializer") || DOMSerializer.fromSchema(view.state.schema);
986
+ const doc = detachedDoc(), wrap = doc.createElement("div");
987
+ wrap.appendChild(serializer.serializeFragment(content, {
988
+ document: doc
989
+ }));
990
+ let firstChild = wrap.firstChild, needsWrap, wrappers = 0;
991
+ while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
992
+ for (let i = needsWrap.length - 1; i >= 0; i--) {
993
+ const wrapper = doc.createElement(needsWrap[i]);
994
+ while (wrap.firstChild) wrapper.appendChild(wrap.firstChild);
995
+ wrap.appendChild(wrapper);
996
+ wrappers++;
997
+ }
998
+ firstChild = wrap.firstChild;
999
+ }
1000
+ if (firstChild && firstChild.nodeType == 1) firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
1001
+ const text = view.someProp("clipboardTextSerializer", (f) => f(slice, view)) || slice.content.textBetween(0, slice.content.size, "\n\n");
1002
+ return {
1003
+ dom: wrap,
1004
+ text,
1005
+ slice
1006
+ };
1007
+ }
1008
+ const wrapMap = {
1009
+ thead: ["table"],
1010
+ tbody: ["table"],
1011
+ tfoot: ["table"],
1012
+ caption: ["table"],
1013
+ colgroup: ["table"],
1014
+ col: ["table", "colgroup"],
1015
+ tr: ["table", "tbody"],
1016
+ td: ["table", "tbody", "tr"],
1017
+ th: ["table", "tbody", "tr"]
1018
+ };
1019
+ let _detachedDoc = null;
1020
+ function detachedDoc() {
1021
+ return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
1022
+ }
1023
+ function absoluteRect(element) {
1024
+ const data = element.getBoundingClientRect();
1025
+ let ancestor = element.parentElement;
1026
+ while (ancestor && window.getComputedStyle(ancestor).position === "static") {
1027
+ ancestor = ancestor.parentElement;
1028
+ }
1029
+ const ancestorRect = ancestor?.getBoundingClientRect();
602
1030
  return {
603
- top: o.top,
604
- left: o.left,
605
- width: o.width
1031
+ top: data.top - (ancestorRect?.top ?? 0),
1032
+ left: data.left - (ancestorRect?.left ?? 0),
1033
+ width: data.width
606
1034
  };
607
1035
  }
608
- function I(e) {
609
- return document.elementsFromPoint(e.x, e.y).find(
610
- (o) => o.parentElement?.matches?.(".ProseMirror") || o.matches(
611
- ["li", "p:not(:first-child)", "pre", "blockquote", "h1, h2, h3, h4, h5, h6"].join(", ")
612
- )
613
- );
1036
+ function nodeDOMAtCoords(coords) {
1037
+ return document.elementsFromPoint(coords.x, coords.y).find((elem) => elem.parentElement?.matches?.(".ProseMirror") || elem.matches(["li", "p:not(:first-child)", "pre", "blockquote", "h1, h2, h3, h4, h5, h6"].join(", ")));
614
1038
  }
615
- function O(e, o, t) {
616
- const r = e.getBoundingClientRect();
617
- return o.posAtCoords({
618
- left: r.left + 50 + t.dragHandleWidth,
619
- top: r.top + 1
1039
+ function nodePosAtDOM(node, view, options) {
1040
+ const boundingRect = node.getBoundingClientRect();
1041
+ return view.posAtCoords({
1042
+ left: boundingRect.left + 50 + options.dragHandleWidth,
1043
+ top: boundingRect.top + 1
620
1044
  })?.inside;
621
1045
  }
622
- function wt(e) {
623
- function o(n, i) {
624
- if (i.focus(), !n.dataTransfer)
625
- return;
626
- const d = I({
627
- x: n.clientX + 50 + e.dragHandleWidth,
628
- y: n.clientY
1046
+ function DragHandle(options) {
1047
+ function handleDragStart(event, view) {
1048
+ view.focus();
1049
+ if (!event.dataTransfer) return;
1050
+ const node = nodeDOMAtCoords({
1051
+ x: event.clientX + 50 + options.dragHandleWidth,
1052
+ y: event.clientY
629
1053
  });
630
- if (!(d instanceof Element))
631
- return;
632
- const u = O(d, i, e);
633
- if (u == null || u < 0)
634
- return;
635
- i.dispatch(i.state.tr.setSelection($.create(i.state.doc, u)));
636
- const p = i.state.selection.content(), { dom: h, text: f } = Ye(i, p);
637
- n.dataTransfer.clearData(), n.dataTransfer.setData("text/html", h.innerHTML), n.dataTransfer.setData("text/plain", f), n.dataTransfer.effectAllowed = "copyMove", n.dataTransfer.setDragImage(d, 0, 0), i.dragging = { slice: p, move: n.ctrlKey };
638
- }
639
- function t(n, i) {
640
- i.focus(), i.dom.classList.remove("dragging");
641
- const d = I({
642
- x: n.clientX + 50 + e.dragHandleWidth,
643
- y: n.clientY
1054
+ if (!(node instanceof Element)) return;
1055
+ const nodePos = nodePosAtDOM(node, view, options);
1056
+ if (nodePos == null || nodePos < 0) return;
1057
+ view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)));
1058
+ const slice = view.state.selection.content();
1059
+ const {
1060
+ dom,
1061
+ text
1062
+ } = serializeForClipboard(view, slice);
1063
+ event.dataTransfer.clearData();
1064
+ event.dataTransfer.setData("text/html", dom.innerHTML);
1065
+ event.dataTransfer.setData("text/plain", text);
1066
+ event.dataTransfer.effectAllowed = "copyMove";
1067
+ event.dataTransfer.setDragImage(node, 0, 0);
1068
+ view.dragging = {
1069
+ slice,
1070
+ move: event.ctrlKey
1071
+ };
1072
+ }
1073
+ function handleClick(event, view) {
1074
+ view.focus();
1075
+ view.dom.classList.remove("dragging");
1076
+ const node = nodeDOMAtCoords({
1077
+ x: event.clientX + 50 + options.dragHandleWidth,
1078
+ y: event.clientY
644
1079
  });
645
- if (!(d instanceof Element))
646
- return;
647
- const u = O(d, i, e);
648
- u && i.dispatch(i.state.tr.setSelection($.create(i.state.doc, u)));
649
- }
650
- let r = null;
651
- function a() {
652
- r && r.classList.add("hide");
653
- }
654
- function c() {
655
- r && r.classList.remove("hide");
656
- }
657
- return new Je({
658
- view: (n) => (r = document.createElement("div"), r.draggable = !0, r.dataset.dragHandle = "", r.classList.add("drag-handle"), r.addEventListener("dragstart", (i) => {
659
- o(i, n);
660
- }), r.addEventListener("click", (i) => {
661
- t(i, n);
662
- }), a(), n?.dom?.parentElement?.appendChild(r), {
663
- destroy: () => {
664
- r?.remove?.(), r = null;
665
- }
666
- }),
1080
+ if (!(node instanceof Element)) return;
1081
+ const nodePos = nodePosAtDOM(node, view, options);
1082
+ if (!nodePos) return;
1083
+ view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)));
1084
+ }
1085
+ let dragHandleElement = null;
1086
+ function hideDragHandle() {
1087
+ if (dragHandleElement) {
1088
+ dragHandleElement.classList.add("hide");
1089
+ }
1090
+ }
1091
+ function showDragHandle() {
1092
+ if (dragHandleElement) {
1093
+ dragHandleElement.classList.remove("hide");
1094
+ }
1095
+ }
1096
+ return new Plugin$1({
1097
+ view: (view) => {
1098
+ dragHandleElement = document.createElement("div");
1099
+ dragHandleElement.draggable = true;
1100
+ dragHandleElement.dataset.dragHandle = "";
1101
+ dragHandleElement.classList.add("drag-handle");
1102
+ dragHandleElement.addEventListener("dragstart", (e) => {
1103
+ handleDragStart(e, view);
1104
+ });
1105
+ dragHandleElement.addEventListener("click", (e) => {
1106
+ handleClick(e, view);
1107
+ });
1108
+ hideDragHandle();
1109
+ view?.dom?.parentElement?.appendChild(dragHandleElement);
1110
+ return {
1111
+ destroy: () => {
1112
+ }
1113
+ };
1114
+ },
667
1115
  props: {
668
1116
  handleDOMEvents: {
669
- mousemove: (n, i) => {
670
- if (!n.editable)
1117
+ mousemove: (view, event) => {
1118
+ if (!view.editable) {
671
1119
  return;
672
- const d = I({
673
- x: i.clientX + 50 + e.dragHandleWidth,
674
- y: i.clientY
1120
+ }
1121
+ const node = nodeDOMAtCoords({
1122
+ x: event.clientX + 50 + options.dragHandleWidth,
1123
+ y: event.clientY
675
1124
  });
676
- if (!(d instanceof Element)) {
677
- a();
1125
+ if (!(node instanceof Element)) {
1126
+ hideDragHandle();
678
1127
  return;
679
1128
  }
680
- const u = window.getComputedStyle(d), p = parseInt(u.lineHeight, 10), h = parseInt(u.paddingTop, 10), f = Ct(d);
681
- f.top += (p - 24) / 2, f.top += h, d.matches("ul:not([data-type=taskList]) li, ol li") && (f.left -= e.dragHandleWidth), f.width = e.dragHandleWidth, r && (r.style.left = `${f.left - f.width}px`, r.style.top = `${f.top}px`, c());
1129
+ const compStyle = window.getComputedStyle(node);
1130
+ const lineHeight = parseInt(compStyle.lineHeight, 10);
1131
+ const paddingTop = parseInt(compStyle.paddingTop, 10);
1132
+ const rect = absoluteRect(node);
1133
+ rect.top += (lineHeight - 24) / 2;
1134
+ rect.top += paddingTop;
1135
+ if (node.matches("ul:not([data-type=taskList]) li, ol li")) {
1136
+ rect.left -= options.dragHandleWidth;
1137
+ }
1138
+ rect.width = options.dragHandleWidth;
1139
+ if (!dragHandleElement) return;
1140
+ dragHandleElement.style.left = `${rect.left - rect.width}px`;
1141
+ dragHandleElement.style.top = `${rect.top}px`;
1142
+ showDragHandle();
682
1143
  },
683
1144
  keydown: () => {
684
- a();
1145
+ hideDragHandle();
685
1146
  },
686
1147
  mousewheel: () => {
687
- a();
1148
+ hideDragHandle();
688
1149
  },
689
1150
  // dragging class is used for CSS
690
- dragstart: (n) => {
691
- n.dom.classList.add("dragging");
1151
+ dragstart: (view) => {
1152
+ view.dom.classList.add("dragging");
692
1153
  },
693
- drop: (n) => {
694
- n.dom.classList.remove("dragging");
1154
+ drop: (view) => {
1155
+ view.dom.classList.remove("dragging");
695
1156
  },
696
- dragend: (n) => {
697
- n.dom.classList.remove("dragging");
1157
+ dragend: (view) => {
1158
+ view.dom.classList.remove("dragging");
698
1159
  }
699
1160
  }
700
1161
  }
701
1162
  });
702
1163
  }
703
- const At = B.create({
1164
+ const DragAndDrop = Extension.create({
704
1165
  name: "dragAndDrop",
705
1166
  addProseMirrorPlugins() {
706
- return [
707
- wt({
708
- dragHandleWidth: 24
1167
+ return [DragHandle({
1168
+ dragHandleWidth: 24
1169
+ })];
1170
+ }
1171
+ });
1172
+ function buildDecorationSet(highlight, doc) {
1173
+ const decorations = [];
1174
+ if (highlight) {
1175
+ decorations.push(Decoration$1.inline(highlight.from, highlight.to, {
1176
+ class: "dark:bg-surface-accent-700 bg-surface-accent-300"
1177
+ }));
1178
+ }
1179
+ const decorationSet = DecorationSet$1.create(doc, decorations);
1180
+ return decorationSet;
1181
+ }
1182
+ const HighlightDecorationExtension = (initialHighlight) => Extension.create({
1183
+ name: "highlightDecoration",
1184
+ addOptions() {
1185
+ return {
1186
+ pluginKey: new PluginKey$1("highlightDecoration"),
1187
+ highlight: initialHighlight
1188
+ };
1189
+ },
1190
+ addProseMirrorPlugins() {
1191
+ const pluginKey = this.options.pluginKey;
1192
+ return [new Plugin$1({
1193
+ key: pluginKey,
1194
+ state: {
1195
+ init: (_, {
1196
+ doc
1197
+ }) => {
1198
+ const highlight = this.options.highlight;
1199
+ const decorationSet = highlight && doc ? buildDecorationSet(highlight, doc) : DecorationSet$1.empty;
1200
+ return {
1201
+ decorationSet,
1202
+ highlight
1203
+ };
1204
+ },
1205
+ apply(transaction, oldState) {
1206
+ const action = transaction.getMeta(pluginKey);
1207
+ const highlight = action?.range;
1208
+ if (action?.type === "highlightDecoration") {
1209
+ const doc = transaction.doc;
1210
+ const {
1211
+ remove
1212
+ } = action;
1213
+ if (remove) {
1214
+ return {
1215
+ decorationSet: DecorationSet$1.empty
1216
+ };
1217
+ }
1218
+ const decorationSet = buildDecorationSet(highlight, doc);
1219
+ return {
1220
+ decorationSet,
1221
+ highlight
1222
+ };
1223
+ } else {
1224
+ return oldState;
1225
+ }
1226
+ }
1227
+ },
1228
+ props: {
1229
+ decorations(state) {
1230
+ const autocompleteState = this.getState(state);
1231
+ if (autocompleteState?.decorationSet) {
1232
+ return autocompleteState.decorationSet;
1233
+ } else {
1234
+ return DecorationSet$1.empty;
1235
+ }
1236
+ }
1237
+ }
1238
+ })];
1239
+ },
1240
+ addCommands() {
1241
+ return {
1242
+ toggleAutocompleteHighlight: (range) => ({
1243
+ state,
1244
+ dispatch
1245
+ }) => {
1246
+ const {
1247
+ selection
1248
+ } = state;
1249
+ const pos = selection.from;
1250
+ if (!dispatch) return false;
1251
+ const pluginKey = this.options.pluginKey;
1252
+ const tr = state.tr.setMeta(pluginKey, {
1253
+ pos,
1254
+ type: "highlightDecoration",
1255
+ remove: false,
1256
+ range
1257
+ });
1258
+ dispatch(tr);
1259
+ return true;
1260
+ },
1261
+ removeAutocompleteHighlight: () => ({
1262
+ state,
1263
+ dispatch
1264
+ }) => {
1265
+ if (!dispatch) return false;
1266
+ const pluginKey = this.options.pluginKey;
1267
+ const tr = state.tr.setMeta(pluginKey, {
1268
+ pos: 0,
1269
+ // We can pass any position as it will remove the entire decoration set
1270
+ type: "highlightDecoration",
1271
+ remove: true
1272
+ });
1273
+ dispatch(tr);
1274
+ return true;
1275
+ }
1276
+ };
1277
+ }
1278
+ });
1279
+ const CommandPluginKey = new PluginKey$1("slash-command");
1280
+ const SlashCommand = Node.create({
1281
+ name: "command",
1282
+ addOptions() {
1283
+ return {
1284
+ HTMLAttributes: {},
1285
+ renderText({
1286
+ options,
1287
+ node
1288
+ }) {
1289
+ return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`;
1290
+ },
1291
+ deleteTriggerWithBackspace: false,
1292
+ renderHTML({
1293
+ options,
1294
+ node
1295
+ }) {
1296
+ return ["span", mergeAttributes(this.HTMLAttributes, options.HTMLAttributes), `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`];
1297
+ },
1298
+ suggestion: {
1299
+ char: "/",
1300
+ pluginKey: CommandPluginKey,
1301
+ command: ({
1302
+ editor,
1303
+ range,
1304
+ props
1305
+ }) => {
1306
+ const nodeAfter = editor.view.state.selection.$to.nodeAfter;
1307
+ const overrideSpace = nodeAfter?.text?.startsWith(" ");
1308
+ if (overrideSpace) {
1309
+ range.to += 1;
1310
+ }
1311
+ editor.chain().focus().insertContentAt(range, [{
1312
+ type: this.name,
1313
+ attrs: props
1314
+ }, {
1315
+ type: "text",
1316
+ text: " "
1317
+ }]).run();
1318
+ window.getSelection()?.collapseToEnd();
1319
+ },
1320
+ allow: ({
1321
+ state,
1322
+ range
1323
+ }) => {
1324
+ const $from = state.doc.resolve(range.from);
1325
+ const type = state.schema.nodes[this.name];
1326
+ const allow = !!$from.parent.type.contentMatch.matchType(type);
1327
+ return allow;
1328
+ }
1329
+ }
1330
+ };
1331
+ },
1332
+ group: "inline",
1333
+ inline: true,
1334
+ selectable: false,
1335
+ atom: true,
1336
+ addAttributes() {
1337
+ return {
1338
+ id: {
1339
+ default: null,
1340
+ parseHTML: (element) => element.getAttribute("data-id"),
1341
+ renderHTML: (attributes) => {
1342
+ if (!attributes.id) {
1343
+ return {};
1344
+ }
1345
+ return {
1346
+ "data-id": attributes.id
1347
+ };
1348
+ }
1349
+ },
1350
+ label: {
1351
+ default: null,
1352
+ parseHTML: (element) => element.getAttribute("data-label"),
1353
+ renderHTML: (attributes) => {
1354
+ if (!attributes.label) {
1355
+ return {};
1356
+ }
1357
+ return {
1358
+ "data-label": attributes.label
1359
+ };
1360
+ }
1361
+ }
1362
+ };
1363
+ },
1364
+ parseHTML() {
1365
+ return [{
1366
+ tag: `span[data-type="${this.name}"]`
1367
+ }];
1368
+ },
1369
+ renderHTML({
1370
+ node,
1371
+ HTMLAttributes
1372
+ }) {
1373
+ if (this.options.renderLabel !== void 0) {
1374
+ console.warn("renderLabel is deprecated use renderText and renderHTML instead");
1375
+ return ["span", mergeAttributes({
1376
+ "data-type": this.name
1377
+ }, this.options.HTMLAttributes, HTMLAttributes), this.options.renderLabel({
1378
+ options: this.options,
1379
+ node
1380
+ })];
1381
+ }
1382
+ const mergedOptions = {
1383
+ ...this.options
1384
+ };
1385
+ mergedOptions.HTMLAttributes = mergeAttributes({
1386
+ "data-type": this.name
1387
+ }, this.options.HTMLAttributes, HTMLAttributes);
1388
+ const html = this.options.renderHTML({
1389
+ options: mergedOptions,
1390
+ node
1391
+ });
1392
+ if (typeof html === "string") {
1393
+ return ["span", mergeAttributes({
1394
+ "data-type": this.name
1395
+ }, this.options.HTMLAttributes, HTMLAttributes), html];
1396
+ }
1397
+ return html;
1398
+ },
1399
+ renderText({
1400
+ node
1401
+ }) {
1402
+ return this.options.renderText({
1403
+ options: this.options,
1404
+ node
1405
+ });
1406
+ },
1407
+ addKeyboardShortcuts() {
1408
+ return {
1409
+ Backspace: () => this.editor.commands.command(({
1410
+ tr,
1411
+ state
1412
+ }) => {
1413
+ let isCommand = false;
1414
+ const {
1415
+ selection
1416
+ } = state;
1417
+ const {
1418
+ empty,
1419
+ anchor
1420
+ } = selection;
1421
+ if (!empty) {
1422
+ return false;
1423
+ }
1424
+ state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {
1425
+ if (node.type.name === this.name) {
1426
+ isCommand = true;
1427
+ tr.insertText(this.options.deleteTriggerWithBackspace ? "" : this.options.suggestion.char || "", pos, pos + node.nodeSize);
1428
+ return false;
1429
+ }
1430
+ return true;
1431
+ });
1432
+ return isCommand;
709
1433
  })
710
- ];
711
- }
712
- }), eo = ({
713
- handleImageUpload: e,
714
- initialContent: o,
715
- onJsonContentChange: t,
716
- onHtmlContentChange: r,
717
- onMarkdownContentChange: a
718
- }) => {
719
- const c = {
720
- handleDOMEvents: {
721
- keydown: (l, m) => !!(["ArrowUp", "ArrowDown", "Enter"].includes(m.key) && document.querySelector("#slash-command"))
1434
+ };
1435
+ },
1436
+ addProseMirrorPlugins() {
1437
+ return [Suggestion({
1438
+ editor: this.editor,
1439
+ ...this.options.suggestion
1440
+ })];
1441
+ }
1442
+ });
1443
+ const suggestion = (ref, {
1444
+ upload,
1445
+ aiController
1446
+ }) => ({
1447
+ items: ({
1448
+ query
1449
+ }) => {
1450
+ const availableSuggestionItems = [...suggestionItems];
1451
+ if (aiController) {
1452
+ availableSuggestionItems.push(autocompleteSuggestionItem);
722
1453
  }
723
- // handlePaste: (view, event) => {
724
- // if (event.clipboardData && event.clipboardData.files && event.clipboardData.files[0]) {
725
- // event.preventDefault();
726
- // const file = event.clipboardData.files[0];
727
- // const pos = view.state.selection.from;
728
- //
729
- // // startImageUpload({ file, view, pos, handleImageUpload });
730
- // return true;
731
- // }
732
- // return false;
733
- // },
734
- // handleDrop: (view, event, _slice, moved) => {
735
- // console.log("handleDrop", { event, moved });
736
- // if (!moved && event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {
737
- // console.log("handleDrop!!!", { event, moved });
738
- // event.preventDefault();
739
- // const file = event.dataTransfer.files[0];
740
- // const coordinates = view.posAtCoords({
741
- // left: event.clientX,
742
- // top: event.clientY
743
- // });
744
- // // here we deduct 1 from the pos or else the image will create an extra node
745
- // startImageUpload({
746
- // file,
747
- // view,
748
- // pos: coordinates?.pos || 0 - 1,
749
- // handleImageUpload,
750
- // });
751
- // return true;
752
- // }
753
- // return false;
754
- // }
755
- }, n = at([
756
- {
757
- title: "Text",
758
- description: "Just start typing with plain text.",
759
- searchTerms: ["p", "paragraph"],
760
- icon: /* @__PURE__ */ s(X, { size: 18 }),
761
- command: ({ editor: l, range: m }) => {
762
- l.chain().focus().deleteRange(m).toggleNode("paragraph", "paragraph").run();
1454
+ return availableSuggestionItems.filter((item) => {
1455
+ const inTitle = item.title.toLowerCase().startsWith(query.toLowerCase());
1456
+ if (inTitle) return inTitle;
1457
+ const inSearchTerms = item.searchTerms?.some((term) => term.toLowerCase().startsWith(query.toLowerCase()));
1458
+ return inSearchTerms;
1459
+ });
1460
+ },
1461
+ render: () => {
1462
+ let component;
1463
+ let popup;
1464
+ return {
1465
+ onStart: (props) => {
1466
+ component = new ReactRenderer(CommandList, {
1467
+ props: {
1468
+ ...props,
1469
+ upload,
1470
+ aiController
1471
+ },
1472
+ editor: props.editor
1473
+ });
1474
+ if (!props.clientRect) {
1475
+ return;
1476
+ }
1477
+ popup = tippy("body", {
1478
+ getReferenceClientRect: props.clientRect,
1479
+ appendTo: ref?.current,
1480
+ content: component.element,
1481
+ showOnCreate: true,
1482
+ interactive: true,
1483
+ trigger: "manual",
1484
+ placement: "bottom-start"
1485
+ });
1486
+ },
1487
+ onUpdate(props) {
1488
+ component.updateProps(props);
1489
+ if (!props.clientRect) {
1490
+ return;
1491
+ }
1492
+ popup[0].setProps({
1493
+ getReferenceClientRect: props.clientRect
1494
+ });
1495
+ },
1496
+ onKeyDown(props) {
1497
+ if (props.event.key === "Escape") {
1498
+ popup[0].hide();
1499
+ props.event.preventDefault();
1500
+ return true;
1501
+ }
1502
+ return component.ref?.onKeyDown(props);
1503
+ },
1504
+ onExit() {
1505
+ if (popup && popup[0]) popup[0].destroy();
1506
+ component?.destroy();
763
1507
  }
764
- },
765
- {
766
- title: "To-do List",
767
- description: "Track tasks with a to-do list.",
768
- searchTerms: ["todo", "task", "list", "check", "checkbox"],
769
- icon: /* @__PURE__ */ s(j, { size: 18 }),
770
- command: ({ editor: l, range: m }) => {
771
- l.chain().focus().deleteRange(m).toggleTaskList().run();
1508
+ };
1509
+ }
1510
+ });
1511
+ const CommandList = forwardRef((props, ref) => {
1512
+ const $ = c(33);
1513
+ const [selectedIndex, setSelectedIndex] = useState(0);
1514
+ const {
1515
+ editor
1516
+ } = useCurrentEditor();
1517
+ let t0;
1518
+ if ($[0] !== editor || $[1] !== props.aiController || $[2] !== props.range || $[3] !== props.upload) {
1519
+ t0 = (item) => {
1520
+ if (!editor) {
1521
+ return;
772
1522
  }
773
- },
774
- {
775
- title: "Heading 1",
776
- description: "Big section heading.",
777
- searchTerms: ["title", "big", "large"],
778
- icon: /* @__PURE__ */ s(Y, { size: 18 }),
779
- command: ({ editor: l, range: m }) => {
780
- l.chain().focus().deleteRange(m).setNode("heading", { level: 1 }).run();
1523
+ item?.command?.({
1524
+ editor,
1525
+ range: props.range,
1526
+ upload: props.upload,
1527
+ aiController: props.aiController
1528
+ });
1529
+ };
1530
+ $[0] = editor;
1531
+ $[1] = props.aiController;
1532
+ $[2] = props.range;
1533
+ $[3] = props.upload;
1534
+ $[4] = t0;
1535
+ } else {
1536
+ t0 = $[4];
1537
+ }
1538
+ const selectItem = t0;
1539
+ let t1;
1540
+ if ($[5] !== props.items.length || $[6] !== selectedIndex) {
1541
+ t1 = () => {
1542
+ setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length);
1543
+ };
1544
+ $[5] = props.items.length;
1545
+ $[6] = selectedIndex;
1546
+ $[7] = t1;
1547
+ } else {
1548
+ t1 = $[7];
1549
+ }
1550
+ const upHandler = t1;
1551
+ let t2;
1552
+ if ($[8] !== props.items.length || $[9] !== selectedIndex) {
1553
+ t2 = () => {
1554
+ setSelectedIndex((selectedIndex + 1) % props.items.length);
1555
+ };
1556
+ $[8] = props.items.length;
1557
+ $[9] = selectedIndex;
1558
+ $[10] = t2;
1559
+ } else {
1560
+ t2 = $[10];
1561
+ }
1562
+ const downHandler = t2;
1563
+ let t3;
1564
+ if ($[11] !== props.items || $[12] !== selectItem || $[13] !== selectedIndex) {
1565
+ t3 = () => {
1566
+ const item_0 = props.items[selectedIndex];
1567
+ selectItem(item_0);
1568
+ };
1569
+ $[11] = props.items;
1570
+ $[12] = selectItem;
1571
+ $[13] = selectedIndex;
1572
+ $[14] = t3;
1573
+ } else {
1574
+ t3 = $[14];
1575
+ }
1576
+ const enterHandler = t3;
1577
+ let t4;
1578
+ if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
1579
+ t4 = () => setSelectedIndex(0);
1580
+ $[15] = t4;
1581
+ } else {
1582
+ t4 = $[15];
1583
+ }
1584
+ let t5;
1585
+ if ($[16] !== props.items) {
1586
+ t5 = [props.items];
1587
+ $[16] = props.items;
1588
+ $[17] = t5;
1589
+ } else {
1590
+ t5 = $[17];
1591
+ }
1592
+ useEffect(t4, t5);
1593
+ let t6;
1594
+ if ($[18] !== downHandler || $[19] !== enterHandler || $[20] !== upHandler) {
1595
+ t6 = () => ({
1596
+ onKeyDown: (t72) => {
1597
+ const {
1598
+ event
1599
+ } = t72;
1600
+ if (event.key === "ArrowUp") {
1601
+ upHandler();
1602
+ return true;
1603
+ }
1604
+ if (event.key === "ArrowDown") {
1605
+ downHandler();
1606
+ return true;
1607
+ }
1608
+ if (event.key === "Enter") {
1609
+ enterHandler();
1610
+ return true;
1611
+ }
1612
+ return false;
781
1613
  }
782
- },
783
- {
784
- title: "Heading 2",
785
- description: "Medium section heading.",
786
- searchTerms: ["subtitle", "medium"],
787
- icon: /* @__PURE__ */ s(J, { size: 18 }),
788
- command: ({ editor: l, range: m }) => {
789
- l.chain().focus().deleteRange(m).setNode("heading", { level: 2 }).run();
1614
+ });
1615
+ $[18] = downHandler;
1616
+ $[19] = enterHandler;
1617
+ $[20] = upHandler;
1618
+ $[21] = t6;
1619
+ } else {
1620
+ t6 = $[21];
1621
+ }
1622
+ useImperativeHandle(ref, t6);
1623
+ let t7;
1624
+ if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
1625
+ t7 = [];
1626
+ $[22] = t7;
1627
+ } else {
1628
+ t7 = $[22];
1629
+ }
1630
+ const itemRefs = useRef(t7);
1631
+ let t8;
1632
+ let t9;
1633
+ if ($[23] !== selectedIndex) {
1634
+ t8 = () => {
1635
+ if (itemRefs.current[selectedIndex]) {
1636
+ itemRefs.current[selectedIndex].scrollIntoView({
1637
+ block: "nearest"
1638
+ });
790
1639
  }
791
- },
792
- {
793
- title: "Heading 3",
794
- description: "Small section heading.",
795
- searchTerms: ["subtitle", "small"],
796
- icon: /* @__PURE__ */ s(G, { size: 18 }),
797
- command: ({ editor: l, range: m }) => {
798
- l.chain().focus().deleteRange(m).setNode("heading", { level: 3 }).run();
1640
+ };
1641
+ t9 = [selectedIndex];
1642
+ $[23] = selectedIndex;
1643
+ $[24] = t8;
1644
+ $[25] = t9;
1645
+ } else {
1646
+ t8 = $[24];
1647
+ t9 = $[25];
1648
+ }
1649
+ useEffect(t8, t9);
1650
+ let t10;
1651
+ if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
1652
+ t10 = cls("text-surface-900 dark:text-white z-50 max-h-[280px] h-auto w-72 overflow-y-auto rounded-md border bg-white dark:bg-surface-900 px-1 py-2 shadow transition-all", defaultBorderMixin);
1653
+ $[26] = t10;
1654
+ } else {
1655
+ t10 = $[26];
1656
+ }
1657
+ let t11;
1658
+ if ($[27] !== props.items || $[28] !== selectItem || $[29] !== selectedIndex) {
1659
+ t11 = props.items.length ? props.items.map((item_1, index) => /* @__PURE__ */ jsxs("button", { value: item_1.title, ref: (el) => {
1660
+ if (!el) {
1661
+ return;
799
1662
  }
800
- },
801
- {
802
- title: "Bullet List",
803
- description: "Create a simple bullet list.",
804
- searchTerms: ["unordered", "point"],
805
- icon: /* @__PURE__ */ s(ee, { size: 18 }),
806
- command: ({ editor: l, range: m }) => {
807
- l.chain().focus().deleteRange(m).toggleBulletList().run();
1663
+ itemRefs.current[index] = el;
1664
+ }, onClick: () => selectItem(item_1), tabIndex: index === selectedIndex ? 0 : -1, "aria-selected": index === selectedIndex, className: cls("flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-blue-50 hover:dark:bg-surface-700 aria-selected:bg-blue-50 aria-selected:dark:bg-surface-700", index === selectedIndex ? "bg-blue-100 dark:bg-surface-accent-950" : ""), children: [
1665
+ /* @__PURE__ */ jsx("div", { className: cls("flex h-10 w-10 items-center justify-center rounded-md border bg-white dark:bg-surface-900", defaultBorderMixin), children: item_1.icon }),
1666
+ /* @__PURE__ */ jsxs("div", { children: [
1667
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: item_1.title }),
1668
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-surface-700 dark:text-surface-accent-300", children: item_1.description })
1669
+ ] })
1670
+ ] }, item_1.title)) : /* @__PURE__ */ jsx("div", { className: "item", children: "No result" });
1671
+ $[27] = props.items;
1672
+ $[28] = selectItem;
1673
+ $[29] = selectedIndex;
1674
+ $[30] = t11;
1675
+ } else {
1676
+ t11 = $[30];
1677
+ }
1678
+ let t12;
1679
+ if ($[31] !== t11) {
1680
+ t12 = /* @__PURE__ */ jsx("div", { className: t10, children: t11 });
1681
+ $[31] = t11;
1682
+ $[32] = t12;
1683
+ } else {
1684
+ t12 = $[32];
1685
+ }
1686
+ return t12;
1687
+ });
1688
+ CommandList.displayName = "CommandList";
1689
+ const autocompleteSuggestionItem = {
1690
+ title: "Autocomplete",
1691
+ description: "Add text based on the context.",
1692
+ searchTerms: ["ai"],
1693
+ icon: /* @__PURE__ */ jsx(AutoFixHighIcon, { size: 18 }),
1694
+ command: async ({
1695
+ editor,
1696
+ range,
1697
+ aiController
1698
+ }) => {
1699
+ if (!aiController) throw Error("No AiController");
1700
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
1701
+ const {
1702
+ state
1703
+ } = editor;
1704
+ const {
1705
+ from,
1706
+ to
1707
+ } = state.selection;
1708
+ const textBeforeCursor = state.doc.textBetween(0, from, "\n");
1709
+ const textAfterCursor = state.doc.textBetween(to, state.doc.content.size, "\n");
1710
+ let buffer = "";
1711
+ const result = await aiController.autocomplete(textBeforeCursor, textAfterCursor, (delta) => {
1712
+ buffer += delta;
1713
+ if (delta.length !== 0) {
1714
+ editor.chain().focus().toggleLoadingDecoration(buffer).run();
808
1715
  }
809
- },
810
- {
811
- title: "Numbered List",
812
- description: "Create a list with numbering.",
813
- searchTerms: ["ordered"],
814
- icon: /* @__PURE__ */ s(te, { size: 18 }),
815
- command: ({ editor: l, range: m }) => {
816
- l.chain().focus().deleteRange(m).toggleOrderedList().run();
1716
+ });
1717
+ editor.chain().focus().insertContent(result, {
1718
+ applyInputRules: false,
1719
+ applyPasteRules: false,
1720
+ parseOptions: {
1721
+ preserveWhitespace: false
817
1722
  }
818
- },
819
- {
820
- title: "Quote",
821
- description: "Capture a quote.",
822
- searchTerms: ["blockquote"],
823
- icon: /* @__PURE__ */ s(oe, { size: 18 }),
824
- command: ({ editor: l, range: m }) => l.chain().focus().deleteRange(m).toggleNode("paragraph", "paragraph").toggleBlockquote().run()
825
- },
826
- {
827
- title: "Code",
828
- description: "Capture a code snippet.",
829
- searchTerms: ["codeblock"],
830
- icon: /* @__PURE__ */ s(z, { size: 18 }),
831
- command: ({ editor: l, range: m }) => l.chain().focus().deleteRange(m).toggleCodeBlock().run()
832
- },
833
- {
834
- title: "Image",
835
- description: "Upload an image from your computer.",
836
- searchTerms: ["photo", "picture", "media"],
837
- icon: /* @__PURE__ */ s(_e, { size: 18 }),
838
- command: ({ editor: l, range: m }) => {
839
- l.chain().focus().deleteRange(m).run();
840
- const k = document.createElement("input");
841
- k.type = "file", k.accept = "image/*", k.onchange = async () => {
842
- if (k.files?.length) {
843
- if (!k.files[0])
844
- return;
845
- l.view.state.selection.from;
846
- }
847
- }, k.click();
1723
+ }).run();
1724
+ }
1725
+ };
1726
+ const suggestionItems = [{
1727
+ title: "Text",
1728
+ description: "Just start typing with plain text.",
1729
+ searchTerms: ["p", "paragraph"],
1730
+ icon: /* @__PURE__ */ jsx(TextFieldsIcon, { size: 18 }),
1731
+ command: ({
1732
+ editor,
1733
+ range
1734
+ }) => {
1735
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
1736
+ }
1737
+ }, {
1738
+ title: "To-do List",
1739
+ description: "Track tasks with a to-do list.",
1740
+ searchTerms: ["todo", "task", "list", "check", "checkbox"],
1741
+ icon: /* @__PURE__ */ jsx(CheckBoxIcon, { size: 18 }),
1742
+ command: ({
1743
+ editor,
1744
+ range
1745
+ }) => {
1746
+ editor.chain().focus().deleteRange(range).toggleTaskList().run();
1747
+ }
1748
+ }, {
1749
+ title: "Heading 1",
1750
+ description: "Big section heading.",
1751
+ searchTerms: ["title", "big", "large"],
1752
+ icon: /* @__PURE__ */ jsx(LooksOneIcon, { size: 18 }),
1753
+ command: ({
1754
+ editor,
1755
+ range
1756
+ }) => {
1757
+ editor.chain().focus().deleteRange(range).setNode("heading", {
1758
+ level: 1
1759
+ }).run();
1760
+ }
1761
+ }, {
1762
+ title: "Heading 2",
1763
+ description: "Medium section heading.",
1764
+ searchTerms: ["subtitle", "medium"],
1765
+ icon: /* @__PURE__ */ jsx(LooksTwoIcon, { size: 18 }),
1766
+ command: ({
1767
+ editor,
1768
+ range
1769
+ }) => {
1770
+ editor.chain().focus().deleteRange(range).setNode("heading", {
1771
+ level: 2
1772
+ }).run();
1773
+ }
1774
+ }, {
1775
+ title: "Heading 3",
1776
+ description: "Small section heading.",
1777
+ searchTerms: ["subtitle", "small"],
1778
+ icon: /* @__PURE__ */ jsx(Looks3Icon, { size: 18 }),
1779
+ command: ({
1780
+ editor,
1781
+ range
1782
+ }) => {
1783
+ editor.chain().focus().deleteRange(range).setNode("heading", {
1784
+ level: 3
1785
+ }).run();
1786
+ }
1787
+ }, {
1788
+ title: "Bullet List",
1789
+ description: "Create a simple bullet list.",
1790
+ searchTerms: ["unordered", "point"],
1791
+ icon: /* @__PURE__ */ jsx(FormatListBulletedIcon, { size: 18 }),
1792
+ command: ({
1793
+ editor,
1794
+ range
1795
+ }) => {
1796
+ editor.chain().focus().deleteRange(range).toggleBulletList().run();
1797
+ }
1798
+ }, {
1799
+ title: "Numbered List",
1800
+ description: "Create a list with numbering.",
1801
+ searchTerms: ["ordered"],
1802
+ icon: /* @__PURE__ */ jsx(FormatListNumberedIcon, { size: 18 }),
1803
+ command: ({
1804
+ editor,
1805
+ range
1806
+ }) => {
1807
+ editor.chain().focus().deleteRange(range).toggleOrderedList().run();
1808
+ }
1809
+ }, {
1810
+ title: "Quote",
1811
+ description: "Capture a quote.",
1812
+ searchTerms: ["blockquote"],
1813
+ icon: /* @__PURE__ */ jsx(FormatQuoteIcon, { size: 18 }),
1814
+ command: ({
1815
+ editor,
1816
+ range
1817
+ }) => editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run()
1818
+ }, {
1819
+ title: "Code",
1820
+ description: "Capture a code snippet.",
1821
+ searchTerms: ["codeblock"],
1822
+ icon: /* @__PURE__ */ jsx(CodeIcon, { size: 18 }),
1823
+ command: ({
1824
+ editor,
1825
+ range
1826
+ }) => editor.chain().focus().deleteRange(range).toggleCodeBlock().run()
1827
+ }, {
1828
+ title: "Image",
1829
+ description: "Upload an image from your computer.",
1830
+ searchTerms: ["photo", "picture", "media", "upload", "file"],
1831
+ icon: /* @__PURE__ */ jsx(ImageIcon, { size: 18 }),
1832
+ command: ({
1833
+ editor,
1834
+ range,
1835
+ upload
1836
+ }) => {
1837
+ editor.chain().focus().deleteRange(range).run();
1838
+ const input = document.createElement("input");
1839
+ input.type = "file";
1840
+ input.accept = "image/*";
1841
+ input.onchange = async () => {
1842
+ if (input.files?.length) {
1843
+ const file = input.files[0];
1844
+ if (!file) return;
1845
+ const pos = editor.view.state.selection.from;
1846
+ const fileList = input.files;
1847
+ const files = Array.from(fileList);
1848
+ const images = files.filter((file2) => /image/i.test(file2.type));
1849
+ if (images.length === 0) {
1850
+ console.log("No images found in uploaded files");
1851
+ return false;
1852
+ }
1853
+ const view = editor.view;
1854
+ images.forEach((image) => {
1855
+ const reader = new FileReader();
1856
+ reader.onload = async (readerEvent) => {
1857
+ await onFileRead(view, readerEvent, pos, upload, image);
1858
+ };
1859
+ reader.readAsDataURL(image);
1860
+ });
848
1861
  }
1862
+ return true;
1863
+ };
1864
+ input.click();
1865
+ }
1866
+ }];
1867
+ const CustomDocument = Document.extend({
1868
+ // content: 'heading block*',
1869
+ });
1870
+ const proseClasses = {
1871
+ "sm": "prose-sm",
1872
+ "base": "prose-base",
1873
+ "lg": "prose-lg"
1874
+ };
1875
+ const FireCMSEditor = ({
1876
+ content,
1877
+ onJsonContentChange,
1878
+ onHtmlContentChange,
1879
+ onMarkdownContentChange,
1880
+ version,
1881
+ textSize = "base",
1882
+ highlight,
1883
+ handleImageUpload,
1884
+ aiController,
1885
+ disabled
1886
+ }) => {
1887
+ const ref = React.useRef(null);
1888
+ const editorRef = React.useRef(null);
1889
+ const imagePlugin = createDropImagePlugin(handleImageUpload);
1890
+ const imageExtension = useMemo(() => createImageExtension(imagePlugin), []);
1891
+ const [openNode, setOpenNode] = useState(false);
1892
+ const [openLink, setOpenLink] = useState(false);
1893
+ useInjectStyles("Editor", cssStyles);
1894
+ const deferredHighlight = useDeferredValue(highlight);
1895
+ useEffect(() => {
1896
+ if (version === void 0) return;
1897
+ if (version > -1 && editorRef.current) {
1898
+ editorRef.current?.commands.setContent(content ?? "");
1899
+ }
1900
+ }, [version]);
1901
+ useEffect(() => {
1902
+ editorRef?.current?.setEditable(!disabled);
1903
+ }, [disabled]);
1904
+ useEffect(() => {
1905
+ if (version === void 0) return;
1906
+ if (editorRef.current && version > 0) {
1907
+ const chain = editorRef.current.chain();
1908
+ if (deferredHighlight) {
1909
+ chain.focus().toggleAutocompleteHighlight(deferredHighlight).run();
1910
+ } else {
1911
+ chain.focus().removeAutocompleteHighlight().run();
1912
+ }
1913
+ }
1914
+ }, [deferredHighlight?.from, deferredHighlight?.to]);
1915
+ const onEditorUpdate = (editor) => {
1916
+ editorRef.current = editor;
1917
+ if (onMarkdownContentChange) {
1918
+ const markdown = editorRef.current.storage.markdown.getMarkdown();
1919
+ onMarkdownContentChange?.(addLineBreakAfterImages(markdown));
1920
+ }
1921
+ if (onJsonContentChange) {
1922
+ const jsonContent = removeClassesFromJson(editor.getJSON());
1923
+ onJsonContentChange(jsonContent);
849
1924
  }
850
- ]), i = rt.configure({
851
- suggestion: {
852
- items: () => n,
853
- render: nt
1925
+ if (onHtmlContentChange) {
1926
+ onHtmlContentChange?.(editor.getHTML());
854
1927
  }
855
- }), d = Z(() => yt(e), []), u = [
856
- me,
857
- ge,
858
- pe,
859
- he.configure({
860
- multicolor: !0
1928
+ };
1929
+ const proseClass = proseClasses[textSize];
1930
+ const extensions = useMemo(() => [
1931
+ starterKit,
1932
+ CustomDocument,
1933
+ HighlightDecorationExtension(highlight),
1934
+ TextLoadingDecorationExtension,
1935
+ Underline,
1936
+ Bold,
1937
+ TextStyle,
1938
+ Italic,
1939
+ Strike,
1940
+ Color,
1941
+ Highlight.configure({
1942
+ multicolor: true
861
1943
  }),
862
- fe.configure({
863
- html: !1,
864
- transformCopiedText: !0
1944
+ // CustomBlock.configure({
1945
+ // component: CustomComponent,
1946
+ // delimiter: "```custom"
1947
+ // }),
1948
+ Heading,
1949
+ CustomKeymap,
1950
+ DragAndDrop,
1951
+ placeholder,
1952
+ tiptapLink,
1953
+ imageExtension,
1954
+ taskList,
1955
+ taskItem,
1956
+ Markdown.configure({
1957
+ html: true
865
1958
  }),
866
- vt,
867
- At,
868
- kt,
869
- gt,
870
- pt,
871
- // tiptapImage,
872
- d,
873
- // updatedImage,
874
- ft,
875
- ht,
876
- bt,
877
- i
878
- ], [p, h] = v(!1), [f, A] = v(!1);
879
- Ze("Editor", Tt);
880
- const E = L.useRef(null), [ie, ce] = v(null), [M, le] = v(null), [N, de] = v(null), ue = (l) => {
881
- E.current = l, a && ce(l.storage.markdown.getMarkdown()), t && le(H(l.getJSON())), r && de(l.getHTML());
882
- };
883
- return R(ie, () => {
884
- if (E.current) {
885
- const l = E.current.storage.markdown.getMarkdown();
886
- a?.(Lt(l));
887
- }
888
- }, !1, 500), R(M, () => {
889
- M && t?.(M);
890
- }, !1, 500), R(N, () => {
891
- N && r?.(N);
892
- }, !1, 500), o ? /* @__PURE__ */ s("div", { className: "relative w-full p-8", children: /* @__PURE__ */ s(Ge, { children: /* @__PURE__ */ s(
893
- "div",
894
- {
895
- className: "relative min-h-[500px] w-full bg-white dark:bg-gray-950 rounded-lg",
896
- children: /* @__PURE__ */ b(
897
- ye,
898
- {
899
- content: o,
900
- extensions: u,
901
- editorProps: {
902
- ...c,
903
- attributes: {
904
- class: "prose-lg prose-headings:font-title font-default focus:outline-none max-w-full p-12"
905
- }
906
- },
907
- onUpdate: ({ editor: l }) => {
908
- console.log("editor updated"), ue(l);
909
- },
910
- children: [
911
- /* @__PURE__ */ b(
912
- tt,
913
- {
914
- className: g("text-gray-900 dark:text-white z-50 h-auto max-h-[330px] w-72 overflow-y-auto rounded-md border bg-white dark:bg-gray-900 px-1 py-2 shadow transition-all", x),
915
- children: [
916
- /* @__PURE__ */ s(ot, { className: "px-2 text-gray-700 dark:text-slate-300", children: "No results" }),
917
- n.map((l) => /* @__PURE__ */ b(
918
- se,
919
- {
920
- value: l.title,
921
- onCommand: (m) => l?.command?.(m),
922
- className: "flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-blue-50 hover:dark:bg-gray-700 aria-selected:bg-blue-50 aria-selected:dark:bg-gray-700",
923
- children: [
924
- /* @__PURE__ */ s(
925
- "div",
926
- {
927
- className: g("flex h-10 w-10 items-center justify-center rounded-md border bg-white dark:bg-gray-900", x),
928
- children: l.icon
929
- }
930
- ),
931
- /* @__PURE__ */ b("div", { children: [
932
- /* @__PURE__ */ s("p", { className: "font-medium", children: l.title }),
933
- /* @__PURE__ */ s("p", { className: "text-xs text-gray-700 dark:text-slate-300", children: l.description })
934
- ] })
935
- ]
936
- },
937
- l.title
938
- ))
939
- ]
940
- }
941
- ),
942
- /* @__PURE__ */ b(
943
- je,
944
- {
945
- tippyOptions: {
946
- placement: "top"
947
- },
948
- className: g("flex w-fit max-w-[90vw] h-10 overflow-hidden rounded border bg-white dark:bg-gray-900 shadow", x),
949
- children: [
950
- /* @__PURE__ */ s(ct, { open: p, onOpenChange: h }),
951
- /* @__PURE__ */ s(K, { orientation: "vertical" }),
952
- /* @__PURE__ */ s(ut, { open: f, onOpenChange: A }),
953
- /* @__PURE__ */ s(K, { orientation: "vertical" }),
954
- /* @__PURE__ */ s(mt, {})
955
- ]
956
- }
957
- )
958
- ]
959
- }
960
- )
1959
+ horizontalRule,
1960
+ bulletList,
1961
+ orderedList,
1962
+ listItem,
1963
+ blockquote,
1964
+ codeBlock,
1965
+ code,
1966
+ SlashCommand.configure({
1967
+ HTMLAttributes: {
1968
+ class: "mention"
1969
+ },
1970
+ suggestion: suggestion(ref, {
1971
+ upload: handleImageUpload,
1972
+ aiController
1973
+ })
1974
+ })
1975
+ ], []);
1976
+ return /* @__PURE__ */ jsx("div", { ref, className: "relative min-h-[300px] w-full", children: /* @__PURE__ */ jsx(EditorProvider, { content: content ?? "", extensions, editorProps: {
1977
+ editable: () => !disabled,
1978
+ attributes: {
1979
+ class: cls(proseClass, "prose-headings:font-title font-default focus:outline-none max-w-full p-12")
961
1980
  }
962
- ) }) }) : null;
1981
+ }, onCreate: ({
1982
+ editor: editor_0
1983
+ }) => {
1984
+ editorRef.current = editor_0;
1985
+ editor_0.setEditable(!disabled);
1986
+ }, onUpdate: ({
1987
+ editor: editor_1
1988
+ }) => {
1989
+ onEditorUpdate(editor_1);
1990
+ }, children: /* @__PURE__ */ jsxs(EditorBubble, { tippyOptions: {
1991
+ placement: "top"
1992
+ }, className: cls("flex w-fit max-w-[90vw] h-10 overflow-hidden rounded border bg-white dark:bg-surface-900 shadow", defaultBorderMixin), children: [
1993
+ /* @__PURE__ */ jsx(NodeSelector, { portalContainer: ref.current, open: openNode, onOpenChange: setOpenNode }),
1994
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical" }),
1995
+ /* @__PURE__ */ jsx(LinkSelector, { open: openLink, onOpenChange: setOpenLink }),
1996
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical" }),
1997
+ /* @__PURE__ */ jsx(TextButtons, {})
1998
+ ] }) }) });
963
1999
  };
964
- function Lt(e) {
965
- const o = /!\[.*?\]\(.*?\)/g;
966
- return e.replace(o, (t) => `${t}
2000
+ function addLineBreakAfterImages(markdown) {
2001
+ const imageRegex = /!\[.*?\]\(.*?\)/g;
2002
+ return markdown.replace(imageRegex, (match) => `${match}
967
2003
  `);
968
2004
  }
969
- const Tt = `
970
-
2005
+ const cssStyles = `
2006
+ .ProseMirror {
2007
+ box-shadow: none !important;
2008
+ }
971
2009
  .ProseMirror .is-editor-empty:first-child::before {
972
2010
  content: attr(data-placeholder);
973
2011
  float: left;
@@ -990,6 +2028,7 @@ const Tt = `
990
2028
  }
991
2029
 
992
2030
  .is-empty {
2031
+ cursor: text;
993
2032
  color: rgb(100 116 139); //500
994
2033
  }
995
2034
 
@@ -1007,6 +2046,7 @@ const Tt = `
1007
2046
  &.ProseMirror-selectednode {
1008
2047
  outline: 3px solid #5abbf7;
1009
2048
  filter: brightness(90%);
2049
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000) !important;
1010
2050
  }
1011
2051
  }
1012
2052
 
@@ -1034,7 +2074,7 @@ ul[data-type="taskList"] li > label {
1034
2074
  }
1035
2075
 
1036
2076
  &:active {
1037
- background-color: rgb(71 85 105);;
2077
+ background-color: rgb(71 85 105);
1038
2078
  }
1039
2079
  }
1040
2080
  }
@@ -1101,7 +2141,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
1101
2141
  }
1102
2142
 
1103
2143
  .ProseMirror:not(.dragging) .ProseMirror-selectednode {
1104
- outline: none !important;
2144
+ // outline: none !important;
1105
2145
  background-color: rgb(219 234 254); // blue 100
1106
2146
  transition: background-color 0.2s;
1107
2147
  box-shadow: none;
@@ -1111,8 +2151,12 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
1111
2151
  background-color: rgb(51 65 85); // 700
1112
2152
  }
1113
2153
 
2154
+ .prose-base table p {
2155
+ margin: 0;
2156
+ }
2157
+
1114
2158
  .drag-handle {
1115
- position: fixed;
2159
+ position: absolute;
1116
2160
  opacity: 1;
1117
2161
  transition: opacity ease-in 0.2s;
1118
2162
  border-radius: 0.25rem;
@@ -1123,7 +2167,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
1123
2167
  background-position: center;
1124
2168
  width: 1.2rem;
1125
2169
  height: 1.5rem;
1126
- z-index: 50;
2170
+ z-index: 100;
1127
2171
  cursor: grab;
1128
2172
 
1129
2173
  &:hover {
@@ -1158,6 +2202,6 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
1158
2202
  }
1159
2203
  `;
1160
2204
  export {
1161
- eo as FireCMSEditor
2205
+ FireCMSEditor
1162
2206
  };
1163
2207
  //# sourceMappingURL=index.es.js.map