@emabuild/core 0.0.4 → 0.0.5

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 (47) hide show
  1. package/README.md +17 -2
  2. package/dist/canvas/column-renderer.d.ts +4 -4
  3. package/dist/canvas/column-renderer.d.ts.map +1 -1
  4. package/dist/canvas/content-renderer.d.ts +4 -4
  5. package/dist/canvas/content-renderer.d.ts.map +1 -1
  6. package/dist/canvas/editor-canvas.d.ts +4 -4
  7. package/dist/canvas/editor-canvas.d.ts.map +1 -1
  8. package/dist/canvas/row-renderer.d.ts +4 -4
  9. package/dist/canvas/row-renderer.d.ts.map +1 -1
  10. package/dist/dnd/drag-manager.d.ts.map +1 -1
  11. package/dist/form-tool-BucdYK9Z.js +69 -0
  12. package/dist/form-tool-BucdYK9Z.js.map +1 -0
  13. package/dist/html-tool-CDX3fL-9.js +49 -0
  14. package/dist/html-tool-CDX3fL-9.js.map +1 -0
  15. package/dist/index.js +4 -4
  16. package/dist/mail-editor-DNPaJKo3.js +1568 -0
  17. package/dist/mail-editor-DNPaJKo3.js.map +1 -0
  18. package/dist/mail-editor.d.ts +7 -0
  19. package/dist/mail-editor.d.ts.map +1 -1
  20. package/dist/mail-editor.js +2 -2
  21. package/dist/menu-tool-BrT6-Pvh.js +61 -0
  22. package/dist/menu-tool-BrT6-Pvh.js.map +1 -0
  23. package/dist/properties/property-panel.d.ts +4 -4
  24. package/dist/properties/property-panel.d.ts.map +1 -1
  25. package/dist/sidebar/body-settings.d.ts +4 -4
  26. package/dist/sidebar/body-settings.d.ts.map +1 -1
  27. package/dist/sidebar/editor-sidebar.d.ts +4 -4
  28. package/dist/sidebar/editor-sidebar.d.ts.map +1 -1
  29. package/dist/social-tool-B4BUlJ2I.js +62 -0
  30. package/dist/social-tool-B4BUlJ2I.js.map +1 -0
  31. package/dist/state/editor-store.d.ts +30 -1
  32. package/dist/state/editor-store.d.ts.map +1 -1
  33. package/dist/table-tool-Bo_g3Un_.js +63 -0
  34. package/dist/table-tool-Bo_g3Un_.js.map +1 -0
  35. package/dist/timer-tool-3mF08efm.js +54 -0
  36. package/dist/timer-tool-3mF08efm.js.map +1 -0
  37. package/dist/tools/built-in/tool-manifest.d.ts +9 -0
  38. package/dist/tools/built-in/tool-manifest.d.ts.map +1 -0
  39. package/dist/tools/tool-registry.d.ts +52 -1
  40. package/dist/tools/tool-registry.d.ts.map +1 -1
  41. package/dist/utils/store-controller.d.ts +19 -0
  42. package/dist/utils/store-controller.d.ts.map +1 -0
  43. package/dist/video-tool-CwWMKobZ.js +52 -0
  44. package/dist/video-tool-CwWMKobZ.js.map +1 -0
  45. package/package.json +3 -3
  46. package/dist/mail-editor-D0FbEUZu.js +0 -2245
  47. package/dist/mail-editor-D0FbEUZu.js.map +0 -1
@@ -0,0 +1,1568 @@
1
+ import { html as m, css as z, LitElement as L } from "lit";
2
+ import { property as W, customElement as j } from "lit/decorators.js";
3
+ import { unsafeHTML as A } from "lit/directives/unsafe-html.js";
4
+ function U() {
5
+ const e = {};
6
+ return {
7
+ getCounters() {
8
+ return { ...e };
9
+ },
10
+ setCounters(t) {
11
+ for (const o of Object.keys(e))
12
+ delete e[o];
13
+ Object.assign(e, t);
14
+ },
15
+ next(t) {
16
+ const o = e[t] ?? 0;
17
+ return e[t] = o + 1, e[t];
18
+ }
19
+ };
20
+ }
21
+ class O {
22
+ constructor() {
23
+ this.listeners = /* @__PURE__ */ new Map();
24
+ }
25
+ /** Register a listener for an event */
26
+ on(t, o) {
27
+ this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(o);
28
+ }
29
+ /** Remove a specific listener */
30
+ off(t, o) {
31
+ this.listeners.get(t)?.delete(o);
32
+ }
33
+ /** Emit an event with a payload. Errors in listeners are caught and logged. */
34
+ emit(t, o) {
35
+ this.listeners.get(t)?.forEach((n) => {
36
+ try {
37
+ n(o);
38
+ } catch (i) {
39
+ console.error(`[emabuild] Error in "${t}" listener:`, i);
40
+ }
41
+ });
42
+ }
43
+ /** Remove all listeners, optionally scoped to a single event */
44
+ removeAllListeners(t) {
45
+ t ? this.listeners.delete(t) : this.listeners.clear();
46
+ }
47
+ }
48
+ class N {
49
+ constructor(t = 50) {
50
+ this.undoStack = [], this.redoStack = [], this.maxHistory = t;
51
+ }
52
+ /** Whether there are states to undo to */
53
+ get canUndo() {
54
+ return this.undoStack.length > 0;
55
+ }
56
+ /** Whether there are states to redo to */
57
+ get canRedo() {
58
+ return this.redoStack.length > 0;
59
+ }
60
+ /** Save current design to the undo stack before a mutation */
61
+ push(t) {
62
+ this.undoStack.push(structuredClone(t)), this.undoStack.length > this.maxHistory && this.undoStack.shift(), this.redoStack = [];
63
+ }
64
+ /** Restore the previous state, pushing current state to redo. Returns the restored design or undefined. */
65
+ undo(t) {
66
+ const o = this.undoStack.pop();
67
+ if (o)
68
+ return this.redoStack.push(structuredClone(t)), o;
69
+ }
70
+ /** Restore the next state, pushing current state to undo. Returns the restored design or undefined. */
71
+ redo(t) {
72
+ const o = this.redoStack.pop();
73
+ if (o)
74
+ return this.undoStack.push(structuredClone(t)), o;
75
+ }
76
+ /** Clear all history (e.g. when loading a new design) */
77
+ clear() {
78
+ this.undoStack = [], this.redoStack = [];
79
+ }
80
+ }
81
+ function F() {
82
+ return {
83
+ counters: { u_row: 0, u_column: 0 },
84
+ body: {
85
+ id: "u_body",
86
+ rows: [],
87
+ headers: [],
88
+ footers: [],
89
+ values: {
90
+ backgroundColor: "#e7e7e7",
91
+ contentAlign: "center",
92
+ contentVerticalAlign: "center",
93
+ contentWidth: "600px",
94
+ fontFamily: { label: "Arial", value: "arial,helvetica,sans-serif" },
95
+ textColor: "#000000",
96
+ linkStyle: {
97
+ body: !0,
98
+ linkColor: "#0000ee",
99
+ linkHoverColor: "#0000ee",
100
+ linkUnderline: !0,
101
+ linkHoverUnderline: !0
102
+ },
103
+ preheaderText: "",
104
+ popupPosition: "center",
105
+ popupWidth: "600px",
106
+ popupHeight: "auto",
107
+ borderRadius: "10px",
108
+ popupBackgroundColor: "#FFFFFF",
109
+ popupBackgroundImage: { url: "", fullWidth: !0, repeat: "no-repeat", center: !0, cover: !0 },
110
+ popupOverlay_backgroundColor: "rgba(0, 0, 0, 0.1)",
111
+ popupCloseButton_position: "top-right",
112
+ popupCloseButton_backgroundColor: "#DDDDDD",
113
+ popupCloseButton_iconColor: "#000000",
114
+ popupCloseButton_borderRadius: "0px",
115
+ popupCloseButton_margin: "0px",
116
+ popupCloseButton_action: {
117
+ name: "close_popup",
118
+ attrs: { onClick: "document.querySelector('.u-popup-container').style.display = 'none';" }
119
+ },
120
+ _meta: { htmlID: "u_body", htmlClassNames: "u_body" }
121
+ }
122
+ },
123
+ schemaVersion: 16
124
+ };
125
+ }
126
+ function q(e, t) {
127
+ const o = e.next("u_row"), n = t.map(() => {
128
+ const i = e.next("u_column");
129
+ return {
130
+ id: `u_column_${i}`,
131
+ contents: [],
132
+ values: {
133
+ backgroundColor: "",
134
+ padding: "0px",
135
+ border: {},
136
+ borderRadius: "0px",
137
+ _meta: { htmlID: `u_column_${i}`, htmlClassNames: "u_column" }
138
+ }
139
+ };
140
+ });
141
+ return {
142
+ id: `u_row_${o}`,
143
+ cells: t,
144
+ columns: n,
145
+ values: {
146
+ displayCondition: null,
147
+ columns: !1,
148
+ backgroundColor: "",
149
+ columnsBackgroundColor: "",
150
+ backgroundImage: { url: "", fullWidth: !0, repeat: !1, center: !0, cover: !1 },
151
+ padding: "0px",
152
+ anchor: "",
153
+ hideDesktop: !1,
154
+ hideMobile: !1,
155
+ _meta: { htmlID: `u_row_${o}`, htmlClassNames: "u_row" }
156
+ }
157
+ };
158
+ }
159
+ function G(e, t, o = {}) {
160
+ const n = e.next(`u_content_${t}`), i = `u_content_${t}_${n}`;
161
+ return {
162
+ id: i,
163
+ type: t,
164
+ values: {
165
+ containerPadding: "10px",
166
+ anchor: "",
167
+ hideDesktop: !1,
168
+ hideMobile: !1,
169
+ displayCondition: null,
170
+ _meta: { htmlID: i, htmlClassNames: `u_content_${t}` },
171
+ ...o
172
+ }
173
+ };
174
+ }
175
+ function D(e, t) {
176
+ return e.body.rows.find((o) => o.id === t);
177
+ }
178
+ function C(e, t) {
179
+ for (const o of e.body.rows) {
180
+ const n = o.columns.find((i) => i.id === t);
181
+ if (n) return n;
182
+ }
183
+ }
184
+ function $(e, t) {
185
+ for (const o of e.body.rows)
186
+ for (const n of o.columns) {
187
+ const i = n.contents.find((r) => r.id === t);
188
+ if (i) return i;
189
+ }
190
+ }
191
+ function K(e, t) {
192
+ for (const o of e.body.rows)
193
+ for (const n of o.columns)
194
+ if (n.contents.some((i) => i.id === t)) return n;
195
+ }
196
+ function J(e, t) {
197
+ for (const o of e.body.rows)
198
+ if (o.columns.some((n) => n.id === t)) return o;
199
+ }
200
+ function I(e, t) {
201
+ return e.body.rows.findIndex((o) => o.id === t);
202
+ }
203
+ class X {
204
+ constructor() {
205
+ this.history = new N(), this.counterManager = U(), this.subscribers = /* @__PURE__ */ new Set(), this.channelSubscribers = /* @__PURE__ */ new Map(), this.events = new O(), this._selectedId = null, this._hoveredId = null, this._viewMode = "desktop", this._activeTab = "content", this.design = F();
206
+ }
207
+ // ── Subscriptions ──────────────────────────────────────────
208
+ /** Subscribe to ALL state changes (legacy). Returns an unsubscribe function. */
209
+ subscribe(t) {
210
+ return this.subscribers.add(t), () => this.subscribers.delete(t);
211
+ }
212
+ /**
213
+ * Subscribe to specific channels only. The callback is invoked only
214
+ * when one of the listed channels fires. Returns an unsubscribe function.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * // Only re-render when the design changes, not on hover/selection
219
+ * store.subscribeChannels(['design'], () => this.requestUpdate());
220
+ * ```
221
+ */
222
+ subscribeChannels(t, o) {
223
+ for (const n of t)
224
+ this.channelSubscribers.has(n) || this.channelSubscribers.set(n, /* @__PURE__ */ new Set()), this.channelSubscribers.get(n).add(o);
225
+ return () => {
226
+ for (const n of t)
227
+ this.channelSubscribers.get(n)?.delete(o);
228
+ };
229
+ }
230
+ /** Notify legacy (all) subscribers */
231
+ notify() {
232
+ this.subscribers.forEach((t) => t());
233
+ }
234
+ /** Notify only subscribers of specific channels + legacy subscribers */
235
+ notifyChannels(...t) {
236
+ const o = /* @__PURE__ */ new Set();
237
+ for (const n of this.subscribers) o.add(n);
238
+ for (const n of t) {
239
+ const i = this.channelSubscribers.get(n);
240
+ if (i) for (const r of i) o.add(r);
241
+ }
242
+ o.forEach((n) => n());
243
+ }
244
+ // ── Getters ────────────────────────────────────────────────
245
+ /** Get the full design document */
246
+ getDesign() {
247
+ return this.design;
248
+ }
249
+ /** Get the design body */
250
+ getBody() {
251
+ return this.design.body;
252
+ }
253
+ /** Get all rows */
254
+ getRows() {
255
+ return this.design.body.rows;
256
+ }
257
+ /** Get body-level values (background, fonts, etc.) */
258
+ getBodyValues() {
259
+ return this.design.body.values;
260
+ }
261
+ get selectedId() {
262
+ return this._selectedId;
263
+ }
264
+ get hoveredId() {
265
+ return this._hoveredId;
266
+ }
267
+ get viewMode() {
268
+ return this._viewMode;
269
+ }
270
+ get activeTab() {
271
+ return this._activeTab;
272
+ }
273
+ get canUndo() {
274
+ return this.history.canUndo;
275
+ }
276
+ get canRedo() {
277
+ return this.history.canRedo;
278
+ }
279
+ // ── Design Loading ─────────────────────────────────────────
280
+ /** Load a design document, resetting history and selection */
281
+ loadDesign(t) {
282
+ this.design = structuredClone(t), this.counterManager.setCounters(this.design.counters), this.history.clear(), this._selectedId = null, this.notifyChannels("design", "selection"), this.events.emit("design:loaded", { design: this.design });
283
+ }
284
+ // ── Undo / Redo ────────────────────────────────────────────
285
+ undo() {
286
+ const t = this.history.undo(this.design);
287
+ t && (this.design = t, this.counterManager.setCounters(this.design.counters), this.notifyChannels("design"), this.emitUpdate("content_updated"));
288
+ }
289
+ redo() {
290
+ const t = this.history.redo(this.design);
291
+ t && (this.design = t, this.counterManager.setCounters(this.design.counters), this.notifyChannels("design"), this.emitUpdate("content_updated"));
292
+ }
293
+ // ── Selection / UI State ───────────────────────────────────
294
+ select(t) {
295
+ this._selectedId = t, this.notifyChannels("selection");
296
+ }
297
+ hover(t) {
298
+ this._hoveredId = t, this.notifyChannels("hover");
299
+ }
300
+ setViewMode(t) {
301
+ this._viewMode = t, this.notifyChannels("viewMode");
302
+ }
303
+ setActiveTab(t) {
304
+ this._activeTab = t, this.notifyChannels("activeTab");
305
+ }
306
+ // ── Row Operations ─────────────────────────────────────────
307
+ /** Add a row at the given index (or at the end) */
308
+ addRow(t, o) {
309
+ this.history.push(this.design);
310
+ const n = this.design.body.rows, i = structuredClone(t);
311
+ o !== void 0 && o >= 0 && o <= n.length ? n.splice(o, 0, i) : n.push(i), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("row_added", i);
312
+ }
313
+ /** Remove a row by ID */
314
+ removeRow(t) {
315
+ const o = I(this.design, t);
316
+ o !== -1 && (this.history.push(this.design), this.design.body.rows.splice(o, 1), this._selectedId === t && (this._selectedId = null), this.notifyChannels("design"), this.emitUpdate("row_removed"));
317
+ }
318
+ /** Move a row from one index to another */
319
+ moveRow(t, o) {
320
+ this.history.push(this.design);
321
+ const n = this.design.body.rows, [i] = n.splice(t, 1);
322
+ n.splice(o, 0, i), this.notifyChannels("design"), this.emitUpdate("row_reordered");
323
+ }
324
+ /** Duplicate a row, assigning fresh IDs to all nested elements */
325
+ duplicateRow(t) {
326
+ const o = D(this.design, t);
327
+ if (!o) return;
328
+ this.history.push(this.design);
329
+ const n = structuredClone(o), i = this.counterManager.next("u_row");
330
+ n.id = `u_row_${i}`, n.values._meta = { htmlID: n.id, htmlClassNames: "u_row" };
331
+ for (const l of n.columns) {
332
+ const a = this.counterManager.next("u_column");
333
+ l.id = `u_column_${a}`, l.values._meta = { htmlID: l.id, htmlClassNames: "u_column" };
334
+ for (const d of l.contents) {
335
+ const c = this.counterManager.next(`u_content_${d.type}`);
336
+ d.id = `u_content_${d.type}_${c}`, d.values._meta = { htmlID: d.id, htmlClassNames: `u_content_${d.type}` };
337
+ }
338
+ }
339
+ const r = I(this.design, t);
340
+ this.design.body.rows.splice(r + 1, 0, n), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("row_added", n);
341
+ }
342
+ /** Get the index of a row */
343
+ getRowIndex(t) {
344
+ return I(this.design, t);
345
+ }
346
+ /** Update row-level values */
347
+ updateRowValues(t, o) {
348
+ const n = D(this.design, t);
349
+ n && (this.history.push(this.design), Object.assign(n.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"));
350
+ }
351
+ // ── Column Operations ──────────────────────────────────────
352
+ /** Update column-level values */
353
+ updateColumnValues(t, o) {
354
+ const n = C(this.design, t);
355
+ n && (this.history.push(this.design), Object.assign(n.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"));
356
+ }
357
+ // ── Content Operations ─────────────────────────────────────
358
+ /** Add content to a column at the given index */
359
+ addContent(t, o, n) {
360
+ const i = C(this.design, t);
361
+ if (!i) return;
362
+ this.history.push(this.design);
363
+ const r = structuredClone(o);
364
+ n !== void 0 && n >= 0 && n <= i.contents.length ? i.contents.splice(n, 0, r) : i.contents.push(r), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("content_added", r);
365
+ }
366
+ /** Remove a content block by ID */
367
+ removeContent(t) {
368
+ for (const o of this.design.body.rows)
369
+ for (const n of o.columns) {
370
+ const i = n.contents.findIndex((r) => r.id === t);
371
+ if (i !== -1) {
372
+ this.history.push(this.design), n.contents.splice(i, 1), this._selectedId === t && (this._selectedId = null), this.notifyChannels("design"), this.emitUpdate("content_removed");
373
+ return;
374
+ }
375
+ }
376
+ }
377
+ /** Update content values by ID */
378
+ updateContentValues(t, o) {
379
+ const n = $(this.design, t);
380
+ n && (this.history.push(this.design), Object.assign(n.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"));
381
+ }
382
+ /** Move a content block to a different column at a given index */
383
+ moveContent(t, o, n) {
384
+ const i = $(this.design, t);
385
+ if (!i) return;
386
+ this.history.push(this.design);
387
+ for (const l of this.design.body.rows)
388
+ for (const a of l.columns) {
389
+ const d = a.contents.findIndex((c) => c.id === t);
390
+ if (d !== -1) {
391
+ a.contents.splice(d, 1);
392
+ break;
393
+ }
394
+ }
395
+ const r = C(this.design, o);
396
+ r && r.contents.splice(n, 0, i), this.notifyChannels("design"), this.emitUpdate("content_reordered");
397
+ }
398
+ /** Duplicate a content block, inserting the copy right after the original */
399
+ duplicateContent(t) {
400
+ const o = $(this.design, t);
401
+ if (o)
402
+ for (const n of this.design.body.rows)
403
+ for (const i of n.columns) {
404
+ const r = i.contents.findIndex((l) => l.id === t);
405
+ if (r !== -1) {
406
+ this.history.push(this.design);
407
+ const l = structuredClone(o), a = this.counterManager.next(`u_content_${o.type}`);
408
+ l.id = `u_content_${o.type}_${a}`, l.values._meta = { htmlID: l.id, htmlClassNames: `u_content_${o.type}` }, i.contents.splice(r + 1, 0, l), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("content_added", l);
409
+ return;
410
+ }
411
+ }
412
+ }
413
+ // ── Body Values ────────────────────────────────────────────
414
+ /** Update body-level values (background, fonts, etc.) */
415
+ updateBodyValues(t) {
416
+ this.history.push(this.design), Object.assign(this.design.body.values, t), this.notifyChannels("design"), this.emitUpdate("body_updated");
417
+ }
418
+ // ── Lookups (delegate to design-lookup) ────────────────────
419
+ findRow(t) {
420
+ return D(this.design, t);
421
+ }
422
+ findColumn(t) {
423
+ return C(this.design, t);
424
+ }
425
+ findContent(t) {
426
+ return $(this.design, t);
427
+ }
428
+ findParentColumn(t) {
429
+ return K(this.design, t);
430
+ }
431
+ findParentRow(t) {
432
+ return J(this.design, t);
433
+ }
434
+ // ── Factory Methods (delegate to design-factory) ───────────
435
+ /** Create a new row with the given column layout */
436
+ createRow(t) {
437
+ const o = q(this.counterManager, t);
438
+ return this.syncCounters(), o;
439
+ }
440
+ /** Create a new content block for the given tool type */
441
+ createContent(t, o = {}) {
442
+ const n = G(this.counterManager, t, o);
443
+ return this.syncCounters(), n;
444
+ }
445
+ // ── Private Helpers ────────────────────────────────────────
446
+ syncCounters() {
447
+ this.design.counters = this.counterManager.getCounters();
448
+ }
449
+ emitUpdate(t, o) {
450
+ this.events.emit("design:updated", { type: t, item: o });
451
+ }
452
+ }
453
+ class Y {
454
+ constructor() {
455
+ this.tools = /* @__PURE__ */ new Map(), this.lazyLoaders = /* @__PURE__ */ new Map(), this.lazyMeta = /* @__PURE__ */ new Map(), this.loadingPromises = /* @__PURE__ */ new Map();
456
+ }
457
+ /** Register a tool eagerly (available immediately) */
458
+ register(t) {
459
+ this.tools.set(t.name, t), this.lazyLoaders.delete(t.name), this.lazyMeta.delete(t.name);
460
+ }
461
+ /**
462
+ * Register a tool lazily. The tool's code is only loaded when first needed.
463
+ * Provide metadata (name, label, icon) so the tool can appear in the sidebar.
464
+ *
465
+ * @param meta - Display metadata for the sidebar palette
466
+ * @param loader - Async function that imports and returns the tool definition
467
+ *
468
+ * @example
469
+ * ```ts
470
+ * registry.registerLazy(
471
+ * { name: 'timer', label: 'Timer', icon: '<svg>...</svg>', position: 11 },
472
+ * () => import('./built-in/timer-tool.js').then(m => m.timerTool),
473
+ * );
474
+ * ```
475
+ */
476
+ registerLazy(t, o) {
477
+ this.tools.has(t.name) || (this.lazyMeta.set(t.name, t), this.lazyLoaders.set(t.name, o));
478
+ }
479
+ /** Get a tool by name. Returns undefined if not loaded yet (use ensureLoaded for lazy tools). */
480
+ get(t) {
481
+ return this.tools.get(t);
482
+ }
483
+ /** Check if a tool is registered (eager or lazy) */
484
+ has(t) {
485
+ return this.tools.has(t) || this.lazyLoaders.has(t);
486
+ }
487
+ /** Check if a tool is fully loaded and ready to render */
488
+ isLoaded(t) {
489
+ return this.tools.has(t);
490
+ }
491
+ /**
492
+ * Ensure a lazy tool is loaded. Returns the tool definition.
493
+ * If the tool is already loaded, returns it immediately.
494
+ * If it's being loaded, returns the in-flight promise.
495
+ */
496
+ async ensureLoaded(t) {
497
+ if (this.tools.has(t)) return this.tools.get(t);
498
+ if (this.loadingPromises.has(t)) return this.loadingPromises.get(t);
499
+ const o = this.lazyLoaders.get(t);
500
+ if (!o) return;
501
+ const n = o().then((i) => (this.tools.set(t, i), this.lazyLoaders.delete(t), this.lazyMeta.delete(t), this.loadingPromises.delete(t), i));
502
+ return this.loadingPromises.set(t, n), n;
503
+ }
504
+ /**
505
+ * Get all tools for display in the sidebar palette.
506
+ * Returns both loaded tools and lazy tool metadata, sorted by position.
507
+ */
508
+ getAll() {
509
+ return Array.from(this.tools.values()).sort((t, o) => (t.position ?? 0) - (o.position ?? 0));
510
+ }
511
+ /**
512
+ * Get all tool names and display metadata (including lazy tools not yet loaded).
513
+ * Used by the sidebar to show all available tools.
514
+ */
515
+ getAllMeta() {
516
+ const t = [];
517
+ for (const o of this.tools.values())
518
+ t.push({ name: o.name, label: o.label, icon: o.icon, position: o.position });
519
+ for (const o of this.lazyMeta.values())
520
+ t.push(o);
521
+ return t.sort((o, n) => (o.position ?? 0) - (n.position ?? 0));
522
+ }
523
+ /** Get default values for a tool. Loads lazily if needed (sync — returns empty if not loaded). */
524
+ getDefaultValues(t) {
525
+ const o = this.tools.get(t);
526
+ if (!o) return {};
527
+ const n = { ...o.defaultValues };
528
+ for (const i of Object.values(o.options))
529
+ for (const [r, l] of Object.entries(i.options))
530
+ r in n || (n[r] = l.defaultValue);
531
+ return n;
532
+ }
533
+ /** Get property groups for a tool */
534
+ getPropertyGroups(t) {
535
+ return this.tools.get(t)?.options ?? {};
536
+ }
537
+ }
538
+ const R = {
539
+ /** ID of the content currently being dragged (null if not dragging content) */
540
+ draggingContentId: null,
541
+ startContentDrag(e) {
542
+ this.draggingContentId = e;
543
+ },
544
+ reset() {
545
+ this.draggingContentId = null;
546
+ }
547
+ };
548
+ function T(e) {
549
+ const t = document.createElement("div");
550
+ return Object.assign(t.style, {
551
+ position: "absolute",
552
+ left: "0",
553
+ right: "0",
554
+ height: "3px",
555
+ background: e,
556
+ borderRadius: "2px",
557
+ pointerEvents: "none",
558
+ zIndex: "1000",
559
+ display: "none",
560
+ boxShadow: `0 0 6px ${e}80`
561
+ }), t;
562
+ }
563
+ function M(e, t, o, n, i = "4px") {
564
+ e.parentNode !== t && (e.remove(), t.appendChild(e));
565
+ const l = (t instanceof ShadowRoot ? t.host : t).getBoundingClientRect();
566
+ let a;
567
+ o.length === 0 || n === 0 ? a = o.length === 0 ? 0 : o[0].getBoundingClientRect().top - l.top : n >= o.length ? a = o[o.length - 1].getBoundingClientRect().bottom - l.top : a = o[n].getBoundingClientRect().top - l.top, Object.assign(e.style, {
568
+ display: "block",
569
+ top: `${a}px`,
570
+ left: i,
571
+ right: i,
572
+ width: "auto"
573
+ });
574
+ }
575
+ function x(e) {
576
+ e && (e.style.display = "none");
577
+ }
578
+ function S(e, t) {
579
+ const o = (e instanceof ShadowRoot, e.children);
580
+ for (const n of Array.from(o)) {
581
+ const i = n;
582
+ t(i), i.shadowRoot && S(i.shadowRoot, t), i.children?.length && S(i, t);
583
+ }
584
+ }
585
+ function V(e, t) {
586
+ const o = [];
587
+ return S(e, (n) => {
588
+ n.matches?.(t) && o.push(n);
589
+ }), o;
590
+ }
591
+ class Q {
592
+ constructor(t, o, n) {
593
+ this.currentDrop = null, this.contentIndicator = null, this.rowIndicator = null, this.onDragOver = (i) => {
594
+ const r = i.dataTransfer?.types || [], l = r.includes("application/maileditor-tool"), a = r.includes("application/maileditor-layout"), d = r.includes("application/maileditor-content") || !!R.draggingContentId;
595
+ !l && !d && !a || (i.preventDefault(), i.dataTransfer.dropEffect = l || a ? "copy" : "move", a ? (this.currentDrop = this.findRowDropTarget(i.clientY), x(this.contentIndicator), this.showRowIndicator()) : (this.currentDrop = this.findContentDropTarget(i.clientX, i.clientY), x(this.rowIndicator), this.showContentIndicator()));
596
+ }, this.onDrop = (i) => {
597
+ i.preventDefault(), this.hideAllIndicators();
598
+ const r = this.currentDrop, l = i.dataTransfer?.getData("application/maileditor-layout");
599
+ if (l) {
600
+ this.handleLayoutDrop(JSON.parse(l), r), this.reset();
601
+ return;
602
+ }
603
+ const a = i.dataTransfer?.getData("application/maileditor-tool");
604
+ if (a) {
605
+ this.handleToolDrop(a, r), this.reset();
606
+ return;
607
+ }
608
+ const d = i.dataTransfer?.getData("application/maileditor-content") || R.draggingContentId;
609
+ d && this.handleContentDrop(d, r), this.reset();
610
+ }, this.onDragEnd = () => {
611
+ this.hideAllIndicators(), this.reset();
612
+ }, this.onDragLeave = (i) => {
613
+ const r = i.relatedTarget;
614
+ (!r || !this.root.contains(r)) && (this.hideAllIndicators(), this.currentDrop = null);
615
+ }, this.store = t, this.toolRegistry = o, this.root = n;
616
+ }
617
+ /** Attach all drag event listeners to the shadow root */
618
+ attach() {
619
+ this.root.addEventListener("dragover", this.onDragOver), this.root.addEventListener("drop", this.onDrop), this.root.addEventListener("dragend", this.onDragEnd), this.root.addEventListener("dragleave", this.onDragLeave), this.contentIndicator = T("#3b82f6"), this.rowIndicator = T("#8b5cf6");
620
+ }
621
+ /** Remove all event listeners and clean up indicators */
622
+ detach() {
623
+ this.root.removeEventListener("dragover", this.onDragOver), this.root.removeEventListener("drop", this.onDrop), this.root.removeEventListener("dragend", this.onDragEnd), this.root.removeEventListener("dragleave", this.onDragLeave), this.contentIndicator?.remove(), this.rowIndicator?.remove();
624
+ }
625
+ // ── Drop Handlers ──────────────────────────────────────────
626
+ handleLayoutDrop(t, o = this.currentDrop) {
627
+ const n = this.store.createRow(t), i = o?.type === "row" ? o.rowIndex : void 0;
628
+ this.store.addRow(n, i);
629
+ }
630
+ async handleToolDrop(t, o) {
631
+ if (await this.toolRegistry.ensureLoaded(t), o?.type === "content" && o.columnId) {
632
+ const n = this.toolRegistry.getDefaultValues(t), i = this.store.createContent(t, n);
633
+ this.store.addContent(o.columnId, i, o.contentIndex), this.store.select(i.id);
634
+ } else {
635
+ const n = this.store.createRow([1]);
636
+ this.store.addRow(n);
637
+ const i = this.toolRegistry.getDefaultValues(t), r = this.store.createContent(t, i);
638
+ this.store.addContent(n.columns[0].id, r), this.store.select(r.id);
639
+ }
640
+ }
641
+ handleContentDrop(t, o) {
642
+ o?.type === "content" && o.columnId && (this.store.moveContent(t, o.columnId, o.contentIndex), this.store.select(t));
643
+ }
644
+ // ── Drop Target Detection ─────────────────────────────────
645
+ findRowDropTarget(t) {
646
+ const o = this.root.querySelector("me-editor-canvas");
647
+ if (!o?.shadowRoot) return null;
648
+ const n = Array.from(o.shadowRoot.querySelectorAll("me-row-renderer"));
649
+ if (n.length === 0) return { type: "row", rowIndex: 0, y: 0 };
650
+ let i = Math.abs(t - n[0].getBoundingClientRect().top), r = { type: "row", rowIndex: 0, y: n[0].getBoundingClientRect().top };
651
+ for (let l = 0; l < n.length; l++) {
652
+ const a = n[l].getBoundingClientRect().bottom, d = Math.abs(t - a);
653
+ d < i && (i = d, r = { type: "row", rowIndex: l + 1, y: a });
654
+ }
655
+ return r;
656
+ }
657
+ findContentDropTarget(t, o) {
658
+ const n = V(this.root, "me-column-renderer");
659
+ let i = null, r = 1 / 0;
660
+ for (const l of n) {
661
+ const a = l.dataset.columnId;
662
+ if (!a || !l.shadowRoot) continue;
663
+ const d = l.getBoundingClientRect();
664
+ if (t < d.left || t > d.right) continue;
665
+ const c = Array.from(l.shadowRoot.querySelectorAll("me-content-renderer"));
666
+ if (c.length === 0) {
667
+ const h = Math.abs(o - (d.top + d.height / 2));
668
+ h < r && (r = h, i = { type: "content", columnId: a, contentIndex: 0, y: d.top + d.height / 2 });
669
+ continue;
670
+ }
671
+ const u = c[0].getBoundingClientRect().top;
672
+ let g = Math.abs(o - u);
673
+ g < r && (r = g, i = { type: "content", columnId: a, contentIndex: 0, y: u });
674
+ for (let h = 0; h < c.length; h++) {
675
+ const f = c[h].getBoundingClientRect(), b = c[h + 1]?.getBoundingClientRect(), p = b ? (f.bottom + b.top) / 2 : f.bottom;
676
+ g = Math.abs(o - p), g < r && (r = g, i = { type: "content", columnId: a, contentIndex: h + 1, y: p });
677
+ }
678
+ }
679
+ return i;
680
+ }
681
+ // ── Indicator Positioning ──────────────────────────────────
682
+ showContentIndicator() {
683
+ if (!this.contentIndicator || !this.currentDrop?.columnId) {
684
+ x(this.contentIndicator);
685
+ return;
686
+ }
687
+ const o = V(this.root, "me-column-renderer").find((i) => i.dataset.columnId === this.currentDrop.columnId);
688
+ if (!o?.shadowRoot) return;
689
+ const n = Array.from(o.shadowRoot.querySelectorAll("me-content-renderer"));
690
+ M(this.contentIndicator, o.shadowRoot, n, this.currentDrop.contentIndex ?? 0, "4px");
691
+ }
692
+ showRowIndicator() {
693
+ if (!this.rowIndicator || !this.currentDrop) {
694
+ x(this.rowIndicator);
695
+ return;
696
+ }
697
+ const t = this.root.querySelector("me-editor-canvas"), o = t?.shadowRoot?.querySelector(".canvas-body");
698
+ if (!o) return;
699
+ const n = Array.from(t.shadowRoot.querySelectorAll("me-row-renderer"));
700
+ M(this.rowIndicator, o, n, this.currentDrop.rowIndex ?? 0, "0");
701
+ }
702
+ hideAllIndicators() {
703
+ x(this.contentIndicator), x(this.rowIndicator);
704
+ }
705
+ reset() {
706
+ this.currentDrop = null, R.reset();
707
+ }
708
+ }
709
+ function s(e, t, o = "") {
710
+ const n = e[t];
711
+ return typeof n == "string" && n !== "" ? n : o;
712
+ }
713
+ function bt(e, t) {
714
+ if (typeof e != "string") return t;
715
+ try {
716
+ return JSON.parse(e);
717
+ } catch {
718
+ return t;
719
+ }
720
+ }
721
+ function y(e, t) {
722
+ const { padding: o, align: n = "left", extraTdStyle: i = "" } = t;
723
+ return `<table role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0">
724
+ <tbody><tr><td style="${`overflow-wrap:break-word;word-break:break-word;padding:${o};font-family:arial,helvetica,sans-serif;${i}`}" align="${n}">
725
+ ${e}
726
+ </td></tr></tbody>
727
+ </table>`;
728
+ }
729
+ function Z(e, t, o) {
730
+ const { bgColor: n, textColor: i, fontSize: r, fontWeight: l, borderRadius: a } = o, d = parseInt(a) || 0;
731
+ if (d <= 0) return "";
732
+ const c = Math.round(d / 20 * 100);
733
+ return `<!--[if mso]>
734
+ <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${t}" style="height:auto;v-text-anchor:middle;width:auto;" arcsize="${c}%" stroke="f" fillcolor="${n}">
735
+ <w:anchorlock/>
736
+ <center style="color:${i};font-family:arial,helvetica,sans-serif;font-size:${r};font-weight:${l};">${e}</center>
737
+ </v:roundrect>
738
+ <![endif]-->`;
739
+ }
740
+ const tt = {
741
+ name: "text",
742
+ label: "Text",
743
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7V4h16v3"/><path d="M9 20h6"/><path d="M12 4v16"/></svg>',
744
+ supportedDisplayModes: ["email", "web"],
745
+ position: 1,
746
+ options: {
747
+ text: {
748
+ title: "Text",
749
+ options: {
750
+ text: {
751
+ label: "Text Content",
752
+ defaultValue: '<p style="font-size: 14px;">This is a new text block. Change the text.</p>',
753
+ widget: "rich_text"
754
+ }
755
+ }
756
+ },
757
+ style: {
758
+ title: "Style",
759
+ options: {
760
+ color: { label: "Text Color", defaultValue: "#000000", widget: "color_picker" },
761
+ backgroundColor: { label: "Background Color", defaultValue: "", widget: "color_picker" },
762
+ textAlign: { label: "Text Align", defaultValue: "left", widget: "alignment" },
763
+ lineHeight: {
764
+ label: "Line Height",
765
+ defaultValue: "140%",
766
+ widget: "dropdown",
767
+ widgetParams: { options: [
768
+ { label: "100%", value: "100%" },
769
+ { label: "120%", value: "120%" },
770
+ { label: "140%", value: "140%" },
771
+ { label: "160%", value: "160%" },
772
+ { label: "180%", value: "180%" },
773
+ { label: "200%", value: "200%" }
774
+ ] }
775
+ }
776
+ }
777
+ },
778
+ spacing: {
779
+ title: "Spacing",
780
+ options: {
781
+ containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" }
782
+ }
783
+ },
784
+ general: {
785
+ title: "General",
786
+ options: {
787
+ anchor: { label: "Anchor", defaultValue: "", widget: "text" },
788
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
789
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
790
+ }
791
+ }
792
+ },
793
+ defaultValues: {
794
+ text: '<p style="font-size: 14px;">This is a new text block. Change the text.</p>',
795
+ color: "#000000",
796
+ backgroundColor: "",
797
+ lineHeight: "140%",
798
+ containerPadding: "10px",
799
+ textAlign: "left"
800
+ },
801
+ renderer: {
802
+ renderEditor(e) {
803
+ const t = s(e, "containerPadding", "10px"), o = s(e, "backgroundColor", "transparent"), n = s(e, "color", "inherit"), i = s(e, "lineHeight", "140%"), r = s(e, "text");
804
+ return m`
805
+ <div style="padding:${t};background-color:${o};color:${n};line-height:${i};word-break:break-word;">
806
+ ${A(r)}
807
+ </div>
808
+ `;
809
+ },
810
+ renderHtml(e) {
811
+ const t = s(e, "containerPadding", "10px"), o = s(e, "backgroundColor"), n = s(e, "color", "#000000"), i = s(e, "lineHeight", "140%"), r = s(e, "textAlign", "left"), l = s(e, "text"), a = o ? `background-color:${o};` : "", d = `<div style="font-size:14px;color:${n};line-height:${i};text-align:${r};word-wrap:break-word;">${l}</div>`;
812
+ return y(d, { padding: t, extraTdStyle: a });
813
+ }
814
+ }
815
+ }, et = {
816
+ name: "heading",
817
+ label: "Heading",
818
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 12h12"/><path d="M6 4v16"/><path d="M18 4v16"/></svg>',
819
+ supportedDisplayModes: ["email", "web"],
820
+ position: 2,
821
+ options: {
822
+ text: {
823
+ title: "Heading",
824
+ options: {
825
+ text: { label: "Text", defaultValue: "Heading", widget: "text" },
826
+ headingType: {
827
+ label: "Heading Type",
828
+ defaultValue: "h1",
829
+ widget: "dropdown",
830
+ widgetParams: { options: [
831
+ { label: "H1", value: "h1" },
832
+ { label: "H2", value: "h2" },
833
+ { label: "H3", value: "h3" },
834
+ { label: "H4", value: "h4" }
835
+ ] }
836
+ }
837
+ }
838
+ },
839
+ style: {
840
+ title: "Style",
841
+ options: {
842
+ fontSize: {
843
+ label: "Font Size",
844
+ defaultValue: "22px",
845
+ widget: "dropdown",
846
+ widgetParams: { options: [
847
+ { label: "14px", value: "14px" },
848
+ { label: "16px", value: "16px" },
849
+ { label: "18px", value: "18px" },
850
+ { label: "20px", value: "20px" },
851
+ { label: "22px", value: "22px" },
852
+ { label: "26px", value: "26px" },
853
+ { label: "30px", value: "30px" },
854
+ { label: "36px", value: "36px" },
855
+ { label: "48px", value: "48px" },
856
+ { label: "60px", value: "60px" }
857
+ ] }
858
+ },
859
+ color: { label: "Text Color", defaultValue: "#000000", widget: "color_picker" },
860
+ textAlign: { label: "Text Align", defaultValue: "left", widget: "alignment" },
861
+ fontWeight: {
862
+ label: "Font Weight",
863
+ defaultValue: "700",
864
+ widget: "dropdown",
865
+ widgetParams: { options: [
866
+ { label: "Normal", value: "400" },
867
+ { label: "Medium", value: "500" },
868
+ { label: "Semi Bold", value: "600" },
869
+ { label: "Bold", value: "700" },
870
+ { label: "Extra Bold", value: "800" }
871
+ ] }
872
+ },
873
+ lineHeight: {
874
+ label: "Line Height",
875
+ defaultValue: "140%",
876
+ widget: "dropdown",
877
+ widgetParams: { options: [
878
+ { label: "100%", value: "100%" },
879
+ { label: "120%", value: "120%" },
880
+ { label: "140%", value: "140%" },
881
+ { label: "160%", value: "160%" },
882
+ { label: "180%", value: "180%" },
883
+ { label: "200%", value: "200%" }
884
+ ] }
885
+ },
886
+ letterSpacing: { label: "Letter Spacing", defaultValue: "normal", widget: "text" }
887
+ }
888
+ },
889
+ spacing: {
890
+ title: "Spacing",
891
+ options: {
892
+ containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" }
893
+ }
894
+ },
895
+ general: {
896
+ title: "General",
897
+ options: {
898
+ anchor: { label: "Anchor", defaultValue: "", widget: "text" },
899
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
900
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
901
+ }
902
+ }
903
+ },
904
+ defaultValues: {
905
+ text: "Heading",
906
+ headingType: "h1",
907
+ fontSize: "22px",
908
+ color: "#000000",
909
+ textAlign: "left",
910
+ fontWeight: "700",
911
+ lineHeight: "140%",
912
+ letterSpacing: "normal",
913
+ containerPadding: "10px"
914
+ },
915
+ renderer: {
916
+ renderEditor(e) {
917
+ const t = s(e, "containerPadding", "10px"), o = s(e, "fontSize", "22px"), n = s(e, "color", "#000000"), i = s(e, "textAlign", "left"), r = s(e, "fontWeight", "700"), l = s(e, "lineHeight", "140%"), a = s(e, "text", "Heading");
918
+ return m`
919
+ <div style="padding:${t};font-size:${o};color:${n};text-align:${i};font-weight:${r};line-height:${l};">
920
+ ${a}
921
+ </div>
922
+ `;
923
+ },
924
+ renderHtml(e) {
925
+ const t = s(e, "containerPadding", "10px"), o = s(e, "fontSize", "22px"), n = s(e, "color", "#000000"), i = s(e, "textAlign", "left"), r = s(e, "fontWeight", "700"), l = s(e, "lineHeight", "140%"), a = s(e, "letterSpacing", "normal"), d = s(e, "headingType", "h1"), c = s(e, "text", "Heading"), u = `<${d} style="margin:0;font-size:${o};color:${n};text-align:${i};font-weight:${r};line-height:${l};letter-spacing:${a};">${c}</${d}>`;
926
+ return y(u, { padding: t });
927
+ }
928
+ }
929
+ }, ot = {
930
+ name: "paragraph",
931
+ label: "Paragraph",
932
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><line x1="3" y1="14" x2="17" y2="14"/></svg>',
933
+ supportedDisplayModes: ["email", "web"],
934
+ position: 3,
935
+ options: {
936
+ text: {
937
+ title: "Paragraph",
938
+ options: {
939
+ text: {
940
+ label: "Text",
941
+ defaultValue: '<p style="font-size:14px;line-height:1.6;">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>',
942
+ widget: "rich_text"
943
+ }
944
+ }
945
+ },
946
+ style: {
947
+ title: "Style",
948
+ options: {
949
+ color: { label: "Text Color", defaultValue: "#374151", widget: "color_picker" },
950
+ textAlign: { label: "Text Align", defaultValue: "left", widget: "alignment" },
951
+ lineHeight: { label: "Line Height", defaultValue: "160%", widget: "text" },
952
+ letterSpacing: { label: "Letter Spacing", defaultValue: "normal", widget: "text" }
953
+ }
954
+ },
955
+ spacing: {
956
+ title: "Spacing",
957
+ options: {
958
+ containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" }
959
+ }
960
+ }
961
+ },
962
+ defaultValues: {
963
+ text: '<p style="font-size:14px;line-height:1.6;">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
964
+ color: "#374151",
965
+ lineHeight: "160%",
966
+ letterSpacing: "normal",
967
+ textAlign: "left",
968
+ containerPadding: "10px"
969
+ },
970
+ renderer: {
971
+ renderEditor(e) {
972
+ const t = s(e, "containerPadding", "10px"), o = s(e, "color", "#374151"), n = s(e, "lineHeight", "160%");
973
+ return m`<div style="padding:${t};color:${o};line-height:${n};word-break:break-word;">${A(s(e, "text"))}</div>`;
974
+ },
975
+ renderHtml(e) {
976
+ const t = s(e, "containerPadding", "10px"), o = s(e, "color", "#374151"), n = s(e, "lineHeight", "160%"), i = s(e, "textAlign", "left"), r = s(e, "letterSpacing", "normal"), l = `<div style="font-size:14px;color:${o};line-height:${n};text-align:${i};letter-spacing:${r};word-wrap:break-word;">${s(e, "text")}</div>`;
977
+ return y(l, { padding: t });
978
+ }
979
+ }
980
+ }, nt = {
981
+ name: "image",
982
+ label: "Image",
983
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>',
984
+ supportedDisplayModes: ["email", "web"],
985
+ position: 3,
986
+ options: {
987
+ image: {
988
+ title: "Image",
989
+ options: {
990
+ src: { label: "Image URL", defaultValue: "", widget: "text" },
991
+ alt: { label: "Alt Text", defaultValue: "", widget: "text" },
992
+ href: { label: "Link URL", defaultValue: "", widget: "text" },
993
+ target: { label: "Link Target", defaultValue: "_blank", widget: "text" }
994
+ }
995
+ },
996
+ style: {
997
+ title: "Style",
998
+ options: {
999
+ width: {
1000
+ label: "Width",
1001
+ defaultValue: "100%",
1002
+ widget: "dropdown",
1003
+ widgetParams: { options: [
1004
+ { label: "Auto", value: "auto" },
1005
+ { label: "25%", value: "25%" },
1006
+ { label: "50%", value: "50%" },
1007
+ { label: "75%", value: "75%" },
1008
+ { label: "100%", value: "100%" }
1009
+ ] }
1010
+ },
1011
+ align: { label: "Align", defaultValue: "center", widget: "alignment" },
1012
+ borderRadius: { label: "Border Radius", defaultValue: "0px", widget: "text" }
1013
+ }
1014
+ },
1015
+ spacing: {
1016
+ title: "Spacing",
1017
+ options: { containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" } }
1018
+ },
1019
+ general: {
1020
+ title: "General",
1021
+ options: {
1022
+ anchor: { label: "Anchor", defaultValue: "", widget: "text" },
1023
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
1024
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
1025
+ }
1026
+ }
1027
+ },
1028
+ defaultValues: {
1029
+ src: "https://placehold.co/600x200/e2e8f0/64748b?text=Drop+Image+Here",
1030
+ alt: "Image",
1031
+ href: "",
1032
+ target: "_blank",
1033
+ width: "100%",
1034
+ maxWidth: "100%",
1035
+ align: "center",
1036
+ borderRadius: "0px",
1037
+ containerPadding: "10px"
1038
+ },
1039
+ renderer: {
1040
+ renderEditor(e) {
1041
+ const t = s(e, "containerPadding", "10px"), o = s(e, "src"), n = s(e, "alt"), i = s(e, "width", "100%"), r = s(e, "borderRadius", "0px"), l = s(e, "align", "center");
1042
+ return o ? m`<div style="padding:${t};text-align:${l};"><img src=${o} alt=${n} style="display:inline-block;max-width:100%;width:${i};border-radius:${r};border:0;" /></div>` : m`<div style="padding:${t};text-align:${l};"><div style="background:#f1f5f9;border:2px dashed #cbd5e1;border-radius:8px;padding:40px 20px;text-align:center;color:#94a3b8;font-size:13px;">No image set. Enter a URL in the property panel.</div></div>`;
1043
+ },
1044
+ renderHtml(e, t) {
1045
+ const o = s(e, "containerPadding", "10px"), n = s(e, "src"), i = s(e, "alt"), r = s(e, "href"), l = s(e, "target", "_blank"), a = s(e, "width", "100%"), d = s(e, "borderRadius", "0px"), c = s(e, "align", "center"), u = a === "100%" ? t.columnWidth : parseInt(a), g = d !== "0px" ? `border-radius:${d};` : "", h = `<img align="${c}" border="0" src="${n}" alt="${i}" title="${i}" style="outline:none;text-decoration:none;clear:both;display:inline-block!important;border:none;height:auto;float:none;width:${a};max-width:${u}px;${g}" width="${u}" />`, f = r ? `<a href="${r}" target="${l}" style="text-decoration:none;">${h}</a>` : h;
1046
+ return y(f, { padding: o, align: c });
1047
+ }
1048
+ }
1049
+ }, it = {
1050
+ name: "button",
1051
+ label: "Button",
1052
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="10" rx="2"/><path d="M12 7v10"/><path d="m8 12 4-3 4 3"/></svg>',
1053
+ supportedDisplayModes: ["email", "web"],
1054
+ position: 4,
1055
+ options: {
1056
+ button: {
1057
+ title: "Button",
1058
+ options: {
1059
+ text: { label: "Button Text", defaultValue: "Click Me", widget: "text" },
1060
+ href: { label: "Link URL", defaultValue: "#", widget: "text" },
1061
+ target: { label: "Target", defaultValue: "_blank", widget: "text" }
1062
+ }
1063
+ },
1064
+ style: {
1065
+ title: "Style",
1066
+ options: {
1067
+ backgroundColor: { label: "Button Color", defaultValue: "#3b82f6", widget: "color_picker" },
1068
+ textColor: { label: "Text Color", defaultValue: "#ffffff", widget: "color_picker" },
1069
+ fontSize: {
1070
+ label: "Font Size",
1071
+ defaultValue: "14px",
1072
+ widget: "dropdown",
1073
+ widgetParams: { options: [
1074
+ { label: "12px", value: "12px" },
1075
+ { label: "13px", value: "13px" },
1076
+ { label: "14px", value: "14px" },
1077
+ { label: "16px", value: "16px" },
1078
+ { label: "18px", value: "18px" },
1079
+ { label: "20px", value: "20px" }
1080
+ ] }
1081
+ },
1082
+ fontWeight: {
1083
+ label: "Font Weight",
1084
+ defaultValue: "700",
1085
+ widget: "dropdown",
1086
+ widgetParams: { options: [{ label: "Normal", value: "400" }, { label: "Bold", value: "700" }] }
1087
+ },
1088
+ borderRadius: { label: "Border Radius", defaultValue: "4px", widget: "text" },
1089
+ buttonWidth: {
1090
+ label: "Width",
1091
+ defaultValue: "auto",
1092
+ widget: "dropdown",
1093
+ widgetParams: { options: [
1094
+ { label: "Auto", value: "auto" },
1095
+ { label: "100%", value: "100%" },
1096
+ { label: "50%", value: "50%" }
1097
+ ] }
1098
+ },
1099
+ textAlign: { label: "Align", defaultValue: "center", widget: "alignment" },
1100
+ buttonPadding: { label: "Button Padding", defaultValue: "10px 20px", widget: "padding" },
1101
+ borderColor: { label: "Border Color", defaultValue: "", widget: "color_picker" },
1102
+ borderWidth: { label: "Border Width", defaultValue: "0px", widget: "text" }
1103
+ }
1104
+ },
1105
+ spacing: {
1106
+ title: "Spacing",
1107
+ options: { containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" } }
1108
+ },
1109
+ general: {
1110
+ title: "General",
1111
+ options: {
1112
+ anchor: { label: "Anchor", defaultValue: "", widget: "text" },
1113
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
1114
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
1115
+ }
1116
+ }
1117
+ },
1118
+ defaultValues: {
1119
+ text: "Click Me",
1120
+ href: "#",
1121
+ target: "_blank",
1122
+ backgroundColor: "#3b82f6",
1123
+ textColor: "#ffffff",
1124
+ fontSize: "14px",
1125
+ fontWeight: "700",
1126
+ borderRadius: "4px",
1127
+ buttonWidth: "auto",
1128
+ textAlign: "center",
1129
+ buttonPadding: "10px 20px",
1130
+ borderColor: "",
1131
+ borderWidth: "0px",
1132
+ containerPadding: "10px"
1133
+ },
1134
+ renderer: {
1135
+ renderEditor(e) {
1136
+ const t = s(e, "containerPadding", "10px"), o = s(e, "backgroundColor", "#3b82f6"), n = s(e, "textColor", "#ffffff"), i = s(e, "fontSize", "14px"), r = s(e, "fontWeight", "700"), l = s(e, "borderRadius", "4px"), a = s(e, "buttonPadding", "10px 20px"), d = s(e, "text", "Click Me"), c = s(e, "textAlign", "center"), u = s(e, "buttonWidth", "auto"), g = s(e, "borderWidth", "0px"), h = s(e, "borderColor", o), f = g !== "0px" ? `border:${g} solid ${h};` : "border:none;", b = u === "auto" ? "display:inline-block;" : `display:block;width:${u};`;
1137
+ return m`
1138
+ <div style="padding:${t};text-align:${c};">
1139
+ <a style="${b}background-color:${o};color:${n};font-size:${i};font-weight:${r};border-radius:${l};padding:${a};text-decoration:none;text-align:center;${f}cursor:pointer;font-family:arial,helvetica,sans-serif;box-sizing:border-box;">${d}</a>
1140
+ </div>
1141
+ `;
1142
+ },
1143
+ renderHtml(e) {
1144
+ const t = s(e, "containerPadding", "10px"), o = s(e, "backgroundColor", "#3b82f6"), n = s(e, "textColor", "#ffffff"), i = s(e, "fontSize", "14px"), r = s(e, "fontWeight", "700"), l = s(e, "borderRadius", "4px"), a = s(e, "buttonPadding", "10px 20px"), d = s(e, "text", "Click Me"), c = s(e, "textAlign", "center"), u = s(e, "href", "#"), g = s(e, "target", "_blank"), h = s(e, "borderWidth", "0px"), f = s(e, "borderColor", o), b = h !== "0px" ? `border:${h} solid ${f};` : "border:none;", p = Z(d, u, { bgColor: o, textColor: n, fontSize: i, fontWeight: r, borderRadius: l }), w = p ? `${p}
1145
+ <!--[if !mso]><!-->` : "<!--[if !mso]><!-->", v = `<div align="${c}">
1146
+ ${w}
1147
+ <a href="${u}" target="${g}" style="box-sizing:border-box;display:inline-block;text-decoration:none;text-align:center;color:${n};background-color:${o};border-radius:${l};font-size:${i};font-weight:${r};padding:${a};font-family:arial,helvetica,sans-serif;${b}mso-border-alt:none;word-break:keep-all;"><span style="line-height:120%;">${d}</span></a>
1148
+ <!--<![endif]-->
1149
+ </div>`;
1150
+ return y(v, { padding: t, align: c });
1151
+ }
1152
+ }
1153
+ }, rt = {
1154
+ name: "divider",
1155
+ label: "Divider",
1156
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="2" y1="12" x2="22" y2="12"/></svg>',
1157
+ supportedDisplayModes: ["email", "web"],
1158
+ position: 5,
1159
+ options: {
1160
+ style: {
1161
+ title: "Style",
1162
+ options: {
1163
+ borderTopWidth: { label: "Width", defaultValue: "1px", widget: "text" },
1164
+ borderTopStyle: {
1165
+ label: "Style",
1166
+ defaultValue: "solid",
1167
+ widget: "dropdown",
1168
+ widgetParams: { options: [
1169
+ { label: "Solid", value: "solid" },
1170
+ { label: "Dashed", value: "dashed" },
1171
+ { label: "Dotted", value: "dotted" },
1172
+ { label: "Double", value: "double" }
1173
+ ] }
1174
+ },
1175
+ borderTopColor: { label: "Color", defaultValue: "#cccccc", widget: "color_picker" },
1176
+ width: { label: "Line Width", defaultValue: "100%", widget: "text" }
1177
+ }
1178
+ },
1179
+ spacing: {
1180
+ title: "Spacing",
1181
+ options: { containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" } }
1182
+ },
1183
+ general: {
1184
+ title: "General",
1185
+ options: {
1186
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
1187
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
1188
+ }
1189
+ }
1190
+ },
1191
+ defaultValues: {
1192
+ borderTopWidth: "1px",
1193
+ borderTopStyle: "solid",
1194
+ borderTopColor: "#cccccc",
1195
+ width: "100%",
1196
+ containerPadding: "10px"
1197
+ },
1198
+ renderer: {
1199
+ renderEditor(e) {
1200
+ const t = s(e, "containerPadding", "10px"), o = s(e, "width", "100%"), n = `${s(e, "borderTopWidth", "1px")} ${s(e, "borderTopStyle", "solid")} ${s(e, "borderTopColor", "#cccccc")}`;
1201
+ return m`<div style="padding:${t};"><div style="border-top:${n};width:${o};margin:0 auto;"></div></div>`;
1202
+ },
1203
+ renderHtml(e) {
1204
+ const t = s(e, "containerPadding", "10px"), o = s(e, "width", "100%"), n = `${s(e, "borderTopWidth", "1px")} ${s(e, "borderTopStyle", "solid")} ${s(e, "borderTopColor", "#cccccc")}`, i = `<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="${o}" style="border-collapse:collapse;border-top:${n};"><tbody><tr><td style="font-size:0;line-height:0;">&nbsp;</td></tr></tbody></table>`;
1205
+ return y(i, { padding: t, align: "center" });
1206
+ }
1207
+ }
1208
+ }, st = [
1209
+ tt,
1210
+ et,
1211
+ ot,
1212
+ nt,
1213
+ it,
1214
+ rt
1215
+ ], P = [
1216
+ {
1217
+ meta: { name: "html", label: "HTML", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>', position: 6 },
1218
+ loader: () => import("./html-tool-CDX3fL-9.js").then((e) => e.htmlTool)
1219
+ },
1220
+ {
1221
+ meta: { name: "social", label: "Social", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>', position: 8 },
1222
+ loader: () => import("./social-tool-B4BUlJ2I.js").then((e) => e.socialTool)
1223
+ },
1224
+ {
1225
+ meta: { name: "menu", label: "Menu", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/></svg>', position: 9 },
1226
+ loader: () => import("./menu-tool-BrT6-Pvh.js").then((e) => e.menuTool)
1227
+ },
1228
+ {
1229
+ meta: { name: "video", label: "Video", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>', position: 10 },
1230
+ loader: () => import("./video-tool-CwWMKobZ.js").then((e) => e.videoTool)
1231
+ },
1232
+ {
1233
+ meta: { name: "timer", label: "Timer", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>', position: 11 },
1234
+ loader: () => import("./timer-tool-3mF08efm.js").then((e) => e.timerTool)
1235
+ },
1236
+ {
1237
+ meta: { name: "table", label: "Table", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/><path d="M9 3v18"/><path d="M15 3v18"/></svg>', position: 12 },
1238
+ loader: () => import("./table-tool-Bo_g3Un_.js").then((e) => e.tableTool)
1239
+ },
1240
+ {
1241
+ meta: { name: "form", label: "Form", icon: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M7 7h10"/><path d="M7 12h10"/><path d="M7 17h6"/></svg>', position: 13 },
1242
+ loader: () => import("./form-tool-BucdYK9Z.js").then((e) => e.formTool)
1243
+ }
1244
+ ];
1245
+ function lt(e, t, o) {
1246
+ const n = o.backgroundColor || "#e7e7e7", i = o.contentWidth || "600px", r = o.fontFamily?.value || "arial,helvetica,sans-serif", l = o.textColor || "#000000", a = o.preheaderText || "", d = a ? `<div style="display:none;font-size:1px;color:${n};line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">${a}${"&zwnj;&nbsp;".repeat(80)}</div>` : "";
1247
+ return `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1248
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
1249
+ <head>
1250
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
1251
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1252
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
1253
+ <meta name="x-apple-disable-message-reformatting">
1254
+ <meta name="format-detection" content="telephone=no,address=no,email=no,date=no,url=no">
1255
+ <meta name="color-scheme" content="light dark">
1256
+ <meta name="supported-color-schemes" content="light dark">
1257
+ <title></title>
1258
+ <!--[if mso]>
1259
+ <noscript><xml>
1260
+ <o:OfficeDocumentSettings>
1261
+ <o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch>
1262
+ </o:OfficeDocumentSettings>
1263
+ </xml></noscript>
1264
+ <style type="text/css">
1265
+ table, td, th { font-family: ${r} !important; }
1266
+ </style>
1267
+ <![endif]-->
1268
+ <!--[if !mso]><!-->
1269
+ <style type="text/css">
1270
+ ${t}
1271
+ </style>
1272
+ <!--<![endif]-->
1273
+ <style type="text/css">
1274
+ body { margin: 0; padding: 0; }
1275
+ table, tr, td { vertical-align: top; border-collapse: collapse; }
1276
+ p { margin: 0; }
1277
+ .ie-container table, .mso-container table { table-layout: fixed; }
1278
+ * { line-height: inherit; }
1279
+ a[x-apple-data-detectors='true'] { color: inherit !important; text-decoration: none !important; }
1280
+ </style>
1281
+ </head>
1282
+ <body class="clean-body u_body" style="margin:0;padding:0;-webkit-text-size-adjust:100%;background-color:${n};color:${l};">
1283
+ ${d}
1284
+ <table id="u_body" style="border-collapse:collapse;table-layout:fixed;border-spacing:0;mso-table-lspace:0pt;mso-table-rspace:0pt;vertical-align:top;min-width:320px;margin:0 auto;background-color:${n};width:100%;" cellpadding="0" cellspacing="0" border="0">
1285
+ <tbody>
1286
+ <tr style="vertical-align:top;">
1287
+ <td style="word-break:break-word;border-collapse:collapse !important;vertical-align:top;">
1288
+ <!--[if (mso)|(IE)]><table width="${parseInt(i)}" align="center" cellpadding="0" cellspacing="0" border="0"><tr><td><![endif]-->
1289
+ ${e}
1290
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
1291
+ </td>
1292
+ </tr>
1293
+ </tbody>
1294
+ </table>
1295
+ </body>
1296
+ </html>`;
1297
+ }
1298
+ function at(e, t, o) {
1299
+ const n = parseInt(t.contentWidth || "600"), i = e.values.backgroundColor || "", r = e.values.columnsBackgroundColor || "", l = e.values.padding || "0px", a = e.cells.reduce((p, w) => p + w, 0), d = i ? `background-color:${i};` : "", c = e.values.backgroundImage?.url ? `background-image:url('${e.values.backgroundImage.url}');background-repeat:${e.values.backgroundImage.repeat ? "repeat" : "no-repeat"};background-position:center top;background-size:${e.values.backgroundImage.cover ? "cover" : "auto"};` : "", u = e.columns.map((p, w) => {
1300
+ const k = Math.round(e.cells[w] / a * n);
1301
+ return E(p, k, r, t, o);
1302
+ }), g = e.columns.length > 1;
1303
+ let h;
1304
+ if (g) {
1305
+ const p = e.columns.map((w, k) => {
1306
+ const v = Math.round(e.cells[k] / a * n), B = E(w, v, r, t, o);
1307
+ return `<!--[if (mso)|(IE)]><td align="center" width="${v}" style="width:${v}px;padding:0px;border:none;" valign="top"><![endif]-->
1308
+ ${B}
1309
+ <!--[if (mso)|(IE)]></td><![endif]-->`;
1310
+ });
1311
+ h = `<!--[if (mso)|(IE)]><table role="presentation" width="${n}" cellpadding="0" cellspacing="0" border="0"><tr>${p.join(`
1312
+ `)}</tr></table><![endif]-->
1313
+
1314
+ <!--[if !mso]><!-->
1315
+ <div style="max-width:${n}px;margin:0 auto;">
1316
+ ${u.join(`
1317
+ `)}
1318
+ </div>
1319
+ <!--<![endif]-->`;
1320
+ } else
1321
+ h = u.join(`
1322
+ `);
1323
+ const f = e.values.hideDesktop ? " u_hide_desktop" : "", b = e.values.hideMobile ? " u_hide_mobile" : "";
1324
+ return `<div class="u_row${f}${b}" style="padding:${l};${d}${c}">
1325
+ <div style="margin:0 auto;min-width:320px;max-width:${n}px;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;background-color:transparent;">
1326
+ <div style="border-collapse:collapse;display:table;width:100%;height:100%;background-color:transparent;">
1327
+ ${h}
1328
+ </div>
1329
+ </div>
1330
+ </div>`;
1331
+ }
1332
+ function E(e, t, o, n, i) {
1333
+ const r = e.values.backgroundColor || o || "", l = e.values.padding || "0px", a = e.values.borderRadius || "0px", d = r ? `background-color:${r};` : "", c = e.contents.map((u) => {
1334
+ const g = i.get(u.type);
1335
+ if (!g) return `<!-- unknown tool: ${u.type} -->`;
1336
+ const h = {
1337
+ columnWidth: t,
1338
+ displayMode: "email",
1339
+ contentWidth: parseInt(n.contentWidth || "600"),
1340
+ bodyValues: n
1341
+ };
1342
+ return g(u.values, h);
1343
+ }).join(`
1344
+ `);
1345
+ return `<div class="u_column" style="max-width:${t}px;min-width:${Math.min(t, 320)}px;display:table-cell;vertical-align:top;">
1346
+ <div style="height:100%;width:100% !important;border-radius:${a};-webkit-border-radius:${a};${d}">
1347
+ <div style="box-sizing:border-box;height:100%;padding:${l};border:none;border-radius:${a};-webkit-border-radius:${a};">
1348
+ ${c || '<!--[if (!mso)&(!IE)]><!--><div style="height:0;min-height:1px;font-size:0;">&nbsp;</div><!--<![endif]-->'}
1349
+ </div>
1350
+ </div>
1351
+ </div>`;
1352
+ }
1353
+ function dt(e) {
1354
+ return `
1355
+ @media only screen and (min-width: ${e + 20}px) {
1356
+ .u_row .u_column { display: table-cell; }
1357
+ }
1358
+
1359
+ @media only screen and (max-width: ${e + 20}px) {
1360
+ .u_row .u_column {
1361
+ display: block !important;
1362
+ width: 100% !important;
1363
+ min-width: 320px !important;
1364
+ max-width: 100% !important;
1365
+ }
1366
+ .u_row {
1367
+ width: 100% !important;
1368
+ }
1369
+ }
1370
+
1371
+ @media only screen and (max-width: 620px) {
1372
+ .u_row-container {
1373
+ max-width: 100% !important;
1374
+ padding-left: 0 !important;
1375
+ padding-right: 0 !important;
1376
+ }
1377
+ }
1378
+
1379
+ @media (prefers-color-scheme: dark) {
1380
+ /* Dark mode overrides — add per-client rules as needed */
1381
+ }
1382
+
1383
+ /* Outlook dark mode */
1384
+ [data-ogsb] body,
1385
+ [data-ogsb] table,
1386
+ [data-ogsb] td {
1387
+ /* Preserve original colors */
1388
+ }
1389
+
1390
+ .u_hide_desktop { display: block !important; }
1391
+ .u_hide_mobile { display: block !important; }
1392
+
1393
+ @media only screen and (max-width: ${e + 20}px) {
1394
+ .u_hide_desktop { display: block !important; }
1395
+ .u_hide_mobile { display: none !important; }
1396
+ }
1397
+
1398
+ @media only screen and (min-width: ${e + 21}px) {
1399
+ .u_hide_desktop { display: none !important; }
1400
+ .u_hide_mobile { display: block !important; }
1401
+ }`;
1402
+ }
1403
+ function ct(e, t, o) {
1404
+ const n = e.body.values, i = parseInt(n.contentWidth || "600"), r = e.body.rows.map((g) => at(g, n, t)).join(`
1405
+ `), l = dt(i);
1406
+ let a = lt(r, l, n);
1407
+ if (o?.mergeTags)
1408
+ for (const [g, h] of Object.entries(o.mergeTags))
1409
+ a = a.replaceAll(`{{${g}}}`, h);
1410
+ const d = a.match(/<body[^>]*>([\s\S]*)<\/body>/i), c = a.match(/<style[^>]*>([\s\S]*?)<\/style>/gi), u = [];
1411
+ return n.fontFamily?.url && u.push(n.fontFamily.url), {
1412
+ design: structuredClone(e),
1413
+ html: a,
1414
+ chunks: {
1415
+ body: d?.[1] ?? r,
1416
+ css: c?.map((g) => g.replace(/<\/?style[^>]*>/gi, "")).join(`
1417
+ `) ?? l,
1418
+ fonts: u,
1419
+ js: ""
1420
+ }
1421
+ };
1422
+ }
1423
+ var ht = Object.defineProperty, ut = Object.getOwnPropertyDescriptor, H = (e, t, o, n) => {
1424
+ for (var i = n > 1 ? void 0 : n ? ut(t, o) : t, r = e.length - 1, l; r >= 0; r--)
1425
+ (l = e[r]) && (i = (n ? l(t, o, i) : l(i)) || i);
1426
+ return n && i && ht(t, o, i), i;
1427
+ };
1428
+ let _ = class extends L {
1429
+ constructor() {
1430
+ super(...arguments), this.options = {}, this.store = new X(), this.toolRegistry = new Y(), this.dragManager = null, this.callbacks = /* @__PURE__ */ new Map(), this.unsubscribe = null, this._handleKeydown = (e) => {
1431
+ const t = e.metaKey || e.ctrlKey, n = e.composedPath().some((i) => {
1432
+ const r = i?.tagName;
1433
+ return r === "INPUT" || r === "TEXTAREA" || r === "SELECT";
1434
+ });
1435
+ n && !t || (t && e.key === "z" && !e.shiftKey ? (e.preventDefault(), this.store.undo()) : t && (e.key === "y" || e.key === "z" && e.shiftKey) ? (e.preventDefault(), this.store.redo()) : (e.key === "Delete" || e.key === "Backspace") && this.store.selectedId && !n ? (e.preventDefault(), this.store.removeContent(this.store.selectedId)) : e.key === "Escape" && this.store.select(null));
1436
+ };
1437
+ }
1438
+ connectedCallback() {
1439
+ super.connectedCallback(), this.registerBuiltInTools(), this.applyOptions(), this.setAttribute("tabindex", "0"), this.addEventListener("keydown", this._handleKeydown);
1440
+ }
1441
+ firstUpdated() {
1442
+ this.dragManager = new Q(this.store, this.toolRegistry, this.shadowRoot), this.dragManager.attach(), this.store.events.on("design:loaded", (e) => {
1443
+ this.dispatchEvent(new CustomEvent("design:loaded", { detail: e, bubbles: !0, composed: !0 }));
1444
+ }), this.store.events.on("design:updated", (e) => {
1445
+ this.dispatchEvent(new CustomEvent("design:updated", { detail: e, bubbles: !0, composed: !0 }));
1446
+ }), this.dispatchEvent(new CustomEvent("editor:ready", { bubbles: !0, composed: !0 })), this.preloadLazyTools();
1447
+ }
1448
+ disconnectedCallback() {
1449
+ super.disconnectedCallback(), this.dragManager?.detach(), this.unsubscribe?.(), this.store.events.removeAllListeners(), this.removeEventListener("keydown", this._handleKeydown);
1450
+ }
1451
+ // ----------------------------------------------------------
1452
+ // Public API — public API
1453
+ // ----------------------------------------------------------
1454
+ loadDesign(e) {
1455
+ this.store.loadDesign(e);
1456
+ }
1457
+ saveDesign(e) {
1458
+ e(structuredClone(this.store.getDesign()));
1459
+ }
1460
+ exportHtml(e, t) {
1461
+ const o = this.store.getDesign(), n = /* @__PURE__ */ new Set();
1462
+ for (const r of o.body.rows)
1463
+ for (const l of r.columns)
1464
+ for (const a of l.contents)
1465
+ n.add(a.type);
1466
+ const i = Array.from(n).filter((r) => !this.toolRegistry.isLoaded(r)).map((r) => this.toolRegistry.ensureLoaded(r));
1467
+ i.length > 0 ? Promise.all(i).then(() => this.doExport(o, e, t)) : this.doExport(o, e, t);
1468
+ }
1469
+ doExport(e, t, o) {
1470
+ const n = /* @__PURE__ */ new Map();
1471
+ for (const i of this.toolRegistry.getAll())
1472
+ n.set(i.name, (r, l) => i.renderer.renderHtml(r, l));
1473
+ t(ct(e, n, o));
1474
+ }
1475
+ async exportHtmlAsync(e) {
1476
+ return new Promise((t) => this.exportHtml(t, e));
1477
+ }
1478
+ registerTool(e) {
1479
+ this.toolRegistry.register(e), this.requestUpdate();
1480
+ }
1481
+ registerPropertyEditor(e, t) {
1482
+ }
1483
+ registerTab(e) {
1484
+ }
1485
+ registerCallback(e, t) {
1486
+ this.callbacks.set(e, t);
1487
+ }
1488
+ setMergeTags(e) {
1489
+ }
1490
+ undo() {
1491
+ this.store.undo();
1492
+ }
1493
+ redo() {
1494
+ this.store.redo();
1495
+ }
1496
+ setBodyValues(e) {
1497
+ this.store.updateBodyValues(e);
1498
+ }
1499
+ // ----------------------------------------------------------
1500
+ // Internal
1501
+ // ----------------------------------------------------------
1502
+ /**
1503
+ * Preload lazy tools during browser idle time.
1504
+ * Uses requestIdleCallback to avoid blocking the main thread.
1505
+ * Falls back to setTimeout(1000) for browsers without idle callback support.
1506
+ */
1507
+ preloadLazyTools() {
1508
+ const e = window.requestIdleCallback ?? ((t) => setTimeout(t, 1e3));
1509
+ for (const { meta: t } of P)
1510
+ e(() => {
1511
+ this.toolRegistry.ensureLoaded(t.name);
1512
+ });
1513
+ }
1514
+ registerBuiltInTools() {
1515
+ for (const e of st)
1516
+ this.toolRegistry.register(e);
1517
+ for (const { meta: e, loader: t } of P)
1518
+ this.toolRegistry.registerLazy(e, t);
1519
+ }
1520
+ applyOptions() {
1521
+ this.options.design && this.store.loadDesign(this.options.design);
1522
+ }
1523
+ render() {
1524
+ return m`
1525
+ <me-editor-sidebar
1526
+ .store=${this.store}
1527
+ .toolRegistry=${this.toolRegistry}
1528
+ ></me-editor-sidebar>
1529
+ <me-editor-canvas
1530
+ .store=${this.store}
1531
+ .toolRegistry=${this.toolRegistry}
1532
+ ></me-editor-canvas>
1533
+ <me-property-panel
1534
+ .store=${this.store}
1535
+ .toolRegistry=${this.toolRegistry}
1536
+ ></me-property-panel>
1537
+ `;
1538
+ }
1539
+ };
1540
+ _.styles = z`
1541
+ :host {
1542
+ display: flex;
1543
+ width: 100%;
1544
+ height: 100%;
1545
+ min-height: 500px;
1546
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1547
+ color: #111827;
1548
+ box-sizing: border-box;
1549
+ overflow: hidden;
1550
+ position: relative;
1551
+ }
1552
+ * { box-sizing: border-box; }
1553
+ `;
1554
+ H([
1555
+ W({ type: Object })
1556
+ ], _.prototype, "options", 2);
1557
+ _ = H([
1558
+ j("mail-editor")
1559
+ ], _);
1560
+ export {
1561
+ X as E,
1562
+ _ as M,
1563
+ Y as T,
1564
+ y as e,
1565
+ bt as j,
1566
+ s
1567
+ };
1568
+ //# sourceMappingURL=mail-editor-DNPaJKo3.js.map