@editora/react 1.0.1

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.
@@ -0,0 +1,1044 @@
1
+ import { jsx as l, jsxs as N, Fragment as F } from "react/jsx-runtime";
2
+ import ee, { useRef as E, useState as R, useEffect as T, useMemo as j } from "react";
3
+ import { KeyboardShortcutManager as _, PluginManager as te, Editor as ne } from "@editora/core";
4
+ const oe = ({
5
+ isOpen: e,
6
+ options: t,
7
+ onSelect: d,
8
+ onClose: c,
9
+ anchorRef: i,
10
+ className: r = ""
11
+ }) => {
12
+ const m = E(null), [f, g] = R({ top: 0, left: 0 });
13
+ return T(() => {
14
+ if (e && i.current) {
15
+ const o = i.current.getBoundingClientRect(), s = 120, h = t.length * 36;
16
+ let b = o.bottom + 4, u = o.left;
17
+ const v = window.innerWidth, p = window.innerHeight;
18
+ u + s > v && (u = v - s - 8), b + h > p && (b = o.top - h - 4), g({ top: b, left: u });
19
+ }
20
+ }, [e, i, t.length]), T(() => {
21
+ if (e && i.current && m.current) {
22
+ const o = i.current.getBoundingClientRect(), s = m.current.getBoundingClientRect();
23
+ let h = o.bottom + 4, b = o.left;
24
+ const u = window.innerWidth, v = window.innerHeight;
25
+ b + s.width > u && (b = u - s.width - 8), h + s.height > v && (h = o.top - s.height - 4), g({ top: h, left: b });
26
+ }
27
+ }, [e]), T(() => {
28
+ const o = (h) => {
29
+ m.current && !m.current.contains(h.target) && i.current && !i.current.contains(h.target) && c();
30
+ }, s = (h) => {
31
+ h.key === "Escape" && c();
32
+ };
33
+ return e && (document.addEventListener("mousedown", o), document.addEventListener("keydown", s)), () => {
34
+ document.removeEventListener("mousedown", o), document.removeEventListener("keydown", s);
35
+ };
36
+ }, [e, c, i]), e ? /* @__PURE__ */ l(
37
+ "div",
38
+ {
39
+ ref: m,
40
+ className: `rte-inline-menu ${r}`,
41
+ style: {
42
+ position: "fixed",
43
+ top: f.top,
44
+ left: f.left,
45
+ zIndex: 1e3,
46
+ background: "white",
47
+ border: "1px solid #ccc",
48
+ borderRadius: "4px",
49
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
50
+ minWidth: "120px",
51
+ maxWidth: "200px",
52
+ pointerEvents: "auto"
53
+ },
54
+ children: t.map((o) => /* @__PURE__ */ l(
55
+ "div",
56
+ {
57
+ className: "rte-inline-menu-item",
58
+ onClick: () => {
59
+ d(o.value), c();
60
+ },
61
+ style: {
62
+ padding: "8px 12px",
63
+ cursor: "pointer",
64
+ borderBottom: "1px solid #f0f0f0",
65
+ fontSize: "14px",
66
+ whiteSpace: "nowrap",
67
+ overflow: "hidden",
68
+ textOverflow: "ellipsis"
69
+ },
70
+ onMouseEnter: (s) => {
71
+ s.currentTarget.style.backgroundColor = "#f5f5f5";
72
+ },
73
+ onMouseLeave: (s) => {
74
+ s.currentTarget.style.backgroundColor = "transparent";
75
+ },
76
+ children: o.label
77
+ },
78
+ o.value
79
+ ))
80
+ }
81
+ ) : null;
82
+ }, V = ({
83
+ editor: e,
84
+ position: t = "top",
85
+ sticky: d = !1,
86
+ floating: c = !1
87
+ }) => {
88
+ const [i, r] = R(null), [m, f] = R(null), [g, o] = R(null), [s, h] = R(null), [b, u] = R(!1), v = E({}), p = E(null), y = E(null), C = E(null), w = e.pluginManager.getToolbarItems();
89
+ T(() => {
90
+ const n = () => {
91
+ if (!p.current || !y.current) return;
92
+ const W = p.current.clientWidth, H = 16, Y = 40, U = 4, Z = W - H - Y - U;
93
+ let q = 0, P = 0;
94
+ const $ = y.current.children;
95
+ for (let z = 0; z < $.length; z++) {
96
+ const K = $[z].offsetWidth + U;
97
+ if (q + K <= Z)
98
+ q += K, P++;
99
+ else
100
+ break;
101
+ }
102
+ h(Math.max(1, P));
103
+ }, a = requestAnimationFrame(() => {
104
+ n();
105
+ }), x = new ResizeObserver(() => {
106
+ n();
107
+ });
108
+ p.current && x.observe(p.current);
109
+ const S = new MutationObserver(() => {
110
+ n();
111
+ });
112
+ return y.current && S.observe(y.current, {
113
+ childList: !0,
114
+ subtree: !0
115
+ }), () => {
116
+ cancelAnimationFrame(a), x.disconnect(), S.disconnect();
117
+ };
118
+ }, [w.length]);
119
+ const L = (n) => (v.current[n] || (v.current[n] = ee.createRef()), v.current[n]), k = (n, a) => {
120
+ const x = p.current?.closest("[data-editora-editor]"), S = x?.querySelector(".rte-content");
121
+ if (S && S.focus(), g && (n === "setTextAlignment" || n === "setFontFamily" || n === "setBlockType")) {
122
+ const H = window.getSelection();
123
+ H && (H.removeAllRanges(), H.addRange(g)), o(null);
124
+ }
125
+ typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(n, a), r(null);
126
+ const W = x?.querySelector(".rte-content");
127
+ W && W.focus();
128
+ }, A = (n) => {
129
+ const a = window.getSelection();
130
+ a && a.rangeCount > 0 && o(a.getRangeAt(0).cloneRange()), r(i === n ? null : n);
131
+ }, M = (n) => {
132
+ const a = window.getSelection();
133
+ a && a.rangeCount > 0 && o(a.getRangeAt(0).cloneRange()), f(m === n ? null : n), r(null);
134
+ }, I = (n, a) => {
135
+ if (g) {
136
+ const x = window.getSelection();
137
+ x && (x.removeAllRanges(), x.addRange(g)), o(null);
138
+ }
139
+ k(n, a), f(null);
140
+ }, D = (n, a) => n && n.startsWith("<svg") && n.endsWith("</svg>") ? /* @__PURE__ */ l("span", { dangerouslySetInnerHTML: { __html: n } }) : n && n.length === 1 && /^[BIUSH]$/.test(n) ? /* @__PURE__ */ l("span", { style: { fontWeight: "bold", fontSize: "14px", lineHeight: "1" }, children: n }) : n || "⚪";
141
+ if (c)
142
+ return null;
143
+ const Q = {
144
+ ...d && {
145
+ position: "sticky",
146
+ top: 0,
147
+ zIndex: 100,
148
+ backgroundColor: "#fff",
149
+ boxShadow: "0 2px 4px rgba(0,0,0,0.1)"
150
+ },
151
+ ...t === "bottom" && {
152
+ order: 2
153
+ // Move to bottom in flex container
154
+ }
155
+ }, O = (n) => n.map((a, x) => /* @__PURE__ */ l(
156
+ "div",
157
+ {
158
+ className: "rte-toolbar-item",
159
+ style: {
160
+ display: s !== null && x >= s ? "none" : "flex"
161
+ },
162
+ children: a.type === "dropdown" ? /* @__PURE__ */ N("div", { className: "rte-toolbar-dropdown", children: [
163
+ /* @__PURE__ */ N(
164
+ "button",
165
+ {
166
+ className: "rte-toolbar-button",
167
+ "data-command": a.command,
168
+ "data-active": "false",
169
+ onClick: () => A(a.command),
170
+ children: [
171
+ a.label,
172
+ " ▼"
173
+ ]
174
+ }
175
+ ),
176
+ i === a.command && /* @__PURE__ */ l("div", { className: "rte-toolbar-dropdown-menu", children: a.options?.map((S) => /* @__PURE__ */ l(
177
+ "div",
178
+ {
179
+ className: "rte-toolbar-dropdown-item",
180
+ onClick: () => k(a.command, S.value),
181
+ children: S.label
182
+ },
183
+ S.value
184
+ )) })
185
+ ] }) : a.type === "inline-menu" ? /* @__PURE__ */ l(
186
+ "button",
187
+ {
188
+ ref: L(a.command),
189
+ className: "rte-toolbar-button",
190
+ "data-command": a.command,
191
+ "data-active": "false",
192
+ onClick: () => M(a.command),
193
+ title: a.label,
194
+ children: D(a.icon, a.command)
195
+ }
196
+ ) : a.type === "input" ? /* @__PURE__ */ l(
197
+ "input",
198
+ {
199
+ type: "text",
200
+ className: `rte-toolbar-input ${a.label.toLowerCase().replace(/\s+/g, "-")}`,
201
+ placeholder: a.placeholder,
202
+ onChange: (S) => k(a.command, S.target.value),
203
+ onKeyDown: (S) => {
204
+ S.key === "Enter" && k(
205
+ a.command,
206
+ S.target.value
207
+ );
208
+ },
209
+ title: a.label
210
+ }
211
+ ) : a.type === "group" ? /* @__PURE__ */ l(
212
+ "div",
213
+ {
214
+ className: `rte-toolbar-group-button ${a.label.toLowerCase().replace(/\s+/g, "-")}`,
215
+ title: `${a.label}`,
216
+ children: /* @__PURE__ */ l(
217
+ "div",
218
+ {
219
+ className: `rte-toolbar-group-items ${a.label.toLowerCase().replace(/\s+/g, "-")}`,
220
+ children: O(a.items || [])
221
+ }
222
+ )
223
+ }
224
+ ) : /* @__PURE__ */ l(
225
+ "button",
226
+ {
227
+ className: "rte-toolbar-button",
228
+ "data-command": a.command,
229
+ "data-active": "false",
230
+ onClick: () => k(a.command),
231
+ title: a.label,
232
+ children: D(a.icon, a.command)
233
+ }
234
+ )
235
+ },
236
+ x
237
+ ));
238
+ return /* @__PURE__ */ N(F, { children: [
239
+ /* @__PURE__ */ N("div", { className: "rte-toolbar-wrapper", style: Q, children: [
240
+ /* @__PURE__ */ N("div", { className: "rte-toolbar", ref: p, children: [
241
+ /* @__PURE__ */ l("div", { className: "rte-toolbar-items-container", ref: y, children: O(w) }),
242
+ s !== null && s < w.length && /* @__PURE__ */ l(
243
+ "button",
244
+ {
245
+ ref: C,
246
+ className: `rte-toolbar-more-button ${b ? "active" : ""}`,
247
+ onClick: () => u(!b),
248
+ title: "Show more options",
249
+ "aria-label": "More toolbar options",
250
+ children: "☰"
251
+ }
252
+ )
253
+ ] }),
254
+ s !== null && s < w.length && /* @__PURE__ */ l(
255
+ "div",
256
+ {
257
+ className: `rte-toolbar-expanded-row ${b ? "show" : ""}`,
258
+ children: w.map(
259
+ (n, a) => a >= (s || 0) && /* @__PURE__ */ l("div", { className: "rte-toolbar-item", children: n.type === "dropdown" ? /* @__PURE__ */ N("div", { className: "rte-toolbar-dropdown", children: [
260
+ /* @__PURE__ */ N(
261
+ "button",
262
+ {
263
+ className: "rte-toolbar-button",
264
+ "data-command": n.command,
265
+ "data-active": "false",
266
+ onClick: () => A(n.command),
267
+ children: [
268
+ n.label,
269
+ " ▼"
270
+ ]
271
+ }
272
+ ),
273
+ i === n.command && /* @__PURE__ */ l("div", { className: "rte-toolbar-dropdown-menu", children: n.options?.map((x) => /* @__PURE__ */ l(
274
+ "div",
275
+ {
276
+ className: "rte-toolbar-dropdown-item",
277
+ onClick: () => k(n.command, x.value),
278
+ children: x.label
279
+ },
280
+ x.value
281
+ )) })
282
+ ] }) : n.type === "inline-menu" ? /* @__PURE__ */ l(
283
+ "button",
284
+ {
285
+ ref: L(n.command),
286
+ className: "rte-toolbar-button",
287
+ "data-command": n.command,
288
+ "data-active": "false",
289
+ onClick: () => M(n.command),
290
+ title: n.label,
291
+ children: D(n.icon, n.command)
292
+ }
293
+ ) : n.type === "input" ? /* @__PURE__ */ l(
294
+ "input",
295
+ {
296
+ type: "text",
297
+ className: "rte-toolbar-input",
298
+ placeholder: n.placeholder,
299
+ onChange: (x) => k(n.command, x.target.value),
300
+ onKeyDown: (x) => {
301
+ x.key === "Enter" && k(
302
+ n.command,
303
+ x.target.value
304
+ );
305
+ },
306
+ title: n.label
307
+ }
308
+ ) : /* @__PURE__ */ l(
309
+ "button",
310
+ {
311
+ className: "rte-toolbar-button",
312
+ "data-command": n.command,
313
+ "data-active": "false",
314
+ onClick: () => k(n.command),
315
+ title: n.label,
316
+ children: D(n.icon, n.command)
317
+ }
318
+ ) }, a)
319
+ )
320
+ }
321
+ )
322
+ ] }),
323
+ w.map((n) => n.type === "inline-menu" ? /* @__PURE__ */ l(
324
+ oe,
325
+ {
326
+ isOpen: m === n.command,
327
+ options: n.options || [],
328
+ onSelect: (a) => I(n.command, a),
329
+ onClose: () => f(null),
330
+ anchorRef: L(n.command)
331
+ },
332
+ `menu-${n.command}`
333
+ ) : null)
334
+ ] });
335
+ };
336
+ function re(e, t) {
337
+ const d = E(), c = E("");
338
+ return T(() => {
339
+ if (!t?.enabled) return;
340
+ const r = t.intervalMs || 3e4, m = t.storageKey || "rte-autosave", f = t.provider || "localStorage", g = async () => {
341
+ const o = e();
342
+ if (o !== c.current) {
343
+ if (c.current = o, f === "localStorage")
344
+ try {
345
+ localStorage.setItem(m, o), localStorage.setItem(`${m}-timestamp`, Date.now().toString()), console.log("[Autosave] Content saved to localStorage");
346
+ } catch (s) {
347
+ console.error("[Autosave] Failed to save to localStorage:", s);
348
+ }
349
+ else if (f === "api" && t.apiUrl)
350
+ try {
351
+ await fetch(t.apiUrl, {
352
+ method: "POST",
353
+ headers: {
354
+ "Content-Type": "application/json"
355
+ },
356
+ body: JSON.stringify({ content: o, timestamp: Date.now() })
357
+ }), console.log("[Autosave] Content saved to API");
358
+ } catch (s) {
359
+ console.error("[Autosave] Failed to save to API:", s);
360
+ }
361
+ }
362
+ };
363
+ return d.current = setInterval(g, r), () => {
364
+ d.current && clearInterval(d.current);
365
+ };
366
+ }, [t?.enabled, t?.intervalMs, t?.storageKey, t?.provider, t?.apiUrl, e]), { restore: () => {
367
+ if (!t?.enabled) return null;
368
+ const r = t.storageKey || "rte-autosave";
369
+ if ((t.provider || "localStorage") === "localStorage")
370
+ try {
371
+ const f = localStorage.getItem(r), g = localStorage.getItem(`${r}-timestamp`);
372
+ if (f && g)
373
+ return console.log("[Autosave] Restored from localStorage, saved at:", new Date(parseInt(g))), f;
374
+ } catch (f) {
375
+ console.error("[Autosave] Failed to restore from localStorage:", f);
376
+ }
377
+ return null;
378
+ } };
379
+ }
380
+ const ae = [
381
+ "p",
382
+ "br",
383
+ "strong",
384
+ "em",
385
+ "u",
386
+ "s",
387
+ "b",
388
+ "i",
389
+ "h1",
390
+ "h2",
391
+ "h3",
392
+ "h4",
393
+ "h5",
394
+ "h6",
395
+ "ul",
396
+ "ol",
397
+ "li",
398
+ "a",
399
+ "img",
400
+ "video",
401
+ "audio",
402
+ "table",
403
+ "thead",
404
+ "tbody",
405
+ "tr",
406
+ "th",
407
+ "td",
408
+ "blockquote",
409
+ "pre",
410
+ "code",
411
+ "span",
412
+ "div",
413
+ "sup",
414
+ "sub",
415
+ "hr"
416
+ ], le = {
417
+ "*": ["class", "style", "id", "data-*"],
418
+ a: ["href", "target", "rel", "title"],
419
+ img: ["src", "alt", "width", "height", "loading"],
420
+ video: ["src", "controls", "width", "height", "autoplay", "loop", "muted"],
421
+ audio: ["src", "controls", "autoplay", "loop", "muted"],
422
+ table: ["border", "cellpadding", "cellspacing"],
423
+ td: ["colspan", "rowspan", "align", "valign"],
424
+ th: ["colspan", "rowspan", "align", "valign"]
425
+ };
426
+ function G(e, t, d) {
427
+ if (t?.sanitize === !1)
428
+ return e;
429
+ const c = t?.allowedTags && t.allowedTags.length > 0 ? t.allowedTags : ae, i = t?.allowedAttributes || le, r = document.createElement("div");
430
+ return r.innerHTML = e, X(r, c, i), r.innerHTML;
431
+ }
432
+ function X(e, t, d) {
433
+ const c = Array.from(e.childNodes);
434
+ for (const i of c)
435
+ if (i.nodeType === Node.ELEMENT_NODE) {
436
+ const r = i, m = r.tagName.toLowerCase();
437
+ if (!t.includes(m)) {
438
+ for (; r.firstChild; )
439
+ e.insertBefore(r.firstChild, r);
440
+ e.removeChild(r);
441
+ continue;
442
+ }
443
+ ie(r, d), X(r, t, d);
444
+ } else {
445
+ if (i.nodeType === Node.TEXT_NODE)
446
+ continue;
447
+ e.removeChild(i);
448
+ }
449
+ }
450
+ function ie(e, t) {
451
+ const d = e.tagName.toLowerCase(), c = Array.from(e.attributes), i = t[d] || [], r = t["*"] || [], m = [...i, ...r];
452
+ for (const f of c) {
453
+ const g = f.name.toLowerCase();
454
+ let o = !1;
455
+ m.includes(g) && (o = !0);
456
+ for (const s of m)
457
+ if (s.endsWith("*")) {
458
+ const h = s.slice(0, -1);
459
+ if (g.startsWith(h)) {
460
+ o = !0;
461
+ break;
462
+ }
463
+ }
464
+ (g.startsWith("on") || // Event handlers
465
+ g === "javascript:" || g === "href" && f.value.trim().toLowerCase().startsWith("javascript:") || g === "src" && f.value.trim().toLowerCase().startsWith("javascript:")) && (o = !1), o || e.removeAttribute(f.name);
466
+ }
467
+ e.hasAttribute("href") && (e.getAttribute("href") || "").trim().toLowerCase().startsWith("javascript:") && e.removeAttribute("href"), e.hasAttribute("src") && (e.getAttribute("src") || "").trim().toLowerCase().startsWith("javascript:") && e.removeAttribute("src");
468
+ }
469
+ function ce(e, t, d) {
470
+ return d?.sanitizeOnPaste === !1 ? e : G(e, t);
471
+ }
472
+ function se(e, t, d) {
473
+ return d?.sanitizeOnInput === !1 ? e : G(e, t);
474
+ }
475
+ const de = ({
476
+ editor: e,
477
+ defaultValue: t,
478
+ value: d,
479
+ onChange: c,
480
+ pasteConfig: i,
481
+ contentConfig: r,
482
+ securityConfig: m,
483
+ performanceConfig: f,
484
+ autosaveConfig: g
485
+ }) => {
486
+ const o = E(null), s = d !== void 0, h = E(), { restore: b } = re(
487
+ () => o.current?.innerHTML || "",
488
+ g
489
+ );
490
+ return T(() => {
491
+ if (!o.current) return;
492
+ const u = b(), v = u || d || t;
493
+ v && o.current.innerHTML !== v && (o.current.innerHTML = v, u && c && c(u));
494
+ }, []), T(() => {
495
+ !o.current || !s || d !== o.current.innerHTML && (o.current.innerHTML = d);
496
+ }, [d, s]), T(() => {
497
+ if (!o.current) return;
498
+ const u = () => {
499
+ if (!o.current || !c) return;
500
+ let C = o.current.innerHTML;
501
+ if (m?.sanitizeOnInput !== !1 && r?.sanitize !== !1 && (C = se(C, r, m), C !== o.current.innerHTML)) {
502
+ const w = window.getSelection(), L = w && w.rangeCount > 0 ? w.getRangeAt(0) : null;
503
+ if (o.current.innerHTML = C, L && w)
504
+ try {
505
+ w.removeAllRanges(), w.addRange(L);
506
+ } catch {
507
+ }
508
+ }
509
+ f?.debounceInputMs ? (h.current && clearTimeout(h.current), h.current = setTimeout(() => {
510
+ c(C);
511
+ }, f.debounceInputMs)) : c(C);
512
+ }, v = (C) => {
513
+ C.preventDefault();
514
+ let w = C.clipboardData?.getData("text/html");
515
+ const L = C.clipboardData?.getData("text/plain");
516
+ if (i?.clean || !i?.keepFormatting) {
517
+ L && document.execCommand("insertText", !1, L);
518
+ return;
519
+ }
520
+ if (w) {
521
+ m?.sanitizeOnPaste !== !1 && r?.sanitize !== !1 && (w = ce(w, r, m));
522
+ const k = window.getSelection();
523
+ if (k && k.rangeCount > 0) {
524
+ const A = k.getRangeAt(0);
525
+ A.deleteContents();
526
+ const M = document.createElement("div");
527
+ M.innerHTML = w;
528
+ const I = document.createDocumentFragment();
529
+ for (; M.firstChild; )
530
+ I.appendChild(M.firstChild);
531
+ A.insertNode(I), A.collapse(!1), k.removeAllRanges(), k.addRange(A);
532
+ }
533
+ } else L && document.execCommand("insertText", !1, L);
534
+ }, p = (C) => {
535
+ const w = C.target;
536
+ (w.tagName === "IMG" || w.tagName === "VIDEO") && (w.style.resize = "both", w.style.overflow = "auto", w.style.display = "inline-block");
537
+ }, y = o.current;
538
+ return y.addEventListener("input", u), y.addEventListener("paste", v), y.addEventListener("click", p), y.focus(), () => {
539
+ h.current && clearTimeout(h.current), y.removeEventListener("input", u), y.removeEventListener("paste", v), y.removeEventListener("click", p);
540
+ };
541
+ }, [e, c, i, r, m, f]), T(() => {
542
+ if (!o.current || typeof window > "u") return;
543
+ const u = new _(), v = o.current, p = (y) => {
544
+ u.handleKeyDown(y, (C, w) => {
545
+ typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(C, w);
546
+ });
547
+ };
548
+ return v.addEventListener("keydown", p), () => {
549
+ v.removeEventListener("keydown", p);
550
+ };
551
+ }, []), /* @__PURE__ */ l(
552
+ "div",
553
+ {
554
+ ref: o,
555
+ contentEditable: !0,
556
+ suppressContentEditableWarning: !0,
557
+ className: "rte-content",
558
+ style: {
559
+ minHeight: "200px",
560
+ maxHeight: "100%",
561
+ padding: "16px",
562
+ outline: "none",
563
+ border: "1px solid #ddd",
564
+ borderRadius: "4px",
565
+ fontSize: "14px",
566
+ lineHeight: "1.5",
567
+ overflow: "auto",
568
+ flex: 1,
569
+ boxSizing: "border-box",
570
+ wordWrap: "break-word",
571
+ overflowWrap: "break-word"
572
+ },
573
+ children: /* @__PURE__ */ l("p", { children: /* @__PURE__ */ l("br", {}) })
574
+ }
575
+ );
576
+ }, ue = ({
577
+ editor: e,
578
+ isEnabled: t
579
+ }) => {
580
+ const [d, c] = R(!1), [i, r] = R({ top: 0, left: 0 }), m = E(null), f = E(null), g = E(null), o = E(null);
581
+ T(() => {
582
+ if (!t) {
583
+ c(!1);
584
+ return;
585
+ }
586
+ o.current = m.current?.closest("[data-editora-editor]");
587
+ const h = () => {
588
+ g.current && clearTimeout(g.current);
589
+ const u = window.getSelection();
590
+ if (!u || u.rangeCount === 0) {
591
+ c(!1), f.current = null;
592
+ return;
593
+ }
594
+ const v = u.getRangeAt(0), p = u.toString().trim(), y = o.current?.querySelector(".rte-content");
595
+ if (!y || !y.contains(v.commonAncestorContainer)) {
596
+ c(!1), f.current = null;
597
+ return;
598
+ }
599
+ if (p.length > 0) {
600
+ const C = v.getBoundingClientRect(), w = y.getBoundingClientRect(), L = 300;
601
+ if (C && w) {
602
+ const k = C.top - 50;
603
+ let A = C.left + C.width / 2;
604
+ const M = L / 2, I = w.left, D = w.right;
605
+ A - M < I && (A = I + M + 10), A + M > D && (A = D - M - 10), r({ top: k, left: A }), g.current = setTimeout(() => {
606
+ c(!0), f.current = v.cloneRange();
607
+ }, 300);
608
+ }
609
+ } else
610
+ c(!1), f.current = null;
611
+ }, b = (u) => {
612
+ m.current && !m.current.contains(u.target) && (window.getSelection(), o.current?.querySelector(".rte-content")?.contains(u.target) || (c(!1), f.current = null));
613
+ };
614
+ return document.addEventListener("selectionchange", h), document.addEventListener("mousedown", b), document.addEventListener("keydown", (u) => {
615
+ u.key === "Escape" && (c(!1), f.current = null);
616
+ }), () => {
617
+ document.removeEventListener("selectionchange", h), document.removeEventListener("mousedown", b), g.current && clearTimeout(g.current);
618
+ };
619
+ }, [t]);
620
+ const s = (h, b) => {
621
+ if (!f.current) return;
622
+ const u = o.current?.querySelector(".rte-content");
623
+ u && u.focus(), {
624
+ toggleBold: () => document.execCommand("bold", !1),
625
+ toggleItalic: () => document.execCommand("italic", !1),
626
+ toggleUnderline: () => document.execCommand("underline", !1),
627
+ toggleStrikethrough: () => document.execCommand("strikeThrough", !1),
628
+ createLink: () => {
629
+ typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand("openLinkDialog");
630
+ },
631
+ clearFormatting: () => {
632
+ document.execCommand("removeFormat", !1), document.execCommand("unlink", !1);
633
+ },
634
+ toggleCode: () => {
635
+ const p = window.getSelection();
636
+ if (p && p.rangeCount > 0) {
637
+ const y = p.getRangeAt(0), C = document.createElement("code");
638
+ y.surroundContents(C);
639
+ }
640
+ },
641
+ setBlockType: () => {
642
+ if (b === "blockquote") {
643
+ const p = window.getSelection();
644
+ if (p && p.rangeCount > 0) {
645
+ const y = p.getRangeAt(0);
646
+ (y.commonAncestorContainer.nodeType === Node.TEXT_NODE ? y.commonAncestorContainer.parentElement : y.commonAncestorContainer)?.closest?.("blockquote") ? document.execCommand("formatBlock", !1, "p") : document.execCommand("formatBlock", !1, "blockquote");
647
+ }
648
+ } else b && document.execCommand("formatBlock", !1, b);
649
+ }
650
+ }[h]?.(), c(!1), f.current = null, u && u.focus();
651
+ };
652
+ return !t || !d ? null : /* @__PURE__ */ N(
653
+ "div",
654
+ {
655
+ ref: m,
656
+ className: "floating-toolbar",
657
+ style: {
658
+ position: "fixed",
659
+ top: `${i.top}px`,
660
+ left: `${i.left}px`,
661
+ transform: "translateX(-50%)",
662
+ zIndex: 1e3,
663
+ background: "white",
664
+ border: "1px solid #e1e5e9",
665
+ borderRadius: "6px",
666
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
667
+ padding: "6px",
668
+ display: "flex",
669
+ gap: "4px",
670
+ alignItems: "center"
671
+ },
672
+ children: [
673
+ /* @__PURE__ */ l(
674
+ "button",
675
+ {
676
+ className: "floating-toolbar-btn",
677
+ onClick: () => s("toggleBold"),
678
+ title: "Bold (Ctrl+B)",
679
+ children: /* @__PURE__ */ l("strong", { children: "B" })
680
+ }
681
+ ),
682
+ /* @__PURE__ */ l(
683
+ "button",
684
+ {
685
+ className: "floating-toolbar-btn",
686
+ onClick: () => s("toggleItalic"),
687
+ title: "Italic (Ctrl+I)",
688
+ children: /* @__PURE__ */ l("em", { children: "I" })
689
+ }
690
+ ),
691
+ /* @__PURE__ */ l(
692
+ "button",
693
+ {
694
+ className: "floating-toolbar-btn",
695
+ onClick: () => s("toggleUnderline"),
696
+ title: "Underline (Ctrl+U)",
697
+ children: /* @__PURE__ */ l("u", { children: "U" })
698
+ }
699
+ ),
700
+ /* @__PURE__ */ l(
701
+ "button",
702
+ {
703
+ className: "floating-toolbar-btn",
704
+ onClick: () => s("toggleStrikethrough"),
705
+ title: "Strikethrough",
706
+ children: /* @__PURE__ */ l("s", { children: "S" })
707
+ }
708
+ ),
709
+ /* @__PURE__ */ l("div", { className: "floating-toolbar-separator" }),
710
+ /* @__PURE__ */ l(
711
+ "button",
712
+ {
713
+ className: "floating-toolbar-btn",
714
+ onClick: () => s("clearFormatting"),
715
+ title: "Clear Formatting",
716
+ children: "⌫"
717
+ }
718
+ ),
719
+ /* @__PURE__ */ l(
720
+ "button",
721
+ {
722
+ className: "floating-toolbar-btn",
723
+ onClick: () => s("createLink"),
724
+ title: "Insert Link",
725
+ children: "🔗"
726
+ }
727
+ ),
728
+ /* @__PURE__ */ l(
729
+ "button",
730
+ {
731
+ className: "floating-toolbar-btn",
732
+ onClick: () => s("toggleCode"),
733
+ title: "Code",
734
+ children: "Code"
735
+ }
736
+ ),
737
+ /* @__PURE__ */ l("div", { className: "floating-toolbar-separator" }),
738
+ /* @__PURE__ */ l(
739
+ "button",
740
+ {
741
+ className: "floating-toolbar-btn",
742
+ onClick: () => s("setBlockType", "blockquote"),
743
+ title: "Quote",
744
+ children: "❝"
745
+ }
746
+ )
747
+ ]
748
+ }
749
+ );
750
+ }, fe = ({
751
+ plugins: e,
752
+ children: t
753
+ }) => {
754
+ const d = e.filter((i) => i.context?.provider);
755
+ return d.length === 0 ? /* @__PURE__ */ l(F, { children: t }) : d.reduce(
756
+ (i, r) => {
757
+ const m = r.context.provider;
758
+ return /* @__PURE__ */ l(m, { children: i }, r.name);
759
+ },
760
+ /* @__PURE__ */ l(F, { children: t })
761
+ );
762
+ }, me = {
763
+ toolbar: {
764
+ items: [],
765
+ floating: !1,
766
+ sticky: !1
767
+ },
768
+ menubar: {
769
+ enabled: !1,
770
+ items: []
771
+ },
772
+ contextMenu: {
773
+ enabled: !0
774
+ },
775
+ media: {
776
+ uploadUrl: "",
777
+ libraryUrl: "",
778
+ maxFileSize: 10 * 1024 * 1024,
779
+ // 10MB
780
+ allowedTypes: ["image/jpeg", "image/png", "image/gif", "image/webp"],
781
+ headers: {},
782
+ withCredentials: !1
783
+ },
784
+ paste: {
785
+ clean: !0,
786
+ keepFormatting: !1,
787
+ convertWord: !0
788
+ },
789
+ history: {
790
+ maxSteps: 100,
791
+ debounceMs: 300
792
+ },
793
+ language: {
794
+ locale: "en",
795
+ direction: "ltr"
796
+ },
797
+ spellcheck: {
798
+ enabled: !1,
799
+ provider: "browser",
800
+ apiUrl: "",
801
+ apiHeaders: {}
802
+ },
803
+ autosave: {
804
+ enabled: !1,
805
+ intervalMs: 3e4,
806
+ // 30 seconds
807
+ storageKey: "rte-autosave",
808
+ provider: "localStorage",
809
+ apiUrl: ""
810
+ },
811
+ accessibility: {
812
+ enableARIA: !0,
813
+ keyboardNavigation: !0,
814
+ checker: !1
815
+ },
816
+ performance: {
817
+ debounceInputMs: 100,
818
+ viewportOnlyScan: !0
819
+ },
820
+ content: {
821
+ allowedTags: [],
822
+ allowedAttributes: {},
823
+ sanitize: !0
824
+ },
825
+ security: {
826
+ sanitizeOnPaste: !0,
827
+ sanitizeOnInput: !0
828
+ }
829
+ };
830
+ function J(e, t) {
831
+ const d = { ...e };
832
+ for (const c in t) {
833
+ const i = t[c], r = d[c];
834
+ i !== void 0 && (typeof i == "object" && i !== null && !Array.isArray(i) && typeof r == "object" && r !== null && !Array.isArray(r) ? d[c] = J(r, i) : d[c] = i);
835
+ }
836
+ return d;
837
+ }
838
+ function ge(e) {
839
+ const t = J(me, {
840
+ toolbar: e.toolbar,
841
+ menubar: e.menubar,
842
+ contextMenu: e.contextMenu,
843
+ media: e.media,
844
+ paste: e.paste,
845
+ history: e.history,
846
+ language: e.language,
847
+ spellcheck: e.spellcheck,
848
+ autosave: e.autosave,
849
+ accessibility: e.accessibility,
850
+ performance: e.performance,
851
+ content: e.content,
852
+ security: e.security
853
+ });
854
+ return e.floatingToolbar !== void 0 && (t.toolbar = {
855
+ ...t.toolbar,
856
+ floating: e.floatingToolbar.enabled ?? t.toolbar.floating
857
+ }), e.mediaConfig && (t.media = {
858
+ ...t.media,
859
+ uploadUrl: e.mediaConfig.uploadUrl || t.media.uploadUrl,
860
+ libraryUrl: e.mediaConfig.libraryUrl || t.media.libraryUrl,
861
+ maxFileSize: e.mediaConfig.maxFileSize || t.media.maxFileSize,
862
+ allowedTypes: e.mediaConfig.allowedTypes || t.media.allowedTypes
863
+ }), {
864
+ ...t,
865
+ id: e.id,
866
+ className: e.className,
867
+ value: e.value,
868
+ defaultValue: e.defaultValue,
869
+ onChange: e.onChange,
870
+ onInit: e.onInit,
871
+ onDestroy: e.onDestroy,
872
+ plugins: Array.isArray(e.plugins) ? e.plugins.filter((c) => typeof c != "string") : [],
873
+ pluginConfig: e.pluginConfig || {}
874
+ };
875
+ }
876
+ const B = /* @__PURE__ */ new Map();
877
+ typeof window < "u" && (window.registerEditorCommand = (e, t) => {
878
+ B.set(e, t);
879
+ }, window.executeEditorCommand = (e, t) => {
880
+ const d = B.get(e);
881
+ return d ? d(t) : (console.warn(`No handler registered for command: ${e}`), !1);
882
+ });
883
+ const be = (e) => {
884
+ const t = j(() => ge(e), [
885
+ e.id,
886
+ e.className,
887
+ e.value,
888
+ e.defaultValue,
889
+ e.plugins,
890
+ e.toolbar,
891
+ e.menubar,
892
+ e.contextMenu,
893
+ e.media,
894
+ e.paste,
895
+ e.history,
896
+ e.language,
897
+ e.spellcheck,
898
+ e.autosave,
899
+ e.accessibility,
900
+ e.performance,
901
+ e.content,
902
+ e.security,
903
+ e.floatingToolbar,
904
+ e.mediaConfig
905
+ ]), d = E(null), c = E(null), i = E(e.onInit), r = E(e.onDestroy), m = E(null);
906
+ T(() => {
907
+ i.current = e.onInit, r.current = e.onDestroy;
908
+ });
909
+ const f = j(() => {
910
+ const h = new te();
911
+ t.plugins.forEach((u) => {
912
+ h.register(u), u.commands && typeof window < "u" && Object.entries(u.commands).forEach(([v, p]) => {
913
+ B.set(v, p);
914
+ });
915
+ });
916
+ const b = new ne(h);
917
+ return d.current = b, b;
918
+ }, [t.plugins]);
919
+ T(() => {
920
+ const h = {
921
+ getHTML: () => m.current?.querySelector(".rte-content")?.innerHTML || "",
922
+ setHTML: (b) => {
923
+ const u = m.current?.querySelector(".rte-content");
924
+ u && (u.innerHTML = b);
925
+ },
926
+ execCommand: (b, u) => {
927
+ typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(b, u);
928
+ },
929
+ registerCommand: (b, u) => {
930
+ typeof window < "u" && window.registerEditorCommand && window.registerEditorCommand(b, u);
931
+ },
932
+ focus: () => {
933
+ m.current?.querySelector(".rte-content")?.focus();
934
+ },
935
+ blur: () => {
936
+ m.current?.querySelector(".rte-content")?.blur();
937
+ },
938
+ destroy: () => {
939
+ r.current && r.current();
940
+ },
941
+ onChange: (b) => () => {
942
+ },
943
+ getState: () => ({
944
+ plugins: t.plugins,
945
+ config: t
946
+ }),
947
+ toolbar: {
948
+ items: f.toolbar?.items || []
949
+ }
950
+ };
951
+ return c.current = h, i.current && i.current(h), () => {
952
+ r.current && r.current();
953
+ };
954
+ }, []);
955
+ const g = t.toolbar.floating ?? !1, o = t.toolbar.position || "top", s = t.toolbar.sticky ?? !1;
956
+ return /* @__PURE__ */ l(fe, { plugins: t.plugins, children: /* @__PURE__ */ N(
957
+ "div",
958
+ {
959
+ ref: m,
960
+ id: t.id,
961
+ "data-editora-editor": !0,
962
+ className: `rte-editor ${t.className || ""}`,
963
+ dir: t.language.direction,
964
+ style: {
965
+ display: "flex",
966
+ flexDirection: "column",
967
+ height: "100%"
968
+ },
969
+ children: [
970
+ o !== "bottom" && /* @__PURE__ */ l(
971
+ V,
972
+ {
973
+ editor: f,
974
+ position: o,
975
+ sticky: s,
976
+ floating: g
977
+ }
978
+ ),
979
+ /* @__PURE__ */ l(
980
+ de,
981
+ {
982
+ editor: f,
983
+ defaultValue: t.defaultValue,
984
+ value: t.value,
985
+ onChange: t.onChange,
986
+ pasteConfig: t.paste,
987
+ contentConfig: t.content,
988
+ securityConfig: t.security,
989
+ performanceConfig: t.performance,
990
+ autosaveConfig: t.autosave
991
+ }
992
+ ),
993
+ o === "bottom" && /* @__PURE__ */ l(
994
+ V,
995
+ {
996
+ editor: f,
997
+ position: o,
998
+ sticky: s,
999
+ floating: g
1000
+ }
1001
+ ),
1002
+ /* @__PURE__ */ l(
1003
+ ue,
1004
+ {
1005
+ editor: f,
1006
+ isEnabled: g
1007
+ }
1008
+ )
1009
+ ]
1010
+ }
1011
+ ) });
1012
+ }, ye = (e) => /* @__PURE__ */ l(be, { ...e });
1013
+ function Ce(e = {}) {
1014
+ const t = E(null), d = E(e.onCommand);
1015
+ return T(() => {
1016
+ d.current = e.onCommand;
1017
+ }), T(() => {
1018
+ if (typeof window > "u" || e.enabled === !1) return;
1019
+ const c = new _(e);
1020
+ t.current = c;
1021
+ const i = (m) => c.handleKeyDown(m, (g, o) => {
1022
+ d.current && d.current(g, o), typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(g, o);
1023
+ }), r = e.editorElement || document;
1024
+ return r && r.addEventListener("keydown", i), () => {
1025
+ r && r.removeEventListener("keydown", i);
1026
+ };
1027
+ }, [e.editorElement, e.enabled, e.shortcuts, e.customShortcuts]), {
1028
+ getShortcuts: () => t.current?.getAllShortcuts() || [],
1029
+ getShortcutForCommand: (c) => t.current?.getShortcutForCommand(c),
1030
+ getShortcutsHelp: () => t.current?.getShortcutsHelp() || "",
1031
+ enable: () => t.current?.enable(),
1032
+ disable: () => t.current?.disable(),
1033
+ isEnabled: () => t.current?.isEnabled() || !1
1034
+ };
1035
+ }
1036
+ export {
1037
+ de as EditorContent,
1038
+ ye as EditoraEditor,
1039
+ oe as InlineMenu,
1040
+ ye as RichTextEditor,
1041
+ V as Toolbar,
1042
+ ge as mergeConfig,
1043
+ Ce as useKeyboardShortcuts
1044
+ };