@emabuild/core 0.0.8 → 0.1.0

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 (33) hide show
  1. package/dist/canvas/content-renderer.d.ts.map +1 -1
  2. package/dist/canvas/row-renderer.d.ts.map +1 -1
  3. package/dist/{form-tool-C9ccGMTE.js → form-tool-DSXsWpjQ.js} +2 -2
  4. package/dist/{form-tool-C9ccGMTE.js.map → form-tool-DSXsWpjQ.js.map} +1 -1
  5. package/dist/{html-tool-Dx0bJnRa.js → html-tool-Be4HAhoj.js} +2 -2
  6. package/dist/{html-tool-Dx0bJnRa.js.map → html-tool-Be4HAhoj.js.map} +1 -1
  7. package/dist/index-CZt184D3.js +2695 -0
  8. package/dist/index-CZt184D3.js.map +1 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +5 -4
  12. package/dist/{menu-tool-D34uGd81.js → menu-tool-HPxxeiRV.js} +2 -2
  13. package/dist/{menu-tool-D34uGd81.js.map → menu-tool-HPxxeiRV.js.map} +1 -1
  14. package/dist/register-elements.d.ts +6 -0
  15. package/dist/register-elements.d.ts.map +1 -0
  16. package/dist/{social-tool-_2fRc5-k.js → social-tool-bc46FNgk.js} +2 -2
  17. package/dist/{social-tool-_2fRc5-k.js.map → social-tool-bc46FNgk.js.map} +1 -1
  18. package/dist/{table-tool-B_MVWfF5.js → table-tool-LzRcAPFb.js} +2 -2
  19. package/dist/{table-tool-B_MVWfF5.js.map → table-tool-LzRcAPFb.js.map} +1 -1
  20. package/dist/{timer-tool-BUl5TiH0.js → timer-tool-GPhdsvRE.js} +2 -2
  21. package/dist/{timer-tool-BUl5TiH0.js.map → timer-tool-GPhdsvRE.js.map} +1 -1
  22. package/dist/tools/built-in/image-tool.d.ts.map +1 -1
  23. package/dist/tools/helpers/index.d.ts +1 -1
  24. package/dist/tools/helpers/index.d.ts.map +1 -1
  25. package/dist/tools/helpers/value-extractor.d.ts +35 -0
  26. package/dist/tools/helpers/value-extractor.d.ts.map +1 -1
  27. package/dist/{video-tool-HOA8TCla.js → video-tool-CPjCWbTX.js} +2 -2
  28. package/dist/{video-tool-HOA8TCla.js.map → video-tool-CPjCWbTX.js.map} +1 -1
  29. package/package.json +3 -7
  30. package/dist/mail-editor-D3QbvBKs.js +0 -1569
  31. package/dist/mail-editor-D3QbvBKs.js.map +0 -1
  32. package/dist/mail-editor.js +0 -7
  33. package/dist/mail-editor.js.map +0 -1
@@ -1,1569 +0,0 @@
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-Dx0bJnRa.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-_2fRc5-k.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-D34uGd81.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-HOA8TCla.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-BUl5TiH0.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-B_MVWfF5.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-C9ccGMTE.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
- flex: 1;
1546
- min-height: 500px;
1547
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1548
- color: #111827;
1549
- box-sizing: border-box;
1550
- overflow: hidden;
1551
- position: relative;
1552
- }
1553
- * { box-sizing: border-box; }
1554
- `;
1555
- H([
1556
- W({ type: Object })
1557
- ], _.prototype, "options", 2);
1558
- _ = H([
1559
- j("mail-editor")
1560
- ], _);
1561
- export {
1562
- X as E,
1563
- _ as M,
1564
- Y as T,
1565
- y as e,
1566
- bt as j,
1567
- s
1568
- };
1569
- //# sourceMappingURL=mail-editor-D3QbvBKs.js.map