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