@firecms/editor 3.0.0-canary.99 → 3.0.0-rc.2

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