@editora/core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +9 -0
  2. package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs +475 -0
  3. package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs.map +1 -0
  4. package/dist/AnchorPlugin.native-7es9PVZ9.mjs +340 -0
  5. package/dist/AnchorPlugin.native-7es9PVZ9.mjs.map +1 -0
  6. package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs +449 -0
  7. package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs.map +1 -0
  8. package/dist/BlockquotePlugin.native-JFmOLsxN.mjs +48 -0
  9. package/dist/BlockquotePlugin.native-JFmOLsxN.mjs.map +1 -0
  10. package/dist/BoldPlugin.native-BAzzoqU5.mjs +45 -0
  11. package/dist/BoldPlugin.native-BAzzoqU5.mjs.map +1 -0
  12. package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs +79 -0
  13. package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs.map +1 -0
  14. package/dist/ChecklistPlugin.native-Dccs3nLe.mjs +153 -0
  15. package/dist/ChecklistPlugin.native-Dccs3nLe.mjs.map +1 -0
  16. package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs +27 -0
  17. package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs.map +1 -0
  18. package/dist/CodePlugin.native-DD9xFIid.mjs +1679 -0
  19. package/dist/CodePlugin.native-DD9xFIid.mjs.map +1 -0
  20. package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs +326 -0
  21. package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs.map +1 -0
  22. package/dist/CommentsPlugin.native-2zQV8Ia4.mjs +473 -0
  23. package/dist/CommentsPlugin.native-2zQV8Ia4.mjs.map +1 -0
  24. package/dist/DirectionPlugin.native-Be7wCzkI.mjs +59 -0
  25. package/dist/DirectionPlugin.native-Be7wCzkI.mjs.map +1 -0
  26. package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs +116 -0
  27. package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs.map +1 -0
  28. package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs +461 -0
  29. package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs.map +1 -0
  30. package/dist/EmojisPlugin.native-D6mJSnSR.mjs +1033 -0
  31. package/dist/EmojisPlugin.native-D6mJSnSR.mjs.map +1 -0
  32. package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs +106 -0
  33. package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs.map +1 -0
  34. package/dist/FontSizePlugin.native-DkLMLPue.mjs +186 -0
  35. package/dist/FontSizePlugin.native-DkLMLPue.mjs.map +1 -0
  36. package/dist/FootnotePlugin.native-BciVc9W6.mjs +128 -0
  37. package/dist/FootnotePlugin.native-BciVc9W6.mjs.map +1 -0
  38. package/dist/FullscreenPlugin.native-ChXyxeNw.mjs +77 -0
  39. package/dist/FullscreenPlugin.native-ChXyxeNw.mjs.map +1 -0
  40. package/dist/HeadingPlugin.native-DrLYwQnQ.mjs +64 -0
  41. package/dist/HeadingPlugin.native-DrLYwQnQ.mjs.map +1 -0
  42. package/dist/HistoryPlugin.native-DoDRifCf.mjs +89 -0
  43. package/dist/HistoryPlugin.native-DoDRifCf.mjs.map +1 -0
  44. package/dist/IndentPlugin.native-CbFugPoi.mjs +133 -0
  45. package/dist/IndentPlugin.native-CbFugPoi.mjs.map +1 -0
  46. package/dist/ItalicPlugin.native-CQjjDyUL.mjs +43 -0
  47. package/dist/ItalicPlugin.native-CQjjDyUL.mjs.map +1 -0
  48. package/dist/LineHeightPlugin.native-CWQT2FIa.mjs +73 -0
  49. package/dist/LineHeightPlugin.native-CWQT2FIa.mjs.map +1 -0
  50. package/dist/LinkPlugin.native-BdAOV-iu.mjs +206 -0
  51. package/dist/LinkPlugin.native-BdAOV-iu.mjs.map +1 -0
  52. package/dist/ListPlugin.native-CLFU5AUQ.mjs +59 -0
  53. package/dist/ListPlugin.native-CLFU5AUQ.mjs.map +1 -0
  54. package/dist/MathPlugin.native-DE_ii-LA.mjs +182 -0
  55. package/dist/MathPlugin.native-DE_ii-LA.mjs.map +1 -0
  56. package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs +533 -0
  57. package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs.map +1 -0
  58. package/dist/MergeTagPlugin.native-CrxyThyn.mjs +178 -0
  59. package/dist/MergeTagPlugin.native-CrxyThyn.mjs.map +1 -0
  60. package/dist/PageBreakPlugin.native-DDjcDyRW.mjs +172 -0
  61. package/dist/PageBreakPlugin.native-DDjcDyRW.mjs.map +1 -0
  62. package/dist/PreviewPlugin.native-DBvfpmIv.mjs +322 -0
  63. package/dist/PreviewPlugin.native-DBvfpmIv.mjs.map +1 -0
  64. package/dist/PrintPlugin.native-BUpm52VJ.mjs +311 -0
  65. package/dist/PrintPlugin.native-BUpm52VJ.mjs.map +1 -0
  66. package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs +731 -0
  67. package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs.map +1 -0
  68. package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs +465 -0
  69. package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs.map +1 -0
  70. package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs +43 -0
  71. package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs.map +1 -0
  72. package/dist/TablePlugin.native-EEWXn1-s.mjs +491 -0
  73. package/dist/TablePlugin.native-EEWXn1-s.mjs.map +1 -0
  74. package/dist/TemplatePlugin.native-BlSn1c9h.mjs +564 -0
  75. package/dist/TemplatePlugin.native-BlSn1c9h.mjs.map +1 -0
  76. package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs +97 -0
  77. package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs.map +1 -0
  78. package/dist/TextColorPlugin.native-D6SmTglm.mjs +432 -0
  79. package/dist/TextColorPlugin.native-D6SmTglm.mjs.map +1 -0
  80. package/dist/UnderlinePlugin.native-QpIcK4L2.mjs +35 -0
  81. package/dist/UnderlinePlugin.native-QpIcK4L2.mjs.map +1 -0
  82. package/dist/core.css +1 -0
  83. package/dist/documentManager-irzj9n3V.mjs +37627 -0
  84. package/dist/documentManager-irzj9n3V.mjs.map +1 -0
  85. package/dist/editorContainerHelpers-C7kdWnS0.mjs +27 -0
  86. package/dist/editorContainerHelpers-C7kdWnS0.mjs.map +1 -0
  87. package/dist/editora.min.js +519 -4
  88. package/dist/editora.min.js.map +1 -0
  89. package/dist/editora.umd.js +519 -4
  90. package/dist/editora.umd.js.map +1 -0
  91. package/dist/index-BF5RBhL9.js +4 -0
  92. package/dist/index-BF5RBhL9.js.map +1 -0
  93. package/dist/index-BPsf460l.mjs +1243 -0
  94. package/dist/index-BPsf460l.mjs.map +1 -0
  95. package/dist/index.cjs.js +517 -4
  96. package/dist/index.cjs.js.map +1 -0
  97. package/dist/index.es-CuicffkQ.mjs +6665 -0
  98. package/dist/index.es-CuicffkQ.mjs.map +1 -0
  99. package/dist/index.esm.js +1403 -122
  100. package/dist/index.esm.js.map +1 -0
  101. package/dist/plugin-loader.js +55 -0
  102. package/dist/plugin-loader.js.map +1 -0
  103. package/dist/purify.es-CKpwg8Tk.mjs +471 -0
  104. package/dist/purify.es-CKpwg8Tk.mjs.map +1 -0
  105. package/dist/webcomponent-core.js +1243 -0
  106. package/dist/webcomponent-core.js.map +1 -0
  107. package/dist/webcomponent-core.min.css +1 -0
  108. package/dist/webcomponent-core.min.js +597 -0
  109. package/dist/webcomponent-core.min.js.map +1 -0
  110. package/dist/webcomponent.cjs.js +2 -0
  111. package/dist/webcomponent.cjs.js.map +1 -0
  112. package/dist/webcomponent.esm.js +6 -0
  113. package/dist/webcomponent.esm.js.map +1 -0
  114. package/dist/webcomponent.js +1286 -0
  115. package/dist/webcomponent.js.map +1 -0
  116. package/dist/webcomponent.min.css +1 -0
  117. package/dist/webcomponent.min.js +4076 -0
  118. package/dist/webcomponent.min.js.map +1 -0
  119. package/package.json +64 -6
package/dist/index.esm.js CHANGED
@@ -1,20 +1,39 @@
1
- class l {
2
- constructor(e, t, i) {
3
- this.doc = e, this.selection = t, this.schema = i;
1
+ import { P as g, E as y, a as f, T as b, R as v } from "./index-BPsf460l.mjs";
2
+ import { C as B, h as G, F as K, i as V, S as W, b as X, e as _, d as Y, g as J, f as Q, c as Z } from "./index-BPsf460l.mjs";
3
+ class k {
4
+ constructor(e) {
5
+ if (this.listeners = [], e instanceof g)
6
+ this.pluginManager = e;
7
+ else {
8
+ const i = e;
9
+ this.pluginManager = new g(), i.plugins && Array.isArray(i.plugins) && i.plugins.forEach((s) => {
10
+ this.pluginManager.register(s);
11
+ }), i.element && (this.domElement = i.element, this.setupDOMElement(i));
12
+ }
13
+ const t = this.pluginManager.buildSchema();
14
+ this.state = y.create(t), this.commands = this.pluginManager.getCommands();
4
15
  }
5
- static create(e, t) {
6
- const i = t || e.node("doc", {}, [e.node("paragraph")]);
7
- return new l(i, { anchor: 0, head: 0 }, e);
16
+ setupDOMElement(e) {
17
+ this.domElement && (e.enableToolbar !== !1 && e.toolbarElement ? this.toolbarElement = e.toolbarElement : e.enableToolbar !== !1 && (this.toolbarElement = document.createElement("div"), this.toolbarElement.className = "editora-toolbar-container", this.domElement.appendChild(this.toolbarElement)), this.contentElement = document.createElement("div"), this.contentElement.contentEditable = "true", this.contentElement.className = "editora-content", this.contentElement.style.minHeight = "200px", this.contentElement.style.outline = "none", this.contentElement.style.padding = "12px", e.content && (this.contentElement.innerHTML = e.content), this.domElement.appendChild(this.contentElement), this.contentElement.addEventListener("input", () => {
18
+ this.listeners.forEach((t) => t(this.state));
19
+ }));
8
20
  }
9
- apply(e, t) {
10
- return new l(e, t || this.selection, this.schema);
21
+ setupKeyboardShortcuts(e) {
22
+ const t = {};
23
+ e.forEach((i) => {
24
+ i.shortcut && (t[i.shortcut.toLowerCase()] = i.command);
25
+ }), document.addEventListener("keydown", (i) => {
26
+ if (this.contentElement !== document.activeElement && !(document.activeElement instanceof HTMLElement && document.activeElement.contentEditable === "true"))
27
+ return;
28
+ const s = [];
29
+ (i.ctrlKey || i.metaKey) && s.push("ctrl"), i.shiftKey && s.push("shift"), i.altKey && s.push("alt");
30
+ const n = i.key.toLowerCase(), o = s.length > 0 ? `${s.join("+")}+${n}` : n, r = t[o];
31
+ r && (i.preventDefault(), this.execCommand(r));
32
+ });
11
33
  }
12
- }
13
- class y {
14
- constructor(e) {
15
- this.listeners = [], this.pluginManager = e;
16
- const t = e.buildSchema();
17
- this.state = l.create(t), this.commands = e.getCommands();
34
+ handleToolbarCommand(e, t) {
35
+ const s = this.pluginManager.getToolbarItems().find((n) => n.id && n.id === e || n.command === e);
36
+ s && (t !== void 0 ? this.execCommand(s.command, t) : this.execCommand(s.command));
18
37
  }
19
38
  setState(e) {
20
39
  this.state = e, this.listeners.forEach((t) => t(e));
@@ -24,54 +43,33 @@ class y {
24
43
  this.listeners = this.listeners.filter((t) => t !== e);
25
44
  };
26
45
  }
27
- execCommand(e) {
28
- const t = this.commands[e];
29
- if (!t) return !1;
30
- const i = t(this.state);
31
- return i ? (this.setState(i), !0) : !1;
32
- }
33
- setContent(e) {
34
- this.setState(this.state.apply(e));
35
- }
36
- getContent() {
37
- return this.state.doc;
46
+ // Alias for onChange to support both patterns
47
+ on(e, t) {
48
+ return e === "change" || e === "input" ? this.onChange(t) : () => {
49
+ };
38
50
  }
39
- }
40
- class g {
41
- constructor(e, t) {
42
- this.nodes = new Map(Object.entries(e)), this.marks = new Map(Object.entries(t));
51
+ getElement() {
52
+ return this.contentElement || this.domElement || null;
43
53
  }
44
- node(e, t, i) {
45
- return { type: e, attrs: t, content: i };
54
+ execCommand(e, t) {
55
+ const i = this.commands[e];
56
+ if (!i)
57
+ return console.warn(`Command not found: ${e}`), !1;
58
+ let s;
59
+ return t !== void 0 ? s = i(this.state, t) : s = i(this.state), s ? (this.setState(s), !0) : !1;
46
60
  }
47
- text(e, t) {
48
- return { type: "text", text: e, marks: t };
61
+ setContent(e) {
62
+ typeof e == "string" ? this.contentElement && (this.contentElement.innerHTML = e) : this.setState(this.state.apply(e));
49
63
  }
50
- }
51
- class k {
52
- constructor() {
53
- this.plugins = [];
54
- }
55
- register(e) {
56
- this.plugins.push(e);
57
- }
58
- buildSchema() {
59
- const e = {}, t = {};
60
- return this.plugins.forEach((i) => {
61
- i.nodes && Object.assign(e, i.nodes), i.marks && Object.assign(t, i.marks);
62
- }), new g(e, t);
63
- }
64
- getCommands() {
65
- const e = {};
66
- return this.plugins.forEach((t) => {
67
- t.commands && Object.assign(e, t.commands);
68
- }), e;
64
+ getContent() {
65
+ return this.contentElement ? this.contentElement.innerHTML : this.state.doc;
69
66
  }
70
- getToolbarItems() {
71
- return this.plugins.flatMap((e) => e.toolbar || []);
67
+ destroy() {
68
+ this.listeners = [], this.contentElement && this.contentElement.removeEventListener("input", () => {
69
+ });
72
70
  }
73
71
  }
74
- class m {
72
+ class E {
75
73
  constructor(e) {
76
74
  this.initialized = !1, this.plugin = e;
77
75
  }
@@ -79,37 +77,40 @@ class m {
79
77
  * Safe initialization
80
78
  */
81
79
  initialize(e) {
80
+ var t, i;
82
81
  if (this.initialized)
83
82
  return console.warn(`Plugin "${this.plugin.name}" already initialized`), !1;
84
83
  try {
85
- return this.context = e, this.plugin.context?.initialize && this.plugin.context.initialize(), this.plugin.context?.onEditorReady && e.provider && this.plugin.context.onEditorReady(e), this.initialized = !0, !0;
86
- } catch (t) {
87
- return console.error(`Failed to initialize plugin "${this.plugin.name}":`, t), !1;
84
+ return this.context = e, (t = this.plugin.context) != null && t.initialize && this.plugin.context.initialize(), (i = this.plugin.context) != null && i.onEditorReady && e.provider && this.plugin.context.onEditorReady(e), this.initialized = !0, !0;
85
+ } catch (s) {
86
+ return console.error(`Failed to initialize plugin "${this.plugin.name}":`, s), !1;
88
87
  }
89
88
  }
90
89
  /**
91
90
  * Safe destruction
92
91
  */
93
92
  destroy() {
93
+ var e;
94
94
  if (!this.initialized)
95
95
  return !1;
96
96
  try {
97
- return this.plugin.context?.destroy && this.plugin.context.destroy(), this.initialized = !1, this.context = void 0, !0;
98
- } catch (e) {
99
- return console.error(`Failed to destroy plugin "${this.plugin.name}":`, e), !1;
97
+ return (e = this.plugin.context) != null && e.destroy && this.plugin.context.destroy(), this.initialized = !1, this.context = void 0, !0;
98
+ } catch (t) {
99
+ return console.error(`Failed to destroy plugin "${this.plugin.name}":`, t), !1;
100
100
  }
101
101
  }
102
102
  /**
103
103
  * Safe command execution
104
104
  */
105
105
  executeCommand(e, ...t) {
106
+ var i;
106
107
  if (!this.initialized)
107
108
  return console.warn(`Plugin "${this.plugin.name}" not initialized, cannot execute command "${e}"`), null;
108
109
  try {
109
- const i = this.plugin.commands?.[e];
110
- return i ? i(...t) : (console.warn(`Command "${e}" not found in plugin "${this.plugin.name}"`), null);
111
- } catch (i) {
112
- return console.error(`Error executing command "${e}" in plugin "${this.plugin.name}":`, i), null;
110
+ const s = (i = this.plugin.commands) == null ? void 0 : i[e];
111
+ return s ? s(...t) : (console.warn(`Command "${e}" not found in plugin "${this.plugin.name}"`), null);
112
+ } catch (s) {
113
+ return console.error(`Error executing command "${e}" in plugin "${this.plugin.name}":`, s), null;
113
114
  }
114
115
  }
115
116
  /**
@@ -137,12 +138,12 @@ class m {
137
138
  return this.context;
138
139
  }
139
140
  }
140
- function S(n) {
141
- return new m(n);
141
+ function M(a) {
142
+ return new E(a);
142
143
  }
143
- class M {
144
+ class L {
144
145
  constructor(e) {
145
- this.shortcuts = /* @__PURE__ */ new Map(), this.enabled = !0, this.isMac = typeof navigator < "u" && navigator.platform.toUpperCase().indexOf("MAC") >= 0, e?.enabled === !1 && (this.enabled = !1), this.registerDefaultShortcuts(), e?.shortcuts && e.shortcuts.forEach((t) => this.registerShortcut(t)), e?.customShortcuts && Object.values(e.customShortcuts).forEach((t) => {
146
+ this.shortcuts = /* @__PURE__ */ new Map(), this.enabled = !0, this.isMac = typeof navigator != "undefined" && navigator.platform.toUpperCase().indexOf("MAC") >= 0, (e == null ? void 0 : e.enabled) === !1 && (this.enabled = !1), this.registerDefaultShortcuts(), e != null && e.shortcuts && e.shortcuts.forEach((t) => this.registerShortcut(t)), e != null && e.customShortcuts && Object.values(e.customShortcuts).forEach((t) => {
146
147
  this.registerShortcut(t);
147
148
  });
148
149
  }
@@ -427,8 +428,8 @@ class M {
427
428
  }
428
429
  handleKeyDown(e, t) {
429
430
  if (!this.enabled) return !1;
430
- const i = this.getEventKey(e), r = this.shortcuts.get(i);
431
- return r ? (r.preventDefault !== !1 && (e.preventDefault(), e.stopPropagation()), t(r.command, r.params), !0) : !1;
431
+ const i = this.getEventKey(e), s = this.shortcuts.get(i);
432
+ return s ? (s.preventDefault !== !1 && (e.preventDefault(), e.stopPropagation()), t(s.command, s.params), !0) : !1;
432
433
  }
433
434
  enable() {
434
435
  this.enabled = !0;
@@ -453,19 +454,19 @@ class M {
453
454
  }
454
455
  getShortcutsHelp() {
455
456
  const e = this.getAllShortcuts(), t = /* @__PURE__ */ new Map();
456
- e.forEach((r) => {
457
- const a = this.getShortcutCategory(r.command);
458
- t.has(a) || t.set(a, []), t.get(a).push(r);
457
+ e.forEach((s) => {
458
+ const n = this.getShortcutCategory(s.command);
459
+ t.has(n) || t.set(n, []), t.get(n).push(s);
459
460
  });
460
461
  let i = `# Keyboard Shortcuts
461
462
 
462
463
  `;
463
- return t.forEach((r, a) => {
464
- i += `## ${a}
464
+ return t.forEach((s, n) => {
465
+ i += `## ${n}
465
466
 
466
- `, r.forEach((c) => {
467
- const o = this.getShortcutDescription(c);
468
- i += `- **${o}**: ${c.description || c.command}
467
+ `, s.forEach((o) => {
468
+ const r = this.getShortcutDescription(o);
469
+ i += `- **${r}**: ${o.description || o.command}
469
470
  `;
470
471
  }), i += `
471
472
  `;
@@ -475,17 +476,17 @@ class M {
475
476
  return e.includes("toggle") && (e.includes("Bold") || e.includes("Italic") || e.includes("Underline") || e.includes("Strike") || e.includes("Code") || e.includes("Super") || e.includes("Sub")) ? "Text Formatting" : e.includes("Heading") || e.includes("Paragraph") ? "Block Formatting" : e.includes("List") || e.includes("Checklist") ? "Lists" : e.includes("Alignment") || e.includes("Indent") ? "Alignment & Indentation" : e.includes("undo") || e.includes("redo") ? "History" : e.includes("insert") ? "Insert" : e.includes("find") || e.includes("replace") ? "Find & Replace" : e.includes("Accessibility") || e.includes("spell") ? "Tools" : "Other";
476
477
  }
477
478
  }
478
- function b(n = {}) {
479
+ function T(a = {}) {
479
480
  const {
480
481
  enabled: e = !1,
481
482
  provider: t = "browser",
482
483
  apiUrl: i = "",
483
- apiHeaders: r = {},
484
- language: a = "en",
485
- customDictionary: c = [],
486
- ignoreAllCaps: o = !0,
487
- ignoreNumbers: p = !0
488
- } = n;
484
+ apiHeaders: s = {},
485
+ language: n = "en",
486
+ customDictionary: o = [],
487
+ ignoreAllCaps: r = !0,
488
+ ignoreNumbers: l = !0
489
+ } = a;
489
490
  return {
490
491
  name: "spellcheck",
491
492
  context: {
@@ -493,7 +494,7 @@ function b(n = {}) {
493
494
  if (e)
494
495
  switch (console.log("[Spellcheck Plugin] Initialized", {
495
496
  provider: t,
496
- language: a
497
+ language: n
497
498
  }), t) {
498
499
  case "browser":
499
500
  console.log("[Spellcheck] Using browser spellcheck");
@@ -509,13 +510,13 @@ function b(n = {}) {
509
510
  destroy: () => {
510
511
  console.log("[Spellcheck Plugin] Destroyed");
511
512
  },
512
- onEditorReady: (u) => {
513
+ onEditorReady: (d) => {
513
514
  console.log("[Spellcheck Plugin] Editor ready");
514
515
  }
515
516
  },
516
517
  commands: {
517
518
  toggleSpellcheck: () => (console.log("[Spellcheck] Toggle command (not implemented)"), null),
518
- addToDictionary: (u) => (console.log("[Spellcheck] Add to dictionary:", u), null),
519
+ addToDictionary: (d) => (console.log("[Spellcheck] Add to dictionary:", d), null),
519
520
  checkSpelling: async () => (console.log("[Spellcheck] Check spelling (not implemented)"), null)
520
521
  },
521
522
  toolbar: e ? [
@@ -528,22 +529,22 @@ function b(n = {}) {
528
529
  ] : []
529
530
  };
530
531
  }
531
- function v(n = {}) {
532
+ function I(a = {}) {
532
533
  const {
533
534
  uploadUrl: e = "",
534
535
  libraryUrl: t = "",
535
536
  maxFileSize: i = 10 * 1024 * 1024,
536
537
  // 10MB
537
- allowedTypes: r = ["image/jpeg", "image/png", "image/gif", "image/webp"],
538
- headers: a = {},
539
- withCredentials: c = !1,
540
- chunkSize: o = 1024 * 1024,
538
+ allowedTypes: s = ["image/jpeg", "image/png", "image/gif", "image/webp"],
539
+ headers: n = {},
540
+ withCredentials: o = !1,
541
+ chunkSize: r = 1024 * 1024,
541
542
  // 1MB chunks
542
- enableChunking: p = !0,
543
- onProgress: u,
544
- onError: d,
545
- onSuccess: f
546
- } = n;
543
+ enableChunking: l = !0,
544
+ onProgress: d,
545
+ onError: h,
546
+ onSuccess: w
547
+ } = a;
547
548
  return {
548
549
  name: "media",
549
550
  context: {
@@ -552,35 +553,35 @@ function v(n = {}) {
552
553
  uploadUrl: e,
553
554
  libraryUrl: t,
554
555
  maxFileSize: i,
555
- allowedTypes: r
556
+ allowedTypes: s
556
557
  }), e || console.warn("[Media] No uploadUrl provided - upload will not work");
557
558
  },
558
559
  destroy: () => {
559
560
  console.log("[Media Plugin] Destroyed");
560
561
  },
561
- onEditorReady: (s) => {
562
+ onEditorReady: (c) => {
562
563
  console.log("[Media Plugin] Editor ready");
563
564
  }
564
565
  },
565
566
  commands: {
566
- insertImage: async (s) => {
567
- if (console.log("[Media] Insert image command (not implemented)", s), !s)
567
+ insertImage: async (c) => {
568
+ if (console.log("[Media] Insert image command (not implemented)", c), !c)
568
569
  return console.log("[Media] No file provided - should open picker"), null;
569
- if (!r.includes(s.type)) {
570
- const h = new Error(`File type ${s.type} not allowed`);
571
- return d?.(h), null;
570
+ if (!s.includes(c.type)) {
571
+ const p = new Error(`File type ${c.type} not allowed`);
572
+ return h == null || h(p), null;
572
573
  }
573
- if (s.size > i) {
574
- const h = new Error(`File size ${s.size} exceeds max ${i}`);
575
- return d?.(h), null;
574
+ if (c.size > i) {
575
+ const p = new Error(`File size ${c.size} exceeds max ${i}`);
576
+ return h == null || h(p), null;
576
577
  }
577
578
  return null;
578
579
  },
579
580
  openMediaLibrary: () => (console.log("[Media] Open media library (not implemented)"), t || console.warn("[Media] No libraryUrl provided"), null),
580
- uploadMedia: async (s) => (console.log("[Media] Upload media (not implemented)", {
581
- name: s.name,
582
- size: s.size,
583
- type: s.type
581
+ uploadMedia: async (c) => (console.log("[Media] Upload media (not implemented)", {
582
+ name: c.name,
583
+ size: c.size,
584
+ type: c.type
584
585
  }), null)
585
586
  },
586
587
  toolbar: [
@@ -599,14 +600,1294 @@ function v(n = {}) {
599
600
  ]
600
601
  };
601
602
  }
603
+ class m {
604
+ constructor(e, t = { anchor: 0, head: 0 }) {
605
+ this.doc = e, this.selection = t;
606
+ }
607
+ getDocument() {
608
+ return this.doc;
609
+ }
610
+ setDocument(e) {
611
+ return new m(e, this.selection);
612
+ }
613
+ getSelection() {
614
+ return { ...this.selection };
615
+ }
616
+ setSelection(e) {
617
+ return new m(this.doc, e);
618
+ }
619
+ /**
620
+ * Create a new model with updated document and selection
621
+ */
622
+ update(e, t) {
623
+ return new m(
624
+ e || this.doc,
625
+ t || this.selection
626
+ );
627
+ }
628
+ /**
629
+ * Get text content
630
+ */
631
+ getTextContent() {
632
+ return "";
633
+ }
634
+ /**
635
+ * Check if selection is empty
636
+ */
637
+ isSelectionEmpty() {
638
+ return this.selection.anchor === this.selection.head;
639
+ }
640
+ }
641
+ class u {
642
+ constructor(e) {
643
+ this.config = {
644
+ closeOnEscape: !0,
645
+ closeOnBackdrop: !0,
646
+ ...e
647
+ }, this.element = this.createElement(), this.attachEventListeners();
648
+ }
649
+ createElement() {
650
+ const e = document.createElement("dialog");
651
+ if (e.className = "editora-dialog", this.config.width && (e.style.width = this.config.width), this.config.height && (e.style.height = this.config.height), e.innerHTML = `
652
+ <div class="editora-dialog-container">
653
+ <div class="editora-dialog-header">
654
+ <h3>${this.config.title}</h3>
655
+ <button class="editora-dialog-close" aria-label="Close">&times;</button>
656
+ </div>
657
+ <div class="editora-dialog-body">
658
+ ${typeof this.config.content == "string" ? this.config.content : ""}
659
+ </div>
660
+ <div class="editora-dialog-footer">
661
+ <button type="button" class="editora-btn editora-btn-cancel">Cancel</button>
662
+ <button type="button" class="editora-btn editora-btn-primary">OK</button>
663
+ </div>
664
+ </div>
665
+ `, typeof this.config.content != "string") {
666
+ const t = e.querySelector(".editora-dialog-body");
667
+ t && (t.innerHTML = "", t.appendChild(this.config.content));
668
+ }
669
+ return e;
670
+ }
671
+ attachEventListeners() {
672
+ const e = this.element.querySelector(".editora-dialog-close");
673
+ e == null || e.addEventListener("click", () => this.close());
674
+ const t = this.element.querySelector(".editora-btn-cancel");
675
+ t == null || t.addEventListener("click", () => {
676
+ var s, n;
677
+ (n = (s = this.config).onCancel) == null || n.call(s), this.close();
678
+ });
679
+ const i = this.element.querySelector(".editora-btn-primary");
680
+ i == null || i.addEventListener("click", () => this.handleSubmit()), this.config.closeOnEscape && this.element.addEventListener("cancel", (s) => {
681
+ s.preventDefault(), this.close();
682
+ }), this.config.closeOnBackdrop && this.element.addEventListener("click", (s) => {
683
+ const n = this.element.getBoundingClientRect();
684
+ (s.clientX < n.left || s.clientX > n.right || s.clientY < n.top || s.clientY > n.bottom) && this.close();
685
+ });
686
+ }
687
+ handleSubmit() {
688
+ var t, i, s, n;
689
+ const e = this.element.querySelector("form");
690
+ if (e) {
691
+ const o = new FormData(e);
692
+ (i = (t = this.config).onSubmit) == null || i.call(t, o);
693
+ } else {
694
+ const o = this.element.querySelectorAll("input, select, textarea"), r = new FormData();
695
+ o.forEach((l) => {
696
+ l.name && r.append(l.name, l.value);
697
+ }), (n = (s = this.config).onSubmit) == null || n.call(s, r);
698
+ }
699
+ this.close();
700
+ }
701
+ show() {
702
+ document.body.appendChild(this.element), this.element.showModal();
703
+ }
704
+ close() {
705
+ this.element.close(), this.element.remove();
706
+ }
707
+ destroy() {
708
+ this.close();
709
+ }
710
+ }
711
+ class D {
712
+ constructor(e) {
713
+ this.isOpen = !1, this.config = e, this.selectedValue = e.value, this.element = this.createElement(), this.attachEventListeners();
714
+ }
715
+ createElement() {
716
+ const e = document.createElement("div");
717
+ e.className = "editora-dropdown", this.config.width && (e.style.width = this.config.width);
718
+ const t = this.config.options.find((s) => s.value === this.selectedValue), i = (t == null ? void 0 : t.label) || this.config.placeholder || "Select...";
719
+ return e.innerHTML = `
720
+ <button class="editora-dropdown-toggle" type="button">
721
+ <span class="editora-dropdown-label">${i}</span>
722
+ <span class="editora-dropdown-arrow">▼</span>
723
+ </button>
724
+ <div class="editora-dropdown-menu" style="display: none;">
725
+ ${this.config.options.map((s) => `
726
+ <div class="editora-dropdown-item" data-value="${s.value}">
727
+ ${s.icon ? `<span class="editora-dropdown-icon">${s.icon}</span>` : ""}
728
+ <span>${s.label}</span>
729
+ </div>
730
+ `).join("")}
731
+ </div>
732
+ `, e;
733
+ }
734
+ attachEventListeners() {
735
+ const e = this.element.querySelector(".editora-dropdown-toggle"), t = this.element.querySelector(".editora-dropdown-menu");
736
+ e.addEventListener("click", (s) => {
737
+ s.stopPropagation(), this.isOpen = !this.isOpen, t.style.display = this.isOpen ? "block" : "none";
738
+ }), this.element.querySelectorAll(".editora-dropdown-item").forEach((s) => {
739
+ s.addEventListener("click", () => {
740
+ var o, r;
741
+ const n = s.getAttribute("data-value");
742
+ n && (this.setValue(n), (r = (o = this.config).onChange) == null || r.call(o, n), this.close());
743
+ });
744
+ }), document.addEventListener("click", (s) => {
745
+ this.element.contains(s.target) || this.close();
746
+ });
747
+ }
748
+ setValue(e) {
749
+ this.selectedValue = e;
750
+ const t = this.config.options.find((s) => s.value === e), i = this.element.querySelector(".editora-dropdown-label");
751
+ i && t && (i.textContent = t.label);
752
+ }
753
+ getValue() {
754
+ return this.selectedValue;
755
+ }
756
+ close() {
757
+ this.isOpen = !1;
758
+ const e = this.element.querySelector(".editora-dropdown-menu");
759
+ e && (e.style.display = "none");
760
+ }
761
+ getElement() {
762
+ return this.element;
763
+ }
764
+ destroy() {
765
+ this.element.remove();
766
+ }
767
+ }
768
+ class F {
769
+ constructor(e) {
770
+ this.defaultPresets = [
771
+ "#000000",
772
+ "#434343",
773
+ "#666666",
774
+ "#999999",
775
+ "#B7B7B7",
776
+ "#CCCCCC",
777
+ "#D9D9D9",
778
+ "#EFEFEF",
779
+ "#F3F3F3",
780
+ "#FFFFFF",
781
+ "#980000",
782
+ "#FF0000",
783
+ "#FF9900",
784
+ "#FFFF00",
785
+ "#00FF00",
786
+ "#00FFFF",
787
+ "#4A86E8",
788
+ "#0000FF",
789
+ "#9900FF",
790
+ "#FF00FF",
791
+ "#E6B8AF",
792
+ "#F4CCCC",
793
+ "#FCE5CD",
794
+ "#FFF2CC",
795
+ "#D9EAD3",
796
+ "#D0E0E3",
797
+ "#C9DAF8",
798
+ "#CFE2F3",
799
+ "#D9D2E9",
800
+ "#EAD1DC"
801
+ ], this.config = {
802
+ presetColors: this.defaultPresets,
803
+ ...e
804
+ }, this.selectedColor = e.value, this.element = this.createElement(), this.attachEventListeners();
805
+ }
806
+ createElement() {
807
+ var t;
808
+ const e = document.createElement("div");
809
+ return e.className = "editora-color-picker", e.innerHTML = `
810
+ <div class="editora-color-picker-input">
811
+ <input type="color" value="${this.selectedColor || "#000000"}" />
812
+ <input type="text" value="${this.selectedColor || "#000000"}" placeholder="#000000" />
813
+ </div>
814
+ <div class="editora-color-picker-presets">
815
+ ${(t = this.config.presetColors) == null ? void 0 : t.map((i) => `
816
+ <button
817
+ class="editora-color-preset"
818
+ style="background-color: ${i};"
819
+ data-color="${i}"
820
+ title="${i}"
821
+ ></button>
822
+ `).join("")}
823
+ </div>
824
+ `, e;
825
+ }
826
+ attachEventListeners() {
827
+ const e = this.element.querySelector('input[type="color"]'), t = this.element.querySelector('input[type="text"]');
828
+ e.addEventListener("input", (s) => {
829
+ var o, r;
830
+ const n = s.target.value;
831
+ t.value = n, this.selectedColor = n, (r = (o = this.config).onChange) == null || r.call(o, n);
832
+ }), t.addEventListener("input", (s) => {
833
+ var o, r;
834
+ const n = s.target.value;
835
+ /^#[0-9A-Fa-f]{6}$/.test(n) && (e.value = n, this.selectedColor = n, (r = (o = this.config).onChange) == null || r.call(o, n));
836
+ }), this.element.querySelectorAll(".editora-color-preset").forEach((s) => {
837
+ s.addEventListener("click", () => {
838
+ var o, r;
839
+ const n = s.getAttribute("data-color");
840
+ n && (e.value = n, t.value = n, this.selectedColor = n, (r = (o = this.config).onChange) == null || r.call(o, n));
841
+ });
842
+ });
843
+ }
844
+ getValue() {
845
+ return this.selectedColor;
846
+ }
847
+ setValue(e) {
848
+ this.selectedColor = e;
849
+ const t = this.element.querySelector('input[type="color"]'), i = this.element.querySelector('input[type="text"]');
850
+ t && (t.value = e), i && (i.value = e);
851
+ }
852
+ getElement() {
853
+ return this.element;
854
+ }
855
+ destroy() {
856
+ this.element.remove();
857
+ }
858
+ }
859
+ class j {
860
+ constructor(e) {
861
+ const { initialUrl: t = "", initialText: i = "", onSubmit: s, onCancel: n } = e;
862
+ this.dialog = new u({
863
+ title: "Insert/Edit Link",
864
+ content: this.createFormHTML(t, i),
865
+ onSubmit: (o) => {
866
+ const r = (o.get("url") || "").trim(), l = (o.get("text") || "").trim(), d = o.get("openInNewTab") === "on";
867
+ if (!r) {
868
+ alert("Please enter a URL");
869
+ return;
870
+ }
871
+ s({ url: r, text: l, openInNewTab: d }), this.dialog.close();
872
+ },
873
+ onCancel: () => {
874
+ n == null || n(), this.dialog.close();
875
+ },
876
+ width: "500px"
877
+ });
878
+ }
879
+ createFormHTML(e, t) {
880
+ return `
881
+ <form class="link-dialog-form">
882
+ <div class="form-group">
883
+ <label for="link-url">URL</label>
884
+ <input
885
+ type="url"
886
+ id="link-url"
887
+ name="url"
888
+ placeholder="https://example.com"
889
+ value="${this.escapeHtml(e)}"
890
+ required
891
+ autofocus
892
+ />
893
+ <small>Enter the web address (URL) for the link</small>
894
+ </div>
895
+
896
+ <div class="form-group">
897
+ <label for="link-text">Link Text</label>
898
+ <input
899
+ type="text"
900
+ id="link-text"
901
+ name="text"
902
+ placeholder="Click here"
903
+ value="${this.escapeHtml(t)}"
904
+ />
905
+ <small>Text to display for the link (leave empty to use URL)</small>
906
+ </div>
907
+
908
+ <div class="form-group">
909
+ <label class="checkbox-label">
910
+ <input
911
+ type="checkbox"
912
+ name="openInNewTab"
913
+ id="link-new-tab"
914
+ />
915
+ <span>Open link in new tab</span>
916
+ </label>
917
+ </div>
918
+
919
+ <div class="form-actions">
920
+ <button type="button" class="btn btn-secondary" data-action="cancel">
921
+ Cancel
922
+ </button>
923
+ <button type="submit" class="btn btn-primary">
924
+ Insert Link
925
+ </button>
926
+ </div>
927
+ </form>
928
+ `;
929
+ }
930
+ escapeHtml(e) {
931
+ const t = document.createElement("div");
932
+ return t.textContent = e, t.innerHTML;
933
+ }
934
+ show() {
935
+ this.dialog.show();
936
+ }
937
+ close() {
938
+ this.dialog.close();
939
+ }
940
+ }
941
+ class q {
942
+ constructor(e) {
943
+ const { onSubmit: t, onCancel: i } = e;
944
+ this.dialog = new u({
945
+ title: "Insert Table",
946
+ content: this.createFormHTML(),
947
+ onSubmit: (s) => {
948
+ const n = parseInt(s.get("rows"), 10), o = parseInt(s.get("cols"), 10), r = s.get("headerRow") === "on";
949
+ if (n < 1 || n > 100) {
950
+ alert("Please enter a valid number of rows (1-100)");
951
+ return;
952
+ }
953
+ if (o < 1 || o > 20) {
954
+ alert("Please enter a valid number of columns (1-20)");
955
+ return;
956
+ }
957
+ t({ rows: n, cols: o, headerRow: r }), this.dialog.close();
958
+ },
959
+ onCancel: () => {
960
+ i == null || i(), this.dialog.close();
961
+ },
962
+ width: "400px"
963
+ });
964
+ }
965
+ createFormHTML() {
966
+ return `
967
+ <form class="table-dialog-form">
968
+ <div class="form-group">
969
+ <label for="table-rows">Rows</label>
970
+ <input
971
+ type="number"
972
+ id="table-rows"
973
+ name="rows"
974
+ min="1"
975
+ max="100"
976
+ value="3"
977
+ required
978
+ autofocus
979
+ />
980
+ <small>Number of rows (1-100)</small>
981
+ </div>
982
+
983
+ <div class="form-group">
984
+ <label for="table-cols">Columns</label>
985
+ <input
986
+ type="number"
987
+ id="table-cols"
988
+ name="cols"
989
+ min="1"
990
+ max="20"
991
+ value="3"
992
+ required
993
+ />
994
+ <small>Number of columns (1-20)</small>
995
+ </div>
996
+
997
+ <div class="form-group">
998
+ <label class="checkbox-label">
999
+ <input
1000
+ type="checkbox"
1001
+ name="headerRow"
1002
+ id="table-header"
1003
+ checked
1004
+ />
1005
+ <span>Include header row</span>
1006
+ </label>
1007
+ </div>
1008
+
1009
+ <div class="table-preview">
1010
+ <strong>Preview:</strong>
1011
+ <div id="table-preview-content" style="margin-top: 8px; font-size: 12px; color: #666;">
1012
+ 3 rows × 3 columns with header
1013
+ </div>
1014
+ </div>
1015
+
1016
+ <div class="form-actions">
1017
+ <button type="button" class="btn btn-secondary" data-action="cancel">
1018
+ Cancel
1019
+ </button>
1020
+ <button type="submit" class="btn btn-primary">
1021
+ Insert Table
1022
+ </button>
1023
+ </div>
1024
+ </form>
1025
+ `;
1026
+ }
1027
+ show() {
1028
+ this.dialog.show(), this.attachPreviewListeners();
1029
+ }
1030
+ close() {
1031
+ this.dialog.close();
1032
+ }
1033
+ attachPreviewListeners() {
1034
+ const e = document.querySelector(".table-dialog-form");
1035
+ if (!e) return;
1036
+ const t = e.querySelector("#table-rows"), i = e.querySelector("#table-cols"), s = e.querySelector("#table-header"), n = e.querySelector("#table-preview-content"), o = () => {
1037
+ const r = parseInt((t == null ? void 0 : t.value) || "3", 10), l = parseInt((i == null ? void 0 : i.value) || "3", 10), d = s == null ? void 0 : s.checked;
1038
+ n && (n.textContent = `${r} rows × ${l} columns${d ? " with header" : ""}`);
1039
+ };
1040
+ t == null || t.addEventListener("input", o), i == null || i.addEventListener("input", o), s == null || s.addEventListener("change", o);
1041
+ }
1042
+ }
1043
+ class A {
1044
+ constructor(e) {
1045
+ this.config = e;
1046
+ const { onSubmit: t, onCancel: i } = e;
1047
+ this.dialog = new u({
1048
+ title: "Insert Image",
1049
+ content: this.createFormHTML(),
1050
+ onSubmit: (s) => {
1051
+ const n = (s.get("src") || "").trim(), o = (s.get("alt") || "").trim(), r = (s.get("width") || "").trim(), l = (s.get("height") || "").trim();
1052
+ if (!n) {
1053
+ alert("Please enter an image URL or upload an image");
1054
+ return;
1055
+ }
1056
+ t({
1057
+ src: n,
1058
+ alt: o,
1059
+ width: r || void 0,
1060
+ height: l || void 0
1061
+ }), this.dialog.close();
1062
+ },
1063
+ onCancel: () => {
1064
+ i == null || i(), this.dialog.close();
1065
+ },
1066
+ width: "500px"
1067
+ });
1068
+ }
1069
+ createFormHTML() {
1070
+ return `
1071
+ <form class="image-dialog-form">
1072
+ ${this.config.allowUpload ? `
1073
+ <div class="form-group">
1074
+ <label for="image-upload">Upload Image</label>
1075
+ <input
1076
+ type="file"
1077
+ id="image-upload"
1078
+ accept="image/*"
1079
+ />
1080
+ <small>Or upload an image from your computer</small>
1081
+ </div>
1082
+ <div class="form-divider">OR</div>
1083
+ ` : ""}
1084
+
1085
+ <div class="form-group">
1086
+ <label for="image-src">Image URL</label>
1087
+ <input
1088
+ type="url"
1089
+ id="image-src"
1090
+ name="src"
1091
+ placeholder="https://example.com/image.jpg"
1092
+ ${this.config.allowUpload ? "" : "required autofocus"}
1093
+ />
1094
+ <small>Enter the web address (URL) of the image</small>
1095
+ </div>
1096
+
1097
+ <div class="form-group">
1098
+ <label for="image-alt">Alt Text</label>
1099
+ <input
1100
+ type="text"
1101
+ id="image-alt"
1102
+ name="alt"
1103
+ placeholder="Description of the image"
1104
+ />
1105
+ <small>Alternative text for accessibility (recommended)</small>
1106
+ </div>
1107
+
1108
+ <div class="form-row">
1109
+ <div class="form-group">
1110
+ <label for="image-width">Width</label>
1111
+ <input
1112
+ type="text"
1113
+ id="image-width"
1114
+ name="width"
1115
+ placeholder="auto"
1116
+ />
1117
+ </div>
1118
+
1119
+ <div class="form-group">
1120
+ <label for="image-height">Height</label>
1121
+ <input
1122
+ type="text"
1123
+ id="image-height"
1124
+ name="height"
1125
+ placeholder="auto"
1126
+ />
1127
+ </div>
1128
+ </div>
1129
+
1130
+ <div class="image-preview" id="image-preview" style="display: none;">
1131
+ <strong>Preview:</strong>
1132
+ <img id="preview-img" style="max-width: 100%; max-height: 200px; margin-top: 8px;" />
1133
+ </div>
1134
+
1135
+ <div class="form-actions">
1136
+ <button type="button" class="btn btn-secondary" data-action="cancel">
1137
+ Cancel
1138
+ </button>
1139
+ <button type="submit" class="btn btn-primary">
1140
+ Insert Image
1141
+ </button>
1142
+ </div>
1143
+ </form>
1144
+ `;
1145
+ }
1146
+ show() {
1147
+ this.dialog.show(), this.attachImagePreview(), this.attachFileUpload();
1148
+ }
1149
+ close() {
1150
+ this.dialog.close();
1151
+ }
1152
+ attachImagePreview() {
1153
+ const e = document.querySelector(".image-dialog-form");
1154
+ if (!e) return;
1155
+ const t = e.querySelector("#image-src"), i = e.querySelector("#image-preview"), s = e.querySelector("#preview-img");
1156
+ t == null || t.addEventListener("input", () => {
1157
+ const n = t.value.trim();
1158
+ n && this.isValidImageUrl(n) ? (s.src = n, i.style.display = "block", s.onerror = () => {
1159
+ i.style.display = "none";
1160
+ }) : i.style.display = "none";
1161
+ });
1162
+ }
1163
+ attachFileUpload() {
1164
+ if (!this.config.allowUpload) return;
1165
+ const e = document.querySelector(".image-dialog-form");
1166
+ if (!e) return;
1167
+ const t = e.querySelector("#image-upload"), i = e.querySelector("#image-src");
1168
+ t == null || t.addEventListener("change", async (s) => {
1169
+ var r;
1170
+ const n = (r = s.target.files) == null ? void 0 : r[0];
1171
+ if (!n) return;
1172
+ const o = new FileReader();
1173
+ o.onload = (l) => {
1174
+ var h;
1175
+ const d = (h = l.target) == null ? void 0 : h.result;
1176
+ i.value = d, i.dispatchEvent(new Event("input"));
1177
+ }, o.readAsDataURL(n);
1178
+ });
1179
+ }
1180
+ isValidImageUrl(e) {
1181
+ try {
1182
+ return new URL(e), /\.(jpg|jpeg|png|gif|svg|webp|bmp)$/i.test(e) || e.startsWith("data:image/");
1183
+ } catch (t) {
1184
+ return !1;
1185
+ }
1186
+ }
1187
+ }
1188
+ class P {
1189
+ constructor(e) {
1190
+ this.onSubmit = e.onSubmit;
1191
+ const t = this.createContent();
1192
+ this.dialog = new u({
1193
+ title: "Insert Math Equation",
1194
+ content: t,
1195
+ buttons: [
1196
+ {
1197
+ label: "Cancel",
1198
+ onClick: () => this.dialog.close()
1199
+ },
1200
+ {
1201
+ label: "Insert",
1202
+ onClick: () => this.handleSubmit(),
1203
+ primary: !0
1204
+ }
1205
+ ]
1206
+ }), this.latexInput = t.querySelector("#math-latex"), this.previewDiv = t.querySelector("#math-preview"), this.displayTypeSelect = t.querySelector("#math-display-type"), this.latexInput.addEventListener("input", () => this.updatePreview());
1207
+ }
1208
+ createContent() {
1209
+ const e = document.createElement("div");
1210
+ return e.className = "math-dialog-content", e.style.minWidth = "500px", e.innerHTML = `
1211
+ <style>
1212
+ .math-dialog-content {
1213
+ display: flex;
1214
+ flex-direction: column;
1215
+ gap: 1rem;
1216
+ }
1217
+ .math-form-group {
1218
+ display: flex;
1219
+ flex-direction: column;
1220
+ gap: 0.5rem;
1221
+ }
1222
+ .math-form-group label {
1223
+ font-weight: 500;
1224
+ color: #333;
1225
+ }
1226
+ .math-latex-input {
1227
+ width: 100%;
1228
+ min-height: 80px;
1229
+ padding: 0.5rem;
1230
+ border: 1px solid #ddd;
1231
+ border-radius: 4px;
1232
+ font-family: 'Courier New', monospace;
1233
+ font-size: 14px;
1234
+ resize: vertical;
1235
+ }
1236
+ .math-preview {
1237
+ padding: 1rem;
1238
+ background: #f9f9f9;
1239
+ border: 1px solid #ddd;
1240
+ border-radius: 4px;
1241
+ min-height: 60px;
1242
+ font-size: 18px;
1243
+ text-align: center;
1244
+ }
1245
+ .math-preview:empty::before {
1246
+ content: 'Preview will appear here...';
1247
+ color: #999;
1248
+ font-style: italic;
1249
+ }
1250
+ .math-symbols {
1251
+ display: grid;
1252
+ grid-template-columns: repeat(8, 1fr);
1253
+ gap: 0.5rem;
1254
+ padding: 0.5rem;
1255
+ background: #f5f5f5;
1256
+ border-radius: 4px;
1257
+ }
1258
+ .math-symbol-btn {
1259
+ padding: 0.5rem;
1260
+ border: 1px solid #ddd;
1261
+ background: white;
1262
+ border-radius: 4px;
1263
+ cursor: pointer;
1264
+ font-size: 18px;
1265
+ transition: all 0.2s;
1266
+ }
1267
+ .math-symbol-btn:hover {
1268
+ background: #e3f2fd;
1269
+ border-color: #2196f3;
1270
+ }
1271
+ .math-display-select {
1272
+ padding: 0.5rem;
1273
+ border: 1px solid #ddd;
1274
+ border-radius: 4px;
1275
+ font-size: 14px;
1276
+ }
1277
+ </style>
1278
+
1279
+ <div class="math-form-group">
1280
+ <label for="math-latex">LaTeX Expression:</label>
1281
+ <textarea
1282
+ id="math-latex"
1283
+ class="math-latex-input"
1284
+ placeholder="Enter LaTeX (e.g., x^2 + y^2 = r^2)"
1285
+ ></textarea>
1286
+ </div>
1287
+
1288
+ <div class="math-form-group">
1289
+ <label>Common Symbols:</label>
1290
+ <div class="math-symbols">
1291
+ <button class="math-symbol-btn" data-symbol="\\frac{a}{b}" title="Fraction">a/b</button>
1292
+ <button class="math-symbol-btn" data-symbol="x^{2}" title="Superscript">x²</button>
1293
+ <button class="math-symbol-btn" data-symbol="x_{i}" title="Subscript">xᵢ</button>
1294
+ <button class="math-symbol-btn" data-symbol="\\sqrt{x}" title="Square root">√x</button>
1295
+ <button class="math-symbol-btn" data-symbol="\\sum" title="Sum">∑</button>
1296
+ <button class="math-symbol-btn" data-symbol="\\int" title="Integral">∫</button>
1297
+ <button class="math-symbol-btn" data-symbol="\\pi" title="Pi">π</button>
1298
+ <button class="math-symbol-btn" data-symbol="\\alpha" title="Alpha">α</button>
1299
+ <button class="math-symbol-btn" data-symbol="\\beta" title="Beta">β</button>
1300
+ <button class="math-symbol-btn" data-symbol="\\gamma" title="Gamma">γ</button>
1301
+ <button class="math-symbol-btn" data-symbol="\\theta" title="Theta">θ</button>
1302
+ <button class="math-symbol-btn" data-symbol="\\lambda" title="Lambda">λ</button>
1303
+ <button class="math-symbol-btn" data-symbol="\\infty" title="Infinity">∞</button>
1304
+ <button class="math-symbol-btn" data-symbol="\\leq" title="Less or equal">≤</button>
1305
+ <button class="math-symbol-btn" data-symbol="\\geq" title="Greater or equal">≥</button>
1306
+ <button class="math-symbol-btn" data-symbol="\\neq" title="Not equal">≠</button>
1307
+ </div>
1308
+ </div>
1309
+
1310
+ <div class="math-form-group">
1311
+ <label for="math-preview">Preview:</label>
1312
+ <div id="math-preview" class="math-preview"></div>
1313
+ </div>
1314
+
1315
+ <div class="math-form-group">
1316
+ <label for="math-display-type">Display Type:</label>
1317
+ <select id="math-display-type" class="math-display-select">
1318
+ <option value="inline">Inline (within text)</option>
1319
+ <option value="block">Block (centered, new line)</option>
1320
+ </select>
1321
+ </div>
1322
+ `, e.querySelectorAll(".math-symbol-btn").forEach((i) => {
1323
+ i.addEventListener("click", (s) => {
1324
+ s.preventDefault();
1325
+ const n = i.getAttribute("data-symbol");
1326
+ if (n && this.latexInput) {
1327
+ const o = this.latexInput.selectionStart, r = this.latexInput.selectionEnd, l = this.latexInput.value;
1328
+ this.latexInput.value = l.substring(0, o) + n + l.substring(r), this.latexInput.focus(), this.latexInput.selectionStart = this.latexInput.selectionEnd = o + n.length, this.updatePreview();
1329
+ }
1330
+ });
1331
+ }), e;
1332
+ }
1333
+ updatePreview() {
1334
+ const e = this.latexInput.value.trim();
1335
+ if (!e) {
1336
+ this.previewDiv.textContent = "";
1337
+ return;
1338
+ }
1339
+ let t = e.replace(/\\frac\{([^}]+)\}\{([^}]+)\}/g, "($1)/($2)").replace(/\^\{([^}]+)\}/g, "^$1").replace(/\_\{([^}]+)\}/g, "_$1").replace(/\\sqrt\{([^}]+)\}/g, "√($1)").replace(/\\sum/g, "∑").replace(/\\int/g, "∫").replace(/\\pi/g, "π").replace(/\\alpha/g, "α").replace(/\\beta/g, "β").replace(/\\gamma/g, "γ").replace(/\\theta/g, "θ").replace(/\\lambda/g, "λ").replace(/\\infty/g, "∞").replace(/\\leq/g, "≤").replace(/\\geq/g, "≥").replace(/\\neq/g, "≠");
1340
+ this.previewDiv.textContent = t;
1341
+ }
1342
+ handleSubmit() {
1343
+ const e = this.latexInput.value.trim();
1344
+ if (!e) {
1345
+ alert("Please enter a LaTeX expression.");
1346
+ return;
1347
+ }
1348
+ const t = this.displayTypeSelect.value;
1349
+ this.onSubmit({ latex: e, display: t }), this.dialog.close();
1350
+ }
1351
+ show() {
1352
+ this.dialog.show(), this.latexInput.value = "", this.previewDiv.textContent = "", this.displayTypeSelect.value = "inline", setTimeout(() => this.latexInput.focus(), 100);
1353
+ }
1354
+ close() {
1355
+ this.dialog.close();
1356
+ }
1357
+ }
1358
+ class $ {
1359
+ constructor(e) {
1360
+ this.characters = {
1361
+ common: ["©", "®", "™", "§", "¶", "†", "‡", "•", "‣", "⁃", "◦", "▪", "▫", "◊", "○", "●", "□", "■", "△", "▲", "▽", "▼", "◇", "◆", "★", "☆"],
1362
+ arrows: ["←", "→", "↑", "↓", "↔", "↕", "⇐", "⇒", "⇑", "⇓", "⇔", "⇕", "⟵", "⟶", "⟷", "↖", "↗", "↘", "↙", "⇖", "⇗", "⇘", "⇙"],
1363
+ currency: ["$", "€", "£", "¥", "₹", "₽", "₩", "₪", "₦", "฿", "₴", "₡", "₵", "₸", "₫", "₱", "₲", "₳", "₭"],
1364
+ math: ["±", "×", "÷", "=", "≠", "≈", "≡", "≤", "≥", "<", ">", "∞", "∑", "∏", "∫", "∂", "√", "∛", "∜", "°", "′", "″", "∠", "∟", "⊥", "∥"],
1365
+ greek: ["α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "σ", "τ", "υ", "φ", "χ", "ψ", "ω", "Α", "Β", "Γ", "Δ", "Ε", "Ζ", "Η", "Θ"],
1366
+ punctuation: ["‚", "„", "“", "”", "‘", "’", "«", "»", "‹", "›", "—", "–", "…", "·", "¡", "¿", "‰", "′", "″", "‴"],
1367
+ superscript: ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", "⁺", "⁻", "⁼", "⁽", "⁾", "ⁿ", "ⁱ"],
1368
+ subscript: ["₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", "₊", "₋", "₌", "₍", "₎"]
1369
+ }, this.onSelect = e.onSelect;
1370
+ const t = this.createContent();
1371
+ this.dialog = new u({
1372
+ title: "Insert Special Character",
1373
+ content: t,
1374
+ buttons: [
1375
+ {
1376
+ label: "Close",
1377
+ onClick: () => this.dialog.close()
1378
+ }
1379
+ ]
1380
+ }), this.searchInput = t.querySelector("#char-search"), this.categorySelect = t.querySelector("#char-category"), this.charactersGrid = t.querySelector("#char-grid"), this.searchInput.addEventListener("input", () => this.filterCharacters()), this.categorySelect.addEventListener("change", () => this.updateGrid()), this.updateGrid();
1381
+ }
1382
+ createContent() {
1383
+ const e = document.createElement("div");
1384
+ return e.className = "character-dialog-content", e.style.minWidth = "500px", e.innerHTML = `
1385
+ <style>
1386
+ .character-dialog-content {
1387
+ display: flex;
1388
+ flex-direction: column;
1389
+ gap: 1rem;
1390
+ }
1391
+ .char-controls {
1392
+ display: flex;
1393
+ gap: 0.5rem;
1394
+ }
1395
+ .char-search, .char-category {
1396
+ padding: 0.5rem;
1397
+ border: 1px solid #ddd;
1398
+ border-radius: 4px;
1399
+ font-size: 14px;
1400
+ }
1401
+ .char-search {
1402
+ flex: 1;
1403
+ }
1404
+ .char-category {
1405
+ min-width: 150px;
1406
+ }
1407
+ .char-grid {
1408
+ display: grid;
1409
+ grid-template-columns: repeat(10, 1fr);
1410
+ gap: 0.5rem;
1411
+ max-height: 300px;
1412
+ overflow-y: auto;
1413
+ padding: 1rem;
1414
+ background: #f9f9f9;
1415
+ border: 1px solid #ddd;
1416
+ border-radius: 4px;
1417
+ }
1418
+ .char-button {
1419
+ aspect-ratio: 1;
1420
+ display: flex;
1421
+ align-items: center;
1422
+ justify-content: center;
1423
+ padding: 0.5rem;
1424
+ border: 1px solid #ddd;
1425
+ background: white;
1426
+ border-radius: 4px;
1427
+ cursor: pointer;
1428
+ font-size: 20px;
1429
+ transition: all 0.2s;
1430
+ }
1431
+ .char-button:hover {
1432
+ background: #e3f2fd;
1433
+ border-color: #2196f3;
1434
+ transform: scale(1.1);
1435
+ }
1436
+ .char-info {
1437
+ padding: 0.5rem;
1438
+ background: #f5f5f5;
1439
+ border-radius: 4px;
1440
+ font-size: 12px;
1441
+ color: #666;
1442
+ text-align: center;
1443
+ }
1444
+ </style>
1445
+
1446
+ <div class="char-controls">
1447
+ <input
1448
+ type="text"
1449
+ id="char-search"
1450
+ class="char-search"
1451
+ placeholder="Search characters..."
1452
+ />
1453
+ <select id="char-category" class="char-category">
1454
+ <option value="all">All Categories</option>
1455
+ <option value="common">Common Symbols</option>
1456
+ <option value="arrows">Arrows</option>
1457
+ <option value="currency">Currency</option>
1458
+ <option value="math">Mathematics</option>
1459
+ <option value="greek">Greek Letters</option>
1460
+ <option value="punctuation">Punctuation</option>
1461
+ <option value="superscript">Superscript</option>
1462
+ <option value="subscript">Subscript</option>
1463
+ </select>
1464
+ </div>
1465
+
1466
+ <div id="char-grid" class="char-grid"></div>
1467
+
1468
+ <div class="char-info">
1469
+ Click any character to insert it into your document.
1470
+ </div>
1471
+ `, e;
1472
+ }
1473
+ updateGrid() {
1474
+ const e = this.categorySelect.value;
1475
+ this.charactersGrid.innerHTML = "";
1476
+ let t = [];
1477
+ e === "all" ? t = Object.values(this.characters).flat() : t = this.characters[e] || [], t.forEach((i) => {
1478
+ const s = document.createElement("button");
1479
+ s.className = "char-button", s.textContent = i, s.title = `Insert ${i} (U+${i.charCodeAt(0).toString(16).toUpperCase()})`, s.addEventListener("click", (n) => {
1480
+ n.preventDefault(), this.handleSelect(i);
1481
+ }), this.charactersGrid.appendChild(s);
1482
+ });
1483
+ }
1484
+ filterCharacters() {
1485
+ const e = this.searchInput.value.toLowerCase();
1486
+ this.charactersGrid.querySelectorAll(".char-button").forEach((i) => {
1487
+ const s = i.textContent || "", n = `u+${s.charCodeAt(0).toString(16)}`, o = !e || s.includes(e) || n.includes(e);
1488
+ i.style.display = o ? "flex" : "none";
1489
+ });
1490
+ }
1491
+ handleSelect(e) {
1492
+ this.onSelect(e), this.dialog.close();
1493
+ }
1494
+ show() {
1495
+ this.dialog.show(), this.searchInput.value = "", this.categorySelect.value = "all", this.updateGrid(), setTimeout(() => this.searchInput.focus(), 100);
1496
+ }
1497
+ close() {
1498
+ this.dialog.close();
1499
+ }
1500
+ }
1501
+ class H {
1502
+ constructor(e) {
1503
+ this.emojis = {
1504
+ popular: ["😀", "😃", "😄", "😁", "😊", "😍", "🤩", "😘", "😗", "😚", "😙", "🙂", "🤗", "🤔", "🤨", "😐", "😑", "😶", "🙄", "😏", "👍", "👎", "👌", "✌️", "🤞", "🤝", "👏", "🙌", "👋", "🤚", "✋", "🖐️", "🖖", "👊", "✊", "🤛", "🤜", "💪"],
1505
+ smileys: ["😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂", "🙂", "🙃", "😉", "😊", "😇", "🥰", "😍", "🤩", "😘", "😗", "😚", "😙", "😋", "😛", "😜", "🤪", "😝", "🤑", "🤗", "🤭", "🤫", "🤔"],
1506
+ emotions: ["😳", "😞", "😟", "😠", "😡", "🤬", "😔", "😕", "🙁", "😬", "🥺", "😣", "😖", "😫", "😩", "🥱", "😤", "😮", "😱", "😨", "😰", "😥", "😢", "😭", "😪", "😓", "🤤", "😴", "😷", "🤒"],
1507
+ gestures: ["👍", "👎", "👌", "✌️", "🤞", "🤟", "🤘", "🤙", "👈", "👉", "👆", "👇", "☝️", "👋", "🤚", "✋", "🖐️", "🖖", "👏", "🙌", "👐", "🤲", "🤝", "🙏", "✍️", "💅", "🤳", "💪", "🦾", "🦿"],
1508
+ people: ["👶", "👧", "🧒", "👦", "👩", "🧑", "👨", "👵", "🧓", "👴", "👲", "👳", "🧕", "👮", "👷", "💂", "🕵️", "👩‍⚕️", "👨‍⚕️", "👩‍🎓", "👨‍🎓", "👩‍🏫", "👨‍🏫", "👩‍⚖️", "👨‍⚖️", "👩‍🌾", "👨‍🌾", "👩‍🍳", "👨‍🍳", "👩‍🔧"],
1509
+ animals: ["🐶", "🐱", "🐭", "🐹", "🐰", "🦊", "🐻", "🐼", "🐨", "🐯", "🦁", "🐮", "🐷", "🐸", "🐵", "🙈", "🙉", "🙊", "🐔", "🐧", "🐦", "🐤", "🐣", "🐥", "🦆", "🦅", "🦉", "🦇", "🐺", "🐗"],
1510
+ nature: ["🌵", "🎄", "🌲", "🌳", "🌴", "🌱", "🌿", "☘️", "🍀", "🎍", "🎋", "🍃", "🍂", "🍁", "🍄", "🌾", "💐", "🌷", "🌹", "🥀", "🌺", "🌸", "🌼", "🌻", "🌞", "🌝", "🌛", "🌜", "⭐", "🌟"],
1511
+ food: ["🍏", "🍎", "🍐", "🍊", "🍋", "🍌", "🍉", "🍇", "🍓", "🍈", "🍒", "🍑", "🥭", "🍍", "🥥", "🥝", "🍅", "🍆", "🥑", "🥦", "🥬", "🥒", "🌶️", "🌽", "🥕", "🧄", "🧅", "🥔", "🍠", "🥐"],
1512
+ objects: ["⌚", "📱", "💻", "⌨️", "🖥️", "🖨️", "🖱️", "🕹️", "💾", "💿", "📀", "📷", "📹", "🎥", "📞", "☎️", "📟", "📠", "📺", "📻", "🎙️", "🎚️", "🎛️", "🧭", "⏱️", "⏰", "📡", "🔋", "🔌", "💡"],
1513
+ symbols: ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍", "🤎", "💔", "❣️", "💕", "💞", "💓", "💗", "💖", "💘", "💝", "✨", "💫", "⭐", "🌟", "✔️", "✅", "❌", "❎", "➕", "➖", "✖️", "➗"],
1514
+ activities: ["⚽", "🏀", "🏈", "⚾", "🥎", "🎾", "🏐", "🏉", "🥏", "🎱", "🪀", "🏓", "🏸", "🏒", "🏑", "🥍", "🏏", "🪃", "🥅", "⛳", "🪁", "🏹", "🎣", "🤿", "🥊", "🥋", "🎽", "🛹", "🛼", "🛷"]
1515
+ }, this.onSelect = e.onSelect;
1516
+ const t = this.createContent();
1517
+ this.dialog = new u({
1518
+ title: "Insert Emoji",
1519
+ content: t,
1520
+ buttons: [
1521
+ {
1522
+ label: "Close",
1523
+ onClick: () => this.dialog.close()
1524
+ }
1525
+ ]
1526
+ }), this.searchInput = t.querySelector("#emoji-search"), this.categorySelect = t.querySelector("#emoji-category"), this.emojisGrid = t.querySelector("#emoji-grid"), this.searchInput.addEventListener("input", () => this.filterEmojis()), this.categorySelect.addEventListener("change", () => this.updateGrid()), this.updateGrid();
1527
+ }
1528
+ createContent() {
1529
+ const e = document.createElement("div");
1530
+ return e.className = "emoji-dialog-content", e.style.minWidth = "500px", e.innerHTML = `
1531
+ <style>
1532
+ .emoji-dialog-content {
1533
+ display: flex;
1534
+ flex-direction: column;
1535
+ gap: 1rem;
1536
+ }
1537
+ .emoji-controls {
1538
+ display: flex;
1539
+ gap: 0.5rem;
1540
+ }
1541
+ .emoji-search, .emoji-category {
1542
+ padding: 0.5rem;
1543
+ border: 1px solid #ddd;
1544
+ border-radius: 4px;
1545
+ font-size: 14px;
1546
+ }
1547
+ .emoji-search {
1548
+ flex: 1;
1549
+ }
1550
+ .emoji-category {
1551
+ min-width: 150px;
1552
+ }
1553
+ .emoji-grid {
1554
+ display: grid;
1555
+ grid-template-columns: repeat(10, 1fr);
1556
+ gap: 0.5rem;
1557
+ max-height: 350px;
1558
+ overflow-y: auto;
1559
+ padding: 1rem;
1560
+ background: #f9f9f9;
1561
+ border: 1px solid #ddd;
1562
+ border-radius: 4px;
1563
+ }
1564
+ .emoji-button {
1565
+ aspect-ratio: 1;
1566
+ display: flex;
1567
+ align-items: center;
1568
+ justify-content: center;
1569
+ padding: 0.5rem;
1570
+ border: 1px solid #ddd;
1571
+ background: white;
1572
+ border-radius: 4px;
1573
+ cursor: pointer;
1574
+ font-size: 24px;
1575
+ transition: all 0.2s;
1576
+ }
1577
+ .emoji-button:hover {
1578
+ background: #fff3e0;
1579
+ border-color: #ff9800;
1580
+ transform: scale(1.15);
1581
+ }
1582
+ .emoji-info {
1583
+ padding: 0.5rem;
1584
+ background: #f5f5f5;
1585
+ border-radius: 4px;
1586
+ font-size: 12px;
1587
+ color: #666;
1588
+ text-align: center;
1589
+ }
1590
+ </style>
1591
+
1592
+ <div class="emoji-controls">
1593
+ <input
1594
+ type="text"
1595
+ id="emoji-search"
1596
+ class="emoji-search"
1597
+ placeholder="Search emojis..."
1598
+ />
1599
+ <select id="emoji-category" class="emoji-category">
1600
+ <option value="all">All Emojis</option>
1601
+ <option value="popular">Popular</option>
1602
+ <option value="smileys">Smileys & Faces</option>
1603
+ <option value="emotions">Emotions</option>
1604
+ <option value="gestures">Gestures & Hands</option>
1605
+ <option value="people">People</option>
1606
+ <option value="animals">Animals</option>
1607
+ <option value="nature">Nature</option>
1608
+ <option value="food">Food & Drink</option>
1609
+ <option value="objects">Objects</option>
1610
+ <option value="symbols">Symbols</option>
1611
+ <option value="activities">Activities & Sports</option>
1612
+ </select>
1613
+ </div>
1614
+
1615
+ <div id="emoji-grid" class="emoji-grid"></div>
1616
+
1617
+ <div class="emoji-info">
1618
+ Click any emoji to insert it into your document.
1619
+ </div>
1620
+ `, e;
1621
+ }
1622
+ updateGrid() {
1623
+ const e = this.categorySelect.value;
1624
+ this.emojisGrid.innerHTML = "";
1625
+ let t = [];
1626
+ e === "all" ? t = Object.values(this.emojis).flat() : t = this.emojis[e] || [], t.forEach((i) => {
1627
+ const s = document.createElement("button");
1628
+ s.className = "emoji-button", s.textContent = i, s.title = `Insert ${i}`, s.addEventListener("click", (n) => {
1629
+ n.preventDefault(), this.handleSelect(i);
1630
+ }), this.emojisGrid.appendChild(s);
1631
+ });
1632
+ }
1633
+ filterEmojis() {
1634
+ const e = this.searchInput.value.toLowerCase();
1635
+ this.emojisGrid.querySelectorAll(".emoji-button").forEach((i) => {
1636
+ const s = i.textContent || "", n = !e || s.includes(e);
1637
+ i.style.display = n ? "flex" : "none";
1638
+ });
1639
+ }
1640
+ handleSelect(e) {
1641
+ this.onSelect(e), this.dialog.close();
1642
+ }
1643
+ show() {
1644
+ this.dialog.show(), this.searchInput.value = "", this.categorySelect.value = "popular", this.updateGrid(), setTimeout(() => this.searchInput.focus(), 100);
1645
+ }
1646
+ close() {
1647
+ this.dialog.close();
1648
+ }
1649
+ }
1650
+ class S {
1651
+ constructor(e = {}) {
1652
+ this.changeListeners = [], this.options = e, this.engine = new f({
1653
+ content: e.content,
1654
+ plugins: e.plugins || [],
1655
+ readonly: e.readonly
1656
+ }), e.onChange && this.onChange(e.onChange), this.engine.on("change", () => {
1657
+ const t = this.getHTML();
1658
+ this.changeListeners.forEach((i) => i(t));
1659
+ });
1660
+ }
1661
+ /**
1662
+ * Mount editor to DOM elements
1663
+ */
1664
+ mount(e, t) {
1665
+ this.contentElement = e, this.toolbarElement = t, this.contentElement.contentEditable = this.options.readonly ? "false" : "true", this.contentElement.className = "rte-content", this.options.content && (this.contentElement.innerHTML = this.options.content), this.options.toolbar !== !1 && this.toolbarElement && (this.toolbar = new b(
1666
+ {
1667
+ items: typeof this.options.toolbar == "string" ? this.options.toolbar : void 0
1668
+ },
1669
+ this.options.plugins || []
1670
+ ), this.toolbar.setCommandHandler((i, s) => {
1671
+ this.execCommand(i, s);
1672
+ }), this.toolbar.render(this.toolbarElement)), this.contentElement.addEventListener("input", () => {
1673
+ const i = this.getHTML();
1674
+ this.changeListeners.forEach((s) => s(i));
1675
+ }), this.options.onInit && this.options.onInit(this.getAPI());
1676
+ }
1677
+ /**
1678
+ * Get HTML content
1679
+ */
1680
+ getHTML() {
1681
+ var e;
1682
+ return ((e = this.contentElement) == null ? void 0 : e.innerHTML) || "";
1683
+ }
1684
+ /**
1685
+ * Set HTML content
1686
+ */
1687
+ setHTML(e) {
1688
+ this.contentElement && (this.contentElement.innerHTML = e);
1689
+ }
1690
+ /**
1691
+ * Execute command
1692
+ */
1693
+ execCommand(e, t) {
1694
+ const i = this.engine.execCommand(e, t);
1695
+ return this.toolbar, i;
1696
+ }
1697
+ /**
1698
+ * Focus editor
1699
+ */
1700
+ focus() {
1701
+ var e;
1702
+ (e = this.contentElement) == null || e.focus();
1703
+ }
1704
+ /**
1705
+ * Blur editor
1706
+ */
1707
+ blur() {
1708
+ var e;
1709
+ (e = this.contentElement) == null || e.blur();
1710
+ }
1711
+ /**
1712
+ * Register change listener
1713
+ */
1714
+ onChange(e) {
1715
+ return this.changeListeners.push(e), () => {
1716
+ const t = this.changeListeners.indexOf(e);
1717
+ t > -1 && this.changeListeners.splice(t, 1);
1718
+ };
1719
+ }
1720
+ /**
1721
+ * Register command
1722
+ */
1723
+ registerCommand(e, t) {
1724
+ if (typeof window != "undefined") {
1725
+ const i = window.__editorCommands || /* @__PURE__ */ new Map();
1726
+ i.set(e, t), window.__editorCommands = i;
1727
+ }
1728
+ }
1729
+ /**
1730
+ * Get state
1731
+ */
1732
+ getState() {
1733
+ return {
1734
+ plugins: this.options.plugins,
1735
+ config: this.options,
1736
+ engine: this.engine.getState()
1737
+ };
1738
+ }
1739
+ /**
1740
+ * Get public API
1741
+ */
1742
+ getAPI() {
1743
+ var e;
1744
+ return {
1745
+ getHTML: () => this.getHTML(),
1746
+ setHTML: (t) => this.setHTML(t),
1747
+ execCommand: (t, i) => this.execCommand(t, i),
1748
+ focus: () => this.focus(),
1749
+ blur: () => this.blur(),
1750
+ destroy: () => this.destroy(),
1751
+ registerCommand: (t, i) => this.registerCommand(t, i),
1752
+ onChange: (t) => this.onChange(t),
1753
+ getState: () => this.getState(),
1754
+ toolbar: {
1755
+ items: ((e = this.options.plugins) == null ? void 0 : e.flatMap((t) => t.toolbar || [])) || []
1756
+ }
1757
+ };
1758
+ }
1759
+ /**
1760
+ * Destroy editor
1761
+ */
1762
+ destroy() {
1763
+ var e;
1764
+ this.engine.destroy(), (e = this.toolbar) == null || e.destroy(), this.changeListeners = [], this.options.onDestroy && this.options.onDestroy();
1765
+ }
1766
+ }
1767
+ function z(a) {
1768
+ return new S(a);
1769
+ }
1770
+ class x {
1771
+ constructor(e) {
1772
+ this.options = e, this.containerElement = e.element;
1773
+ const t = this.resolvePlugins(e.plugins);
1774
+ this.engine = new f({
1775
+ content: e.content,
1776
+ plugins: t,
1777
+ readonly: e.readonly
1778
+ }), this.initializeDOM();
1779
+ }
1780
+ /**
1781
+ * Resolve plugins from string or array
1782
+ */
1783
+ resolvePlugins(e) {
1784
+ return e ? typeof e == "string" ? (console.warn("String-based plugin loading not yet implemented for VanillaAdapter"), []) : e : [];
1785
+ }
1786
+ /**
1787
+ * Initialize DOM elements
1788
+ */
1789
+ initializeDOM() {
1790
+ this.containerElement.innerHTML = "", this.containerElement.classList.add("editora-editor"), this.options.enableToolbar !== !1 && this.options.toolbar !== !1 && (this.toolbarElement = document.createElement("div"), this.toolbarElement.className = "editora-toolbar-container", this.containerElement.appendChild(this.toolbarElement), this.toolbar = new b(
1791
+ {
1792
+ items: typeof this.options.toolbar == "string" ? this.options.toolbar : void 0
1793
+ },
1794
+ this.options.plugins || []
1795
+ ), this.toolbar.setCommandHandler((e, t) => {
1796
+ this.execCommand(e, t);
1797
+ }), this.toolbar.render(this.toolbarElement)), this.contentElement = document.createElement("div"), this.contentElement.className = "editora-content", this.contentElement.contentEditable = this.options.readonly ? "false" : "true", this.contentElement.style.minHeight = "200px", this.contentElement.style.outline = "none", this.contentElement.style.padding = "12px", this.options.content && (this.contentElement.innerHTML = this.options.content), this.containerElement.appendChild(this.contentElement), this.contentElement.addEventListener("input", () => {
1798
+ this.containerElement.dispatchEvent(new CustomEvent("change", {
1799
+ detail: { html: this.getContent() }
1800
+ }));
1801
+ });
1802
+ }
1803
+ /**
1804
+ * Get content
1805
+ */
1806
+ getContent() {
1807
+ var e;
1808
+ return ((e = this.contentElement) == null ? void 0 : e.innerHTML) || "";
1809
+ }
1810
+ /**
1811
+ * Set content
1812
+ */
1813
+ setContent(e) {
1814
+ this.contentElement && (this.contentElement.innerHTML = e);
1815
+ }
1816
+ /**
1817
+ * Execute command
1818
+ */
1819
+ execCommand(e, t) {
1820
+ return this.engine.execCommand(e, t);
1821
+ }
1822
+ /**
1823
+ * Focus editor
1824
+ */
1825
+ focus() {
1826
+ var e;
1827
+ (e = this.contentElement) == null || e.focus();
1828
+ }
1829
+ /**
1830
+ * Add event listener
1831
+ */
1832
+ on(e, t) {
1833
+ const i = (s) => {
1834
+ t(s.detail);
1835
+ };
1836
+ return this.containerElement.addEventListener(e, i), () => {
1837
+ this.containerElement.removeEventListener(e, i);
1838
+ };
1839
+ }
1840
+ /**
1841
+ * Destroy editor
1842
+ */
1843
+ destroy() {
1844
+ var e;
1845
+ this.engine.destroy(), (e = this.toolbar) == null || e.destroy(), this.containerElement.innerHTML = "";
1846
+ }
1847
+ }
1848
+ function U(a) {
1849
+ return new x(a);
1850
+ }
1851
+ function R() {
1852
+ typeof window != "undefined" && !customElements.get("editora-editor") && customElements.define("editora-editor", v);
1853
+ }
602
1854
  export {
603
- y as Editor,
604
- l as EditorState,
605
- M as KeyboardShortcutManager,
606
- k as PluginManager,
607
- m as PluginRuntime,
608
- g as Schema,
609
- v as createMediaPlugin,
610
- S as createPluginRuntime,
611
- b as createSpellcheckPlugin
1855
+ $ as CharacterDialog,
1856
+ F as ColorPicker,
1857
+ B as CommandRegistry,
1858
+ G as ConfigResolver,
1859
+ u as Dialog,
1860
+ m as DocumentModel,
1861
+ D as Dropdown,
1862
+ k as Editor,
1863
+ f as EditorEngine,
1864
+ y as EditorState,
1865
+ H as EmojiDialog,
1866
+ K as FloatingToolbar,
1867
+ A as ImageDialog,
1868
+ L as KeyboardShortcutManager,
1869
+ j as LinkDialog,
1870
+ P as MathDialog,
1871
+ I as MediaPlugin,
1872
+ V as PluginLoader,
1873
+ g as PluginManager,
1874
+ E as PluginRuntime,
1875
+ S as ReactAdapter,
1876
+ v as RichTextEditorElement,
1877
+ W as Schema,
1878
+ T as SpellcheckPlugin,
1879
+ X as StatusBar,
1880
+ q as TableDialog,
1881
+ b as ToolbarRenderer,
1882
+ x as VanillaAdapter,
1883
+ _ as calculateTextStats,
1884
+ Y as countLines,
1885
+ U as createEditor,
1886
+ M as createPluginRuntime,
1887
+ z as createReactAdapter,
1888
+ J as getCursorPosition,
1889
+ Q as getSelectionInfo,
1890
+ Z as getTextOffset,
1891
+ R as initWebComponent
612
1892
  };
1893
+ //# sourceMappingURL=index.esm.js.map