@react-email/editor 0.0.0-experimental.22 → 0.0.0-experimental.25

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.
Files changed (44) hide show
  1. package/dist/columns-CUxUEHje.mjs +497 -0
  2. package/dist/columns-CUxUEHje.mjs.map +1 -0
  3. package/dist/columns-ZSaLdkg9.cjs +630 -0
  4. package/dist/core/index.cjs +8 -0
  5. package/dist/core/index.d.cts +2 -0
  6. package/dist/core/index.d.mts +2 -0
  7. package/dist/core/index.mjs +4 -0
  8. package/dist/core-C5_RDJBI.mjs +1982 -0
  9. package/dist/core-C5_RDJBI.mjs.map +1 -0
  10. package/dist/core-Rxnpk8B_.cjs +2239 -0
  11. package/dist/extensions/index.cjs +47 -0
  12. package/dist/extensions/index.d.cts +394 -0
  13. package/dist/extensions/index.d.cts.map +1 -0
  14. package/dist/extensions/index.d.mts +394 -0
  15. package/dist/extensions/index.d.mts.map +1 -0
  16. package/dist/extensions/index.mjs +4 -0
  17. package/dist/index-CfslA7KT.d.cts +130 -0
  18. package/dist/index-CfslA7KT.d.cts.map +1 -0
  19. package/dist/index-hbHRR7oB.d.mts +130 -0
  20. package/dist/index-hbHRR7oB.d.mts.map +1 -0
  21. package/dist/set-text-alignment-Bx3bPteH.cjs +24 -0
  22. package/dist/set-text-alignment-DZvgnbvz.mjs +19 -0
  23. package/dist/set-text-alignment-DZvgnbvz.mjs.map +1 -0
  24. package/dist/ui/index.cjs +1646 -0
  25. package/dist/ui/index.d.cts +668 -0
  26. package/dist/ui/index.d.cts.map +1 -0
  27. package/dist/ui/index.d.mts +668 -0
  28. package/dist/ui/index.d.mts.map +1 -0
  29. package/dist/ui/index.mjs +1584 -0
  30. package/dist/ui/index.mjs.map +1 -0
  31. package/dist/utils/index.cjs +3 -0
  32. package/dist/utils/index.d.cts +7 -0
  33. package/dist/utils/index.d.cts.map +1 -0
  34. package/dist/utils/index.d.mts +7 -0
  35. package/dist/utils/index.d.mts.map +1 -0
  36. package/dist/utils/index.mjs +3 -0
  37. package/package.json +39 -11
  38. package/dist/index.cjs +0 -4228
  39. package/dist/index.d.cts +0 -1175
  40. package/dist/index.d.cts.map +0 -1
  41. package/dist/index.d.mts +0 -1175
  42. package/dist/index.d.mts.map +0 -1
  43. package/dist/index.mjs +0 -4072
  44. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,1646 @@
1
+ const require_columns = require('../columns-ZSaLdkg9.cjs');
2
+ const require_set_text_alignment = require('../set-text-alignment-Bx3bPteH.cjs');
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ let _tiptap_react = require("@tiptap/react");
5
+ let react = require("react");
6
+ react = require_columns.__toESM(react);
7
+ let _tiptap_pm_state = require("@tiptap/pm/state");
8
+ let lucide_react = require("lucide-react");
9
+ let _radix_ui_react_popover = require("@radix-ui/react-popover");
10
+ _radix_ui_react_popover = require_columns.__toESM(_radix_ui_react_popover);
11
+ let _tiptap_react_menus = require("@tiptap/react/menus");
12
+ let _floating_ui_react_dom = require("@floating-ui/react-dom");
13
+ let _tiptap_suggestion = require("@tiptap/suggestion");
14
+ _tiptap_suggestion = require_columns.__toESM(_tiptap_suggestion);
15
+ let react_dom = require("react-dom");
16
+
17
+ //#region src/ui/bubble-menu/context.tsx
18
+ const BubbleMenuContext = react.createContext(null);
19
+ function useBubbleMenuContext() {
20
+ const context = react.useContext(BubbleMenuContext);
21
+ if (!context) throw new Error("BubbleMenu compound components must be used within <BubbleMenu.Root>");
22
+ return context;
23
+ }
24
+
25
+ //#endregion
26
+ //#region src/ui/bubble-menu/item.tsx
27
+ function BubbleMenuItem({ name, isActive, onCommand, className, children, ...rest }) {
28
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
29
+ type: "button",
30
+ "aria-label": name,
31
+ "aria-pressed": isActive,
32
+ className,
33
+ "data-re-bubble-menu-item": "",
34
+ "data-item": name,
35
+ ...isActive ? { "data-active": "" } : {},
36
+ onMouseDown: (e) => e.preventDefault(),
37
+ onClick: onCommand,
38
+ ...rest,
39
+ children
40
+ });
41
+ }
42
+
43
+ //#endregion
44
+ //#region src/ui/bubble-menu/align-center.tsx
45
+ function BubbleMenuAlignCenter({ className, children }) {
46
+ const { editor } = useBubbleMenuContext();
47
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
48
+ name: "align-center",
49
+ isActive: (0, _tiptap_react.useEditorState)({
50
+ editor,
51
+ selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "center" }) ?? false
52
+ }),
53
+ onCommand: () => require_set_text_alignment.setTextAlignment(editor, "center"),
54
+ className,
55
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlignCenterIcon, {})
56
+ });
57
+ }
58
+
59
+ //#endregion
60
+ //#region src/ui/bubble-menu/align-left.tsx
61
+ function BubbleMenuAlignLeft({ className, children }) {
62
+ const { editor } = useBubbleMenuContext();
63
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
64
+ name: "align-left",
65
+ isActive: (0, _tiptap_react.useEditorState)({
66
+ editor,
67
+ selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "left" }) ?? false
68
+ }),
69
+ onCommand: () => require_set_text_alignment.setTextAlignment(editor, "left"),
70
+ className,
71
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlignLeftIcon, {})
72
+ });
73
+ }
74
+
75
+ //#endregion
76
+ //#region src/ui/bubble-menu/align-right.tsx
77
+ function BubbleMenuAlignRight({ className, children }) {
78
+ const { editor } = useBubbleMenuContext();
79
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
80
+ name: "align-right",
81
+ isActive: (0, _tiptap_react.useEditorState)({
82
+ editor,
83
+ selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "right" }) ?? false
84
+ }),
85
+ onCommand: () => require_set_text_alignment.setTextAlignment(editor, "right"),
86
+ className,
87
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlignRightIcon, {})
88
+ });
89
+ }
90
+
91
+ //#endregion
92
+ //#region src/ui/bubble-menu/create-mark-bubble-item.tsx
93
+ function createMarkBubbleItem(config) {
94
+ function MarkBubbleItem({ className, children }) {
95
+ const { editor } = useBubbleMenuContext();
96
+ const isActive = (0, _tiptap_react.useEditorState)({
97
+ editor,
98
+ selector: ({ editor: editor$1 }) => {
99
+ if (config.activeParams) return editor$1?.isActive(config.activeName, config.activeParams) ?? false;
100
+ return editor$1?.isActive(config.activeName) ?? false;
101
+ }
102
+ });
103
+ const handleCommand = () => {
104
+ const chain = editor.chain().focus();
105
+ const method = chain[config.command];
106
+ if (method) method.call(chain).run();
107
+ };
108
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
109
+ name: config.name,
110
+ isActive,
111
+ onCommand: handleCommand,
112
+ className,
113
+ children: children ?? config.icon
114
+ });
115
+ }
116
+ MarkBubbleItem.displayName = `BubbleMenu${config.name.charAt(0).toUpperCase() + config.name.slice(1)}`;
117
+ return MarkBubbleItem;
118
+ }
119
+
120
+ //#endregion
121
+ //#region src/ui/bubble-menu/bold.tsx
122
+ const BubbleMenuBold = createMarkBubbleItem({
123
+ name: "bold",
124
+ activeName: "bold",
125
+ command: "toggleBold",
126
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.BoldIcon, {})
127
+ });
128
+
129
+ //#endregion
130
+ //#region src/ui/bubble-menu/code.tsx
131
+ const BubbleMenuCode = createMarkBubbleItem({
132
+ name: "code",
133
+ activeName: "code",
134
+ command: "toggleCode",
135
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CodeIcon, {})
136
+ });
137
+
138
+ //#endregion
139
+ //#region src/ui/bubble-menu/group.tsx
140
+ function BubbleMenuItemGroup({ className, children }) {
141
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("fieldset", {
142
+ className,
143
+ "data-re-bubble-menu-group": "",
144
+ children
145
+ });
146
+ }
147
+
148
+ //#endregion
149
+ //#region src/ui/bubble-menu/italic.tsx
150
+ const BubbleMenuItalic = createMarkBubbleItem({
151
+ name: "italic",
152
+ activeName: "italic",
153
+ command: "toggleItalic",
154
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ItalicIcon, {})
155
+ });
156
+
157
+ //#endregion
158
+ //#region src/ui/bubble-menu/utils.ts
159
+ const SAFE_PROTOCOLS = new Set([
160
+ "http:",
161
+ "https:",
162
+ "mailto:",
163
+ "tel:"
164
+ ]);
165
+ /**
166
+ * Basic URL validation and auto-prefixing.
167
+ * Rejects dangerous schemes (javascript:, data:, vbscript:, etc.).
168
+ * Returns the valid URL string or null.
169
+ */
170
+ function getUrlFromString(str) {
171
+ if (str === "#") return str;
172
+ try {
173
+ const url = new URL(str);
174
+ if (SAFE_PROTOCOLS.has(url.protocol)) return str;
175
+ return null;
176
+ } catch {}
177
+ try {
178
+ if (str.includes(".") && !str.includes(" ")) return new URL(`https://${str}`).toString();
179
+ } catch {}
180
+ return null;
181
+ }
182
+ function setLinkHref(editor, href) {
183
+ if (href.length === 0) {
184
+ editor.chain().unsetLink().run();
185
+ return;
186
+ }
187
+ const { from, to } = editor.state.selection;
188
+ if (from === to) {
189
+ editor.chain().extendMarkRange("link").setLink({ href }).setTextSelection({
190
+ from,
191
+ to
192
+ }).run();
193
+ return;
194
+ }
195
+ editor.chain().setLink({ href }).run();
196
+ }
197
+ function focusEditor(editor) {
198
+ setTimeout(() => {
199
+ editor.commands.focus();
200
+ }, 0);
201
+ }
202
+
203
+ //#endregion
204
+ //#region src/ui/bubble-menu/link-selector.tsx
205
+ function BubbleMenuLinkSelector({ className, showToggle = true, validateUrl, onLinkApply, onLinkRemove, children, open: controlledOpen, onOpenChange }) {
206
+ const { editor } = useBubbleMenuContext();
207
+ const [uncontrolledOpen, setUncontrolledOpen] = react.useState(false);
208
+ const isControlled = controlledOpen !== void 0;
209
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
210
+ const setIsOpen = react.useCallback((value) => {
211
+ if (!isControlled) setUncontrolledOpen(value);
212
+ onOpenChange?.(value);
213
+ }, [isControlled, onOpenChange]);
214
+ const editorState = (0, _tiptap_react.useEditorState)({
215
+ editor,
216
+ selector: ({ editor: editor$1 }) => ({
217
+ isLinkActive: editor$1?.isActive("link") ?? false,
218
+ hasLink: Boolean(editor$1?.getAttributes("link").href),
219
+ currentHref: editor$1?.getAttributes("link").href || ""
220
+ })
221
+ });
222
+ const setIsOpenRef = react.useRef(setIsOpen);
223
+ setIsOpenRef.current = setIsOpen;
224
+ react.useEffect(() => {
225
+ const subscription = require_columns.editorEventBus.on("bubble-menu:add-link", () => {
226
+ setIsOpenRef.current(true);
227
+ });
228
+ return () => {
229
+ setIsOpenRef.current(false);
230
+ subscription.unsubscribe();
231
+ };
232
+ }, []);
233
+ if (!editorState) return null;
234
+ const handleOpenLink = () => {
235
+ setIsOpen(!isOpen);
236
+ };
237
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
238
+ "data-re-link-selector": "",
239
+ ...isOpen ? { "data-open": "" } : {},
240
+ ...editorState.hasLink ? { "data-has-link": "" } : {},
241
+ className,
242
+ children: [showToggle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
243
+ type: "button",
244
+ "aria-expanded": isOpen,
245
+ "aria-haspopup": "true",
246
+ "aria-label": "Add link",
247
+ "aria-pressed": editorState.isLinkActive && editorState.hasLink,
248
+ "data-re-link-selector-trigger": "",
249
+ onClick: handleOpenLink,
250
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LinkIcon, {})
251
+ }), isOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkForm, {
252
+ editor,
253
+ currentHref: editorState.currentHref,
254
+ validateUrl,
255
+ onLinkApply,
256
+ onLinkRemove,
257
+ setIsOpen,
258
+ children
259
+ })]
260
+ });
261
+ }
262
+ function LinkForm({ editor, currentHref, validateUrl, onLinkApply, onLinkRemove, setIsOpen, children }) {
263
+ const inputRef = react.useRef(null);
264
+ const formRef = react.useRef(null);
265
+ const displayHref = currentHref === "#" ? "" : currentHref;
266
+ const [inputValue, setInputValue] = react.useState(displayHref);
267
+ react.useEffect(() => {
268
+ const timeoutId = setTimeout(() => {
269
+ inputRef.current?.focus();
270
+ }, 0);
271
+ return () => clearTimeout(timeoutId);
272
+ }, []);
273
+ react.useEffect(() => {
274
+ const handleKeyDown = (event) => {
275
+ if (event.key === "Escape") {
276
+ if (editor.getAttributes("link").href === "#") editor.chain().unsetLink().run();
277
+ setIsOpen(false);
278
+ }
279
+ };
280
+ const handleClickOutside = (event) => {
281
+ if (formRef.current && !formRef.current.contains(event.target)) {
282
+ const form = formRef.current;
283
+ const submitEvent = new Event("submit", {
284
+ bubbles: true,
285
+ cancelable: true
286
+ });
287
+ form.dispatchEvent(submitEvent);
288
+ setIsOpen(false);
289
+ }
290
+ };
291
+ document.addEventListener("mousedown", handleClickOutside);
292
+ window.addEventListener("keydown", handleKeyDown);
293
+ return () => {
294
+ window.removeEventListener("keydown", handleKeyDown);
295
+ document.removeEventListener("mousedown", handleClickOutside);
296
+ };
297
+ }, [editor, setIsOpen]);
298
+ function handleSubmit(e) {
299
+ e.preventDefault();
300
+ const value = inputValue.trim();
301
+ if (value === "") {
302
+ setLinkHref(editor, "");
303
+ setIsOpen(false);
304
+ focusEditor(editor);
305
+ onLinkRemove?.();
306
+ return;
307
+ }
308
+ const finalValue = (validateUrl ?? getUrlFromString)(value);
309
+ if (!finalValue) {
310
+ setLinkHref(editor, "");
311
+ setIsOpen(false);
312
+ focusEditor(editor);
313
+ onLinkRemove?.();
314
+ return;
315
+ }
316
+ setLinkHref(editor, finalValue);
317
+ setIsOpen(false);
318
+ focusEditor(editor);
319
+ onLinkApply?.(finalValue);
320
+ }
321
+ function handleUnlink(e) {
322
+ e.stopPropagation();
323
+ setLinkHref(editor, "");
324
+ setIsOpen(false);
325
+ focusEditor(editor);
326
+ onLinkRemove?.();
327
+ }
328
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
329
+ ref: formRef,
330
+ "data-re-link-selector-form": "",
331
+ onMouseDown: (e) => e.stopPropagation(),
332
+ onClick: (e) => e.stopPropagation(),
333
+ onKeyDown: (e) => e.stopPropagation(),
334
+ onSubmit: handleSubmit,
335
+ children: [
336
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
337
+ ref: inputRef,
338
+ "data-re-link-selector-input": "",
339
+ value: inputValue,
340
+ onFocus: (e) => e.stopPropagation(),
341
+ onChange: (e) => setInputValue(e.target.value),
342
+ placeholder: "Paste a link",
343
+ type: "text"
344
+ }),
345
+ children,
346
+ displayHref ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
347
+ type: "button",
348
+ "aria-label": "Remove link",
349
+ "data-re-link-selector-unlink": "",
350
+ onClick: handleUnlink,
351
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.UnlinkIcon, {})
352
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
353
+ type: "submit",
354
+ "aria-label": "Apply link",
355
+ "data-re-link-selector-apply": "",
356
+ onMouseDown: (e) => e.stopPropagation(),
357
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, {})
358
+ })
359
+ ]
360
+ });
361
+ }
362
+
363
+ //#endregion
364
+ //#region src/ui/bubble-menu/node-selector.tsx
365
+ const NodeSelectorContext = react.createContext(null);
366
+ function useNodeSelectorContext() {
367
+ const context = react.useContext(NodeSelectorContext);
368
+ if (!context) throw new Error("NodeSelector compound components must be used within <NodeSelector.Root>");
369
+ return context;
370
+ }
371
+ function NodeSelectorRoot({ omit = [], open: controlledOpen, onOpenChange, className, children }) {
372
+ const { editor } = useBubbleMenuContext();
373
+ const [uncontrolledOpen, setUncontrolledOpen] = react.useState(false);
374
+ const isControlled = controlledOpen !== void 0;
375
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
376
+ const setIsOpen = react.useCallback((value) => {
377
+ if (!isControlled) setUncontrolledOpen(value);
378
+ onOpenChange?.(value);
379
+ }, [isControlled, onOpenChange]);
380
+ const editorState = (0, _tiptap_react.useEditorState)({
381
+ editor,
382
+ selector: ({ editor: editor$1 }) => ({
383
+ isParagraphActive: (editor$1?.isActive("paragraph") ?? false) && !editor$1?.isActive("bulletList") && !editor$1?.isActive("orderedList"),
384
+ isHeading1Active: editor$1?.isActive("heading", { level: 1 }) ?? false,
385
+ isHeading2Active: editor$1?.isActive("heading", { level: 2 }) ?? false,
386
+ isHeading3Active: editor$1?.isActive("heading", { level: 3 }) ?? false,
387
+ isBulletListActive: editor$1?.isActive("bulletList") ?? false,
388
+ isOrderedListActive: editor$1?.isActive("orderedList") ?? false,
389
+ isBlockquoteActive: editor$1?.isActive("blockquote") ?? false,
390
+ isCodeBlockActive: editor$1?.isActive("codeBlock") ?? false
391
+ })
392
+ });
393
+ const allItems = react.useMemo(() => [
394
+ {
395
+ name: "Text",
396
+ icon: lucide_react.TextIcon,
397
+ command: () => editor.chain().focus().clearNodes().toggleNode("paragraph", "paragraph").run(),
398
+ isActive: editorState?.isParagraphActive ?? false
399
+ },
400
+ {
401
+ name: "Title",
402
+ icon: lucide_react.Heading1,
403
+ command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 1 }).run(),
404
+ isActive: editorState?.isHeading1Active ?? false
405
+ },
406
+ {
407
+ name: "Subtitle",
408
+ icon: lucide_react.Heading2,
409
+ command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 2 }).run(),
410
+ isActive: editorState?.isHeading2Active ?? false
411
+ },
412
+ {
413
+ name: "Heading",
414
+ icon: lucide_react.Heading3,
415
+ command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 3 }).run(),
416
+ isActive: editorState?.isHeading3Active ?? false
417
+ },
418
+ {
419
+ name: "Bullet List",
420
+ icon: lucide_react.List,
421
+ command: () => editor.chain().focus().clearNodes().toggleBulletList().run(),
422
+ isActive: editorState?.isBulletListActive ?? false
423
+ },
424
+ {
425
+ name: "Numbered List",
426
+ icon: lucide_react.ListOrdered,
427
+ command: () => editor.chain().focus().clearNodes().toggleOrderedList().run(),
428
+ isActive: editorState?.isOrderedListActive ?? false
429
+ },
430
+ {
431
+ name: "Quote",
432
+ icon: lucide_react.TextQuote,
433
+ command: () => editor.chain().focus().clearNodes().toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
434
+ isActive: editorState?.isBlockquoteActive ?? false
435
+ },
436
+ {
437
+ name: "Code",
438
+ icon: lucide_react.Code,
439
+ command: () => editor.chain().focus().clearNodes().toggleCodeBlock().run(),
440
+ isActive: editorState?.isCodeBlockActive ?? false
441
+ }
442
+ ], [editor, editorState]);
443
+ const items = react.useMemo(() => allItems.filter((item) => !omit.includes(item.name)), [allItems, omit]);
444
+ const activeItem = react.useMemo(() => items.find((item) => item.isActive) ?? { name: "Multiple" }, [items]);
445
+ const contextValue = react.useMemo(() => ({
446
+ items,
447
+ activeItem,
448
+ isOpen,
449
+ setIsOpen
450
+ }), [
451
+ items,
452
+ activeItem,
453
+ isOpen,
454
+ setIsOpen
455
+ ]);
456
+ if (!editorState || items.length === 0) return null;
457
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorContext.Provider, {
458
+ value: contextValue,
459
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Root, {
460
+ open: isOpen,
461
+ onOpenChange: setIsOpen,
462
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
463
+ "data-re-node-selector": "",
464
+ ...isOpen ? { "data-open": "" } : {},
465
+ className,
466
+ children
467
+ })
468
+ })
469
+ });
470
+ }
471
+ function NodeSelectorTrigger({ className, children }) {
472
+ const { activeItem, isOpen, setIsOpen } = useNodeSelectorContext();
473
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Trigger, {
474
+ "data-re-node-selector-trigger": "",
475
+ className,
476
+ onClick: () => setIsOpen(!isOpen),
477
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: activeItem.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, {})] })
478
+ });
479
+ }
480
+ function NodeSelectorContent({ className, align = "start", children }) {
481
+ const { items, setIsOpen } = useNodeSelectorContext();
482
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_popover.Content, {
483
+ align,
484
+ "data-re-node-selector-content": "",
485
+ className,
486
+ children: children ? children(items, () => setIsOpen(false)) : items.map((item) => {
487
+ const Icon = item.icon;
488
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
489
+ type: "button",
490
+ "data-re-node-selector-item": "",
491
+ ...item.isActive ? { "data-active": "" } : {},
492
+ onClick: () => {
493
+ item.command();
494
+ setIsOpen(false);
495
+ },
496
+ children: [
497
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {}),
498
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.name }),
499
+ item.isActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, {})
500
+ ]
501
+ }, item.name);
502
+ })
503
+ });
504
+ }
505
+ function BubbleMenuNodeSelector({ omit = [], className, triggerContent, open, onOpenChange }) {
506
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(NodeSelectorRoot, {
507
+ omit,
508
+ open,
509
+ onOpenChange,
510
+ className,
511
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorTrigger, { children: triggerContent }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorContent, {})]
512
+ });
513
+ }
514
+
515
+ //#endregion
516
+ //#region src/ui/bubble-menu/root.tsx
517
+ function BubbleMenuRoot({ excludeNodes = [], placement = "bottom", offset: offset$1 = 8, onHide, className, children }) {
518
+ const { editor } = (0, _tiptap_react.useCurrentEditor)();
519
+ if (!editor) return null;
520
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react_menus.BubbleMenu, {
521
+ editor,
522
+ "data-re-bubble-menu": "",
523
+ shouldShow: ({ editor: editor$1, view }) => {
524
+ for (const node of excludeNodes) if (editor$1.isActive(node)) return false;
525
+ if (view.dom.classList.contains("dragging")) return false;
526
+ return editor$1.view.state.selection.content().size > 0;
527
+ },
528
+ options: {
529
+ placement,
530
+ offset: offset$1,
531
+ onHide
532
+ },
533
+ className,
534
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuContext.Provider, {
535
+ value: { editor },
536
+ children
537
+ })
538
+ });
539
+ }
540
+
541
+ //#endregion
542
+ //#region src/ui/bubble-menu/strike.tsx
543
+ const BubbleMenuStrike = createMarkBubbleItem({
544
+ name: "strike",
545
+ activeName: "strike",
546
+ command: "toggleStrike",
547
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.StrikethroughIcon, {})
548
+ });
549
+
550
+ //#endregion
551
+ //#region src/ui/bubble-menu/underline.tsx
552
+ const BubbleMenuUnderline = createMarkBubbleItem({
553
+ name: "underline",
554
+ activeName: "underline",
555
+ command: "toggleUnderline",
556
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.UnderlineIcon, {})
557
+ });
558
+
559
+ //#endregion
560
+ //#region src/ui/bubble-menu/uppercase.tsx
561
+ const BubbleMenuUppercase = createMarkBubbleItem({
562
+ name: "uppercase",
563
+ activeName: "uppercase",
564
+ command: "toggleUppercase",
565
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CaseUpperIcon, {})
566
+ });
567
+
568
+ //#endregion
569
+ //#region src/ui/bubble-menu/default.tsx
570
+ function BubbleMenuDefault({ excludeItems = [], excludeNodes, placement, offset: offset$1, onHide, className }) {
571
+ const [isNodeSelectorOpen, setIsNodeSelectorOpen] = react.useState(false);
572
+ const [isLinkSelectorOpen, setIsLinkSelectorOpen] = react.useState(false);
573
+ const has = (item) => !excludeItems.includes(item);
574
+ const handleNodeSelectorOpenChange = react.useCallback((open) => {
575
+ setIsNodeSelectorOpen(open);
576
+ if (open) setIsLinkSelectorOpen(false);
577
+ }, []);
578
+ const handleLinkSelectorOpenChange = react.useCallback((open) => {
579
+ setIsLinkSelectorOpen(open);
580
+ if (open) setIsNodeSelectorOpen(false);
581
+ }, []);
582
+ const handleHide = react.useCallback(() => {
583
+ setIsNodeSelectorOpen(false);
584
+ setIsLinkSelectorOpen(false);
585
+ onHide?.();
586
+ }, [onHide]);
587
+ const hasFormattingItems = has("bold") || has("italic") || has("underline") || has("strike") || has("code") || has("uppercase");
588
+ const hasAlignmentItems = has("align-left") || has("align-center") || has("align-right");
589
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(BubbleMenuRoot, {
590
+ excludeNodes,
591
+ placement,
592
+ offset: offset$1,
593
+ onHide: handleHide,
594
+ className,
595
+ children: [
596
+ has("node-selector") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuNodeSelector, {
597
+ open: isNodeSelectorOpen,
598
+ onOpenChange: handleNodeSelectorOpenChange
599
+ }),
600
+ has("link-selector") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuLinkSelector, {
601
+ open: isLinkSelectorOpen,
602
+ onOpenChange: handleLinkSelectorOpenChange
603
+ }),
604
+ hasFormattingItems && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(BubbleMenuItemGroup, { children: [
605
+ has("bold") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuBold, {}),
606
+ has("italic") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItalic, {}),
607
+ has("underline") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuUnderline, {}),
608
+ has("strike") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuStrike, {}),
609
+ has("code") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuCode, {}),
610
+ has("uppercase") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuUppercase, {})
611
+ ] }),
612
+ hasAlignmentItems && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(BubbleMenuItemGroup, { children: [
613
+ has("align-left") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuAlignLeft, {}),
614
+ has("align-center") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuAlignCenter, {}),
615
+ has("align-right") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuAlignRight, {})
616
+ ] })
617
+ ]
618
+ });
619
+ }
620
+
621
+ //#endregion
622
+ //#region src/ui/bubble-menu/separator.tsx
623
+ function BubbleMenuSeparator({ className }) {
624
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("hr", {
625
+ className,
626
+ "data-re-bubble-menu-separator": ""
627
+ });
628
+ }
629
+
630
+ //#endregion
631
+ //#region src/ui/bubble-menu/index.ts
632
+ const BubbleMenu = {
633
+ Root: BubbleMenuRoot,
634
+ ItemGroup: BubbleMenuItemGroup,
635
+ Separator: BubbleMenuSeparator,
636
+ Item: BubbleMenuItem,
637
+ Bold: BubbleMenuBold,
638
+ Italic: BubbleMenuItalic,
639
+ Underline: BubbleMenuUnderline,
640
+ Strike: BubbleMenuStrike,
641
+ Code: BubbleMenuCode,
642
+ Uppercase: BubbleMenuUppercase,
643
+ AlignLeft: BubbleMenuAlignLeft,
644
+ AlignCenter: BubbleMenuAlignCenter,
645
+ AlignRight: BubbleMenuAlignRight,
646
+ NodeSelector: Object.assign(BubbleMenuNodeSelector, {
647
+ Root: NodeSelectorRoot,
648
+ Trigger: NodeSelectorTrigger,
649
+ Content: NodeSelectorContent
650
+ }),
651
+ LinkSelector: BubbleMenuLinkSelector,
652
+ Default: BubbleMenuDefault
653
+ };
654
+
655
+ //#endregion
656
+ //#region src/ui/button-bubble-menu/context.tsx
657
+ const ButtonBubbleMenuContext = react.createContext(null);
658
+ function useButtonBubbleMenuContext() {
659
+ const context = react.useContext(ButtonBubbleMenuContext);
660
+ if (!context) throw new Error("ButtonBubbleMenu compound components must be used within <ButtonBubbleMenu.Root>");
661
+ return context;
662
+ }
663
+
664
+ //#endregion
665
+ //#region src/ui/button-bubble-menu/edit-link.tsx
666
+ function ButtonBubbleMenuEditLink({ className, children, onClick, onMouseDown, ...rest }) {
667
+ const { setIsEditing } = useButtonBubbleMenuContext();
668
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
669
+ ...rest,
670
+ type: "button",
671
+ "aria-label": "Edit link",
672
+ "data-re-btn-bm-item": "",
673
+ "data-item": "edit-link",
674
+ className,
675
+ onMouseDown: (e) => {
676
+ e.preventDefault();
677
+ onMouseDown?.(e);
678
+ },
679
+ onClick: (e) => {
680
+ onClick?.(e);
681
+ setIsEditing(true);
682
+ },
683
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LinkIcon, {})
684
+ });
685
+ }
686
+
687
+ //#endregion
688
+ //#region src/ui/button-bubble-menu/root.tsx
689
+ function ButtonBubbleMenuRoot({ onHide, placement = "top", offset: offset$1 = 8, className, children }) {
690
+ const { editor } = (0, _tiptap_react.useCurrentEditor)();
691
+ const [isEditing, setIsEditing] = react.useState(false);
692
+ if (!editor) return null;
693
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react_menus.BubbleMenu, {
694
+ editor,
695
+ "data-re-btn-bm": "",
696
+ shouldShow: ({ editor: e, view }) => e.isActive("button") && !view.dom.classList.contains("dragging"),
697
+ options: {
698
+ placement,
699
+ offset: offset$1,
700
+ onHide: () => {
701
+ setIsEditing(false);
702
+ onHide?.();
703
+ }
704
+ },
705
+ className,
706
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuContext.Provider, {
707
+ value: {
708
+ editor,
709
+ isEditing,
710
+ setIsEditing
711
+ },
712
+ children
713
+ })
714
+ });
715
+ }
716
+
717
+ //#endregion
718
+ //#region src/ui/button-bubble-menu/toolbar.tsx
719
+ function ButtonBubbleMenuToolbar({ children, ...rest }) {
720
+ const { isEditing } = useButtonBubbleMenuContext();
721
+ if (isEditing) return null;
722
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
723
+ "data-re-btn-bm-toolbar": "",
724
+ ...rest,
725
+ children
726
+ });
727
+ }
728
+
729
+ //#endregion
730
+ //#region src/ui/button-bubble-menu/default.tsx
731
+ function ButtonBubbleMenuDefault({ excludeItems = [], placement, offset: offset$1, onHide, className }) {
732
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuRoot, {
733
+ placement,
734
+ offset: offset$1,
735
+ onHide,
736
+ className,
737
+ children: !excludeItems.includes("edit-link") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuToolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuEditLink, {}) })
738
+ });
739
+ }
740
+
741
+ //#endregion
742
+ //#region src/ui/button-bubble-menu/index.ts
743
+ const ButtonBubbleMenu = {
744
+ Root: ButtonBubbleMenuRoot,
745
+ Toolbar: ButtonBubbleMenuToolbar,
746
+ EditLink: ButtonBubbleMenuEditLink,
747
+ Default: ButtonBubbleMenuDefault
748
+ };
749
+
750
+ //#endregion
751
+ //#region src/ui/image-bubble-menu/context.tsx
752
+ const ImageBubbleMenuContext = react.createContext(null);
753
+ function useImageBubbleMenuContext() {
754
+ const context = react.useContext(ImageBubbleMenuContext);
755
+ if (!context) throw new Error("ImageBubbleMenu compound components must be used within <ImageBubbleMenu.Root>");
756
+ return context;
757
+ }
758
+
759
+ //#endregion
760
+ //#region src/ui/image-bubble-menu/edit-link.tsx
761
+ function ImageBubbleMenuEditLink({ className, children, onClick, onMouseDown, ...rest }) {
762
+ const { setIsEditing } = useImageBubbleMenuContext();
763
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
764
+ ...rest,
765
+ type: "button",
766
+ "aria-label": "Edit link",
767
+ "data-re-img-bm-item": "",
768
+ "data-item": "edit-link",
769
+ className,
770
+ onMouseDown: (e) => {
771
+ e.preventDefault();
772
+ onMouseDown?.(e);
773
+ },
774
+ onClick: (e) => {
775
+ onClick?.(e);
776
+ setIsEditing(true);
777
+ },
778
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LinkIcon, {})
779
+ });
780
+ }
781
+
782
+ //#endregion
783
+ //#region src/ui/image-bubble-menu/root.tsx
784
+ function ImageBubbleMenuRoot({ onHide, placement = "top", offset: offset$1 = 8, className, children }) {
785
+ const { editor } = (0, _tiptap_react.useCurrentEditor)();
786
+ const [isEditing, setIsEditing] = react.useState(false);
787
+ if (!editor) return null;
788
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react_menus.BubbleMenu, {
789
+ editor,
790
+ "data-re-img-bm": "",
791
+ shouldShow: ({ editor: e, view }) => e.isActive("image") && !view.dom.classList.contains("dragging"),
792
+ options: {
793
+ placement,
794
+ offset: offset$1,
795
+ onHide: () => {
796
+ setIsEditing(false);
797
+ onHide?.();
798
+ }
799
+ },
800
+ className,
801
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuContext.Provider, {
802
+ value: {
803
+ editor,
804
+ isEditing,
805
+ setIsEditing
806
+ },
807
+ children
808
+ })
809
+ });
810
+ }
811
+
812
+ //#endregion
813
+ //#region src/ui/image-bubble-menu/toolbar.tsx
814
+ function ImageBubbleMenuToolbar({ children, ...rest }) {
815
+ const { isEditing } = useImageBubbleMenuContext();
816
+ if (isEditing) return null;
817
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
818
+ "data-re-img-bm-toolbar": "",
819
+ ...rest,
820
+ children
821
+ });
822
+ }
823
+
824
+ //#endregion
825
+ //#region src/ui/image-bubble-menu/default.tsx
826
+ function ImageBubbleMenuDefault({ excludeItems = [], placement, offset: offset$1, onHide, className }) {
827
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuRoot, {
828
+ placement,
829
+ offset: offset$1,
830
+ onHide,
831
+ className,
832
+ children: !excludeItems.includes("edit-link") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuToolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuEditLink, {}) })
833
+ });
834
+ }
835
+
836
+ //#endregion
837
+ //#region src/ui/image-bubble-menu/index.ts
838
+ const ImageBubbleMenu = {
839
+ Root: ImageBubbleMenuRoot,
840
+ Toolbar: ImageBubbleMenuToolbar,
841
+ EditLink: ImageBubbleMenuEditLink,
842
+ Default: ImageBubbleMenuDefault
843
+ };
844
+
845
+ //#endregion
846
+ //#region src/ui/link-bubble-menu/context.tsx
847
+ const LinkBubbleMenuContext = react.createContext(null);
848
+ function useLinkBubbleMenuContext() {
849
+ const context = react.useContext(LinkBubbleMenuContext);
850
+ if (!context) throw new Error("LinkBubbleMenu compound components must be used within <LinkBubbleMenu.Root>");
851
+ return context;
852
+ }
853
+
854
+ //#endregion
855
+ //#region src/ui/link-bubble-menu/edit-link.tsx
856
+ function LinkBubbleMenuEditLink({ className, children, onClick, onMouseDown, ...rest }) {
857
+ const { setIsEditing } = useLinkBubbleMenuContext();
858
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
859
+ type: "button",
860
+ "aria-label": "Edit link",
861
+ "data-re-link-bm-item": "",
862
+ "data-item": "edit-link",
863
+ className,
864
+ onMouseDown: (e) => {
865
+ e.preventDefault();
866
+ onMouseDown?.(e);
867
+ },
868
+ onClick: (e) => {
869
+ onClick?.(e);
870
+ setIsEditing(true);
871
+ },
872
+ ...rest,
873
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PencilIcon, {})
874
+ });
875
+ }
876
+
877
+ //#endregion
878
+ //#region src/ui/link-bubble-menu/form.tsx
879
+ function LinkBubbleMenuForm({ className, validateUrl, onLinkApply, onLinkRemove, children }) {
880
+ const { editor, linkHref, isEditing, setIsEditing } = useLinkBubbleMenuContext();
881
+ const inputRef = react.useRef(null);
882
+ const formRef = react.useRef(null);
883
+ const displayHref = linkHref === "#" ? "" : linkHref;
884
+ const [inputValue, setInputValue] = react.useState(displayHref);
885
+ react.useEffect(() => {
886
+ if (!isEditing) return;
887
+ const timeoutId = setTimeout(() => {
888
+ inputRef.current?.focus();
889
+ }, 0);
890
+ return () => clearTimeout(timeoutId);
891
+ }, [isEditing]);
892
+ react.useEffect(() => {
893
+ if (!isEditing) return;
894
+ const handleKeyDown = (event) => {
895
+ if (event.key === "Escape") setIsEditing(false);
896
+ };
897
+ const handleClickOutside = (event) => {
898
+ if (formRef.current && !formRef.current.contains(event.target)) {
899
+ const form = formRef.current;
900
+ const submitEvent = new Event("submit", {
901
+ bubbles: true,
902
+ cancelable: true
903
+ });
904
+ form.dispatchEvent(submitEvent);
905
+ setIsEditing(false);
906
+ }
907
+ };
908
+ document.addEventListener("mousedown", handleClickOutside);
909
+ window.addEventListener("keydown", handleKeyDown);
910
+ return () => {
911
+ window.removeEventListener("keydown", handleKeyDown);
912
+ document.removeEventListener("mousedown", handleClickOutside);
913
+ };
914
+ }, [isEditing, setIsEditing]);
915
+ if (!isEditing) return null;
916
+ function handleSubmit(e) {
917
+ e.preventDefault();
918
+ const value = inputValue.trim();
919
+ if (value === "") {
920
+ setLinkHref(editor, "");
921
+ setIsEditing(false);
922
+ focusEditor(editor);
923
+ onLinkRemove?.();
924
+ return;
925
+ }
926
+ const finalValue = (validateUrl ?? getUrlFromString)(value);
927
+ if (!finalValue) {
928
+ setLinkHref(editor, "");
929
+ setIsEditing(false);
930
+ focusEditor(editor);
931
+ onLinkRemove?.();
932
+ return;
933
+ }
934
+ setLinkHref(editor, finalValue);
935
+ setIsEditing(false);
936
+ focusEditor(editor);
937
+ onLinkApply?.(finalValue);
938
+ }
939
+ function handleUnlink(e) {
940
+ e.stopPropagation();
941
+ setLinkHref(editor, "");
942
+ setIsEditing(false);
943
+ focusEditor(editor);
944
+ onLinkRemove?.();
945
+ }
946
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
947
+ ref: formRef,
948
+ "data-re-link-bm-form": "",
949
+ className,
950
+ onMouseDown: (e) => e.stopPropagation(),
951
+ onClick: (e) => e.stopPropagation(),
952
+ onKeyDown: (e) => e.stopPropagation(),
953
+ onSubmit: handleSubmit,
954
+ children: [
955
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
956
+ ref: inputRef,
957
+ "data-re-link-bm-input": "",
958
+ value: inputValue,
959
+ onFocus: (e) => e.stopPropagation(),
960
+ onChange: (e) => setInputValue(e.target.value),
961
+ placeholder: "Paste a link",
962
+ type: "text"
963
+ }),
964
+ children,
965
+ displayHref ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
966
+ type: "button",
967
+ "aria-label": "Remove link",
968
+ "data-re-link-bm-unlink": "",
969
+ onClick: handleUnlink,
970
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.UnlinkIcon, {})
971
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
972
+ type: "submit",
973
+ "aria-label": "Apply link",
974
+ "data-re-link-bm-apply": "",
975
+ onMouseDown: (e) => e.stopPropagation(),
976
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, {})
977
+ })
978
+ ]
979
+ });
980
+ }
981
+
982
+ //#endregion
983
+ //#region src/ui/link-bubble-menu/open-link.tsx
984
+ function LinkBubbleMenuOpenLink({ className, children, ...rest }) {
985
+ const { linkHref } = useLinkBubbleMenuContext();
986
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
987
+ ...rest,
988
+ href: linkHref,
989
+ target: "_blank",
990
+ rel: "noopener noreferrer",
991
+ "aria-label": "Open link",
992
+ "data-re-link-bm-item": "",
993
+ "data-item": "open-link",
994
+ className,
995
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ExternalLinkIcon, {})
996
+ });
997
+ }
998
+
999
+ //#endregion
1000
+ //#region src/ui/link-bubble-menu/root.tsx
1001
+ function LinkBubbleMenuRoot({ onHide, placement = "top", offset: offset$1 = 8, className, children }) {
1002
+ const { editor } = (0, _tiptap_react.useCurrentEditor)();
1003
+ const [isEditing, setIsEditing] = react.useState(false);
1004
+ const linkHref = (0, _tiptap_react.useEditorState)({
1005
+ editor,
1006
+ selector: ({ editor: e }) => e?.getAttributes("link").href ?? ""
1007
+ });
1008
+ if (!editor) return null;
1009
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react_menus.BubbleMenu, {
1010
+ editor,
1011
+ "data-re-link-bm": "",
1012
+ shouldShow: ({ editor: e }) => e.isActive("link") && e.view.state.selection.content().size === 0,
1013
+ options: {
1014
+ placement,
1015
+ offset: offset$1,
1016
+ onHide: () => {
1017
+ setIsEditing(false);
1018
+ onHide?.();
1019
+ }
1020
+ },
1021
+ className,
1022
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkBubbleMenuContext.Provider, {
1023
+ value: {
1024
+ editor,
1025
+ linkHref: linkHref ?? "",
1026
+ isEditing,
1027
+ setIsEditing
1028
+ },
1029
+ children
1030
+ })
1031
+ });
1032
+ }
1033
+
1034
+ //#endregion
1035
+ //#region src/ui/link-bubble-menu/toolbar.tsx
1036
+ function LinkBubbleMenuToolbar({ children, ...rest }) {
1037
+ const { isEditing } = useLinkBubbleMenuContext();
1038
+ if (isEditing) return null;
1039
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1040
+ "data-re-link-bm-toolbar": "",
1041
+ ...rest,
1042
+ children
1043
+ });
1044
+ }
1045
+
1046
+ //#endregion
1047
+ //#region src/ui/link-bubble-menu/unlink.tsx
1048
+ function LinkBubbleMenuUnlink({ className, children, onClick, onMouseDown, ...rest }) {
1049
+ const { editor } = useLinkBubbleMenuContext();
1050
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1051
+ type: "button",
1052
+ "aria-label": "Remove link",
1053
+ "data-re-link-bm-item": "",
1054
+ "data-item": "unlink",
1055
+ className,
1056
+ onMouseDown: (e) => {
1057
+ e.preventDefault();
1058
+ onMouseDown?.(e);
1059
+ },
1060
+ onClick: (e) => {
1061
+ onClick?.(e);
1062
+ editor.chain().focus().unsetLink().run();
1063
+ },
1064
+ ...rest,
1065
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.UnlinkIcon, {})
1066
+ });
1067
+ }
1068
+
1069
+ //#endregion
1070
+ //#region src/ui/link-bubble-menu/default.tsx
1071
+ function LinkBubbleMenuDefault({ excludeItems = [], placement, offset: offset$1, onHide, className, validateUrl, onLinkApply, onLinkRemove }) {
1072
+ const has = (item) => !excludeItems.includes(item);
1073
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LinkBubbleMenuRoot, {
1074
+ placement,
1075
+ offset: offset$1,
1076
+ onHide,
1077
+ className,
1078
+ children: [(has("edit-link") || has("open-link") || has("unlink")) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LinkBubbleMenuToolbar, { children: [
1079
+ has("edit-link") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkBubbleMenuEditLink, {}),
1080
+ has("open-link") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkBubbleMenuOpenLink, {}),
1081
+ has("unlink") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkBubbleMenuUnlink, {})
1082
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkBubbleMenuForm, {
1083
+ validateUrl,
1084
+ onLinkApply,
1085
+ onLinkRemove
1086
+ })]
1087
+ });
1088
+ }
1089
+
1090
+ //#endregion
1091
+ //#region src/ui/link-bubble-menu/index.ts
1092
+ const LinkBubbleMenu = {
1093
+ Root: LinkBubbleMenuRoot,
1094
+ Toolbar: LinkBubbleMenuToolbar,
1095
+ Form: LinkBubbleMenuForm,
1096
+ EditLink: LinkBubbleMenuEditLink,
1097
+ Unlink: LinkBubbleMenuUnlink,
1098
+ OpenLink: LinkBubbleMenuOpenLink,
1099
+ Default: LinkBubbleMenuDefault
1100
+ };
1101
+
1102
+ //#endregion
1103
+ //#region src/ui/slash-command/utils.ts
1104
+ function isInsideNode(editor, type) {
1105
+ const { $from } = editor.state.selection;
1106
+ for (let d = $from.depth; d > 0; d--) if ($from.node(d).type.name === type) return true;
1107
+ return false;
1108
+ }
1109
+ function isAtMaxColumnsDepth(editor) {
1110
+ const { from } = editor.state.selection;
1111
+ return require_columns.getColumnsDepth(editor.state.doc, from) >= require_columns.MAX_COLUMNS_DEPTH;
1112
+ }
1113
+ function updateScrollView(container, item) {
1114
+ const containerRect = container.getBoundingClientRect();
1115
+ const itemRect = item.getBoundingClientRect();
1116
+ if (itemRect.top < containerRect.top) container.scrollTop -= containerRect.top - itemRect.top;
1117
+ else if (itemRect.bottom > containerRect.bottom) container.scrollTop += itemRect.bottom - containerRect.bottom;
1118
+ }
1119
+
1120
+ //#endregion
1121
+ //#region src/ui/slash-command/command-list.tsx
1122
+ const CATEGORY_ORDER = [
1123
+ "Text",
1124
+ "Media",
1125
+ "Layout",
1126
+ "Utility"
1127
+ ];
1128
+ function groupByCategory(items) {
1129
+ const seen = /* @__PURE__ */ new Map();
1130
+ for (const item of items) {
1131
+ const existing = seen.get(item.category);
1132
+ if (existing) existing.push(item);
1133
+ else seen.set(item.category, [item]);
1134
+ }
1135
+ const ordered = [];
1136
+ for (const cat of CATEGORY_ORDER) {
1137
+ const group = seen.get(cat);
1138
+ if (group) {
1139
+ ordered.push({
1140
+ category: cat,
1141
+ items: group
1142
+ });
1143
+ seen.delete(cat);
1144
+ }
1145
+ }
1146
+ for (const [category, group] of seen) ordered.push({
1147
+ category,
1148
+ items: group
1149
+ });
1150
+ return ordered;
1151
+ }
1152
+ function CommandItem({ item, selected, onSelect }) {
1153
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1154
+ "data-re-slash-command-item": "",
1155
+ "data-selected": selected || void 0,
1156
+ onClick: onSelect,
1157
+ type: "button",
1158
+ children: [item.icon, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.title })]
1159
+ });
1160
+ }
1161
+ function CommandList({ items, query, selectedIndex, onSelect }) {
1162
+ const containerRef = (0, react.useRef)(null);
1163
+ (0, react.useLayoutEffect)(() => {
1164
+ const container = containerRef.current;
1165
+ if (!container) return;
1166
+ const selected = container.querySelector("[data-selected]");
1167
+ if (selected) updateScrollView(container, selected);
1168
+ }, [selectedIndex]);
1169
+ if (items.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1170
+ "data-re-slash-command": "",
1171
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1172
+ "data-re-slash-command-empty": "",
1173
+ children: "No results"
1174
+ })
1175
+ });
1176
+ if (query.trim().length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1177
+ "data-re-slash-command": "",
1178
+ ref: containerRef,
1179
+ children: items.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandItem, {
1180
+ item,
1181
+ onSelect: () => onSelect(index),
1182
+ selected: index === selectedIndex
1183
+ }, item.title))
1184
+ });
1185
+ const groups = groupByCategory(items);
1186
+ let flatIndex = 0;
1187
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1188
+ "data-re-slash-command": "",
1189
+ ref: containerRef,
1190
+ children: groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1191
+ "data-re-slash-command-category": "",
1192
+ children: group.category
1193
+ }), group.items.map((item) => {
1194
+ const currentIndex = flatIndex++;
1195
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandItem, {
1196
+ item,
1197
+ onSelect: () => onSelect(currentIndex),
1198
+ selected: currentIndex === selectedIndex
1199
+ }, item.title);
1200
+ })] }, group.category))
1201
+ });
1202
+ }
1203
+
1204
+ //#endregion
1205
+ //#region src/ui/slash-command/commands.tsx
1206
+ const TEXT = {
1207
+ title: "Text",
1208
+ description: "Plain text block",
1209
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Text, { size: 20 }),
1210
+ category: "Text",
1211
+ searchTerms: ["p", "paragraph"],
1212
+ command: ({ editor, range }) => {
1213
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
1214
+ }
1215
+ };
1216
+ const H1 = {
1217
+ title: "Title",
1218
+ description: "Large heading",
1219
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heading1, { size: 20 }),
1220
+ category: "Text",
1221
+ searchTerms: [
1222
+ "title",
1223
+ "big",
1224
+ "large",
1225
+ "h1"
1226
+ ],
1227
+ command: ({ editor, range }) => {
1228
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
1229
+ }
1230
+ };
1231
+ const H2 = {
1232
+ title: "Subtitle",
1233
+ description: "Medium heading",
1234
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heading2, { size: 20 }),
1235
+ category: "Text",
1236
+ searchTerms: [
1237
+ "subtitle",
1238
+ "medium",
1239
+ "h2"
1240
+ ],
1241
+ command: ({ editor, range }) => {
1242
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
1243
+ }
1244
+ };
1245
+ const H3 = {
1246
+ title: "Heading",
1247
+ description: "Small heading",
1248
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heading3, { size: 20 }),
1249
+ category: "Text",
1250
+ searchTerms: [
1251
+ "subtitle",
1252
+ "small",
1253
+ "h3"
1254
+ ],
1255
+ command: ({ editor, range }) => {
1256
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
1257
+ }
1258
+ };
1259
+ const BULLET_LIST = {
1260
+ title: "Bullet list",
1261
+ description: "Unordered list",
1262
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { size: 20 }),
1263
+ category: "Text",
1264
+ searchTerms: ["unordered", "point"],
1265
+ command: ({ editor, range }) => {
1266
+ editor.chain().focus().deleteRange(range).toggleBulletList().run();
1267
+ }
1268
+ };
1269
+ const NUMBERED_LIST = {
1270
+ title: "Numbered list",
1271
+ description: "Ordered list",
1272
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ListOrdered, { size: 20 }),
1273
+ category: "Text",
1274
+ searchTerms: ["ordered"],
1275
+ command: ({ editor, range }) => {
1276
+ editor.chain().focus().deleteRange(range).toggleOrderedList().run();
1277
+ }
1278
+ };
1279
+ const QUOTE = {
1280
+ title: "Quote",
1281
+ description: "Block quote",
1282
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.TextQuote, { size: 20 }),
1283
+ category: "Text",
1284
+ searchTerms: ["blockquote"],
1285
+ command: ({ editor, range }) => {
1286
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run();
1287
+ }
1288
+ };
1289
+ const CODE = {
1290
+ title: "Code block",
1291
+ description: "Code snippet",
1292
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.SquareCode, { size: 20 }),
1293
+ category: "Text",
1294
+ searchTerms: ["codeblock"],
1295
+ command: ({ editor, range }) => {
1296
+ editor.chain().focus().deleteRange(range).toggleCodeBlock().run();
1297
+ }
1298
+ };
1299
+ const BUTTON = {
1300
+ title: "Button",
1301
+ description: "Clickable button",
1302
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.MousePointer, { size: 20 }),
1303
+ category: "Layout",
1304
+ searchTerms: ["button"],
1305
+ command: ({ editor, range }) => {
1306
+ editor.chain().focus().deleteRange(range).setButton().run();
1307
+ }
1308
+ };
1309
+ const DIVIDER = {
1310
+ title: "Divider",
1311
+ description: "Horizontal separator",
1312
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.SplitSquareVertical, { size: 20 }),
1313
+ category: "Layout",
1314
+ searchTerms: [
1315
+ "hr",
1316
+ "divider",
1317
+ "separator"
1318
+ ],
1319
+ command: ({ editor, range }) => {
1320
+ editor.chain().focus().deleteRange(range).setHorizontalRule().run();
1321
+ }
1322
+ };
1323
+ const SECTION = {
1324
+ title: "Section",
1325
+ description: "Content section",
1326
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Rows2, { size: 20 }),
1327
+ category: "Layout",
1328
+ searchTerms: [
1329
+ "section",
1330
+ "row",
1331
+ "container"
1332
+ ],
1333
+ command: ({ editor, range }) => {
1334
+ editor.chain().focus().deleteRange(range).insertSection().run();
1335
+ }
1336
+ };
1337
+ const TWO_COLUMNS = {
1338
+ title: "2 columns",
1339
+ description: "Two column layout",
1340
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Columns2, { size: 20 }),
1341
+ category: "Layout",
1342
+ searchTerms: [
1343
+ "columns",
1344
+ "column",
1345
+ "layout",
1346
+ "grid",
1347
+ "split",
1348
+ "side-by-side",
1349
+ "multi-column",
1350
+ "row",
1351
+ "two",
1352
+ "2"
1353
+ ],
1354
+ command: ({ editor, range }) => {
1355
+ editor.chain().focus().deleteRange(range).insertColumns(2).run();
1356
+ }
1357
+ };
1358
+ const THREE_COLUMNS = {
1359
+ title: "3 columns",
1360
+ description: "Three column layout",
1361
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Columns3, { size: 20 }),
1362
+ category: "Layout",
1363
+ searchTerms: [
1364
+ "columns",
1365
+ "column",
1366
+ "layout",
1367
+ "grid",
1368
+ "split",
1369
+ "multi-column",
1370
+ "row",
1371
+ "three",
1372
+ "3"
1373
+ ],
1374
+ command: ({ editor, range }) => {
1375
+ editor.chain().focus().deleteRange(range).insertColumns(3).run();
1376
+ }
1377
+ };
1378
+ const FOUR_COLUMNS = {
1379
+ title: "4 columns",
1380
+ description: "Four column layout",
1381
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Columns4, { size: 20 }),
1382
+ category: "Layout",
1383
+ searchTerms: [
1384
+ "columns",
1385
+ "column",
1386
+ "layout",
1387
+ "grid",
1388
+ "split",
1389
+ "multi-column",
1390
+ "row",
1391
+ "four",
1392
+ "4"
1393
+ ],
1394
+ command: ({ editor, range }) => {
1395
+ editor.chain().focus().deleteRange(range).insertColumns(4).run();
1396
+ }
1397
+ };
1398
+ const defaultSlashCommands = [
1399
+ TEXT,
1400
+ H1,
1401
+ H2,
1402
+ H3,
1403
+ BULLET_LIST,
1404
+ NUMBERED_LIST,
1405
+ QUOTE,
1406
+ CODE,
1407
+ BUTTON,
1408
+ DIVIDER,
1409
+ SECTION,
1410
+ TWO_COLUMNS,
1411
+ THREE_COLUMNS,
1412
+ FOUR_COLUMNS
1413
+ ];
1414
+
1415
+ //#endregion
1416
+ //#region src/ui/slash-command/search.ts
1417
+ function scoreItem(item, query) {
1418
+ if (!query) return 100;
1419
+ const q = query.toLowerCase();
1420
+ const title = item.title.toLowerCase();
1421
+ const description = item.description.toLowerCase();
1422
+ const terms = item.searchTerms?.map((t) => t.toLowerCase()) ?? [];
1423
+ if (title === q) return 100;
1424
+ if (title.startsWith(q)) return 90;
1425
+ if (title.split(/\s+/).some((w) => w.startsWith(q))) return 80;
1426
+ if (terms.some((t) => t === q)) return 70;
1427
+ if (terms.some((t) => t.startsWith(q))) return 60;
1428
+ if (title.includes(q)) return 40;
1429
+ if (terms.some((t) => t.includes(q))) return 30;
1430
+ if (description.includes(q)) return 20;
1431
+ return 0;
1432
+ }
1433
+ function filterAndRankItems(items, query) {
1434
+ const trimmed = query.trim();
1435
+ if (!trimmed) return items;
1436
+ const scored = items.map((item) => ({
1437
+ item,
1438
+ score: scoreItem(item, trimmed)
1439
+ })).filter(({ score }) => score > 0);
1440
+ scored.sort((a, b) => b.score - a.score);
1441
+ return scored.map(({ item }) => item);
1442
+ }
1443
+
1444
+ //#endregion
1445
+ //#region src/ui/slash-command/root.tsx
1446
+ const pluginKey = new _tiptap_pm_state.PluginKey("slash-command");
1447
+ const INITIAL_STATE = {
1448
+ active: false,
1449
+ query: "",
1450
+ items: [],
1451
+ clientRect: null
1452
+ };
1453
+ function defaultFilterItems(items, query, editor) {
1454
+ return filterAndRankItems(isAtMaxColumnsDepth(editor) ? items.filter((item) => item.category !== "Layout" || !item.title.includes("column")) : items, query);
1455
+ }
1456
+ function SlashCommandRoot({ items: itemsProp, filterItems: filterItemsProp, char = "/", allow: allowProp, children }) {
1457
+ const { editor } = (0, _tiptap_react.useCurrentEditor)();
1458
+ const [state, setState] = (0, react.useState)(INITIAL_STATE);
1459
+ const [selectedIndex, setSelectedIndex] = (0, react.useState)(0);
1460
+ const itemsRef = (0, react.useRef)(itemsProp ?? defaultSlashCommands);
1461
+ const filterRef = (0, react.useRef)(filterItemsProp ?? defaultFilterItems);
1462
+ const allowRef = (0, react.useRef)(allowProp ?? (({ editor: e }) => !e.isActive("codeBlock")));
1463
+ itemsRef.current = itemsProp ?? defaultSlashCommands;
1464
+ filterRef.current = filterItemsProp ?? defaultFilterItems;
1465
+ allowRef.current = allowProp ?? (({ editor: e }) => !e.isActive("codeBlock"));
1466
+ const commandRef = (0, react.useRef)(null);
1467
+ const suggestionItemsRef = (0, react.useRef)([]);
1468
+ const selectedIndexRef = (0, react.useRef)(0);
1469
+ suggestionItemsRef.current = state.items;
1470
+ selectedIndexRef.current = selectedIndex;
1471
+ const { refs, floatingStyles } = (0, _floating_ui_react_dom.useFloating)({
1472
+ open: state.active,
1473
+ placement: "bottom-start",
1474
+ middleware: [
1475
+ (0, _floating_ui_react_dom.offset)(8),
1476
+ (0, _floating_ui_react_dom.flip)(),
1477
+ (0, _floating_ui_react_dom.shift)({ padding: 8 })
1478
+ ],
1479
+ whileElementsMounted: _floating_ui_react_dom.autoUpdate
1480
+ });
1481
+ (0, react.useEffect)(() => {
1482
+ if (!state.clientRect) return;
1483
+ refs.setReference({ getBoundingClientRect: state.clientRect });
1484
+ }, [state.clientRect, refs]);
1485
+ (0, react.useEffect)(() => {
1486
+ setSelectedIndex(0);
1487
+ }, [state.items]);
1488
+ const onSelect = (0, react.useCallback)((index) => {
1489
+ const item = suggestionItemsRef.current[index];
1490
+ if (item && commandRef.current) commandRef.current(item);
1491
+ }, []);
1492
+ (0, react.useEffect)(() => {
1493
+ if (!editor) return;
1494
+ const plugin = (0, _tiptap_suggestion.default)({
1495
+ pluginKey,
1496
+ editor,
1497
+ char,
1498
+ allow: ({ editor: e }) => allowRef.current({ editor: e }),
1499
+ command: ({ editor: e, range, props }) => {
1500
+ props.command({
1501
+ editor: e,
1502
+ range
1503
+ });
1504
+ },
1505
+ items: ({ query, editor: e }) => filterRef.current(itemsRef.current, query, e),
1506
+ render: () => ({
1507
+ onStart: (props) => {
1508
+ commandRef.current = props.command;
1509
+ setState({
1510
+ active: true,
1511
+ query: props.query,
1512
+ items: props.items,
1513
+ clientRect: props.clientRect ?? null
1514
+ });
1515
+ },
1516
+ onUpdate: (props) => {
1517
+ commandRef.current = props.command;
1518
+ setState({
1519
+ active: true,
1520
+ query: props.query,
1521
+ items: props.items,
1522
+ clientRect: props.clientRect ?? null
1523
+ });
1524
+ },
1525
+ onKeyDown: ({ event }) => {
1526
+ if (event.key === "Escape") {
1527
+ setState(INITIAL_STATE);
1528
+ return true;
1529
+ }
1530
+ const items = suggestionItemsRef.current;
1531
+ if (items.length === 0) return false;
1532
+ if (event.key === "ArrowUp") {
1533
+ setSelectedIndex((i) => (i + items.length - 1) % items.length);
1534
+ return true;
1535
+ }
1536
+ if (event.key === "ArrowDown") {
1537
+ setSelectedIndex((i) => (i + 1) % items.length);
1538
+ return true;
1539
+ }
1540
+ if (event.key === "Enter") {
1541
+ const item = items[selectedIndexRef.current];
1542
+ if (item && commandRef.current) commandRef.current(item);
1543
+ return true;
1544
+ }
1545
+ return false;
1546
+ },
1547
+ onExit: () => {
1548
+ setState(INITIAL_STATE);
1549
+ requestAnimationFrame(() => {
1550
+ commandRef.current = null;
1551
+ });
1552
+ }
1553
+ })
1554
+ });
1555
+ editor.registerPlugin(plugin, (newPlugin, plugins) => [newPlugin, ...plugins]);
1556
+ return () => {
1557
+ editor.unregisterPlugin(pluginKey);
1558
+ };
1559
+ }, [editor, char]);
1560
+ if (!editor || !state.active) return null;
1561
+ const renderProps = {
1562
+ items: state.items,
1563
+ query: state.query,
1564
+ selectedIndex,
1565
+ onSelect
1566
+ };
1567
+ let content;
1568
+ if (children) content = children(renderProps);
1569
+ else content = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandList, { ...renderProps });
1570
+ return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1571
+ ref: refs.setFloating,
1572
+ style: floatingStyles,
1573
+ children: content
1574
+ }), document.body);
1575
+ }
1576
+
1577
+ //#endregion
1578
+ //#region src/ui/slash-command/index.ts
1579
+ const SlashCommand = {
1580
+ Root: SlashCommandRoot,
1581
+ CommandList
1582
+ };
1583
+
1584
+ //#endregion
1585
+ exports.BULLET_LIST = BULLET_LIST;
1586
+ exports.BUTTON = BUTTON;
1587
+ exports.BubbleMenu = BubbleMenu;
1588
+ exports.BubbleMenuAlignCenter = BubbleMenuAlignCenter;
1589
+ exports.BubbleMenuAlignLeft = BubbleMenuAlignLeft;
1590
+ exports.BubbleMenuAlignRight = BubbleMenuAlignRight;
1591
+ exports.BubbleMenuBold = BubbleMenuBold;
1592
+ exports.BubbleMenuCode = BubbleMenuCode;
1593
+ exports.BubbleMenuDefault = BubbleMenuDefault;
1594
+ exports.BubbleMenuItalic = BubbleMenuItalic;
1595
+ exports.BubbleMenuItem = BubbleMenuItem;
1596
+ exports.BubbleMenuItemGroup = BubbleMenuItemGroup;
1597
+ exports.BubbleMenuLinkSelector = BubbleMenuLinkSelector;
1598
+ exports.BubbleMenuNodeSelector = BubbleMenuNodeSelector;
1599
+ exports.BubbleMenuRoot = BubbleMenuRoot;
1600
+ exports.BubbleMenuSeparator = BubbleMenuSeparator;
1601
+ exports.BubbleMenuStrike = BubbleMenuStrike;
1602
+ exports.BubbleMenuUnderline = BubbleMenuUnderline;
1603
+ exports.BubbleMenuUppercase = BubbleMenuUppercase;
1604
+ exports.ButtonBubbleMenu = ButtonBubbleMenu;
1605
+ exports.ButtonBubbleMenuDefault = ButtonBubbleMenuDefault;
1606
+ exports.ButtonBubbleMenuEditLink = ButtonBubbleMenuEditLink;
1607
+ exports.ButtonBubbleMenuRoot = ButtonBubbleMenuRoot;
1608
+ exports.ButtonBubbleMenuToolbar = ButtonBubbleMenuToolbar;
1609
+ exports.CODE = CODE;
1610
+ exports.CommandList = CommandList;
1611
+ exports.DIVIDER = DIVIDER;
1612
+ exports.FOUR_COLUMNS = FOUR_COLUMNS;
1613
+ exports.H1 = H1;
1614
+ exports.H2 = H2;
1615
+ exports.H3 = H3;
1616
+ exports.ImageBubbleMenu = ImageBubbleMenu;
1617
+ exports.ImageBubbleMenuDefault = ImageBubbleMenuDefault;
1618
+ exports.ImageBubbleMenuEditLink = ImageBubbleMenuEditLink;
1619
+ exports.ImageBubbleMenuRoot = ImageBubbleMenuRoot;
1620
+ exports.ImageBubbleMenuToolbar = ImageBubbleMenuToolbar;
1621
+ exports.LinkBubbleMenu = LinkBubbleMenu;
1622
+ exports.LinkBubbleMenuDefault = LinkBubbleMenuDefault;
1623
+ exports.LinkBubbleMenuEditLink = LinkBubbleMenuEditLink;
1624
+ exports.LinkBubbleMenuForm = LinkBubbleMenuForm;
1625
+ exports.LinkBubbleMenuOpenLink = LinkBubbleMenuOpenLink;
1626
+ exports.LinkBubbleMenuRoot = LinkBubbleMenuRoot;
1627
+ exports.LinkBubbleMenuToolbar = LinkBubbleMenuToolbar;
1628
+ exports.LinkBubbleMenuUnlink = LinkBubbleMenuUnlink;
1629
+ exports.NUMBERED_LIST = NUMBERED_LIST;
1630
+ exports.NodeSelectorContent = NodeSelectorContent;
1631
+ exports.NodeSelectorRoot = NodeSelectorRoot;
1632
+ exports.NodeSelectorTrigger = NodeSelectorTrigger;
1633
+ exports.QUOTE = QUOTE;
1634
+ exports.SECTION = SECTION;
1635
+ exports.SlashCommand = SlashCommand;
1636
+ exports.TEXT = TEXT;
1637
+ exports.THREE_COLUMNS = THREE_COLUMNS;
1638
+ exports.TWO_COLUMNS = TWO_COLUMNS;
1639
+ exports.defaultSlashCommands = defaultSlashCommands;
1640
+ exports.filterAndRankItems = filterAndRankItems;
1641
+ exports.isAtMaxColumnsDepth = isAtMaxColumnsDepth;
1642
+ exports.isInsideNode = isInsideNode;
1643
+ exports.scoreItem = scoreItem;
1644
+ exports.useButtonBubbleMenuContext = useButtonBubbleMenuContext;
1645
+ exports.useImageBubbleMenuContext = useImageBubbleMenuContext;
1646
+ exports.useLinkBubbleMenuContext = useLinkBubbleMenuContext;