@editora/core 1.0.0 → 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,1119 @@
1
+ class m {
2
+ constructor(t, e, o) {
3
+ this.doc = t, this.selection = e, this.schema = o;
4
+ }
5
+ static create(t, e) {
6
+ const o = e || t.node("doc", {}, [t.node("paragraph")]);
7
+ return new m(o, { anchor: 0, head: 0 }, t);
8
+ }
9
+ apply(t, e) {
10
+ return new m(t, e || this.selection, this.schema);
11
+ }
12
+ }
13
+ class E {
14
+ constructor(t, e) {
15
+ this.nodes = new Map(Object.entries(t)), this.marks = new Map(Object.entries(e));
16
+ }
17
+ node(t, e, o) {
18
+ return { type: t, attrs: e, content: o };
19
+ }
20
+ text(t, e) {
21
+ return { type: "text", text: t, marks: e };
22
+ }
23
+ }
24
+ class C {
25
+ constructor() {
26
+ this.plugins = [], this.pluginConfigs = /* @__PURE__ */ new Map();
27
+ }
28
+ register(t, e) {
29
+ if (this.plugins.push(t), e && this.pluginConfigs.set(t.name, e), t.initialize) {
30
+ const o = this.pluginConfigs.get(t.name) || t.config;
31
+ t.initialize(o);
32
+ }
33
+ }
34
+ unregister(t) {
35
+ const e = this.plugins.findIndex((o) => o.name === t);
36
+ if (e > -1) {
37
+ const o = this.plugins[e];
38
+ o.destroy && o.destroy(), this.plugins.splice(e, 1), this.pluginConfigs.delete(t);
39
+ }
40
+ }
41
+ getPlugin(t) {
42
+ return this.plugins.find((e) => e.name === t);
43
+ }
44
+ getPluginConfig(t) {
45
+ return this.pluginConfigs.get(t);
46
+ }
47
+ buildSchema() {
48
+ const t = {}, e = {};
49
+ return this.plugins.forEach((o) => {
50
+ o.nodes && Object.assign(t, o.nodes), o.marks && Object.assign(e, o.marks);
51
+ }), new E(t, e);
52
+ }
53
+ getCommands() {
54
+ const t = {};
55
+ return this.plugins.forEach((e) => {
56
+ e.commands && Object.assign(t, e.commands);
57
+ }), t;
58
+ }
59
+ getToolbarItems() {
60
+ return this.plugins.flatMap((t) => t.toolbar || []);
61
+ }
62
+ /**
63
+ * Execute plugin command with mode awareness
64
+ */
65
+ async executePluginCommand(t, e, ...o) {
66
+ const i = this.getPlugin(t);
67
+ if (!i)
68
+ throw new Error(`Plugin not found: ${t}`);
69
+ const n = this.getPluginConfig(t) || i.config || {}, s = n.mode || "local";
70
+ try {
71
+ switch (s) {
72
+ case "local":
73
+ return i.executeLocal ? i.executeLocal(e, ...o) : null;
74
+ case "api":
75
+ if (!i.executeAPI)
76
+ throw new Error(`Plugin ${t} does not support API mode`);
77
+ return await i.executeAPI(e, ...o);
78
+ case "hybrid":
79
+ if (i.executeHybrid)
80
+ return await i.executeHybrid(e, ...o);
81
+ try {
82
+ if (i.executeAPI)
83
+ return await i.executeAPI(e, ...o);
84
+ } catch (r) {
85
+ if (console.warn(`API execution failed for ${t}, falling back to local`, r), i.executeLocal && n.fallbackToLocal !== !1)
86
+ return i.executeLocal(e, ...o);
87
+ throw r;
88
+ }
89
+ break;
90
+ default:
91
+ throw new Error(`Unknown plugin mode: ${s}`);
92
+ }
93
+ } catch (r) {
94
+ throw console.error(`Error executing command ${e} on plugin ${t}:`, r), r;
95
+ }
96
+ }
97
+ /**
98
+ * Destroy all plugins
99
+ */
100
+ async destroyAll() {
101
+ const t = this.plugins.filter((e) => e.destroy).map((e) => e.destroy());
102
+ await Promise.all(t), this.plugins = [], this.pluginConfigs.clear();
103
+ }
104
+ }
105
+ class w {
106
+ constructor(t = {}) {
107
+ this.commands = /* @__PURE__ */ new Map(), Object.entries(t).forEach(([e, o]) => {
108
+ this.register(e, o);
109
+ });
110
+ }
111
+ /**
112
+ * Register a command
113
+ */
114
+ register(t, e) {
115
+ this.commands.has(t) && console.warn(`Command ${t} is being overwritten`), this.commands.set(t, e);
116
+ }
117
+ /**
118
+ * Unregister a command
119
+ */
120
+ unregister(t) {
121
+ this.commands.delete(t);
122
+ }
123
+ /**
124
+ * Get a command handler
125
+ */
126
+ get(t) {
127
+ return this.commands.get(t);
128
+ }
129
+ /**
130
+ * Check if command exists
131
+ */
132
+ has(t) {
133
+ return this.commands.has(t);
134
+ }
135
+ /**
136
+ * Get all command names
137
+ */
138
+ getCommandNames() {
139
+ return Array.from(this.commands.keys());
140
+ }
141
+ /**
142
+ * Clear all commands
143
+ */
144
+ clear() {
145
+ this.commands.clear();
146
+ }
147
+ }
148
+ class k {
149
+ constructor(t = {}) {
150
+ this.listeners = /* @__PURE__ */ new Map(), this.isReadonly = !1, this.isDestroyed = !1, this.isReadonly = t.readonly || !1, this.pluginManager = new C(), t.plugins && Array.isArray(t.plugins) && t.plugins.forEach((o) => this.pluginManager.register(o));
151
+ const e = this.pluginManager.buildSchema();
152
+ this.state = m.create(e), this.commandRegistry = new w(this.pluginManager.getCommands());
153
+ }
154
+ /**
155
+ * Execute a command
156
+ */
157
+ execCommand(t, e) {
158
+ if (this.isReadonly)
159
+ return console.warn("Cannot execute commands in readonly mode"), !1;
160
+ if (this.isDestroyed)
161
+ return console.warn("Cannot execute commands on destroyed editor"), !1;
162
+ const o = this.commandRegistry.get(t);
163
+ if (!o)
164
+ return console.warn(`Command not found: ${t}`), !1;
165
+ let i;
166
+ return e !== void 0 ? i = o(this.state, e) : i = o(this.state), i ? (this.setState(i), this.emit("change", this.state), !0) : !1;
167
+ }
168
+ /**
169
+ * Update editor state
170
+ */
171
+ setState(t) {
172
+ this.isDestroyed || (this.state = t, this.emit("stateChange", t));
173
+ }
174
+ /**
175
+ * Get current state
176
+ */
177
+ getState() {
178
+ return this.state;
179
+ }
180
+ /**
181
+ * Set readonly mode
182
+ */
183
+ setReadonly(t) {
184
+ this.isReadonly = t, this.emit("readonlyChange", t);
185
+ }
186
+ /**
187
+ * Check if readonly
188
+ */
189
+ isReadOnly() {
190
+ return this.isReadonly;
191
+ }
192
+ /**
193
+ * Event emitter
194
+ */
195
+ on(t, e) {
196
+ return this.listeners.has(t) || this.listeners.set(t, []), this.listeners.get(t).push(e), () => {
197
+ const o = this.listeners.get(t);
198
+ if (o) {
199
+ const i = o.indexOf(e);
200
+ i > -1 && o.splice(i, 1);
201
+ }
202
+ };
203
+ }
204
+ /**
205
+ * Emit event
206
+ */
207
+ emit(t, ...e) {
208
+ const o = this.listeners.get(t);
209
+ o && o.forEach((i) => {
210
+ try {
211
+ i(...e);
212
+ } catch (n) {
213
+ console.error(`Error in ${t} handler:`, n);
214
+ }
215
+ });
216
+ }
217
+ /**
218
+ * Destroy editor instance
219
+ */
220
+ destroy() {
221
+ this.isDestroyed || (this.isDestroyed = !0, this.listeners.clear(), this.emit("destroy"));
222
+ }
223
+ /**
224
+ * Check if destroyed
225
+ */
226
+ isEditorDestroyed() {
227
+ return this.isDestroyed;
228
+ }
229
+ }
230
+ class v {
231
+ // PluginLoader instance to get all registered plugins
232
+ constructor(t, e, o) {
233
+ this.config = t, this.plugins = e, this.pluginLoader = o;
234
+ }
235
+ /**
236
+ * Set command handler for toolbar buttons
237
+ */
238
+ setCommandHandler(t) {
239
+ this.commandHandler = t;
240
+ }
241
+ /**
242
+ * Parse toolbar string into button groups
243
+ */
244
+ parseToolbarString(t) {
245
+ const e = [], o = t.split("|").map((r) => r.trim()), i = this.getAvailableToolbarItems(), n = /* @__PURE__ */ new Map();
246
+ i.forEach((r) => {
247
+ r.command && n.set(r.command, r), r.type === "group" && r.label && n.set(r.label, r);
248
+ });
249
+ const s = {
250
+ bold: "toggleBold",
251
+ italic: "toggleItalic",
252
+ underline: "toggleUnderline",
253
+ strikethrough: "toggleStrikethrough",
254
+ bullist: "toggleBulletList",
255
+ numlist: "toggleOrderedList",
256
+ checklist: "toggleChecklist",
257
+ link: "openLinkDialog",
258
+ image: "openImageDialog",
259
+ table: "insertTable",
260
+ anchor: "insertAnchor",
261
+ code: "toggleSourceView",
262
+ blockquote: "toggleBlockquote",
263
+ undo: "undo",
264
+ redo: "redo",
265
+ textColor: "openTextColorPicker",
266
+ backgroundColor: "openBackgroundColorPicker",
267
+ fontSize: "fontSize",
268
+ fontFamily: "setFontFamily",
269
+ lineHeight: "setLineHeight",
270
+ heading: "setBlockType",
271
+ paragraph: "setParagraph",
272
+ textAlignment: "setTextAlignment",
273
+ direction: "setDirectionLTR",
274
+ indent: "increaseIndent",
275
+ outdent: "decreaseIndent",
276
+ capitalization: "setCapitalization",
277
+ math: "insertMath",
278
+ specialCharacters: "insertSpecialCharacter",
279
+ emojis: "openEmojiDialog",
280
+ embedIframe: "openEmbedIframeDialog",
281
+ fullscreen: "toggleFullscreen",
282
+ preview: "togglePreview",
283
+ print: "print",
284
+ a11yChecker: "toggleA11yChecker",
285
+ spellCheck: "toggleSpellCheck",
286
+ comments: "addComment",
287
+ showHideComments: "toggleComments",
288
+ toggleComments: "toggleComments",
289
+ footnote: "insertFootnote",
290
+ mergeTags: "insertMergeTag",
291
+ pageBreak: "insertPageBreak",
292
+ template: "insertTemplate",
293
+ importWord: "importWord",
294
+ exportWord: "exportWord",
295
+ exportPdf: "exportPdf",
296
+ insertImage: "insertImage",
297
+ insertVideo: "insertVideo",
298
+ codeBlock: "insertCodeBlock"
299
+ };
300
+ return o.forEach((r) => {
301
+ const d = [];
302
+ r.split(/\s+/).filter(Boolean).forEach((p) => {
303
+ if (p === "direction") {
304
+ const l = n.get("setDirectionLTR"), u = n.get("setDirectionRTL");
305
+ l && d.push({
306
+ id: "directionLTR",
307
+ label: l.label,
308
+ command: l.command,
309
+ icon: l.icon,
310
+ type: l.type || "button",
311
+ options: l.options
312
+ }), u && d.push({
313
+ id: "directionRTL",
314
+ label: u.label,
315
+ command: u.command,
316
+ icon: u.icon,
317
+ type: u.type || "button",
318
+ options: u.options
319
+ });
320
+ return;
321
+ }
322
+ if (p === "comments") {
323
+ const l = n.get("addComment"), u = n.get("toggleComments");
324
+ l && d.push({
325
+ id: "addComment",
326
+ label: l.label,
327
+ command: l.command,
328
+ icon: l.icon,
329
+ type: l.type || "button",
330
+ options: l.options
331
+ }), u && d.push({
332
+ id: "toggleComments",
333
+ label: u.label,
334
+ command: u.command,
335
+ icon: u.icon,
336
+ type: u.type || "button",
337
+ options: u.options
338
+ });
339
+ return;
340
+ }
341
+ const c = s[p] || p;
342
+ let a = n.get(c);
343
+ a || (a = n.get(p)), a && d.push({
344
+ id: p,
345
+ label: a.label,
346
+ command: a.command,
347
+ icon: a.icon,
348
+ type: a.type === "separator" ? "separator" : a.type || "button",
349
+ options: a.options,
350
+ items: a.items
351
+ });
352
+ }), d.length > 0 && e.push(d);
353
+ }), e;
354
+ }
355
+ /**
356
+ * Get all available toolbar items from plugins
357
+ */
358
+ getAvailableToolbarItems() {
359
+ let t = this.plugins;
360
+ return this.pluginLoader && (t = this.pluginLoader.getRegisteredPluginNames().map((n) => this.pluginLoader.load(n)).filter((n) => n !== null)), t.flatMap((o) => o.toolbar || []);
361
+ }
362
+ /**
363
+ * Render toolbar to DOM element
364
+ */
365
+ render(t) {
366
+ this.container = t, t.innerHTML = "", t.className = "editora-toolbar", this.config.sticky && t.classList.add("editora-toolbar-sticky"), this.config.position && t.classList.add(`editora-toolbar-${this.config.position}`);
367
+ const e = this.config.items || this.getDefaultToolbarString(), o = this.parseToolbarString(e);
368
+ o.forEach((i, n) => {
369
+ const s = document.createElement("div");
370
+ if (s.className = "editora-toolbar-group", i.forEach((r) => {
371
+ this.appendToolbarButton(s, r);
372
+ }), t.appendChild(s), n < o.length - 1) {
373
+ const r = document.createElement("div");
374
+ r.className = "editora-toolbar-separator", t.appendChild(r);
375
+ }
376
+ });
377
+ }
378
+ /**
379
+ * Append a toolbar button or group to a parent element
380
+ */
381
+ appendToolbarButton(t, e) {
382
+ if (e.type === "separator") {
383
+ const o = document.createElement("div");
384
+ o.className = "editora-toolbar-separator", t.appendChild(o);
385
+ } else if (e.type === "dropdown") {
386
+ const o = this.createDropdown(e);
387
+ t.appendChild(o);
388
+ } else if (e.type === "inline-menu") {
389
+ const o = this.createInlineMenu(e);
390
+ t.appendChild(o);
391
+ } else if (e.type === "group" && e.items && e.items.length) {
392
+ const o = this.createGroupButton(e);
393
+ t.appendChild(o);
394
+ } else if (e.type === "input") {
395
+ const o = this.createInput(e);
396
+ t.appendChild(o);
397
+ } else {
398
+ const o = this.createButton(e);
399
+ t.appendChild(o);
400
+ }
401
+ }
402
+ /**
403
+ * Create a toolbar button element
404
+ */
405
+ createGroupButton(t) {
406
+ const e = document.createElement("div");
407
+ if (e.className = "editora-toolbar-group-button", e.title = t.label, t.icon)
408
+ if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) {
409
+ const o = document.createElement("span");
410
+ o.className = "editora-toolbar-icon", o.innerHTML = t.icon, e.appendChild(o);
411
+ } else
412
+ e.innerHTML = t.icon;
413
+ if (t.items && t.items.length) {
414
+ const o = document.createElement("div");
415
+ o.className = "editora-toolbar-group-items", t.items.forEach((i) => {
416
+ this.appendToolbarButton(o, i);
417
+ }), e.appendChild(o);
418
+ }
419
+ return e;
420
+ }
421
+ /**
422
+ * Create a toolbar button element
423
+ */
424
+ createInput(t) {
425
+ const e = document.createElement("input");
426
+ return e.className = `editora-toolbar-input ${t.label.toLowerCase().replace(/\s+/g, "-")}`, e.type = "text", e.title = t.label, e.placeholder = t.placeholder || "", e.setAttribute("data-command", t.command), t.active && e.classList.add("active"), t.disabled && (e.disabled = !0), e.addEventListener("click", (o) => {
427
+ o.preventDefault(), this.commandHandler && this.commandHandler(t.command);
428
+ }), e;
429
+ }
430
+ /**
431
+ * Create a toolbar button element
432
+ */
433
+ createButton(t) {
434
+ const e = document.createElement("button");
435
+ if (e.className = "editora-toolbar-button", e.type = "button", e.title = t.label, e.setAttribute("data-command", t.command), t.icon)
436
+ if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) {
437
+ const o = document.createElement("span");
438
+ o.className = "editora-toolbar-icon", o.innerHTML = t.icon, e.appendChild(o);
439
+ } else
440
+ e.innerHTML = t.icon;
441
+ else
442
+ e.textContent = t.label;
443
+ return t.active && e.classList.add("active"), t.disabled && (e.disabled = !0), e.addEventListener("click", (o) => {
444
+ o.preventDefault(), this.commandHandler && this.commandHandler(t.command);
445
+ }), e;
446
+ }
447
+ /**
448
+ * Create a dropdown element
449
+ */
450
+ createDropdown(t) {
451
+ const e = document.createElement("div");
452
+ e.className = "editora-toolbar-dropdown";
453
+ const o = document.createElement("button");
454
+ o.className = "editora-toolbar-button editora-toolbar-dropdown-trigger", o.type = "button", o.textContent = t.label;
455
+ const i = document.createElement("div");
456
+ i.className = "editora-toolbar-dropdown-menu", i.style.display = "none", t.options && t.options.forEach((s) => {
457
+ const r = document.createElement("button");
458
+ r.className = "editora-toolbar-dropdown-item", r.type = "button", r.textContent = s.label, r.setAttribute("data-value", s.value), r.addEventListener("click", (d) => {
459
+ d.preventDefault(), this.commandHandler && this.commandHandler(t.command, s.value), i.style.display = "none";
460
+ }), i.appendChild(r);
461
+ }), o.addEventListener("click", (s) => {
462
+ s.preventDefault(), s.stopPropagation();
463
+ const r = i.style.display === "block";
464
+ i.style.display = r ? "none" : "block";
465
+ });
466
+ const n = (s) => {
467
+ e.contains(s.target) || (i.style.display = "none");
468
+ };
469
+ return document.addEventListener("click", n), e._cleanupDropdown = () => {
470
+ document.removeEventListener("click", n);
471
+ }, e.appendChild(o), e.appendChild(i), e;
472
+ }
473
+ /**
474
+ * Create an inline menu element (like dropdown but triggered by button click)
475
+ */
476
+ createInlineMenu(t) {
477
+ const e = document.createElement("div");
478
+ e.className = "editora-toolbar-dropdown editora-toolbar-inline-menu";
479
+ const o = document.createElement("button");
480
+ if (o.className = "editora-toolbar-button", o.type = "button", o.title = t.label, t.icon)
481
+ if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) {
482
+ const n = document.createElement("span");
483
+ n.className = "editora-toolbar-icon", n.innerHTML = t.icon, o.appendChild(n);
484
+ } else
485
+ o.innerHTML = t.icon;
486
+ else
487
+ o.textContent = t.label;
488
+ const i = document.createElement("div");
489
+ return i.className = "editora-toolbar-dropdown-menu", i.style.display = "none", t.options && t.options.forEach((n) => {
490
+ const s = document.createElement("button");
491
+ s.className = "editora-toolbar-dropdown-item", s.type = "button", s.textContent = n.label, s.setAttribute("data-value", n.value), s.addEventListener("click", (r) => {
492
+ r.preventDefault(), r.stopPropagation(), this.commandHandler && this.commandHandler(t.command, n.value), i.style.display = "none";
493
+ }), i.appendChild(s);
494
+ }), o.addEventListener("click", (n) => {
495
+ var r;
496
+ n.preventDefault(), n.stopPropagation();
497
+ const s = (r = this.container) == null ? void 0 : r.querySelectorAll(
498
+ ".editora-toolbar-dropdown-menu"
499
+ );
500
+ s == null || s.forEach((d) => {
501
+ d !== i && (d.style.display = "none");
502
+ }), i.style.display = i.style.display === "none" ? "block" : "none";
503
+ }), document.addEventListener("click", (n) => {
504
+ e.contains(n.target) || (i.style.display = "none");
505
+ }), e.appendChild(o), e.appendChild(i), e;
506
+ }
507
+ /**
508
+ * Get default toolbar string if none provided
509
+ */
510
+ getDefaultToolbarString() {
511
+ return this.getAvailableToolbarItems().map((e) => e.command).join(" ");
512
+ }
513
+ /**
514
+ * Update button state
515
+ */
516
+ updateButtonState(t, e) {
517
+ if (!this.container) return;
518
+ const o = this.container.querySelector(
519
+ `[data-command="${t}"]`
520
+ );
521
+ o && (e.active !== void 0 && o.classList.toggle("active", e.active), e.disabled !== void 0 && (o.disabled = e.disabled));
522
+ }
523
+ /**
524
+ * Destroy toolbar
525
+ */
526
+ destroy() {
527
+ this.container && (this.container.querySelectorAll(".editora-toolbar-dropdown").forEach((e) => {
528
+ const o = e._cleanupDropdown;
529
+ o && o();
530
+ }), this.container.innerHTML = ""), this.commandHandler = void 0;
531
+ }
532
+ }
533
+ class L {
534
+ constructor(t) {
535
+ this.visible = !1, this.config = t;
536
+ }
537
+ /**
538
+ * Create and mount floating toolbar
539
+ */
540
+ create(t) {
541
+ const e = document.createElement("div");
542
+ return e.className = "editora-floating-toolbar", e.style.display = "none", e.style.position = "absolute", e.style.zIndex = "1000", this.container = e, t.appendChild(e), e;
543
+ }
544
+ /**
545
+ * Show toolbar at position
546
+ */
547
+ show(t, e) {
548
+ this.container && (this.container.style.display = "block", this.container.style.left = `${t}px`, this.container.style.top = `${e}px`, this.visible = !0);
549
+ }
550
+ /**
551
+ * Hide toolbar
552
+ */
553
+ hide() {
554
+ this.container && (this.container.style.display = "none", this.visible = !1);
555
+ }
556
+ /**
557
+ * Update position
558
+ */
559
+ updatePosition(t, e) {
560
+ !this.container || !this.visible || (this.container.style.left = `${t}px`, this.container.style.top = `${e}px`);
561
+ }
562
+ /**
563
+ * Check if visible
564
+ */
565
+ isVisible() {
566
+ return this.visible;
567
+ }
568
+ /**
569
+ * Destroy floating toolbar
570
+ */
571
+ destroy() {
572
+ this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this.container = void 0, this.visible = !1;
573
+ }
574
+ }
575
+ class T {
576
+ constructor(t = {}) {
577
+ this.statusInfo = {}, this.config = t;
578
+ }
579
+ /**
580
+ * Create and mount status bar
581
+ */
582
+ create(t) {
583
+ const e = document.createElement("div");
584
+ return e.className = "editora-statusbar", this.config.position && e.classList.add(`editora-statusbar-${this.config.position}`), this.container = e, t.appendChild(e), e;
585
+ }
586
+ /**
587
+ * Update status information
588
+ */
589
+ update(t) {
590
+ this.statusInfo = { ...this.statusInfo, ...t }, this.render();
591
+ }
592
+ /**
593
+ * Render status bar content
594
+ */
595
+ render() {
596
+ if (!this.container) return;
597
+ this.container.innerHTML = "";
598
+ const t = [];
599
+ this.statusInfo.wordCount !== void 0 && t.push(`Words: ${this.statusInfo.wordCount}`), this.statusInfo.charCount !== void 0 && t.push(`Characters: ${this.statusInfo.charCount}`), this.statusInfo.lineCount !== void 0 && t.push(`Lines: ${this.statusInfo.lineCount}`), this.statusInfo.language && t.push(`Language: ${this.statusInfo.language}`), this.statusInfo.custom && Object.entries(this.statusInfo.custom).forEach(([e, o]) => {
600
+ t.push(`${e}: ${o}`);
601
+ }), t.forEach((e, o) => {
602
+ const i = document.createElement("span");
603
+ if (i.className = "editora-statusbar-item", i.textContent = e, this.container.appendChild(i), o < t.length - 1) {
604
+ const n = document.createElement("span");
605
+ n.className = "editora-statusbar-separator", n.textContent = "|", this.container.appendChild(n);
606
+ }
607
+ });
608
+ }
609
+ /**
610
+ * Destroy status bar
611
+ */
612
+ destroy() {
613
+ this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this.container = void 0;
614
+ }
615
+ }
616
+ const y = class y {
617
+ /**
618
+ * Resolve configuration from multiple sources with priority
619
+ */
620
+ static resolve(t) {
621
+ const e = {};
622
+ if (Object.assign(e, this.EDITOR_DEFAULTS), t.pluginDefaults && Object.assign(e, t.pluginDefaults), t.attributes) {
623
+ const o = this.parseAttributes(t.attributes);
624
+ Object.assign(e, o);
625
+ }
626
+ return t.jsConfig && Object.assign(e, t.jsConfig), e;
627
+ }
628
+ /**
629
+ * Parse web component attributes
630
+ */
631
+ static parseAttributes(t) {
632
+ const e = {};
633
+ for (const [o, i] of Object.entries(t)) {
634
+ const n = this.kebabToCamel(o);
635
+ e[n] = this.parseAttributeValue(i);
636
+ }
637
+ return e;
638
+ }
639
+ /**
640
+ * Parse attribute value to appropriate type
641
+ */
642
+ static parseAttributeValue(t) {
643
+ if (t === "true") return !0;
644
+ if (t === "false") return !1;
645
+ if (/^\d+$/.test(t)) return parseInt(t, 10);
646
+ if (/^\d+\.\d+$/.test(t)) return parseFloat(t);
647
+ if (t.startsWith("{") || t.startsWith("["))
648
+ try {
649
+ return JSON.parse(t);
650
+ } catch (e) {
651
+ return t;
652
+ }
653
+ return t;
654
+ }
655
+ /**
656
+ * Convert kebab-case to camelCase
657
+ */
658
+ static kebabToCamel(t) {
659
+ return t.replace(/-([a-z])/g, (e, o) => o.toUpperCase());
660
+ }
661
+ /**
662
+ * Validate configuration
663
+ */
664
+ static validate(t) {
665
+ const e = [];
666
+ return t.height !== void 0 && typeof t.height == "number" && t.height < 0 && e.push("height must be a positive number"), t.width !== void 0 && typeof t.width == "number" && t.width < 0 && e.push("width must be a positive number"), t.plugins !== void 0 && !Array.isArray(t.plugins) && typeof t.plugins != "string" && e.push("plugins must be an array or string"), t.theme !== void 0 && typeof t.theme != "string" && e.push("theme must be a string"), {
667
+ valid: e.length === 0,
668
+ errors: e
669
+ };
670
+ }
671
+ /**
672
+ * Get default configuration
673
+ */
674
+ static getDefaults() {
675
+ return { ...this.EDITOR_DEFAULTS };
676
+ }
677
+ /**
678
+ * Merge configurations (deep merge)
679
+ */
680
+ static merge(...t) {
681
+ const e = {};
682
+ for (const o of t)
683
+ for (const [i, n] of Object.entries(o))
684
+ n != null && (typeof n == "object" && !Array.isArray(n) && e[i] ? e[i] = this.merge(e[i], n) : e[i] = n);
685
+ return e;
686
+ }
687
+ };
688
+ y.EDITOR_DEFAULTS = {
689
+ height: 400,
690
+ width: "100%",
691
+ readonly: !1,
692
+ disabled: !1,
693
+ menubar: !0,
694
+ toolbar: !0,
695
+ plugins: [],
696
+ theme: "light",
697
+ content: "",
698
+ placeholder: "Start typing...",
699
+ autofocus: !1,
700
+ autosave: !1,
701
+ spellcheck: !1,
702
+ language: "en"
703
+ };
704
+ let b = y;
705
+ class P {
706
+ constructor() {
707
+ this.loadedPlugins = /* @__PURE__ */ new Map(), this.pluginRegistry = /* @__PURE__ */ new Map();
708
+ }
709
+ /**
710
+ * Register a plugin factory
711
+ */
712
+ register(t, e) {
713
+ this.pluginRegistry.set(t, e);
714
+ }
715
+ /**
716
+ * Load a plugin by name
717
+ */
718
+ load(t, e) {
719
+ if (this.loadedPlugins.has(t))
720
+ return this.loadedPlugins.get(t);
721
+ const o = this.pluginRegistry.get(t);
722
+ if (!o)
723
+ return console.warn(`Plugin not found: ${t}`), null;
724
+ const i = o();
725
+ return e && this.applyPluginConfig(i, e), this.loadedPlugins.set(t, i), i;
726
+ }
727
+ /**
728
+ * Load multiple plugins
729
+ */
730
+ loadMultiple(t, e) {
731
+ return t.map((o) => this.load(o, e)).filter((o) => o !== null);
732
+ }
733
+ /**
734
+ * Parse plugin string "lists link image media"
735
+ */
736
+ parsePluginString(t, e) {
737
+ const o = t.split(/\s+/).filter(Boolean);
738
+ return this.loadMultiple(o, e);
739
+ }
740
+ /**
741
+ * Apply configuration to plugin
742
+ */
743
+ applyPluginConfig(t, e) {
744
+ t.__pluginConfig = e;
745
+ }
746
+ /**
747
+ * Unload a plugin
748
+ */
749
+ unload(t) {
750
+ this.loadedPlugins.delete(t);
751
+ }
752
+ /**
753
+ * Clear all loaded plugins
754
+ */
755
+ clear() {
756
+ this.loadedPlugins.clear();
757
+ }
758
+ /**
759
+ * Get all loaded plugin names
760
+ */
761
+ getLoadedPluginNames() {
762
+ return Array.from(this.loadedPlugins.keys());
763
+ }
764
+ /**
765
+ * Get all registered plugin names (available for loading)
766
+ */
767
+ getRegisteredPluginNames() {
768
+ return Array.from(this.pluginRegistry.keys());
769
+ }
770
+ /**
771
+ * Check if plugin is loaded
772
+ */
773
+ isLoaded(t) {
774
+ return this.loadedPlugins.has(t);
775
+ }
776
+ }
777
+ const I = '.editora-editor{display:flex;flex-direction:column;border:1px solid #ddd;border-radius:4px;background:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;overflow:hidden}.editora-editor *{box-sizing:border-box}.editora-theme-light{background:#fff;color:#333}.editora-theme-dark{background:#1e1e1e;color:#d4d4d4;border-color:#3c3c3c}.editora-toolbar{display:flex;align-items:center;gap:4px;padding:8px;background:#f5f5f5;border-bottom:1px solid #ddd;flex-wrap:wrap}.editora-theme-dark .editora-toolbar{background:#252526;border-bottom-color:#3c3c3c}.editora-toolbar-sticky{position:sticky;top:0;z-index:100}.editora-toolbar-group{display:flex;align-items:center;gap:2px}.editora-toolbar-button{padding:6px 12px;border:1px solid #ccc;background:#fff;cursor:pointer;border-radius:3px;font-weight:600;font-size:14px;height:30px;display:flex;align-items:center;white-space:nowrap}.editora-toolbar-input.font-size{width:40px;padding:.25rem;text-align:center;font-size:14px;background:#fff;border:1px solid var(--rte-color-border-light);border-radius:var(--rte-radius-sm)}.editora-toolbar-group-items{display:flex;align-items:center;border:1px solid #ccc;.editora-toolbar-button{border:none;border-radius:0;&:first-child{border-right:1px solid #ccc;border-top-left-radius:3px;border-bottom-left-radius:3px}&:last-child{border-left:1px solid #ccc;border-top-right-radius:3px;border-bottom-right-radius:3px}}}.editora-theme-dark .editora-toolbar-button{color:#d4d4d4}.editora-toolbar-button:hover{background:#e0e0e0;border-color:#ccc}.editora-theme-dark .editora-toolbar-button:hover{background:#37373d;border-color:#555}.editora-toolbar-button:active,.editora-toolbar-button.active{background:#d0d0d0;border-color:#999}.editora-theme-dark .editora-toolbar-button:active,.editora-theme-dark .editora-toolbar-button.active{background:#2a2d2e;border-color:#666}.editora-toolbar-button:disabled{opacity:.5;cursor:not-allowed}.editora-toolbar-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;line-height:1}.editora-toolbar-button svg,.editora-toolbar-icon svg{width:24px;height:24px;display:block}.editora-toolbar-separator{width:1px;height:24px;background:#ddd;margin:0 4px}.editora-theme-dark .editora-toolbar-separator{background:#3c3c3c}.editora-toolbar-dropdown{position:relative}.editora-toolbar-dropdown-menu{position:absolute;top:100%;left:0;min-width:150px;margin-top:4px;padding:4px 0;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-toolbar-dropdown-menu{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-toolbar-dropdown-item{display:block;width:100%;padding:8px 12px;border:none;background:transparent;color:#333;text-align:left;cursor:pointer;font-size:13px;transition:background .15s ease}.editora-theme-dark .editora-toolbar-dropdown-item{color:#d4d4d4}.editora-toolbar-dropdown-item:hover{background:#f5f5f5}.editora-theme-dark .editora-toolbar-dropdown-item:hover{background:#37373d}.editora-content{flex:1;min-height:200px;padding:16px;outline:none;overflow-y:auto;line-height:1.6}.editora-content:empty:before{content:attr(data-placeholder);color:#999;pointer-events:none}.editora-theme-dark .editora-content:empty:before{color:#6a6a6a}.editora-content h1{font-size:2em;margin:.67em 0;font-weight:600}.editora-content h2{font-size:1.5em;margin:.75em 0;font-weight:600}.editora-content h3{font-size:1.17em;margin:.83em 0;font-weight:600}.editora-content p{margin:1em 0}.editora-content ul,.editora-content ol{margin:1em 0;padding-left:2em}.editora-content a{color:#06c;text-decoration:underline}.editora-theme-dark .editora-content a{color:#4db8ff}.editora-content code{padding:2px 4px;background:#f5f5f5;border-radius:3px;font-family:Monaco,Menlo,Consolas,monospace;font-size:.9em}.editora-theme-dark .editora-content code{background:#1e1e1e}.editora-content pre{padding:12px;background:#f5f5f5;border-radius:4px;overflow-x:auto;margin:1em 0}.editora-theme-dark .editora-content pre{background:#1e1e1e}.editora-content blockquote{margin:1em 0;padding-left:1em;border-left:4px solid #ddd;color:#666}.editora-theme-dark .editora-content blockquote{border-left-color:#3c3c3c;color:#9a9a9a}.editora-floating-toolbar{position:absolute;padding:4px;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-floating-toolbar{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-statusbar{display:flex;align-items:center;gap:12px;padding:6px 12px;background:#f5f5f5;border-top:1px solid #ddd;font-size:12px;color:#666}.editora-theme-dark .editora-statusbar{background:#252526;border-top-color:#3c3c3c;color:#9a9a9a}.editora-statusbar-item{white-space:nowrap}.editora-statusbar-separator{color:#ddd}.editora-theme-dark .editora-statusbar-separator{color:#3c3c3c}.editora-editor[readonly] .editora-content{background:#fafafa;cursor:not-allowed}.editora-theme-dark.editora-editor[readonly] .editora-content{background:#1a1a1a}.editora-editor:focus-within{border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.editora-theme-dark.editora-editor:focus-within{border-color:#4db8ff;box-shadow:0 0 0 3px #4db8ff1a}.editora-editor[disabled]{opacity:.6;pointer-events:none}@media(max-width:768px){.editora-toolbar{padding:4px}.editora-toolbar-button{min-width:28px;min-height:28px;padding:4px 8px;font-size:12px}.editora-content{padding:12px}}.editora-content ::selection{background:#06c3}.editora-theme-dark .editora-content ::selection{background:#4db8ff33}.editora-content table{border-collapse:collapse;width:100%;margin:1em 0}.editora-content th,.editora-content td{border:1px solid #ddd;padding:8px 12px;text-align:left}.editora-theme-dark .editora-content th,.editora-theme-dark .editora-content td{border-color:#3c3c3c}.editora-content th{background:#f5f5f5;font-weight:600}.editora-theme-dark .editora-content th{background:#252526}.editora-content img{max-width:100%;height:auto;border-radius:4px}.editora-editor.loading{opacity:.7;pointer-events:none}.editora-editor.loading:after{content:"";position:absolute;top:50%;left:50%;width:24px;height:24px;margin:-12px 0 0 -12px;border:3px solid #ddd;border-top-color:#06c;border-radius:50%;animation:editora-spin .8s linear infinite}@keyframes editora-spin{to{transform:rotate(360deg)}}';
778
+ let g;
779
+ function A() {
780
+ const h = "editora-webcomponent-styles";
781
+ if (!document.getElementById(h)) {
782
+ const t = document.createElement("style");
783
+ t.id = h, t.textContent = I, document.head.appendChild(t);
784
+ }
785
+ }
786
+ function x() {
787
+ if (!g) {
788
+ const h = M.__globalPluginLoader;
789
+ h ? g = h : g = new P();
790
+ }
791
+ return g;
792
+ }
793
+ function N(h) {
794
+ const t = x();
795
+ Object.entries(h).forEach(([e, o]) => {
796
+ t.register(e, o);
797
+ });
798
+ }
799
+ class M extends HTMLElement {
800
+ constructor() {
801
+ if (super(), this.config = {}, this.isInitialized = !1, this.pluginLoader = x(), A(), !this.hasAttribute("data-initial-content")) {
802
+ const t = this.innerHTML.trim();
803
+ t && this.setAttribute("data-initial-content", t);
804
+ }
805
+ }
806
+ // Observed attributes for reactive updates
807
+ static get observedAttributes() {
808
+ return [
809
+ "height",
810
+ "width",
811
+ "menubar",
812
+ "plugins",
813
+ "toolbar",
814
+ "toolbar-items",
815
+ "readonly",
816
+ "disabled",
817
+ "theme",
818
+ "placeholder",
819
+ "autofocus",
820
+ "language",
821
+ "spellcheck"
822
+ ];
823
+ }
824
+ /**
825
+ * Called when element is added to DOM
826
+ */
827
+ connectedCallback() {
828
+ this.config = this.resolveConfig(), setTimeout(() => {
829
+ this.initialize();
830
+ }, 0);
831
+ }
832
+ /**
833
+ * Called when element is removed from DOM
834
+ */
835
+ disconnectedCallback() {
836
+ this.destroy();
837
+ }
838
+ /**
839
+ * Called when an observed attribute changes
840
+ */
841
+ attributeChangedCallback(t, e, o) {
842
+ e !== o && (this.config = this.resolveConfig(), this.handleAttributeChange(t, o));
843
+ }
844
+ /**
845
+ * Set configuration via JavaScript API
846
+ */
847
+ setConfig(t) {
848
+ this.jsConfig = t, this.config = this.resolveConfig(), this.isConnected && (this.destroy(), this.initialize());
849
+ }
850
+ /**
851
+ * Initialize the editor
852
+ */
853
+ initialize() {
854
+ if (this.querySelector(".editora-toolbar") || this.isInitialized) return;
855
+ this.setAttribute("data-editora-editor", "true"), this.config.height && (this.style.height = typeof this.config.height == "number" ? `${this.config.height}px` : this.config.height), this.config.width && (this.style.width = typeof this.config.width == "number" ? `${this.config.width}px` : this.config.width), this.classList.add("editora-editor"), this.config.theme && this.classList.add(`editora-theme-${this.config.theme}`);
856
+ const t = this.loadPlugins();
857
+ t.forEach((o) => {
858
+ if (o.init && typeof o.init == "function")
859
+ try {
860
+ o.init();
861
+ } catch (i) {
862
+ console.error(`[RichTextEditor] Error initializing plugin ${o.name}:`, i);
863
+ }
864
+ });
865
+ const e = this.getAttribute("data-initial-content") || "";
866
+ this.engine = new k({
867
+ content: e,
868
+ plugins: t,
869
+ readonly: this.config.readonly
870
+ }), this.createUI(t, e), this.setupEventListeners(), this.isInitialized = !0, this.dispatchEvent(new CustomEvent("editor-ready", {
871
+ detail: { api: this.getAPI() },
872
+ bubbles: !0
873
+ }));
874
+ }
875
+ /**
876
+ * Get initial content from slot or attribute
877
+ */
878
+ getInitialContent() {
879
+ if (this.config.content)
880
+ return this.config.content;
881
+ const t = this.querySelector("[slot]");
882
+ return t ? t.innerHTML : this.hasChildNodes() ? Array.from(this.childNodes).map((o) => o.nodeType === Node.TEXT_NODE ? o.textContent : o.nodeType === Node.ELEMENT_NODE ? o.outerHTML : "").join("").trim() : "";
883
+ }
884
+ /**
885
+ * Load plugins based on configuration
886
+ */
887
+ loadPlugins() {
888
+ const t = [];
889
+ if (this.config.plugins && (typeof this.config.plugins == "string" && this.config.plugins.length > 0 || Array.isArray(this.config.plugins) && this.config.plugins.length > 0))
890
+ if (typeof this.config.plugins == "string") {
891
+ const o = this.pluginLoader.parsePluginString(this.config.plugins);
892
+ t.push(...o);
893
+ } else Array.isArray(this.config.plugins) && this.config.plugins.forEach((o) => {
894
+ if (typeof o == "string") {
895
+ const i = this.pluginLoader.load(o);
896
+ i && t.push(i);
897
+ } else
898
+ t.push(o);
899
+ });
900
+ else {
901
+ const o = this.pluginLoader.getRegisteredPluginNames(), i = this.pluginLoader.loadMultiple(o);
902
+ t.push(...i);
903
+ }
904
+ return t;
905
+ }
906
+ /**
907
+ * Create UI elements
908
+ */
909
+ createUI(t, e) {
910
+ const o = this.querySelector('[slot="toolbar"]'), i = this.querySelector('[slot="statusbar"]');
911
+ if (this.innerHTML = "", this.config.toolbar !== !1 && !o) {
912
+ this.toolbarElement = document.createElement("div"), this.toolbarElement.className = "editora-toolbar-container", this.appendChild(this.toolbarElement);
913
+ const n = this.config.toolbarItems || this.config.toolbar;
914
+ this.toolbar = new v(
915
+ {
916
+ items: typeof n == "string" ? n : void 0,
917
+ sticky: this.config.toolbar && typeof this.config.toolbar == "object" ? this.config.toolbar.sticky : !1,
918
+ position: "top"
919
+ },
920
+ t,
921
+ this.pluginLoader
922
+ // Pass plugin loader to get all registered plugins
923
+ ), this.toolbar.setCommandHandler((s, r) => {
924
+ var f, p;
925
+ if (this.contentElement) {
926
+ this.contentElement.focus();
927
+ const c = window.getSelection();
928
+ if (!c || c.rangeCount === 0 || !this.contentElement.contains(c.anchorNode)) {
929
+ const a = document.createRange(), l = this.contentElement.lastChild || this.contentElement;
930
+ l.nodeType === Node.TEXT_NODE ? a.setStart(l, ((f = l.textContent) == null ? void 0 : f.length) || 0) : l.nodeType === Node.ELEMENT_NODE ? (a.selectNodeContents(l), a.collapse(!1)) : a.setStart(this.contentElement, 0), a.collapse(!0), c == null || c.removeAllRanges(), c == null || c.addRange(a);
931
+ }
932
+ }
933
+ const d = t.find((c) => c.commands && c.commands[s]);
934
+ if (d && d.commands) {
935
+ const c = d.commands[s];
936
+ if (typeof c == "function")
937
+ try {
938
+ return c(s === "toggleFullscreen" ? this : r);
939
+ } catch (a) {
940
+ return console.error(`[RichTextEditor] Error executing native command ${s}:`, a), !1;
941
+ }
942
+ }
943
+ return ((p = this.engine) == null ? void 0 : p.execCommand(s, r)) || !1;
944
+ }), this.toolbar.render(this.toolbarElement);
945
+ } else o && this.appendChild(o);
946
+ this.contentElement = document.createElement("div"), this.contentElement.className = "editora-content rte-content", this.contentElement.contentEditable = this.config.readonly ? "false" : "true", this.contentElement.setAttribute("role", "textbox"), this.contentElement.setAttribute("aria-multiline", "true"), this.config.placeholder && this.contentElement.setAttribute("data-placeholder", this.config.placeholder);
947
+ try {
948
+ document.execCommand("defaultParagraphSeparator", !1, "p");
949
+ } catch (n) {
950
+ console.warn("defaultParagraphSeparator not supported:", n);
951
+ }
952
+ if (e) {
953
+ const n = document.createElement("div");
954
+ n.innerHTML = e.trim(), !Array.from(n.childNodes).some((r) => {
955
+ if (r.nodeType === Node.ELEMENT_NODE) {
956
+ const d = r.tagName;
957
+ return ["P", "DIV", "H1", "H2", "H3", "H4", "H5", "H6", "UL", "OL", "BLOCKQUOTE", "PRE"].includes(d);
958
+ }
959
+ return !1;
960
+ }) && e.trim() ? this.contentElement.innerHTML = `<p>${e.trim()}</p>` : this.contentElement.innerHTML = e;
961
+ } else
962
+ this.config.placeholder ? this.contentElement.innerHTML = "" : this.contentElement.innerHTML = "<p><br></p>";
963
+ this.appendChild(this.contentElement), this.config.toolbar && typeof this.config.toolbar == "object" && this.config.toolbar.floating && (this.floatingToolbar = new L({ enabled: !0 }), this.floatingToolbar.create(this)), i ? this.appendChild(i) : this.config.statusbar && (this.statusBarElement = document.createElement("div"), this.statusBarElement.className = "editora-statusbar-container", this.appendChild(this.statusBarElement), this.statusBar = new T({ position: "bottom" }), this.statusBar.create(this.statusBarElement)), this.config.autofocus && setTimeout(() => {
964
+ var n;
965
+ return (n = this.contentElement) == null ? void 0 : n.focus();
966
+ }, 0);
967
+ }
968
+ /**
969
+ * Setup event listeners
970
+ */
971
+ setupEventListeners() {
972
+ !this.contentElement || !this.engine || (this.contentElement.addEventListener("input", () => {
973
+ const t = this.contentElement.innerHTML;
974
+ if (this.dispatchEvent(new CustomEvent("content-change", {
975
+ detail: { html: t },
976
+ bubbles: !0
977
+ })), this.statusBar) {
978
+ const e = this.contentElement.textContent || "", o = e.trim().split(/\s+/).filter(Boolean).length, i = e.length;
979
+ this.statusBar.update({ wordCount: o, charCount: i });
980
+ }
981
+ }), this.contentElement.addEventListener("focus", () => {
982
+ this.dispatchEvent(new Event("editor-focus", { bubbles: !0 }));
983
+ }), this.contentElement.addEventListener("blur", () => {
984
+ this.dispatchEvent(new Event("editor-blur", { bubbles: !0 }));
985
+ }), this.floatingToolbar && document.addEventListener("selectionchange", () => {
986
+ this.updateFloatingToolbar();
987
+ }));
988
+ }
989
+ /**
990
+ * Update floating toolbar position
991
+ */
992
+ updateFloatingToolbar() {
993
+ if (!this.floatingToolbar) return;
994
+ const t = window.getSelection();
995
+ if (!t || t.rangeCount === 0) {
996
+ this.floatingToolbar.hide();
997
+ return;
998
+ }
999
+ const e = t.getRangeAt(0);
1000
+ if (e.collapsed) {
1001
+ this.floatingToolbar.hide();
1002
+ return;
1003
+ }
1004
+ const o = e.getBoundingClientRect();
1005
+ this.floatingToolbar.show(o.left, o.top - 40);
1006
+ }
1007
+ /**
1008
+ * Handle attribute changes
1009
+ */
1010
+ handleAttributeChange(t, e) {
1011
+ switch (t) {
1012
+ case "readonly":
1013
+ this.contentElement && (this.contentElement.contentEditable = e === "true" ? "false" : "true"), this.engine && this.engine.setReadonly(e === "true");
1014
+ break;
1015
+ case "theme":
1016
+ this.classList.forEach((o) => {
1017
+ o.startsWith("editora-theme-") && this.classList.remove(o);
1018
+ }), e && this.classList.add(`editora-theme-${e}`);
1019
+ break;
1020
+ case "placeholder":
1021
+ this.contentElement && this.contentElement.setAttribute("data-placeholder", e);
1022
+ break;
1023
+ case "toolbar":
1024
+ case "plugins":
1025
+ this.isConnected && (this.destroy(), this.initialize());
1026
+ break;
1027
+ }
1028
+ }
1029
+ /**
1030
+ * Resolve configuration from all sources
1031
+ */
1032
+ resolveConfig() {
1033
+ const t = {};
1034
+ for (let e = 0; e < this.attributes.length; e++) {
1035
+ const o = this.attributes[e];
1036
+ t[o.name] = o.value;
1037
+ }
1038
+ return b.resolve({
1039
+ jsConfig: this.jsConfig,
1040
+ attributes: t
1041
+ });
1042
+ }
1043
+ /**
1044
+ * Get public API
1045
+ */
1046
+ getAPI() {
1047
+ return {
1048
+ getContent: () => {
1049
+ var t;
1050
+ return ((t = this.contentElement) == null ? void 0 : t.innerHTML) || "";
1051
+ },
1052
+ setContent: (t) => {
1053
+ this.contentElement && (this.contentElement.innerHTML = t);
1054
+ },
1055
+ execCommand: (t, e) => {
1056
+ var o;
1057
+ return ((o = this.engine) == null ? void 0 : o.execCommand(t, e)) || !1;
1058
+ },
1059
+ focus: () => {
1060
+ var t;
1061
+ (t = this.contentElement) == null || t.focus();
1062
+ },
1063
+ blur: () => {
1064
+ var t;
1065
+ (t = this.contentElement) == null || t.blur();
1066
+ },
1067
+ destroy: () => {
1068
+ this.destroy();
1069
+ },
1070
+ on: (t, e) => (this.addEventListener(t, e), () => this.removeEventListener(t, e)),
1071
+ getConfig: () => ({ ...this.config }),
1072
+ setReadonly: (t) => {
1073
+ this.setAttribute("readonly", t.toString());
1074
+ }
1075
+ };
1076
+ }
1077
+ /**
1078
+ * Destroy the editor
1079
+ */
1080
+ destroy() {
1081
+ var t, e, o, i;
1082
+ (t = this.engine) == null || t.destroy(), (e = this.toolbar) == null || e.destroy(), (o = this.floatingToolbar) == null || o.destroy(), (i = this.statusBar) == null || i.destroy(), this.innerHTML = "", this.isInitialized = !1, this.dispatchEvent(new Event("editor-destroy", { bubbles: !0 }));
1083
+ }
1084
+ // Public API methods
1085
+ getContent() {
1086
+ var t;
1087
+ return ((t = this.contentElement) == null ? void 0 : t.innerHTML) || "";
1088
+ }
1089
+ setContent(t) {
1090
+ this.contentElement && (this.contentElement.innerHTML = t);
1091
+ }
1092
+ execCommand(t, e) {
1093
+ var o;
1094
+ return ((o = this.engine) == null ? void 0 : o.execCommand(t, e)) || !1;
1095
+ }
1096
+ focus() {
1097
+ var t;
1098
+ (t = this.contentElement) == null || t.focus();
1099
+ }
1100
+ blur() {
1101
+ var t;
1102
+ (t = this.contentElement) == null || t.blur();
1103
+ }
1104
+ }
1105
+ export {
1106
+ w as C,
1107
+ m as E,
1108
+ L as F,
1109
+ C as P,
1110
+ M as R,
1111
+ E as S,
1112
+ v as T,
1113
+ k as a,
1114
+ T as b,
1115
+ b as c,
1116
+ P as d,
1117
+ N as i
1118
+ };
1119
+ //# sourceMappingURL=index-BS4zT-KN.mjs.map