@react-email/editor 0.0.0-experimental.4 → 0.0.0-experimental.41

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 (74) hide show
  1. package/dist/core/index.cjs +9 -0
  2. package/dist/core/index.d.cts +2 -0
  3. package/dist/core/index.d.mts +3 -0
  4. package/dist/core/index.mjs +4 -0
  5. package/dist/create-paste-handler-B8BtjBk3.d.cts +14 -0
  6. package/dist/create-paste-handler-B8BtjBk3.d.cts.map +1 -0
  7. package/dist/create-paste-handler-CGR738bC.d.mts +14 -0
  8. package/dist/create-paste-handler-CGR738bC.d.mts.map +1 -0
  9. package/dist/event-bus-CHEzOS_O.mjs +329 -0
  10. package/dist/event-bus-CHEzOS_O.mjs.map +1 -0
  11. package/dist/event-bus-fb8U7hrl.cjs +450 -0
  12. package/dist/extension-DyY8_bh4.mjs +1110 -0
  13. package/dist/extension-DyY8_bh4.mjs.map +1 -0
  14. package/dist/extension-w5VaUeSw.cjs +1235 -0
  15. package/dist/extensions/index.cjs +51 -0
  16. package/dist/extensions/index.d.cts +399 -0
  17. package/dist/extensions/index.d.cts.map +1 -0
  18. package/dist/extensions/index.d.mts +400 -0
  19. package/dist/extensions/index.d.mts.map +1 -0
  20. package/dist/extensions/index.mjs +5 -0
  21. package/dist/extensions-BvfmaKCn.mjs +2088 -0
  22. package/dist/extensions-BvfmaKCn.mjs.map +1 -0
  23. package/dist/extensions-CkjPj2JO.cjs +2369 -0
  24. package/dist/global-content-D_WYaFgX.mjs +78 -0
  25. package/dist/global-content-D_WYaFgX.mjs.map +1 -0
  26. package/dist/global-content-bJgotqmA.cjs +89 -0
  27. package/dist/index-C4KcMQ0R.d.cts +161 -0
  28. package/dist/index-C4KcMQ0R.d.cts.map +1 -0
  29. package/dist/index-CxX7W63O.d.mts +161 -0
  30. package/dist/index-CxX7W63O.d.mts.map +1 -0
  31. package/dist/index.cjs +74 -0
  32. package/dist/index.css +832 -0
  33. package/dist/index.css.map +1 -0
  34. package/dist/index.d.cts +33 -0
  35. package/dist/index.d.cts.map +1 -0
  36. package/dist/index.d.mts +31 -277
  37. package/dist/index.d.mts.map +1 -1
  38. package/dist/index.mjs +64 -1377
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/plugins/index.cjs +23 -0
  41. package/dist/plugins/index.d.cts +191 -0
  42. package/dist/plugins/index.d.cts.map +1 -0
  43. package/dist/plugins/index.d.mts +191 -0
  44. package/dist/plugins/index.d.mts.map +1 -0
  45. package/dist/plugins/index.mjs +3 -0
  46. package/dist/root-Jq1R3tkX.cjs +2832 -0
  47. package/dist/root-pS4l8bVZ.mjs +2316 -0
  48. package/dist/root-pS4l8bVZ.mjs.map +1 -0
  49. package/dist/set-text-alignment-Cv72txmv.cjs +24 -0
  50. package/dist/set-text-alignment-OA8IMWmO.mjs +19 -0
  51. package/dist/set-text-alignment-OA8IMWmO.mjs.map +1 -0
  52. package/dist/styles-C-cCyJCn.cjs +211 -0
  53. package/dist/styles-_TMw3YxC.mjs +194 -0
  54. package/dist/styles-_TMw3YxC.mjs.map +1 -0
  55. package/dist/ui/bubble-menu/bubble-menu.css +285 -0
  56. package/dist/ui/index.cjs +147 -0
  57. package/dist/ui/index.d.cts +939 -0
  58. package/dist/ui/index.d.cts.map +1 -0
  59. package/dist/ui/index.d.mts +939 -0
  60. package/dist/ui/index.d.mts.map +1 -0
  61. package/dist/ui/index.mjs +60 -0
  62. package/dist/ui/index.mjs.map +1 -0
  63. package/dist/ui/slash-command/slash-command.css +44 -0
  64. package/dist/ui/themes/default.css +830 -0
  65. package/dist/utils/index.cjs +3 -0
  66. package/dist/utils/index.d.cts +7 -0
  67. package/dist/utils/index.d.cts.map +1 -0
  68. package/dist/utils/index.d.mts +7 -0
  69. package/dist/utils/index.d.mts.map +1 -0
  70. package/dist/utils/index.mjs +3 -0
  71. package/package.json +109 -21
  72. package/dist/index.d.ts +0 -279
  73. package/dist/index.d.ts.map +0 -1
  74. package/dist/index.js +0 -1436
@@ -0,0 +1,2316 @@
1
+ import { a as MAX_COLUMNS_DEPTH, c as getColumnsDepth, t as editorEventBus } from "./event-bus-CHEzOS_O.mjs";
2
+ import { t as setTextAlignment } from "./set-text-alignment-OA8IMWmO.mjs";
3
+ import { useCurrentEditor, useEditorState } from "@tiptap/react";
4
+ import * as React from "react";
5
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { PluginKey } from "@tiptap/pm/state";
8
+ import { BubbleMenu } from "@tiptap/react/menus";
9
+ import * as Popover from "@radix-ui/react-popover";
10
+ import { autoUpdate, flip, offset, shift, useFloating } from "@floating-ui/react-dom";
11
+ import Suggestion from "@tiptap/suggestion";
12
+ import { createPortal } from "react-dom";
13
+
14
+ //#region src/ui/icons/align-center.tsx
15
+ function AlignCenterIcon({ size, width, height, ...props }) {
16
+ return /* @__PURE__ */ jsxs("svg", {
17
+ xmlns: "http://www.w3.org/2000/svg",
18
+ width: size ?? width ?? 24,
19
+ height: size ?? height ?? 24,
20
+ viewBox: "0 0 24 24",
21
+ fill: "none",
22
+ stroke: "currentColor",
23
+ strokeWidth: 2,
24
+ strokeLinecap: "round",
25
+ strokeLinejoin: "round",
26
+ "aria-hidden": "true",
27
+ ...props,
28
+ children: [
29
+ /* @__PURE__ */ jsx("path", { d: "M21 5H3" }),
30
+ /* @__PURE__ */ jsx("path", { d: "M17 12H7" }),
31
+ /* @__PURE__ */ jsx("path", { d: "M19 19H5" })
32
+ ]
33
+ });
34
+ }
35
+
36
+ //#endregion
37
+ //#region src/ui/icons/align-left.tsx
38
+ function AlignLeftIcon({ size, width, height, ...props }) {
39
+ return /* @__PURE__ */ jsxs("svg", {
40
+ xmlns: "http://www.w3.org/2000/svg",
41
+ width: size ?? width ?? 24,
42
+ height: size ?? height ?? 24,
43
+ viewBox: "0 0 24 24",
44
+ fill: "none",
45
+ stroke: "currentColor",
46
+ strokeWidth: 2,
47
+ strokeLinecap: "round",
48
+ strokeLinejoin: "round",
49
+ "aria-hidden": "true",
50
+ ...props,
51
+ children: [
52
+ /* @__PURE__ */ jsx("path", { d: "M21 5H3" }),
53
+ /* @__PURE__ */ jsx("path", { d: "M15 12H3" }),
54
+ /* @__PURE__ */ jsx("path", { d: "M17 19H3" })
55
+ ]
56
+ });
57
+ }
58
+
59
+ //#endregion
60
+ //#region src/ui/icons/align-right.tsx
61
+ function AlignRightIcon({ size, width, height, ...props }) {
62
+ return /* @__PURE__ */ jsxs("svg", {
63
+ xmlns: "http://www.w3.org/2000/svg",
64
+ width: size ?? width ?? 24,
65
+ height: size ?? height ?? 24,
66
+ viewBox: "0 0 24 24",
67
+ fill: "none",
68
+ stroke: "currentColor",
69
+ strokeWidth: 2,
70
+ strokeLinecap: "round",
71
+ strokeLinejoin: "round",
72
+ "aria-hidden": "true",
73
+ ...props,
74
+ children: [
75
+ /* @__PURE__ */ jsx("path", { d: "M21 5H3" }),
76
+ /* @__PURE__ */ jsx("path", { d: "M21 12H9" }),
77
+ /* @__PURE__ */ jsx("path", { d: "M21 19H7" })
78
+ ]
79
+ });
80
+ }
81
+
82
+ //#endregion
83
+ //#region src/ui/icons/bold.tsx
84
+ function BoldIcon({ size, width, height, ...props }) {
85
+ return /* @__PURE__ */ jsx("svg", {
86
+ xmlns: "http://www.w3.org/2000/svg",
87
+ width: size ?? width ?? 24,
88
+ height: size ?? height ?? 24,
89
+ viewBox: "0 0 24 24",
90
+ fill: "none",
91
+ stroke: "currentColor",
92
+ strokeWidth: 2,
93
+ strokeLinecap: "round",
94
+ strokeLinejoin: "round",
95
+ "aria-hidden": "true",
96
+ ...props,
97
+ children: /* @__PURE__ */ jsx("path", { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" })
98
+ });
99
+ }
100
+
101
+ //#endregion
102
+ //#region src/ui/icons/case-upper.tsx
103
+ function CaseUpperIcon({ size, width, height, ...props }) {
104
+ return /* @__PURE__ */ jsxs("svg", {
105
+ xmlns: "http://www.w3.org/2000/svg",
106
+ width: size ?? width ?? 24,
107
+ height: size ?? height ?? 24,
108
+ viewBox: "0 0 24 24",
109
+ fill: "none",
110
+ stroke: "currentColor",
111
+ strokeWidth: 2,
112
+ strokeLinecap: "round",
113
+ strokeLinejoin: "round",
114
+ "aria-hidden": "true",
115
+ ...props,
116
+ children: [
117
+ /* @__PURE__ */ jsx("path", { d: "M15 11h4.5a1 1 0 0 1 0 5h-4a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h3a1 1 0 0 1 0 5" }),
118
+ /* @__PURE__ */ jsx("path", { d: "m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16" }),
119
+ /* @__PURE__ */ jsx("path", { d: "M3.304 13h6.392" })
120
+ ]
121
+ });
122
+ }
123
+
124
+ //#endregion
125
+ //#region src/ui/icons/check.tsx
126
+ function Check({ size, width, height, ...props }) {
127
+ return /* @__PURE__ */ jsx("svg", {
128
+ xmlns: "http://www.w3.org/2000/svg",
129
+ width: size ?? width ?? 24,
130
+ height: size ?? height ?? 24,
131
+ viewBox: "0 0 24 24",
132
+ fill: "none",
133
+ stroke: "currentColor",
134
+ strokeWidth: 2,
135
+ strokeLinecap: "round",
136
+ strokeLinejoin: "round",
137
+ "aria-hidden": "true",
138
+ ...props,
139
+ children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
140
+ });
141
+ }
142
+
143
+ //#endregion
144
+ //#region src/ui/icons/chevron-down.tsx
145
+ function ChevronDown({ size, width, height, ...props }) {
146
+ return /* @__PURE__ */ jsx("svg", {
147
+ xmlns: "http://www.w3.org/2000/svg",
148
+ width: size ?? width ?? 24,
149
+ height: size ?? height ?? 24,
150
+ viewBox: "0 0 24 24",
151
+ fill: "none",
152
+ stroke: "currentColor",
153
+ strokeWidth: 2,
154
+ strokeLinecap: "round",
155
+ strokeLinejoin: "round",
156
+ "aria-hidden": "true",
157
+ ...props,
158
+ children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
159
+ });
160
+ }
161
+
162
+ //#endregion
163
+ //#region src/ui/icons/code.tsx
164
+ function CodeIcon({ size, width, height, ...props }) {
165
+ return /* @__PURE__ */ jsxs("svg", {
166
+ xmlns: "http://www.w3.org/2000/svg",
167
+ width: size ?? width ?? 24,
168
+ height: size ?? height ?? 24,
169
+ viewBox: "0 0 24 24",
170
+ fill: "none",
171
+ stroke: "currentColor",
172
+ strokeWidth: 2,
173
+ strokeLinecap: "round",
174
+ strokeLinejoin: "round",
175
+ "aria-hidden": "true",
176
+ ...props,
177
+ children: [/* @__PURE__ */ jsx("path", { d: "m16 18 6-6-6-6" }), /* @__PURE__ */ jsx("path", { d: "m8 6-6 6 6 6" })]
178
+ });
179
+ }
180
+ const Code = CodeIcon;
181
+
182
+ //#endregion
183
+ //#region src/ui/icons/columns-2.tsx
184
+ function Columns2({ size, width, height, ...props }) {
185
+ return /* @__PURE__ */ jsxs("svg", {
186
+ xmlns: "http://www.w3.org/2000/svg",
187
+ width: size ?? width ?? 24,
188
+ height: size ?? height ?? 24,
189
+ viewBox: "0 0 24 24",
190
+ fill: "none",
191
+ stroke: "currentColor",
192
+ strokeWidth: 2,
193
+ strokeLinecap: "round",
194
+ strokeLinejoin: "round",
195
+ "aria-hidden": "true",
196
+ ...props,
197
+ children: [/* @__PURE__ */ jsx("rect", {
198
+ width: "18",
199
+ height: "18",
200
+ x: "3",
201
+ y: "3",
202
+ rx: "2"
203
+ }), /* @__PURE__ */ jsx("path", { d: "M12 3v18" })]
204
+ });
205
+ }
206
+
207
+ //#endregion
208
+ //#region src/ui/icons/columns-3.tsx
209
+ function Columns3({ size, width, height, ...props }) {
210
+ return /* @__PURE__ */ jsxs("svg", {
211
+ xmlns: "http://www.w3.org/2000/svg",
212
+ width: size ?? width ?? 24,
213
+ height: size ?? height ?? 24,
214
+ viewBox: "0 0 24 24",
215
+ fill: "none",
216
+ stroke: "currentColor",
217
+ strokeWidth: 2,
218
+ strokeLinecap: "round",
219
+ strokeLinejoin: "round",
220
+ "aria-hidden": "true",
221
+ ...props,
222
+ children: [
223
+ /* @__PURE__ */ jsx("rect", {
224
+ width: "18",
225
+ height: "18",
226
+ x: "3",
227
+ y: "3",
228
+ rx: "2"
229
+ }),
230
+ /* @__PURE__ */ jsx("path", { d: "M9 3v18" }),
231
+ /* @__PURE__ */ jsx("path", { d: "M15 3v18" })
232
+ ]
233
+ });
234
+ }
235
+
236
+ //#endregion
237
+ //#region src/ui/icons/columns-4.tsx
238
+ function Columns4({ size, width, height, ...props }) {
239
+ return /* @__PURE__ */ jsxs("svg", {
240
+ xmlns: "http://www.w3.org/2000/svg",
241
+ width: size ?? width ?? 24,
242
+ height: size ?? height ?? 24,
243
+ viewBox: "0 0 24 24",
244
+ fill: "none",
245
+ stroke: "currentColor",
246
+ strokeWidth: 2,
247
+ strokeLinecap: "round",
248
+ strokeLinejoin: "round",
249
+ "aria-hidden": "true",
250
+ ...props,
251
+ children: [
252
+ /* @__PURE__ */ jsx("rect", {
253
+ width: "18",
254
+ height: "18",
255
+ x: "3",
256
+ y: "3",
257
+ rx: "2"
258
+ }),
259
+ /* @__PURE__ */ jsx("path", { d: "M7.5 3v18" }),
260
+ /* @__PURE__ */ jsx("path", { d: "M12 3v18" }),
261
+ /* @__PURE__ */ jsx("path", { d: "M16.5 3v18" })
262
+ ]
263
+ });
264
+ }
265
+
266
+ //#endregion
267
+ //#region src/ui/icons/external-link.tsx
268
+ function ExternalLinkIcon({ size, width, height, ...props }) {
269
+ return /* @__PURE__ */ jsxs("svg", {
270
+ xmlns: "http://www.w3.org/2000/svg",
271
+ width: size ?? width ?? 24,
272
+ height: size ?? height ?? 24,
273
+ viewBox: "0 0 24 24",
274
+ fill: "none",
275
+ stroke: "currentColor",
276
+ strokeWidth: 2,
277
+ strokeLinecap: "round",
278
+ strokeLinejoin: "round",
279
+ "aria-hidden": "true",
280
+ ...props,
281
+ children: [
282
+ /* @__PURE__ */ jsx("path", { d: "M15 3h6v6" }),
283
+ /* @__PURE__ */ jsx("path", { d: "M10 14 21 3" }),
284
+ /* @__PURE__ */ jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
285
+ ]
286
+ });
287
+ }
288
+
289
+ //#endregion
290
+ //#region src/ui/icons/heading-1.tsx
291
+ function Heading1({ size, width, height, ...props }) {
292
+ return /* @__PURE__ */ jsxs("svg", {
293
+ xmlns: "http://www.w3.org/2000/svg",
294
+ width: size ?? width ?? 24,
295
+ height: size ?? height ?? 24,
296
+ viewBox: "0 0 24 24",
297
+ fill: "none",
298
+ stroke: "currentColor",
299
+ strokeWidth: 2,
300
+ strokeLinecap: "round",
301
+ strokeLinejoin: "round",
302
+ "aria-hidden": "true",
303
+ ...props,
304
+ children: [
305
+ /* @__PURE__ */ jsx("path", { d: "M4 12h8" }),
306
+ /* @__PURE__ */ jsx("path", { d: "M4 18V6" }),
307
+ /* @__PURE__ */ jsx("path", { d: "M12 18V6" }),
308
+ /* @__PURE__ */ jsx("path", { d: "m17 12 3-2v8" })
309
+ ]
310
+ });
311
+ }
312
+
313
+ //#endregion
314
+ //#region src/ui/icons/heading-2.tsx
315
+ function Heading2({ size, width, height, ...props }) {
316
+ return /* @__PURE__ */ jsxs("svg", {
317
+ xmlns: "http://www.w3.org/2000/svg",
318
+ width: size ?? width ?? 24,
319
+ height: size ?? height ?? 24,
320
+ viewBox: "0 0 24 24",
321
+ fill: "none",
322
+ stroke: "currentColor",
323
+ strokeWidth: 2,
324
+ strokeLinecap: "round",
325
+ strokeLinejoin: "round",
326
+ "aria-hidden": "true",
327
+ ...props,
328
+ children: [
329
+ /* @__PURE__ */ jsx("path", { d: "M4 12h8" }),
330
+ /* @__PURE__ */ jsx("path", { d: "M4 18V6" }),
331
+ /* @__PURE__ */ jsx("path", { d: "M12 18V6" }),
332
+ /* @__PURE__ */ jsx("path", { d: "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1" })
333
+ ]
334
+ });
335
+ }
336
+
337
+ //#endregion
338
+ //#region src/ui/icons/heading-3.tsx
339
+ function Heading3({ size, width, height, ...props }) {
340
+ return /* @__PURE__ */ jsxs("svg", {
341
+ xmlns: "http://www.w3.org/2000/svg",
342
+ width: size ?? width ?? 24,
343
+ height: size ?? height ?? 24,
344
+ viewBox: "0 0 24 24",
345
+ fill: "none",
346
+ stroke: "currentColor",
347
+ strokeWidth: 2,
348
+ strokeLinecap: "round",
349
+ strokeLinejoin: "round",
350
+ "aria-hidden": "true",
351
+ ...props,
352
+ children: [
353
+ /* @__PURE__ */ jsx("path", { d: "M4 12h8" }),
354
+ /* @__PURE__ */ jsx("path", { d: "M4 18V6" }),
355
+ /* @__PURE__ */ jsx("path", { d: "M12 18V6" }),
356
+ /* @__PURE__ */ jsx("path", { d: "M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2" }),
357
+ /* @__PURE__ */ jsx("path", { d: "M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2" })
358
+ ]
359
+ });
360
+ }
361
+
362
+ //#endregion
363
+ //#region src/ui/icons/italic.tsx
364
+ function ItalicIcon({ size, width, height, ...props }) {
365
+ return /* @__PURE__ */ jsxs("svg", {
366
+ xmlns: "http://www.w3.org/2000/svg",
367
+ width: size ?? width ?? 24,
368
+ height: size ?? height ?? 24,
369
+ viewBox: "0 0 24 24",
370
+ fill: "none",
371
+ stroke: "currentColor",
372
+ strokeWidth: 2,
373
+ strokeLinecap: "round",
374
+ strokeLinejoin: "round",
375
+ "aria-hidden": "true",
376
+ ...props,
377
+ children: [
378
+ /* @__PURE__ */ jsx("line", {
379
+ x1: "19",
380
+ x2: "10",
381
+ y1: "4",
382
+ y2: "4"
383
+ }),
384
+ /* @__PURE__ */ jsx("line", {
385
+ x1: "14",
386
+ x2: "5",
387
+ y1: "20",
388
+ y2: "20"
389
+ }),
390
+ /* @__PURE__ */ jsx("line", {
391
+ x1: "15",
392
+ x2: "9",
393
+ y1: "4",
394
+ y2: "20"
395
+ })
396
+ ]
397
+ });
398
+ }
399
+
400
+ //#endregion
401
+ //#region src/ui/icons/link.tsx
402
+ function LinkIcon({ size, width, height, ...props }) {
403
+ return /* @__PURE__ */ jsxs("svg", {
404
+ xmlns: "http://www.w3.org/2000/svg",
405
+ width: size ?? width ?? 24,
406
+ height: size ?? height ?? 24,
407
+ viewBox: "0 0 24 24",
408
+ fill: "none",
409
+ stroke: "currentColor",
410
+ strokeWidth: 2,
411
+ strokeLinecap: "round",
412
+ strokeLinejoin: "round",
413
+ "aria-hidden": "true",
414
+ ...props,
415
+ children: [/* @__PURE__ */ jsx("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }), /* @__PURE__ */ jsx("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })]
416
+ });
417
+ }
418
+
419
+ //#endregion
420
+ //#region src/ui/icons/list.tsx
421
+ function List({ size, width, height, ...props }) {
422
+ return /* @__PURE__ */ jsxs("svg", {
423
+ xmlns: "http://www.w3.org/2000/svg",
424
+ width: size ?? width ?? 24,
425
+ height: size ?? height ?? 24,
426
+ viewBox: "0 0 24 24",
427
+ fill: "none",
428
+ stroke: "currentColor",
429
+ strokeWidth: 2,
430
+ strokeLinecap: "round",
431
+ strokeLinejoin: "round",
432
+ "aria-hidden": "true",
433
+ ...props,
434
+ children: [
435
+ /* @__PURE__ */ jsx("path", { d: "M3 5h.01" }),
436
+ /* @__PURE__ */ jsx("path", { d: "M3 12h.01" }),
437
+ /* @__PURE__ */ jsx("path", { d: "M3 19h.01" }),
438
+ /* @__PURE__ */ jsx("path", { d: "M8 5h13" }),
439
+ /* @__PURE__ */ jsx("path", { d: "M8 12h13" }),
440
+ /* @__PURE__ */ jsx("path", { d: "M8 19h13" })
441
+ ]
442
+ });
443
+ }
444
+
445
+ //#endregion
446
+ //#region src/ui/icons/list-ordered.tsx
447
+ function ListOrdered({ size, width, height, ...props }) {
448
+ return /* @__PURE__ */ jsxs("svg", {
449
+ xmlns: "http://www.w3.org/2000/svg",
450
+ width: size ?? width ?? 24,
451
+ height: size ?? height ?? 24,
452
+ viewBox: "0 0 24 24",
453
+ fill: "none",
454
+ stroke: "currentColor",
455
+ strokeWidth: 2,
456
+ strokeLinecap: "round",
457
+ strokeLinejoin: "round",
458
+ "aria-hidden": "true",
459
+ ...props,
460
+ children: [
461
+ /* @__PURE__ */ jsx("path", { d: "M11 5h10" }),
462
+ /* @__PURE__ */ jsx("path", { d: "M11 12h10" }),
463
+ /* @__PURE__ */ jsx("path", { d: "M11 19h10" }),
464
+ /* @__PURE__ */ jsx("path", { d: "M4 4h1v5" }),
465
+ /* @__PURE__ */ jsx("path", { d: "M4 9h2" }),
466
+ /* @__PURE__ */ jsx("path", { d: "M6.5 20H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02" })
467
+ ]
468
+ });
469
+ }
470
+
471
+ //#endregion
472
+ //#region src/ui/icons/mouse-pointer.tsx
473
+ function MousePointer({ size, width, height, ...props }) {
474
+ return /* @__PURE__ */ jsxs("svg", {
475
+ xmlns: "http://www.w3.org/2000/svg",
476
+ width: size ?? width ?? 24,
477
+ height: size ?? height ?? 24,
478
+ viewBox: "0 0 24 24",
479
+ fill: "none",
480
+ stroke: "currentColor",
481
+ strokeWidth: 2,
482
+ strokeLinecap: "round",
483
+ strokeLinejoin: "round",
484
+ "aria-hidden": "true",
485
+ ...props,
486
+ children: [/* @__PURE__ */ jsx("path", { d: "M12.586 12.586 19 19" }), /* @__PURE__ */ jsx("path", { d: "M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z" })]
487
+ });
488
+ }
489
+
490
+ //#endregion
491
+ //#region src/ui/icons/pencil.tsx
492
+ function PencilIcon({ size, width, height, ...props }) {
493
+ return /* @__PURE__ */ jsxs("svg", {
494
+ xmlns: "http://www.w3.org/2000/svg",
495
+ width: size ?? width ?? 24,
496
+ height: size ?? height ?? 24,
497
+ viewBox: "0 0 24 24",
498
+ fill: "none",
499
+ stroke: "currentColor",
500
+ strokeWidth: 2,
501
+ strokeLinecap: "round",
502
+ strokeLinejoin: "round",
503
+ "aria-hidden": "true",
504
+ ...props,
505
+ children: [/* @__PURE__ */ jsx("path", { d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" }), /* @__PURE__ */ jsx("path", { d: "m15 5 4 4" })]
506
+ });
507
+ }
508
+
509
+ //#endregion
510
+ //#region src/ui/icons/rows-2.tsx
511
+ function Rows2({ size, width, height, ...props }) {
512
+ return /* @__PURE__ */ jsxs("svg", {
513
+ xmlns: "http://www.w3.org/2000/svg",
514
+ width: size ?? width ?? 24,
515
+ height: size ?? height ?? 24,
516
+ viewBox: "0 0 24 24",
517
+ fill: "none",
518
+ stroke: "currentColor",
519
+ strokeWidth: 2,
520
+ strokeLinecap: "round",
521
+ strokeLinejoin: "round",
522
+ "aria-hidden": "true",
523
+ ...props,
524
+ children: [/* @__PURE__ */ jsx("rect", {
525
+ width: "18",
526
+ height: "18",
527
+ x: "3",
528
+ y: "3",
529
+ rx: "2"
530
+ }), /* @__PURE__ */ jsx("path", { d: "M3 12h18" })]
531
+ });
532
+ }
533
+
534
+ //#endregion
535
+ //#region src/ui/icons/split-square-vertical.tsx
536
+ function SplitSquareVertical({ size, width, height, ...props }) {
537
+ return /* @__PURE__ */ jsxs("svg", {
538
+ xmlns: "http://www.w3.org/2000/svg",
539
+ width: size ?? width ?? 24,
540
+ height: size ?? height ?? 24,
541
+ viewBox: "0 0 24 24",
542
+ fill: "none",
543
+ stroke: "currentColor",
544
+ strokeWidth: 2,
545
+ strokeLinecap: "round",
546
+ strokeLinejoin: "round",
547
+ "aria-hidden": "true",
548
+ ...props,
549
+ children: [
550
+ /* @__PURE__ */ jsx("path", { d: "M5 8V5c0-1 1-2 2-2h10c1 0 2 1 2 2v3" }),
551
+ /* @__PURE__ */ jsx("path", { d: "M19 16v3c0 1-1 2-2 2H7c-1 0-2-1-2-2v-3" }),
552
+ /* @__PURE__ */ jsx("line", {
553
+ x1: "4",
554
+ x2: "20",
555
+ y1: "12",
556
+ y2: "12"
557
+ })
558
+ ]
559
+ });
560
+ }
561
+
562
+ //#endregion
563
+ //#region src/ui/icons/square-code.tsx
564
+ function SquareCode({ size, width, height, ...props }) {
565
+ return /* @__PURE__ */ jsxs("svg", {
566
+ xmlns: "http://www.w3.org/2000/svg",
567
+ width: size ?? width ?? 24,
568
+ height: size ?? height ?? 24,
569
+ viewBox: "0 0 24 24",
570
+ fill: "none",
571
+ stroke: "currentColor",
572
+ strokeWidth: 2,
573
+ strokeLinecap: "round",
574
+ strokeLinejoin: "round",
575
+ "aria-hidden": "true",
576
+ ...props,
577
+ children: [
578
+ /* @__PURE__ */ jsx("path", { d: "m10 9-3 3 3 3" }),
579
+ /* @__PURE__ */ jsx("path", { d: "m14 15 3-3-3-3" }),
580
+ /* @__PURE__ */ jsx("rect", {
581
+ x: "3",
582
+ y: "3",
583
+ width: "18",
584
+ height: "18",
585
+ rx: "2"
586
+ })
587
+ ]
588
+ });
589
+ }
590
+
591
+ //#endregion
592
+ //#region src/ui/icons/strikethrough.tsx
593
+ function StrikethroughIcon({ size, width, height, ...props }) {
594
+ return /* @__PURE__ */ jsxs("svg", {
595
+ xmlns: "http://www.w3.org/2000/svg",
596
+ width: size ?? width ?? 24,
597
+ height: size ?? height ?? 24,
598
+ viewBox: "0 0 24 24",
599
+ fill: "none",
600
+ stroke: "currentColor",
601
+ strokeWidth: 2,
602
+ strokeLinecap: "round",
603
+ strokeLinejoin: "round",
604
+ "aria-hidden": "true",
605
+ ...props,
606
+ children: [
607
+ /* @__PURE__ */ jsx("path", { d: "M16 4H9a3 3 0 0 0-2.83 4" }),
608
+ /* @__PURE__ */ jsx("path", { d: "M14 12a4 4 0 0 1 0 8H6" }),
609
+ /* @__PURE__ */ jsx("line", {
610
+ x1: "4",
611
+ x2: "20",
612
+ y1: "12",
613
+ y2: "12"
614
+ })
615
+ ]
616
+ });
617
+ }
618
+
619
+ //#endregion
620
+ //#region src/ui/icons/text.tsx
621
+ function TextIcon({ size, width, height, ...props }) {
622
+ return /* @__PURE__ */ jsxs("svg", {
623
+ xmlns: "http://www.w3.org/2000/svg",
624
+ width: size ?? width ?? 24,
625
+ height: size ?? height ?? 24,
626
+ viewBox: "0 0 24 24",
627
+ fill: "none",
628
+ stroke: "currentColor",
629
+ strokeWidth: 2,
630
+ strokeLinecap: "round",
631
+ strokeLinejoin: "round",
632
+ "aria-hidden": "true",
633
+ ...props,
634
+ children: [
635
+ /* @__PURE__ */ jsx("path", { d: "M21 5H3" }),
636
+ /* @__PURE__ */ jsx("path", { d: "M15 12H3" }),
637
+ /* @__PURE__ */ jsx("path", { d: "M17 19H3" })
638
+ ]
639
+ });
640
+ }
641
+ const Text = TextIcon;
642
+
643
+ //#endregion
644
+ //#region src/ui/icons/text-quote.tsx
645
+ function TextQuote({ size, width, height, ...props }) {
646
+ return /* @__PURE__ */ jsxs("svg", {
647
+ xmlns: "http://www.w3.org/2000/svg",
648
+ width: size ?? width ?? 24,
649
+ height: size ?? height ?? 24,
650
+ viewBox: "0 0 24 24",
651
+ fill: "none",
652
+ stroke: "currentColor",
653
+ strokeWidth: 2,
654
+ strokeLinecap: "round",
655
+ strokeLinejoin: "round",
656
+ "aria-hidden": "true",
657
+ ...props,
658
+ children: [
659
+ /* @__PURE__ */ jsx("path", { d: "M17 5H3" }),
660
+ /* @__PURE__ */ jsx("path", { d: "M21 12H8" }),
661
+ /* @__PURE__ */ jsx("path", { d: "M21 19H8" }),
662
+ /* @__PURE__ */ jsx("path", { d: "M3 12v7" })
663
+ ]
664
+ });
665
+ }
666
+
667
+ //#endregion
668
+ //#region src/ui/icons/underline.tsx
669
+ function UnderlineIcon({ size, width, height, ...props }) {
670
+ return /* @__PURE__ */ jsxs("svg", {
671
+ xmlns: "http://www.w3.org/2000/svg",
672
+ width: size ?? width ?? 24,
673
+ height: size ?? height ?? 24,
674
+ viewBox: "0 0 24 24",
675
+ fill: "none",
676
+ stroke: "currentColor",
677
+ strokeWidth: 2,
678
+ strokeLinecap: "round",
679
+ strokeLinejoin: "round",
680
+ "aria-hidden": "true",
681
+ ...props,
682
+ children: [/* @__PURE__ */ jsx("path", { d: "M6 4v6a6 6 0 0 0 12 0V4" }), /* @__PURE__ */ jsx("line", {
683
+ x1: "4",
684
+ x2: "20",
685
+ y1: "20",
686
+ y2: "20"
687
+ })]
688
+ });
689
+ }
690
+
691
+ //#endregion
692
+ //#region src/ui/icons/unlink.tsx
693
+ function UnlinkIcon({ size, width, height, ...props }) {
694
+ return /* @__PURE__ */ jsxs("svg", {
695
+ xmlns: "http://www.w3.org/2000/svg",
696
+ width: size ?? width ?? 24,
697
+ height: size ?? height ?? 24,
698
+ viewBox: "0 0 24 24",
699
+ fill: "none",
700
+ stroke: "currentColor",
701
+ strokeWidth: 2,
702
+ strokeLinecap: "round",
703
+ strokeLinejoin: "round",
704
+ "aria-hidden": "true",
705
+ ...props,
706
+ children: [
707
+ /* @__PURE__ */ jsx("path", { d: "m18.84 12.25 1.72-1.71h-.02a5.004 5.004 0 0 0-.12-7.07 5.006 5.006 0 0 0-6.95 0l-1.72 1.71" }),
708
+ /* @__PURE__ */ jsx("path", { d: "m5.17 11.75-1.71 1.71a5.004 5.004 0 0 0 .12 7.07 5.006 5.006 0 0 0 6.95 0l1.71-1.71" }),
709
+ /* @__PURE__ */ jsx("line", {
710
+ x1: "8",
711
+ x2: "8",
712
+ y1: "2",
713
+ y2: "5"
714
+ }),
715
+ /* @__PURE__ */ jsx("line", {
716
+ x1: "2",
717
+ x2: "5",
718
+ y1: "8",
719
+ y2: "8"
720
+ }),
721
+ /* @__PURE__ */ jsx("line", {
722
+ x1: "16",
723
+ x2: "16",
724
+ y1: "19",
725
+ y2: "22"
726
+ }),
727
+ /* @__PURE__ */ jsx("line", {
728
+ x1: "19",
729
+ x2: "22",
730
+ y1: "16",
731
+ y2: "16"
732
+ })
733
+ ]
734
+ });
735
+ }
736
+
737
+ //#endregion
738
+ //#region src/ui/bubble-menu/context.tsx
739
+ const BubbleMenuContext = React.createContext(null);
740
+ function useBubbleMenuContext() {
741
+ const context = React.useContext(BubbleMenuContext);
742
+ if (!context) throw new Error("BubbleMenu compound components must be used within <BubbleMenu.Root>");
743
+ return context;
744
+ }
745
+
746
+ //#endregion
747
+ //#region src/ui/bubble-menu/button-edit-link.tsx
748
+ function BubbleMenuButtonEditLink({ className, children, onClick, onMouseDown, ...rest }) {
749
+ const { setIsEditing } = useBubbleMenuContext();
750
+ return /* @__PURE__ */ jsx("button", {
751
+ ...rest,
752
+ type: "button",
753
+ "aria-label": "Edit link",
754
+ "data-re-btn-bm-item": "",
755
+ "data-item": "edit-link",
756
+ className,
757
+ onMouseDown: (e) => {
758
+ e.preventDefault();
759
+ onMouseDown?.(e);
760
+ },
761
+ onClick: (e) => {
762
+ onClick?.(e);
763
+ setIsEditing(true);
764
+ },
765
+ children: children ?? /* @__PURE__ */ jsx(PencilIcon, {})
766
+ });
767
+ }
768
+
769
+ //#endregion
770
+ //#region src/ui/bubble-menu/utils.ts
771
+ const SAFE_PROTOCOLS = new Set([
772
+ "http:",
773
+ "https:",
774
+ "mailto:",
775
+ "tel:"
776
+ ]);
777
+ /**
778
+ * Basic URL validation and auto-prefixing.
779
+ * Rejects dangerous schemes (javascript:, data:, vbscript:, etc.).
780
+ * Returns the valid URL string or null.
781
+ */
782
+ function getUrlFromString(str) {
783
+ if (str === "#") return str;
784
+ try {
785
+ const url = new URL(str);
786
+ if (SAFE_PROTOCOLS.has(url.protocol)) return str;
787
+ return null;
788
+ } catch {}
789
+ try {
790
+ if (str.includes(".") && !str.includes(" ")) return new URL(`https://${str}`).toString();
791
+ } catch {}
792
+ return null;
793
+ }
794
+ function setLinkHref(editor, href) {
795
+ if (href.length === 0) {
796
+ editor.chain().unsetLink().run();
797
+ return;
798
+ }
799
+ const { from, to } = editor.state.selection;
800
+ if (from === to) {
801
+ editor.chain().extendMarkRange("link").setLink({ href }).setTextSelection({
802
+ from,
803
+ to
804
+ }).run();
805
+ return;
806
+ }
807
+ editor.chain().setLink({ href }).run();
808
+ }
809
+ function focusEditor(editor) {
810
+ setTimeout(() => {
811
+ editor.commands.focus();
812
+ }, 0);
813
+ }
814
+
815
+ //#endregion
816
+ //#region src/ui/bubble-menu/button-form.tsx
817
+ function BubbleMenuButtonForm({ className, validateUrl, onLinkApply, onLinkRemove }) {
818
+ const { editor, isEditing, setIsEditing } = useBubbleMenuContext();
819
+ const inputRef = React.useRef(null);
820
+ const formRef = React.useRef(null);
821
+ const buttonHref = editor.getAttributes("button").href ?? "";
822
+ const displayHref = buttonHref === "#" ? "" : buttonHref;
823
+ const [inputValue, setInputValue] = React.useState(displayHref);
824
+ React.useEffect(() => {
825
+ if (!isEditing) return;
826
+ const currentHref = editor.getAttributes("button").href ?? "";
827
+ setInputValue(currentHref === "#" ? "" : currentHref);
828
+ const timeoutId = setTimeout(() => {
829
+ inputRef.current?.focus();
830
+ }, 0);
831
+ return () => clearTimeout(timeoutId);
832
+ }, [isEditing, editor]);
833
+ React.useEffect(() => {
834
+ if (!isEditing) return;
835
+ const handleKeyDown = (event) => {
836
+ if (event.key === "Escape") setIsEditing(false);
837
+ };
838
+ const handleClickOutside = (event) => {
839
+ if (formRef.current && !formRef.current.contains(event.target)) {
840
+ const form = formRef.current;
841
+ const submitEvent = new Event("submit", {
842
+ bubbles: true,
843
+ cancelable: true
844
+ });
845
+ form.dispatchEvent(submitEvent);
846
+ setIsEditing(false);
847
+ }
848
+ };
849
+ document.addEventListener("mousedown", handleClickOutside);
850
+ window.addEventListener("keydown", handleKeyDown);
851
+ return () => {
852
+ window.removeEventListener("keydown", handleKeyDown);
853
+ document.removeEventListener("mousedown", handleClickOutside);
854
+ };
855
+ }, [isEditing, setIsEditing]);
856
+ if (!isEditing) return null;
857
+ function handleSubmit(e) {
858
+ e.preventDefault();
859
+ const value = inputValue.trim();
860
+ if (value === "") {
861
+ editor.commands.updateButton({ href: "#" });
862
+ setIsEditing(false);
863
+ focusEditor(editor);
864
+ onLinkRemove?.();
865
+ return;
866
+ }
867
+ const finalValue = (validateUrl ?? getUrlFromString)(value);
868
+ if (!finalValue) {
869
+ editor.commands.updateButton({ href: "#" });
870
+ setIsEditing(false);
871
+ focusEditor(editor);
872
+ onLinkRemove?.();
873
+ return;
874
+ }
875
+ editor.commands.updateButton({ href: finalValue });
876
+ setIsEditing(false);
877
+ focusEditor(editor);
878
+ onLinkApply?.(finalValue);
879
+ }
880
+ function handleUnlink(e) {
881
+ e.stopPropagation();
882
+ editor.commands.updateButton({ href: "#" });
883
+ setIsEditing(false);
884
+ focusEditor(editor);
885
+ onLinkRemove?.();
886
+ }
887
+ return /* @__PURE__ */ jsxs("form", {
888
+ ref: formRef,
889
+ "data-re-btn-bm-form": "",
890
+ className,
891
+ onMouseDown: (e) => e.stopPropagation(),
892
+ onClick: (e) => e.stopPropagation(),
893
+ onKeyDown: (e) => e.stopPropagation(),
894
+ onSubmit: handleSubmit,
895
+ children: [/* @__PURE__ */ jsx("input", {
896
+ ref: inputRef,
897
+ "data-re-btn-bm-input": "",
898
+ value: inputValue,
899
+ onFocus: (e) => e.stopPropagation(),
900
+ onChange: (e) => setInputValue(e.target.value),
901
+ placeholder: "Paste a link",
902
+ type: "text"
903
+ }), displayHref ? /* @__PURE__ */ jsx("button", {
904
+ type: "button",
905
+ "aria-label": "Remove link",
906
+ "data-re-btn-bm-unlink": "",
907
+ onClick: handleUnlink,
908
+ children: /* @__PURE__ */ jsx(UnlinkIcon, {})
909
+ }) : /* @__PURE__ */ jsx("button", {
910
+ type: "submit",
911
+ "aria-label": "Apply link",
912
+ "data-re-btn-bm-apply": "",
913
+ onMouseDown: (e) => e.stopPropagation(),
914
+ children: /* @__PURE__ */ jsx(Check, {})
915
+ })]
916
+ });
917
+ }
918
+
919
+ //#endregion
920
+ //#region src/ui/bubble-menu/button-toolbar.tsx
921
+ function BubbleMenuButtonToolbar({ children, ...rest }) {
922
+ const { isEditing } = useBubbleMenuContext();
923
+ if (isEditing) return null;
924
+ return /* @__PURE__ */ jsx("div", {
925
+ "data-re-btn-bm-toolbar": "",
926
+ ...rest,
927
+ children
928
+ });
929
+ }
930
+
931
+ //#endregion
932
+ //#region src/ui/bubble-menu/button-unlink.tsx
933
+ function BubbleMenuButtonUnlink({ className, children, onClick, onMouseDown, onLinkRemove, ...rest }) {
934
+ const { editor } = useBubbleMenuContext();
935
+ return /* @__PURE__ */ jsx("button", {
936
+ ...rest,
937
+ type: "button",
938
+ "aria-label": "Remove link",
939
+ "data-re-btn-bm-item": "",
940
+ "data-item": "unlink",
941
+ className,
942
+ onMouseDown: (e) => {
943
+ e.preventDefault();
944
+ onMouseDown?.(e);
945
+ },
946
+ onClick: (e) => {
947
+ onClick?.(e);
948
+ editor.commands.updateButton({ href: "#" });
949
+ focusEditor(editor);
950
+ onLinkRemove?.();
951
+ },
952
+ children: children ?? /* @__PURE__ */ jsx(UnlinkIcon, {})
953
+ });
954
+ }
955
+
956
+ //#endregion
957
+ //#region src/ui/bubble-menu/triggers.ts
958
+ const bubbleMenuTriggers = {
959
+ textSelection(hideWhenActiveNodes = [], hideWhenActiveMarks = []) {
960
+ return ({ editor, state }) => {
961
+ for (const node of hideWhenActiveNodes) {
962
+ if (editor.isActive(node)) return false;
963
+ const { $from } = state.selection;
964
+ for (let d = $from.depth; d > 0; d--) if ($from.node(d).type.name === node) return false;
965
+ }
966
+ for (const mark of hideWhenActiveMarks) if (editor.isActive(mark)) return false;
967
+ return editor.view.state.selection.content().size > 0;
968
+ };
969
+ },
970
+ node(name) {
971
+ return ({ editor }) => editor.isActive(name);
972
+ },
973
+ nodeWithoutSelection(name) {
974
+ return ({ editor }) => editor.isActive(name) && editor.view.state.selection.content().size === 0;
975
+ }
976
+ };
977
+
978
+ //#endregion
979
+ //#region src/ui/bubble-menu/root.tsx
980
+ const defaultPluginKey = new PluginKey("bubbleMenu");
981
+ function BubbleMenuRoot({ trigger, pluginKey: pluginKey$1 = defaultPluginKey, hideWhenActiveNodes = [], hideWhenActiveMarks = [], placement = "bottom", offset: offset$1 = 8, onHide, className, children, ...rest }) {
982
+ const { editor } = useCurrentEditor();
983
+ const [isEditing, setIsEditing] = React.useState(false);
984
+ const resolvedTrigger = trigger ?? bubbleMenuTriggers.textSelection(hideWhenActiveNodes, hideWhenActiveMarks);
985
+ if (!editor) return null;
986
+ return /* @__PURE__ */ jsx(BubbleMenu, {
987
+ editor,
988
+ pluginKey: pluginKey$1,
989
+ "data-re-bubble-menu": "",
990
+ shouldShow: resolvedTrigger,
991
+ options: {
992
+ placement,
993
+ offset: offset$1,
994
+ onHide: () => {
995
+ setIsEditing(false);
996
+ onHide?.();
997
+ }
998
+ },
999
+ className,
1000
+ ...rest,
1001
+ children: /* @__PURE__ */ jsx(BubbleMenuContext.Provider, {
1002
+ value: {
1003
+ editor,
1004
+ isEditing,
1005
+ setIsEditing
1006
+ },
1007
+ children
1008
+ })
1009
+ });
1010
+ }
1011
+
1012
+ //#endregion
1013
+ //#region src/ui/bubble-menu/button-default.tsx
1014
+ const buttonPluginKey = new PluginKey("buttonBubbleMenu");
1015
+ function BubbleMenuButtonDefaultInner({ validateUrl, onLinkApply, onLinkRemove }) {
1016
+ const { editor } = useBubbleMenuContext();
1017
+ const buttonHref = useEditorState({
1018
+ editor,
1019
+ selector: ({ editor: e }) => e?.getAttributes("button").href ?? ""
1020
+ });
1021
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(BubbleMenuButtonToolbar, { children: [/* @__PURE__ */ jsx(BubbleMenuButtonEditLink, {}), (buttonHref ?? "") !== "" && buttonHref !== "#" && /* @__PURE__ */ jsx(BubbleMenuButtonUnlink, { onLinkRemove })] }), /* @__PURE__ */ jsx(BubbleMenuButtonForm, {
1022
+ validateUrl,
1023
+ onLinkApply,
1024
+ onLinkRemove
1025
+ })] });
1026
+ }
1027
+ function BubbleMenuButtonDefault({ placement = "top", offset: offset$1, onHide, className, validateUrl, onLinkApply, onLinkRemove, ...rest }) {
1028
+ return /* @__PURE__ */ jsx(BubbleMenuRoot, {
1029
+ trigger: bubbleMenuTriggers.node("button"),
1030
+ pluginKey: buttonPluginKey,
1031
+ placement,
1032
+ offset: offset$1,
1033
+ onHide,
1034
+ className,
1035
+ ...rest,
1036
+ children: /* @__PURE__ */ jsx(BubbleMenuButtonDefaultInner, {
1037
+ validateUrl,
1038
+ onLinkApply,
1039
+ onLinkRemove
1040
+ })
1041
+ });
1042
+ }
1043
+
1044
+ //#endregion
1045
+ //#region src/ui/bubble-menu/item.tsx
1046
+ function BubbleMenuItem({ name, isActive, onCommand, className, children, ...rest }) {
1047
+ return /* @__PURE__ */ jsx("button", {
1048
+ type: "button",
1049
+ "aria-label": name,
1050
+ "aria-pressed": isActive,
1051
+ className,
1052
+ "data-re-bubble-menu-item": "",
1053
+ "data-item": name,
1054
+ ...isActive ? { "data-active": "" } : {},
1055
+ onMouseDown: (e) => e.preventDefault(),
1056
+ onClick: onCommand,
1057
+ ...rest,
1058
+ children
1059
+ });
1060
+ }
1061
+
1062
+ //#endregion
1063
+ //#region src/ui/bubble-menu/align-center.tsx
1064
+ function BubbleMenuAlignCenter({ className, children }) {
1065
+ const { editor } = useBubbleMenuContext();
1066
+ return /* @__PURE__ */ jsx(BubbleMenuItem, {
1067
+ name: "align-center",
1068
+ isActive: useEditorState({
1069
+ editor,
1070
+ selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "center" }) ?? false
1071
+ }),
1072
+ onCommand: () => setTextAlignment(editor, "center"),
1073
+ className,
1074
+ children: children ?? /* @__PURE__ */ jsx(AlignCenterIcon, {})
1075
+ });
1076
+ }
1077
+
1078
+ //#endregion
1079
+ //#region src/ui/bubble-menu/align-left.tsx
1080
+ function BubbleMenuAlignLeft({ className, children }) {
1081
+ const { editor } = useBubbleMenuContext();
1082
+ return /* @__PURE__ */ jsx(BubbleMenuItem, {
1083
+ name: "align-left",
1084
+ isActive: useEditorState({
1085
+ editor,
1086
+ selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "left" }) ?? false
1087
+ }),
1088
+ onCommand: () => setTextAlignment(editor, "left"),
1089
+ className,
1090
+ children: children ?? /* @__PURE__ */ jsx(AlignLeftIcon, {})
1091
+ });
1092
+ }
1093
+
1094
+ //#endregion
1095
+ //#region src/ui/bubble-menu/align-right.tsx
1096
+ function BubbleMenuAlignRight({ className, children }) {
1097
+ const { editor } = useBubbleMenuContext();
1098
+ return /* @__PURE__ */ jsx(BubbleMenuItem, {
1099
+ name: "align-right",
1100
+ isActive: useEditorState({
1101
+ editor,
1102
+ selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "right" }) ?? false
1103
+ }),
1104
+ onCommand: () => setTextAlignment(editor, "right"),
1105
+ className,
1106
+ children: children ?? /* @__PURE__ */ jsx(AlignRightIcon, {})
1107
+ });
1108
+ }
1109
+
1110
+ //#endregion
1111
+ //#region src/ui/bubble-menu/create-mark-bubble-item.tsx
1112
+ function createMarkBubbleItem(config) {
1113
+ function MarkBubbleItem({ className, children }) {
1114
+ const { editor } = useBubbleMenuContext();
1115
+ const isActive = useEditorState({
1116
+ editor,
1117
+ selector: ({ editor: editor$1 }) => {
1118
+ if (config.activeParams) return editor$1?.isActive(config.activeName, config.activeParams) ?? false;
1119
+ return editor$1?.isActive(config.activeName) ?? false;
1120
+ }
1121
+ });
1122
+ const handleCommand = () => {
1123
+ const chain = editor.chain().focus();
1124
+ const method = chain[config.command];
1125
+ if (method) method.call(chain).run();
1126
+ };
1127
+ return /* @__PURE__ */ jsx(BubbleMenuItem, {
1128
+ name: config.name,
1129
+ isActive,
1130
+ onCommand: handleCommand,
1131
+ className,
1132
+ children: children ?? config.icon
1133
+ });
1134
+ }
1135
+ MarkBubbleItem.displayName = `BubbleMenu${config.name.charAt(0).toUpperCase() + config.name.slice(1)}`;
1136
+ return MarkBubbleItem;
1137
+ }
1138
+
1139
+ //#endregion
1140
+ //#region src/ui/bubble-menu/bold.tsx
1141
+ const BubbleMenuBold = createMarkBubbleItem({
1142
+ name: "bold",
1143
+ activeName: "bold",
1144
+ command: "toggleBold",
1145
+ icon: /* @__PURE__ */ jsx(BoldIcon, {})
1146
+ });
1147
+
1148
+ //#endregion
1149
+ //#region src/ui/bubble-menu/code.tsx
1150
+ const BubbleMenuCode = createMarkBubbleItem({
1151
+ name: "code",
1152
+ activeName: "code",
1153
+ command: "toggleCode",
1154
+ icon: /* @__PURE__ */ jsx(CodeIcon, {})
1155
+ });
1156
+
1157
+ //#endregion
1158
+ //#region src/ui/bubble-menu/group.tsx
1159
+ function BubbleMenuItemGroup({ className, children }) {
1160
+ return /* @__PURE__ */ jsx("fieldset", {
1161
+ className,
1162
+ "data-re-bubble-menu-group": "",
1163
+ children
1164
+ });
1165
+ }
1166
+
1167
+ //#endregion
1168
+ //#region src/ui/bubble-menu/italic.tsx
1169
+ const BubbleMenuItalic = createMarkBubbleItem({
1170
+ name: "italic",
1171
+ activeName: "italic",
1172
+ command: "toggleItalic",
1173
+ icon: /* @__PURE__ */ jsx(ItalicIcon, {})
1174
+ });
1175
+
1176
+ //#endregion
1177
+ //#region src/ui/bubble-menu/link-selector.tsx
1178
+ function BubbleMenuLinkSelector({ className, showToggle = true, validateUrl, onLinkApply, onLinkRemove, children, open: controlledOpen, onOpenChange }) {
1179
+ const { editor } = useBubbleMenuContext();
1180
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
1181
+ const isControlled = controlledOpen !== void 0;
1182
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
1183
+ const setIsOpen = React.useCallback((value) => {
1184
+ if (!isControlled) setUncontrolledOpen(value);
1185
+ onOpenChange?.(value);
1186
+ }, [isControlled, onOpenChange]);
1187
+ const editorState = useEditorState({
1188
+ editor,
1189
+ selector: ({ editor: editor$1 }) => ({
1190
+ isLinkActive: editor$1?.isActive("link") ?? false,
1191
+ hasLink: Boolean(editor$1?.getAttributes("link").href),
1192
+ currentHref: editor$1?.getAttributes("link").href || ""
1193
+ })
1194
+ });
1195
+ const setIsOpenRef = React.useRef(setIsOpen);
1196
+ setIsOpenRef.current = setIsOpen;
1197
+ React.useEffect(() => {
1198
+ const subscription = editorEventBus.on("bubble-menu:add-link", () => {
1199
+ setIsOpenRef.current(true);
1200
+ });
1201
+ return () => {
1202
+ setIsOpenRef.current(false);
1203
+ subscription.unsubscribe();
1204
+ };
1205
+ }, []);
1206
+ if (!editorState) return null;
1207
+ const handleOpenLink = () => {
1208
+ setIsOpen(!isOpen);
1209
+ };
1210
+ return /* @__PURE__ */ jsxs("div", {
1211
+ "data-re-link-selector": "",
1212
+ ...isOpen ? { "data-open": "" } : {},
1213
+ ...editorState.hasLink ? { "data-has-link": "" } : {},
1214
+ className,
1215
+ children: [showToggle && /* @__PURE__ */ jsx("button", {
1216
+ type: "button",
1217
+ "aria-expanded": isOpen,
1218
+ "aria-haspopup": "true",
1219
+ "aria-label": "Add link",
1220
+ "aria-pressed": editorState.isLinkActive && editorState.hasLink,
1221
+ "data-re-link-selector-trigger": "",
1222
+ onClick: handleOpenLink,
1223
+ children: /* @__PURE__ */ jsx(LinkIcon, {})
1224
+ }), isOpen && /* @__PURE__ */ jsx(LinkForm, {
1225
+ editor,
1226
+ currentHref: editorState.currentHref,
1227
+ validateUrl,
1228
+ onLinkApply,
1229
+ onLinkRemove,
1230
+ setIsOpen,
1231
+ children
1232
+ })]
1233
+ });
1234
+ }
1235
+ function LinkForm({ editor, currentHref, validateUrl, onLinkApply, onLinkRemove, setIsOpen, children }) {
1236
+ const inputRef = React.useRef(null);
1237
+ const formRef = React.useRef(null);
1238
+ const displayHref = currentHref === "#" ? "" : currentHref;
1239
+ const [inputValue, setInputValue] = React.useState(displayHref);
1240
+ React.useEffect(() => {
1241
+ const timeoutId = setTimeout(() => {
1242
+ inputRef.current?.focus();
1243
+ }, 0);
1244
+ return () => clearTimeout(timeoutId);
1245
+ }, []);
1246
+ React.useEffect(() => {
1247
+ const handleKeyDown = (event) => {
1248
+ if (event.key === "Escape") {
1249
+ if (editor.getAttributes("link").href === "#") editor.chain().unsetLink().run();
1250
+ setIsOpen(false);
1251
+ }
1252
+ };
1253
+ const handleClickOutside = (event) => {
1254
+ if (formRef.current && !formRef.current.contains(event.target)) {
1255
+ const form = formRef.current;
1256
+ const submitEvent = new Event("submit", {
1257
+ bubbles: true,
1258
+ cancelable: true
1259
+ });
1260
+ form.dispatchEvent(submitEvent);
1261
+ setIsOpen(false);
1262
+ }
1263
+ };
1264
+ document.addEventListener("mousedown", handleClickOutside);
1265
+ window.addEventListener("keydown", handleKeyDown);
1266
+ return () => {
1267
+ window.removeEventListener("keydown", handleKeyDown);
1268
+ document.removeEventListener("mousedown", handleClickOutside);
1269
+ };
1270
+ }, [editor, setIsOpen]);
1271
+ function handleSubmit(e) {
1272
+ e.preventDefault();
1273
+ const value = inputValue.trim();
1274
+ if (value === "") {
1275
+ setLinkHref(editor, "");
1276
+ setIsOpen(false);
1277
+ focusEditor(editor);
1278
+ onLinkRemove?.();
1279
+ return;
1280
+ }
1281
+ const finalValue = (validateUrl ?? getUrlFromString)(value);
1282
+ if (!finalValue) {
1283
+ setLinkHref(editor, "");
1284
+ setIsOpen(false);
1285
+ focusEditor(editor);
1286
+ onLinkRemove?.();
1287
+ return;
1288
+ }
1289
+ setLinkHref(editor, finalValue);
1290
+ setIsOpen(false);
1291
+ focusEditor(editor);
1292
+ onLinkApply?.(finalValue);
1293
+ }
1294
+ function handleUnlink(e) {
1295
+ e.stopPropagation();
1296
+ setLinkHref(editor, "");
1297
+ setIsOpen(false);
1298
+ focusEditor(editor);
1299
+ onLinkRemove?.();
1300
+ }
1301
+ return /* @__PURE__ */ jsxs("form", {
1302
+ ref: formRef,
1303
+ "data-re-link-selector-form": "",
1304
+ onMouseDown: (e) => e.stopPropagation(),
1305
+ onClick: (e) => e.stopPropagation(),
1306
+ onKeyDown: (e) => e.stopPropagation(),
1307
+ onSubmit: handleSubmit,
1308
+ children: [
1309
+ /* @__PURE__ */ jsx("input", {
1310
+ ref: inputRef,
1311
+ "data-re-link-selector-input": "",
1312
+ value: inputValue,
1313
+ onFocus: (e) => e.stopPropagation(),
1314
+ onChange: (e) => setInputValue(e.target.value),
1315
+ placeholder: "Paste a link",
1316
+ type: "text"
1317
+ }),
1318
+ children,
1319
+ displayHref ? /* @__PURE__ */ jsx("button", {
1320
+ type: "button",
1321
+ "aria-label": "Remove link",
1322
+ "data-re-link-selector-unlink": "",
1323
+ onClick: handleUnlink,
1324
+ children: /* @__PURE__ */ jsx(UnlinkIcon, {})
1325
+ }) : /* @__PURE__ */ jsx("button", {
1326
+ type: "submit",
1327
+ "aria-label": "Apply link",
1328
+ "data-re-link-selector-apply": "",
1329
+ onMouseDown: (e) => e.stopPropagation(),
1330
+ children: /* @__PURE__ */ jsx(Check, {})
1331
+ })
1332
+ ]
1333
+ });
1334
+ }
1335
+
1336
+ //#endregion
1337
+ //#region src/ui/bubble-menu/node-selector.tsx
1338
+ const NodeSelectorContext = React.createContext(null);
1339
+ function useNodeSelectorContext() {
1340
+ const context = React.useContext(NodeSelectorContext);
1341
+ if (!context) throw new Error("NodeSelector compound components must be used within <NodeSelector.Root>");
1342
+ return context;
1343
+ }
1344
+ function NodeSelectorRoot({ omit = [], open: controlledOpen, onOpenChange, className, children }) {
1345
+ const { editor } = useBubbleMenuContext();
1346
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
1347
+ const isControlled = controlledOpen !== void 0;
1348
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
1349
+ const setIsOpen = React.useCallback((value) => {
1350
+ if (!isControlled) setUncontrolledOpen(value);
1351
+ onOpenChange?.(value);
1352
+ }, [isControlled, onOpenChange]);
1353
+ const editorState = useEditorState({
1354
+ editor,
1355
+ selector: ({ editor: editor$1 }) => ({
1356
+ isParagraphActive: (editor$1?.isActive("paragraph") ?? false) && !editor$1?.isActive("bulletList") && !editor$1?.isActive("orderedList"),
1357
+ isHeading1Active: editor$1?.isActive("heading", { level: 1 }) ?? false,
1358
+ isHeading2Active: editor$1?.isActive("heading", { level: 2 }) ?? false,
1359
+ isHeading3Active: editor$1?.isActive("heading", { level: 3 }) ?? false,
1360
+ isBulletListActive: editor$1?.isActive("bulletList") ?? false,
1361
+ isOrderedListActive: editor$1?.isActive("orderedList") ?? false,
1362
+ isBlockquoteActive: editor$1?.isActive("blockquote") ?? false,
1363
+ isCodeBlockActive: editor$1?.isActive("codeBlock") ?? false
1364
+ })
1365
+ });
1366
+ const allItems = React.useMemo(() => [
1367
+ {
1368
+ name: "Text",
1369
+ icon: TextIcon,
1370
+ command: () => editor.chain().focus().clearNodes().toggleNode("paragraph", "paragraph").run(),
1371
+ isActive: editorState?.isParagraphActive ?? false
1372
+ },
1373
+ {
1374
+ name: "Title",
1375
+ icon: Heading1,
1376
+ command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 1 }).run(),
1377
+ isActive: editorState?.isHeading1Active ?? false
1378
+ },
1379
+ {
1380
+ name: "Subtitle",
1381
+ icon: Heading2,
1382
+ command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 2 }).run(),
1383
+ isActive: editorState?.isHeading2Active ?? false
1384
+ },
1385
+ {
1386
+ name: "Heading",
1387
+ icon: Heading3,
1388
+ command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 3 }).run(),
1389
+ isActive: editorState?.isHeading3Active ?? false
1390
+ },
1391
+ {
1392
+ name: "Bullet List",
1393
+ icon: List,
1394
+ command: () => editor.chain().focus().clearNodes().toggleBulletList().run(),
1395
+ isActive: editorState?.isBulletListActive ?? false
1396
+ },
1397
+ {
1398
+ name: "Numbered List",
1399
+ icon: ListOrdered,
1400
+ command: () => editor.chain().focus().clearNodes().toggleOrderedList().run(),
1401
+ isActive: editorState?.isOrderedListActive ?? false
1402
+ },
1403
+ {
1404
+ name: "Quote",
1405
+ icon: TextQuote,
1406
+ command: () => editor.chain().focus().clearNodes().toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
1407
+ isActive: editorState?.isBlockquoteActive ?? false
1408
+ },
1409
+ {
1410
+ name: "Code",
1411
+ icon: Code,
1412
+ command: () => editor.chain().focus().clearNodes().toggleCodeBlock().run(),
1413
+ isActive: editorState?.isCodeBlockActive ?? false
1414
+ }
1415
+ ], [editor, editorState]);
1416
+ const items = React.useMemo(() => allItems.filter((item) => !omit.includes(item.name)), [allItems, omit]);
1417
+ const activeItem = React.useMemo(() => items.find((item) => item.isActive) ?? { name: "Multiple" }, [items]);
1418
+ const contextValue = React.useMemo(() => ({
1419
+ items,
1420
+ activeItem,
1421
+ isOpen,
1422
+ setIsOpen
1423
+ }), [
1424
+ items,
1425
+ activeItem,
1426
+ isOpen,
1427
+ setIsOpen
1428
+ ]);
1429
+ if (!editorState || items.length === 0) return null;
1430
+ return /* @__PURE__ */ jsx(NodeSelectorContext.Provider, {
1431
+ value: contextValue,
1432
+ children: /* @__PURE__ */ jsx(Popover.Root, {
1433
+ open: isOpen,
1434
+ onOpenChange: setIsOpen,
1435
+ children: /* @__PURE__ */ jsx("div", {
1436
+ "data-re-node-selector": "",
1437
+ ...isOpen ? { "data-open": "" } : {},
1438
+ className,
1439
+ children
1440
+ })
1441
+ })
1442
+ });
1443
+ }
1444
+ function NodeSelectorTrigger({ className, children }) {
1445
+ const { activeItem, isOpen, setIsOpen } = useNodeSelectorContext();
1446
+ return /* @__PURE__ */ jsx(Popover.Trigger, {
1447
+ "data-re-node-selector-trigger": "",
1448
+ className,
1449
+ onClick: () => setIsOpen(!isOpen),
1450
+ children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: activeItem.name }), /* @__PURE__ */ jsx(ChevronDown, {})] })
1451
+ });
1452
+ }
1453
+ function NodeSelectorContent({ className, align = "start", children }) {
1454
+ const { items, setIsOpen } = useNodeSelectorContext();
1455
+ return /* @__PURE__ */ jsx(Popover.Content, {
1456
+ align,
1457
+ "data-re-node-selector-content": "",
1458
+ className,
1459
+ children: children ? children(items, () => setIsOpen(false)) : items.map((item) => {
1460
+ const Icon = item.icon;
1461
+ return /* @__PURE__ */ jsxs("button", {
1462
+ type: "button",
1463
+ "data-re-node-selector-item": "",
1464
+ ...item.isActive ? { "data-active": "" } : {},
1465
+ onClick: () => {
1466
+ item.command();
1467
+ setIsOpen(false);
1468
+ },
1469
+ children: [
1470
+ /* @__PURE__ */ jsx(Icon, {}),
1471
+ /* @__PURE__ */ jsx("span", { children: item.name }),
1472
+ item.isActive && /* @__PURE__ */ jsx(Check, {})
1473
+ ]
1474
+ }, item.name);
1475
+ })
1476
+ });
1477
+ }
1478
+ function BubbleMenuNodeSelector({ omit = [], className, triggerContent, open, onOpenChange }) {
1479
+ return /* @__PURE__ */ jsxs(NodeSelectorRoot, {
1480
+ omit,
1481
+ open,
1482
+ onOpenChange,
1483
+ className,
1484
+ children: [/* @__PURE__ */ jsx(NodeSelectorTrigger, { children: triggerContent }), /* @__PURE__ */ jsx(NodeSelectorContent, {})]
1485
+ });
1486
+ }
1487
+
1488
+ //#endregion
1489
+ //#region src/ui/bubble-menu/strike.tsx
1490
+ const BubbleMenuStrike = createMarkBubbleItem({
1491
+ name: "strike",
1492
+ activeName: "strike",
1493
+ command: "toggleStrike",
1494
+ icon: /* @__PURE__ */ jsx(StrikethroughIcon, {})
1495
+ });
1496
+
1497
+ //#endregion
1498
+ //#region src/ui/bubble-menu/underline.tsx
1499
+ const BubbleMenuUnderline = createMarkBubbleItem({
1500
+ name: "underline",
1501
+ activeName: "underline",
1502
+ command: "toggleUnderline",
1503
+ icon: /* @__PURE__ */ jsx(UnderlineIcon, {})
1504
+ });
1505
+
1506
+ //#endregion
1507
+ //#region src/ui/bubble-menu/uppercase.tsx
1508
+ const BubbleMenuUppercase = createMarkBubbleItem({
1509
+ name: "uppercase",
1510
+ activeName: "uppercase",
1511
+ command: "toggleUppercase",
1512
+ icon: /* @__PURE__ */ jsx(CaseUpperIcon, {})
1513
+ });
1514
+
1515
+ //#endregion
1516
+ //#region src/ui/bubble-menu/default.tsx
1517
+ const textPluginKey = new PluginKey("textBubbleMenu");
1518
+ function BubbleMenuDefault({ excludeItems = [], hideWhenActiveNodes, hideWhenActiveMarks, placement, offset: offset$1, onHide, className, ...rest }) {
1519
+ const [isNodeSelectorOpen, setIsNodeSelectorOpen] = React.useState(false);
1520
+ const [isLinkSelectorOpen, setIsLinkSelectorOpen] = React.useState(false);
1521
+ const has = (item) => !excludeItems.includes(item);
1522
+ const handleNodeSelectorOpenChange = React.useCallback((open) => {
1523
+ setIsNodeSelectorOpen(open);
1524
+ if (open) setIsLinkSelectorOpen(false);
1525
+ }, []);
1526
+ const handleLinkSelectorOpenChange = React.useCallback((open) => {
1527
+ setIsLinkSelectorOpen(open);
1528
+ if (open) setIsNodeSelectorOpen(false);
1529
+ }, []);
1530
+ const handleHide = React.useCallback(() => {
1531
+ setIsNodeSelectorOpen(false);
1532
+ setIsLinkSelectorOpen(false);
1533
+ onHide?.();
1534
+ }, [onHide]);
1535
+ const hasFormattingItems = has("bold") || has("italic") || has("underline") || has("strike") || has("code") || has("uppercase");
1536
+ const hasAlignmentItems = has("align-left") || has("align-center") || has("align-right");
1537
+ return /* @__PURE__ */ jsxs(BubbleMenuRoot, {
1538
+ pluginKey: textPluginKey,
1539
+ hideWhenActiveNodes,
1540
+ hideWhenActiveMarks,
1541
+ placement,
1542
+ offset: offset$1,
1543
+ onHide: handleHide,
1544
+ className,
1545
+ ...rest,
1546
+ children: [
1547
+ has("node-selector") && /* @__PURE__ */ jsx(BubbleMenuNodeSelector, {
1548
+ open: isNodeSelectorOpen,
1549
+ onOpenChange: handleNodeSelectorOpenChange
1550
+ }),
1551
+ has("link-selector") && /* @__PURE__ */ jsx(BubbleMenuLinkSelector, {
1552
+ open: isLinkSelectorOpen,
1553
+ onOpenChange: handleLinkSelectorOpenChange
1554
+ }),
1555
+ hasFormattingItems && /* @__PURE__ */ jsxs(BubbleMenuItemGroup, { children: [
1556
+ has("bold") && /* @__PURE__ */ jsx(BubbleMenuBold, {}),
1557
+ has("italic") && /* @__PURE__ */ jsx(BubbleMenuItalic, {}),
1558
+ has("underline") && /* @__PURE__ */ jsx(BubbleMenuUnderline, {}),
1559
+ has("strike") && /* @__PURE__ */ jsx(BubbleMenuStrike, {}),
1560
+ has("code") && /* @__PURE__ */ jsx(BubbleMenuCode, {}),
1561
+ has("uppercase") && /* @__PURE__ */ jsx(BubbleMenuUppercase, {})
1562
+ ] }),
1563
+ hasAlignmentItems && /* @__PURE__ */ jsxs(BubbleMenuItemGroup, { children: [
1564
+ has("align-left") && /* @__PURE__ */ jsx(BubbleMenuAlignLeft, {}),
1565
+ has("align-center") && /* @__PURE__ */ jsx(BubbleMenuAlignCenter, {}),
1566
+ has("align-right") && /* @__PURE__ */ jsx(BubbleMenuAlignRight, {})
1567
+ ] })
1568
+ ]
1569
+ });
1570
+ }
1571
+
1572
+ //#endregion
1573
+ //#region src/ui/bubble-menu/image-edit-link.tsx
1574
+ function BubbleMenuImageEditLink({ className, children, onClick, onMouseDown, ...rest }) {
1575
+ const { setIsEditing } = useBubbleMenuContext();
1576
+ return /* @__PURE__ */ jsx("button", {
1577
+ ...rest,
1578
+ type: "button",
1579
+ "aria-label": "Edit link",
1580
+ "data-re-img-bm-item": "",
1581
+ "data-item": "edit-link",
1582
+ className,
1583
+ onMouseDown: (e) => {
1584
+ e.preventDefault();
1585
+ onMouseDown?.(e);
1586
+ },
1587
+ onClick: (e) => {
1588
+ onClick?.(e);
1589
+ setIsEditing(true);
1590
+ },
1591
+ children: children ?? /* @__PURE__ */ jsx(LinkIcon, {})
1592
+ });
1593
+ }
1594
+
1595
+ //#endregion
1596
+ //#region src/ui/bubble-menu/image-toolbar.tsx
1597
+ function BubbleMenuImageToolbar({ children, ...rest }) {
1598
+ const { isEditing } = useBubbleMenuContext();
1599
+ if (isEditing) return null;
1600
+ return /* @__PURE__ */ jsx("div", {
1601
+ "data-re-img-bm-toolbar": "",
1602
+ ...rest,
1603
+ children
1604
+ });
1605
+ }
1606
+
1607
+ //#endregion
1608
+ //#region src/ui/bubble-menu/image-default.tsx
1609
+ const imagePluginKey = new PluginKey("imageBubbleMenu");
1610
+ function BubbleMenuImageDefault({ excludeItems = [], placement = "top", offset: offset$1, onHide, className, ...rest }) {
1611
+ const hasEditLink = !excludeItems.includes("edit-link");
1612
+ return /* @__PURE__ */ jsx(BubbleMenuRoot, {
1613
+ trigger: bubbleMenuTriggers.node("image"),
1614
+ pluginKey: imagePluginKey,
1615
+ placement,
1616
+ offset: offset$1,
1617
+ onHide,
1618
+ className,
1619
+ ...rest,
1620
+ children: hasEditLink && /* @__PURE__ */ jsx(BubbleMenuImageToolbar, { children: /* @__PURE__ */ jsx(BubbleMenuImageEditLink, {}) })
1621
+ });
1622
+ }
1623
+
1624
+ //#endregion
1625
+ //#region src/ui/bubble-menu/link-edit-link.tsx
1626
+ function BubbleMenuLinkEditLink({ className, children, onClick, onMouseDown, ...rest }) {
1627
+ const { setIsEditing } = useBubbleMenuContext();
1628
+ return /* @__PURE__ */ jsx("button", {
1629
+ type: "button",
1630
+ "aria-label": "Edit link",
1631
+ "data-re-link-bm-item": "",
1632
+ "data-item": "edit-link",
1633
+ className,
1634
+ onMouseDown: (e) => {
1635
+ e.preventDefault();
1636
+ onMouseDown?.(e);
1637
+ },
1638
+ onClick: (e) => {
1639
+ onClick?.(e);
1640
+ setIsEditing(true);
1641
+ },
1642
+ ...rest,
1643
+ children: children ?? /* @__PURE__ */ jsx(PencilIcon, {})
1644
+ });
1645
+ }
1646
+
1647
+ //#endregion
1648
+ //#region src/ui/bubble-menu/link-form.tsx
1649
+ function BubbleMenuLinkForm({ className, validateUrl, onLinkApply, onLinkRemove, children }) {
1650
+ const { editor, isEditing, setIsEditing } = useBubbleMenuContext();
1651
+ const inputRef = React.useRef(null);
1652
+ const formRef = React.useRef(null);
1653
+ const linkHref = useEditorState({
1654
+ editor,
1655
+ selector: ({ editor: e }) => e?.getAttributes("link").href ?? ""
1656
+ });
1657
+ const displayHref = (linkHref ?? "") === "#" ? "" : linkHref ?? "";
1658
+ const [inputValue, setInputValue] = React.useState(displayHref);
1659
+ React.useEffect(() => {
1660
+ if (!isEditing) return;
1661
+ setInputValue(displayHref);
1662
+ const timeoutId = setTimeout(() => {
1663
+ inputRef.current?.focus();
1664
+ }, 0);
1665
+ return () => clearTimeout(timeoutId);
1666
+ }, [isEditing, displayHref]);
1667
+ React.useEffect(() => {
1668
+ if (!isEditing) return;
1669
+ const handleKeyDown = (event) => {
1670
+ if (event.key === "Escape") setIsEditing(false);
1671
+ };
1672
+ const handleClickOutside = (event) => {
1673
+ if (formRef.current && !formRef.current.contains(event.target)) {
1674
+ const form = formRef.current;
1675
+ const submitEvent = new Event("submit", {
1676
+ bubbles: true,
1677
+ cancelable: true
1678
+ });
1679
+ form.dispatchEvent(submitEvent);
1680
+ setIsEditing(false);
1681
+ }
1682
+ };
1683
+ document.addEventListener("mousedown", handleClickOutside);
1684
+ window.addEventListener("keydown", handleKeyDown);
1685
+ return () => {
1686
+ window.removeEventListener("keydown", handleKeyDown);
1687
+ document.removeEventListener("mousedown", handleClickOutside);
1688
+ };
1689
+ }, [isEditing, setIsEditing]);
1690
+ if (!isEditing) return null;
1691
+ function handleSubmit(e) {
1692
+ e.preventDefault();
1693
+ const value = inputValue.trim();
1694
+ if (value === "") {
1695
+ setLinkHref(editor, "");
1696
+ setIsEditing(false);
1697
+ focusEditor(editor);
1698
+ onLinkRemove?.();
1699
+ return;
1700
+ }
1701
+ const finalValue = (validateUrl ?? getUrlFromString)(value);
1702
+ if (!finalValue) {
1703
+ setLinkHref(editor, "");
1704
+ setIsEditing(false);
1705
+ focusEditor(editor);
1706
+ onLinkRemove?.();
1707
+ return;
1708
+ }
1709
+ setLinkHref(editor, finalValue);
1710
+ setIsEditing(false);
1711
+ focusEditor(editor);
1712
+ onLinkApply?.(finalValue);
1713
+ }
1714
+ function handleUnlink(e) {
1715
+ e.stopPropagation();
1716
+ setLinkHref(editor, "");
1717
+ setIsEditing(false);
1718
+ focusEditor(editor);
1719
+ onLinkRemove?.();
1720
+ }
1721
+ return /* @__PURE__ */ jsxs("form", {
1722
+ ref: formRef,
1723
+ "data-re-link-bm-form": "",
1724
+ className,
1725
+ onMouseDown: (e) => e.stopPropagation(),
1726
+ onClick: (e) => e.stopPropagation(),
1727
+ onKeyDown: (e) => e.stopPropagation(),
1728
+ onSubmit: handleSubmit,
1729
+ children: [
1730
+ /* @__PURE__ */ jsx("input", {
1731
+ ref: inputRef,
1732
+ "data-re-link-bm-input": "",
1733
+ value: inputValue,
1734
+ onFocus: (e) => e.stopPropagation(),
1735
+ onChange: (e) => setInputValue(e.target.value),
1736
+ placeholder: "Paste a link",
1737
+ type: "text"
1738
+ }),
1739
+ children,
1740
+ displayHref ? /* @__PURE__ */ jsx("button", {
1741
+ type: "button",
1742
+ "aria-label": "Remove link",
1743
+ "data-re-link-bm-unlink": "",
1744
+ onClick: handleUnlink,
1745
+ children: /* @__PURE__ */ jsx(UnlinkIcon, {})
1746
+ }) : /* @__PURE__ */ jsx("button", {
1747
+ type: "submit",
1748
+ "aria-label": "Apply link",
1749
+ "data-re-link-bm-apply": "",
1750
+ onMouseDown: (e) => e.stopPropagation(),
1751
+ children: /* @__PURE__ */ jsx(Check, {})
1752
+ })
1753
+ ]
1754
+ });
1755
+ }
1756
+
1757
+ //#endregion
1758
+ //#region src/ui/bubble-menu/link-open-link.tsx
1759
+ function BubbleMenuLinkOpenLink({ className, children, ...rest }) {
1760
+ const { editor } = useBubbleMenuContext();
1761
+ const linkHref = useEditorState({
1762
+ editor,
1763
+ selector: ({ editor: e }) => e?.getAttributes("link").href ?? ""
1764
+ });
1765
+ return /* @__PURE__ */ jsx("a", {
1766
+ ...rest,
1767
+ href: linkHref ?? "",
1768
+ target: "_blank",
1769
+ rel: "noopener noreferrer",
1770
+ "aria-label": "Open link",
1771
+ "data-re-link-bm-item": "",
1772
+ "data-item": "open-link",
1773
+ className,
1774
+ children: children ?? /* @__PURE__ */ jsx(ExternalLinkIcon, {})
1775
+ });
1776
+ }
1777
+
1778
+ //#endregion
1779
+ //#region src/ui/bubble-menu/link-toolbar.tsx
1780
+ function BubbleMenuLinkToolbar({ children, ...rest }) {
1781
+ const { isEditing } = useBubbleMenuContext();
1782
+ if (isEditing) return null;
1783
+ return /* @__PURE__ */ jsx("div", {
1784
+ "data-re-link-bm-toolbar": "",
1785
+ ...rest,
1786
+ children
1787
+ });
1788
+ }
1789
+
1790
+ //#endregion
1791
+ //#region src/ui/bubble-menu/link-unlink.tsx
1792
+ function BubbleMenuLinkUnlink({ className, children, onClick, onMouseDown, ...rest }) {
1793
+ const { editor } = useBubbleMenuContext();
1794
+ return /* @__PURE__ */ jsx("button", {
1795
+ type: "button",
1796
+ "aria-label": "Remove link",
1797
+ "data-re-link-bm-item": "",
1798
+ "data-item": "unlink",
1799
+ className,
1800
+ onMouseDown: (e) => {
1801
+ e.preventDefault();
1802
+ onMouseDown?.(e);
1803
+ },
1804
+ onClick: (e) => {
1805
+ onClick?.(e);
1806
+ editor.chain().focus().unsetLink().run();
1807
+ },
1808
+ ...rest,
1809
+ children: children ?? /* @__PURE__ */ jsx(UnlinkIcon, {})
1810
+ });
1811
+ }
1812
+
1813
+ //#endregion
1814
+ //#region src/ui/bubble-menu/link-default.tsx
1815
+ const linkPluginKey = new PluginKey("linkBubbleMenu");
1816
+ function BubbleMenuLinkDefault({ excludeItems = [], placement = "top", offset: offset$1, onHide, className, validateUrl, onLinkApply, onLinkRemove, ...rest }) {
1817
+ const has = (item) => !excludeItems.includes(item);
1818
+ const hasToolbarItems = has("edit-link") || has("open-link") || has("unlink");
1819
+ return /* @__PURE__ */ jsxs(BubbleMenuRoot, {
1820
+ trigger: bubbleMenuTriggers.nodeWithoutSelection("link"),
1821
+ pluginKey: linkPluginKey,
1822
+ placement,
1823
+ offset: offset$1,
1824
+ onHide,
1825
+ className,
1826
+ ...rest,
1827
+ children: [hasToolbarItems && /* @__PURE__ */ jsxs(BubbleMenuLinkToolbar, { children: [
1828
+ has("edit-link") && /* @__PURE__ */ jsx(BubbleMenuLinkEditLink, {}),
1829
+ has("open-link") && /* @__PURE__ */ jsx(BubbleMenuLinkOpenLink, {}),
1830
+ has("unlink") && /* @__PURE__ */ jsx(BubbleMenuLinkUnlink, {})
1831
+ ] }), /* @__PURE__ */ jsx(BubbleMenuLinkForm, {
1832
+ validateUrl,
1833
+ onLinkApply,
1834
+ onLinkRemove
1835
+ })]
1836
+ });
1837
+ }
1838
+
1839
+ //#endregion
1840
+ //#region src/ui/slash-command/utils.ts
1841
+ function isInsideNode(editor, type) {
1842
+ const { $from } = editor.state.selection;
1843
+ for (let d = $from.depth; d > 0; d--) if ($from.node(d).type.name === type) return true;
1844
+ return false;
1845
+ }
1846
+ function isAtMaxColumnsDepth(editor) {
1847
+ const { from } = editor.state.selection;
1848
+ return getColumnsDepth(editor.state.doc, from) >= MAX_COLUMNS_DEPTH;
1849
+ }
1850
+ function updateScrollView(container, item) {
1851
+ const containerRect = container.getBoundingClientRect();
1852
+ const itemRect = item.getBoundingClientRect();
1853
+ if (itemRect.top < containerRect.top) container.scrollTop -= containerRect.top - itemRect.top;
1854
+ else if (itemRect.bottom > containerRect.bottom) container.scrollTop += itemRect.bottom - containerRect.bottom;
1855
+ }
1856
+
1857
+ //#endregion
1858
+ //#region src/ui/slash-command/command-list.tsx
1859
+ const CATEGORY_ORDER = [
1860
+ "Text",
1861
+ "Media",
1862
+ "Layout",
1863
+ "Utility"
1864
+ ];
1865
+ function groupByCategory(items) {
1866
+ const seen = /* @__PURE__ */ new Map();
1867
+ for (const item of items) {
1868
+ const existing = seen.get(item.category);
1869
+ if (existing) existing.push(item);
1870
+ else seen.set(item.category, [item]);
1871
+ }
1872
+ const ordered = [];
1873
+ for (const cat of CATEGORY_ORDER) {
1874
+ const group = seen.get(cat);
1875
+ if (group) {
1876
+ ordered.push({
1877
+ category: cat,
1878
+ items: group
1879
+ });
1880
+ seen.delete(cat);
1881
+ }
1882
+ }
1883
+ for (const [category, group] of seen) ordered.push({
1884
+ category,
1885
+ items: group
1886
+ });
1887
+ return ordered;
1888
+ }
1889
+ function CommandItem({ item, selected, onSelect }) {
1890
+ return /* @__PURE__ */ jsxs("button", {
1891
+ "data-re-slash-command-item": "",
1892
+ "data-selected": selected || void 0,
1893
+ onClick: onSelect,
1894
+ type: "button",
1895
+ children: [item.icon, /* @__PURE__ */ jsx("span", { children: item.title })]
1896
+ });
1897
+ }
1898
+ function CommandList({ items, query, selectedIndex, onSelect }) {
1899
+ const containerRef = useRef(null);
1900
+ useLayoutEffect(() => {
1901
+ const container = containerRef.current;
1902
+ if (!container) return;
1903
+ const selected = container.querySelector("[data-selected]");
1904
+ if (selected) updateScrollView(container, selected);
1905
+ }, [selectedIndex]);
1906
+ if (items.length === 0) return /* @__PURE__ */ jsx("div", {
1907
+ "data-re-slash-command": "",
1908
+ children: /* @__PURE__ */ jsx("div", {
1909
+ "data-re-slash-command-empty": "",
1910
+ children: "No results"
1911
+ })
1912
+ });
1913
+ if (query.trim().length > 0) return /* @__PURE__ */ jsx("div", {
1914
+ "data-re-slash-command": "",
1915
+ ref: containerRef,
1916
+ children: items.map((item, index) => /* @__PURE__ */ jsx(CommandItem, {
1917
+ item,
1918
+ onSelect: () => onSelect(index),
1919
+ selected: index === selectedIndex
1920
+ }, item.title))
1921
+ });
1922
+ const groups = groupByCategory(items);
1923
+ let flatIndex = 0;
1924
+ return /* @__PURE__ */ jsx("div", {
1925
+ "data-re-slash-command": "",
1926
+ ref: containerRef,
1927
+ children: groups.map((group) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
1928
+ "data-re-slash-command-category": "",
1929
+ children: group.category
1930
+ }), group.items.map((item) => {
1931
+ const currentIndex = flatIndex++;
1932
+ return /* @__PURE__ */ jsx(CommandItem, {
1933
+ item,
1934
+ onSelect: () => onSelect(currentIndex),
1935
+ selected: currentIndex === selectedIndex
1936
+ }, item.title);
1937
+ })] }, group.category))
1938
+ });
1939
+ }
1940
+
1941
+ //#endregion
1942
+ //#region src/ui/slash-command/commands.tsx
1943
+ const TEXT = {
1944
+ title: "Text",
1945
+ description: "Plain text block",
1946
+ icon: /* @__PURE__ */ jsx(Text, { size: 20 }),
1947
+ category: "Text",
1948
+ searchTerms: ["p", "paragraph"],
1949
+ command: ({ editor, range }) => {
1950
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
1951
+ }
1952
+ };
1953
+ const H1 = {
1954
+ title: "Title",
1955
+ description: "Large heading",
1956
+ icon: /* @__PURE__ */ jsx(Heading1, { size: 20 }),
1957
+ category: "Text",
1958
+ searchTerms: [
1959
+ "title",
1960
+ "big",
1961
+ "large",
1962
+ "h1"
1963
+ ],
1964
+ command: ({ editor, range }) => {
1965
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
1966
+ }
1967
+ };
1968
+ const H2 = {
1969
+ title: "Subtitle",
1970
+ description: "Medium heading",
1971
+ icon: /* @__PURE__ */ jsx(Heading2, { size: 20 }),
1972
+ category: "Text",
1973
+ searchTerms: [
1974
+ "subtitle",
1975
+ "medium",
1976
+ "h2"
1977
+ ],
1978
+ command: ({ editor, range }) => {
1979
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
1980
+ }
1981
+ };
1982
+ const H3 = {
1983
+ title: "Heading",
1984
+ description: "Small heading",
1985
+ icon: /* @__PURE__ */ jsx(Heading3, { size: 20 }),
1986
+ category: "Text",
1987
+ searchTerms: [
1988
+ "subtitle",
1989
+ "small",
1990
+ "h3"
1991
+ ],
1992
+ command: ({ editor, range }) => {
1993
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
1994
+ }
1995
+ };
1996
+ const BULLET_LIST = {
1997
+ title: "Bullet list",
1998
+ description: "Unordered list",
1999
+ icon: /* @__PURE__ */ jsx(List, { size: 20 }),
2000
+ category: "Text",
2001
+ searchTerms: ["unordered", "point"],
2002
+ command: ({ editor, range }) => {
2003
+ editor.chain().focus().deleteRange(range).toggleBulletList().run();
2004
+ }
2005
+ };
2006
+ const NUMBERED_LIST = {
2007
+ title: "Numbered list",
2008
+ description: "Ordered list",
2009
+ icon: /* @__PURE__ */ jsx(ListOrdered, { size: 20 }),
2010
+ category: "Text",
2011
+ searchTerms: ["ordered"],
2012
+ command: ({ editor, range }) => {
2013
+ editor.chain().focus().deleteRange(range).toggleOrderedList().run();
2014
+ }
2015
+ };
2016
+ const QUOTE = {
2017
+ title: "Quote",
2018
+ description: "Block quote",
2019
+ icon: /* @__PURE__ */ jsx(TextQuote, { size: 20 }),
2020
+ category: "Text",
2021
+ searchTerms: ["blockquote"],
2022
+ command: ({ editor, range }) => {
2023
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run();
2024
+ }
2025
+ };
2026
+ const CODE = {
2027
+ title: "Code block",
2028
+ description: "Code snippet",
2029
+ icon: /* @__PURE__ */ jsx(SquareCode, { size: 20 }),
2030
+ category: "Text",
2031
+ searchTerms: ["codeblock"],
2032
+ command: ({ editor, range }) => {
2033
+ editor.chain().focus().deleteRange(range).toggleCodeBlock().run();
2034
+ }
2035
+ };
2036
+ const BUTTON = {
2037
+ title: "Button",
2038
+ description: "Clickable button",
2039
+ icon: /* @__PURE__ */ jsx(MousePointer, { size: 20 }),
2040
+ category: "Layout",
2041
+ searchTerms: ["button"],
2042
+ command: ({ editor, range }) => {
2043
+ editor.chain().focus().deleteRange(range).setButton().run();
2044
+ }
2045
+ };
2046
+ const DIVIDER = {
2047
+ title: "Divider",
2048
+ description: "Horizontal separator",
2049
+ icon: /* @__PURE__ */ jsx(SplitSquareVertical, { size: 20 }),
2050
+ category: "Layout",
2051
+ searchTerms: [
2052
+ "hr",
2053
+ "divider",
2054
+ "separator"
2055
+ ],
2056
+ command: ({ editor, range }) => {
2057
+ editor.chain().focus().deleteRange(range).setHorizontalRule().run();
2058
+ }
2059
+ };
2060
+ const SECTION = {
2061
+ title: "Section",
2062
+ description: "Content section",
2063
+ icon: /* @__PURE__ */ jsx(Rows2, { size: 20 }),
2064
+ category: "Layout",
2065
+ searchTerms: [
2066
+ "section",
2067
+ "row",
2068
+ "container"
2069
+ ],
2070
+ command: ({ editor, range }) => {
2071
+ editor.chain().focus().deleteRange(range).insertSection().run();
2072
+ }
2073
+ };
2074
+ const TWO_COLUMNS = {
2075
+ title: "2 columns",
2076
+ description: "Two column layout",
2077
+ icon: /* @__PURE__ */ jsx(Columns2, { size: 20 }),
2078
+ category: "Layout",
2079
+ searchTerms: [
2080
+ "columns",
2081
+ "column",
2082
+ "layout",
2083
+ "grid",
2084
+ "split",
2085
+ "side-by-side",
2086
+ "multi-column",
2087
+ "row",
2088
+ "two",
2089
+ "2"
2090
+ ],
2091
+ command: ({ editor, range }) => {
2092
+ editor.chain().focus().deleteRange(range).insertColumns(2).run();
2093
+ }
2094
+ };
2095
+ const THREE_COLUMNS = {
2096
+ title: "3 columns",
2097
+ description: "Three column layout",
2098
+ icon: /* @__PURE__ */ jsx(Columns3, { size: 20 }),
2099
+ category: "Layout",
2100
+ searchTerms: [
2101
+ "columns",
2102
+ "column",
2103
+ "layout",
2104
+ "grid",
2105
+ "split",
2106
+ "multi-column",
2107
+ "row",
2108
+ "three",
2109
+ "3"
2110
+ ],
2111
+ command: ({ editor, range }) => {
2112
+ editor.chain().focus().deleteRange(range).insertColumns(3).run();
2113
+ }
2114
+ };
2115
+ const FOUR_COLUMNS = {
2116
+ title: "4 columns",
2117
+ description: "Four column layout",
2118
+ icon: /* @__PURE__ */ jsx(Columns4, { size: 20 }),
2119
+ category: "Layout",
2120
+ searchTerms: [
2121
+ "columns",
2122
+ "column",
2123
+ "layout",
2124
+ "grid",
2125
+ "split",
2126
+ "multi-column",
2127
+ "row",
2128
+ "four",
2129
+ "4"
2130
+ ],
2131
+ command: ({ editor, range }) => {
2132
+ editor.chain().focus().deleteRange(range).insertColumns(4).run();
2133
+ }
2134
+ };
2135
+ const defaultSlashCommands = [
2136
+ TEXT,
2137
+ H1,
2138
+ H2,
2139
+ H3,
2140
+ BULLET_LIST,
2141
+ NUMBERED_LIST,
2142
+ QUOTE,
2143
+ CODE,
2144
+ BUTTON,
2145
+ DIVIDER,
2146
+ SECTION,
2147
+ TWO_COLUMNS,
2148
+ THREE_COLUMNS,
2149
+ FOUR_COLUMNS
2150
+ ];
2151
+
2152
+ //#endregion
2153
+ //#region src/ui/slash-command/search.ts
2154
+ function scoreItem(item, query) {
2155
+ if (!query) return 100;
2156
+ const q = query.toLowerCase();
2157
+ const title = item.title.toLowerCase();
2158
+ const description = item.description.toLowerCase();
2159
+ const terms = item.searchTerms?.map((t) => t.toLowerCase()) ?? [];
2160
+ if (title === q) return 100;
2161
+ if (title.startsWith(q)) return 90;
2162
+ if (title.split(/\s+/).some((w) => w.startsWith(q))) return 80;
2163
+ if (terms.some((t) => t === q)) return 70;
2164
+ if (terms.some((t) => t.startsWith(q))) return 60;
2165
+ if (title.includes(q)) return 40;
2166
+ if (terms.some((t) => t.includes(q))) return 30;
2167
+ if (description.includes(q)) return 20;
2168
+ return 0;
2169
+ }
2170
+ function filterAndRankItems(items, query) {
2171
+ const trimmed = query.trim();
2172
+ if (!trimmed) return items;
2173
+ const scored = items.map((item) => ({
2174
+ item,
2175
+ score: scoreItem(item, trimmed)
2176
+ })).filter(({ score }) => score > 0);
2177
+ scored.sort((a, b) => b.score - a.score);
2178
+ return scored.map(({ item }) => item);
2179
+ }
2180
+
2181
+ //#endregion
2182
+ //#region src/ui/slash-command/root.tsx
2183
+ const pluginKey = new PluginKey("slash-command");
2184
+ const INITIAL_STATE = {
2185
+ active: false,
2186
+ query: "",
2187
+ items: [],
2188
+ clientRect: null
2189
+ };
2190
+ function defaultFilterItems(items, query, editor) {
2191
+ return filterAndRankItems(isAtMaxColumnsDepth(editor) ? items.filter((item) => item.category !== "Layout" || !item.title.includes("column")) : items, query);
2192
+ }
2193
+ function SlashCommandRoot({ items: itemsProp, filterItems: filterItemsProp, char = "/", allow: allowProp, children }) {
2194
+ const { editor } = useCurrentEditor();
2195
+ const [state, setState] = useState(INITIAL_STATE);
2196
+ const [selectedIndex, setSelectedIndex] = useState(0);
2197
+ const itemsRef = useRef(itemsProp ?? defaultSlashCommands);
2198
+ const filterRef = useRef(filterItemsProp ?? defaultFilterItems);
2199
+ const allowRef = useRef(allowProp ?? (({ editor: e }) => !e.isActive("codeBlock")));
2200
+ itemsRef.current = itemsProp ?? defaultSlashCommands;
2201
+ filterRef.current = filterItemsProp ?? defaultFilterItems;
2202
+ allowRef.current = allowProp ?? (({ editor: e }) => !e.isActive("codeBlock"));
2203
+ const commandRef = useRef(null);
2204
+ const suggestionItemsRef = useRef([]);
2205
+ const selectedIndexRef = useRef(0);
2206
+ suggestionItemsRef.current = state.items;
2207
+ selectedIndexRef.current = selectedIndex;
2208
+ const { refs, floatingStyles } = useFloating({
2209
+ open: state.active,
2210
+ placement: "bottom-start",
2211
+ middleware: [
2212
+ offset(8),
2213
+ flip(),
2214
+ shift({ padding: 8 })
2215
+ ],
2216
+ whileElementsMounted: autoUpdate
2217
+ });
2218
+ useEffect(() => {
2219
+ if (!state.clientRect) return;
2220
+ refs.setReference({ getBoundingClientRect: state.clientRect });
2221
+ }, [state.clientRect, refs]);
2222
+ useEffect(() => {
2223
+ setSelectedIndex(0);
2224
+ }, [state.items]);
2225
+ const onSelect = useCallback((index) => {
2226
+ const item = suggestionItemsRef.current[index];
2227
+ if (item && commandRef.current) commandRef.current(item);
2228
+ }, []);
2229
+ useEffect(() => {
2230
+ if (!editor) return;
2231
+ const plugin = Suggestion({
2232
+ pluginKey,
2233
+ editor,
2234
+ char,
2235
+ allow: ({ editor: e }) => allowRef.current({ editor: e }),
2236
+ command: ({ editor: e, range, props }) => {
2237
+ props.command({
2238
+ editor: e,
2239
+ range
2240
+ });
2241
+ },
2242
+ items: ({ query, editor: e }) => filterRef.current(itemsRef.current, query, e),
2243
+ render: () => ({
2244
+ onStart: (props) => {
2245
+ commandRef.current = props.command;
2246
+ setState({
2247
+ active: true,
2248
+ query: props.query,
2249
+ items: props.items,
2250
+ clientRect: props.clientRect ?? null
2251
+ });
2252
+ },
2253
+ onUpdate: (props) => {
2254
+ commandRef.current = props.command;
2255
+ setState({
2256
+ active: true,
2257
+ query: props.query,
2258
+ items: props.items,
2259
+ clientRect: props.clientRect ?? null
2260
+ });
2261
+ },
2262
+ onKeyDown: ({ event }) => {
2263
+ if (event.key === "Escape") {
2264
+ setState(INITIAL_STATE);
2265
+ return true;
2266
+ }
2267
+ const items = suggestionItemsRef.current;
2268
+ if (items.length === 0) return false;
2269
+ if (event.key === "ArrowUp") {
2270
+ setSelectedIndex((i) => (i + items.length - 1) % items.length);
2271
+ return true;
2272
+ }
2273
+ if (event.key === "ArrowDown") {
2274
+ setSelectedIndex((i) => (i + 1) % items.length);
2275
+ return true;
2276
+ }
2277
+ if (event.key === "Enter") {
2278
+ const item = items[selectedIndexRef.current];
2279
+ if (item && commandRef.current) commandRef.current(item);
2280
+ return true;
2281
+ }
2282
+ return false;
2283
+ },
2284
+ onExit: () => {
2285
+ setState(INITIAL_STATE);
2286
+ requestAnimationFrame(() => {
2287
+ commandRef.current = null;
2288
+ });
2289
+ }
2290
+ })
2291
+ });
2292
+ editor.registerPlugin(plugin, (newPlugin, plugins) => [newPlugin, ...plugins]);
2293
+ return () => {
2294
+ editor.unregisterPlugin(pluginKey);
2295
+ };
2296
+ }, [editor, char]);
2297
+ if (!editor || !state.active) return null;
2298
+ const renderProps = {
2299
+ items: state.items,
2300
+ query: state.query,
2301
+ selectedIndex,
2302
+ onSelect
2303
+ };
2304
+ let content;
2305
+ if (children) content = children(renderProps);
2306
+ else content = /* @__PURE__ */ jsx(CommandList, { ...renderProps });
2307
+ return createPortal(/* @__PURE__ */ jsx("div", {
2308
+ ref: refs.setFloating,
2309
+ style: floatingStyles,
2310
+ children: content
2311
+ }), document.body);
2312
+ }
2313
+
2314
+ //#endregion
2315
+ export { BubbleMenuButtonForm as $, BubbleMenuImageEditLink as A, AlignRightIcon as At, BubbleMenuItalic as B, BubbleMenuLinkUnlink as C, Columns2 as Ct, BubbleMenuLinkEditLink as D, Check as Dt, BubbleMenuLinkForm as E, ChevronDown as Et, BubbleMenuNodeSelector as F, BubbleMenuAlignLeft as G, BubbleMenuCode as H, NodeSelectorContent as I, BubbleMenuButtonDefault as J, BubbleMenuAlignCenter as K, NodeSelectorRoot as L, BubbleMenuUppercase as M, AlignCenterIcon as Mt, BubbleMenuUnderline as N, BubbleMenuImageDefault as O, CaseUpperIcon as Ot, BubbleMenuStrike as P, BubbleMenuButtonToolbar as Q, NodeSelectorTrigger as R, BubbleMenuLinkDefault as S, Columns3 as St, BubbleMenuLinkOpenLink as T, CodeIcon as Tt, BubbleMenuBold as U, BubbleMenuItemGroup as V, BubbleMenuAlignRight as W, bubbleMenuTriggers as X, BubbleMenuRoot as Y, BubbleMenuButtonUnlink as Z, TWO_COLUMNS as _, Heading3 as _t, BUTTON as a, Text as at, isAtMaxColumnsDepth as b, ExternalLinkIcon as bt, FOUR_COLUMNS as c, SquareCode as ct, H3 as d, PencilIcon as dt, BubbleMenuButtonEditLink as et, NUMBERED_LIST as f, MousePointer as ft, THREE_COLUMNS as g, ItalicIcon as gt, TEXT as h, LinkIcon as ht, BULLET_LIST as i, TextQuote as it, BubbleMenuDefault as j, AlignLeftIcon as jt, BubbleMenuImageToolbar as k, BoldIcon as kt, H1 as l, SplitSquareVertical as lt, SECTION as m, List as mt, filterAndRankItems as n, UnlinkIcon as nt, CODE as o, TextIcon as ot, QUOTE as p, ListOrdered as pt, BubbleMenuItem as q, scoreItem as r, UnderlineIcon as rt, DIVIDER as s, StrikethroughIcon as st, SlashCommandRoot as t, useBubbleMenuContext as tt, H2 as u, Rows2 as ut, defaultSlashCommands as v, Heading2 as vt, BubbleMenuLinkToolbar as w, Code as wt, isInsideNode as x, Columns4 as xt, CommandList as y, Heading1 as yt, BubbleMenuLinkSelector as z };
2316
+ //# sourceMappingURL=root-pS4l8bVZ.mjs.map