@emabuild/core 0.1.5 → 0.3.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 (73) hide show
  1. package/dist/canvas/column-renderer.d.ts.map +1 -1
  2. package/dist/canvas/content-renderer.d.ts +6 -3
  3. package/dist/canvas/content-renderer.d.ts.map +1 -1
  4. package/dist/canvas/editor-canvas.d.ts +11 -0
  5. package/dist/canvas/editor-canvas.d.ts.map +1 -1
  6. package/dist/canvas/inline-toolbar.d.ts +8 -0
  7. package/dist/canvas/inline-toolbar.d.ts.map +1 -1
  8. package/dist/canvas/row-renderer.d.ts +2 -0
  9. package/dist/canvas/row-renderer.d.ts.map +1 -1
  10. package/dist/compat/unlayer-adapter.d.ts +33 -0
  11. package/dist/compat/unlayer-adapter.d.ts.map +1 -0
  12. package/dist/dnd/drag-manager.d.ts +1 -0
  13. package/dist/dnd/drag-manager.d.ts.map +1 -1
  14. package/dist/dnd/drag-state.d.ts +10 -3
  15. package/dist/dnd/drag-state.d.ts.map +1 -1
  16. package/dist/{form-tool-CduLiZgt.js → form-tool-C7760Hvm.js} +12 -11
  17. package/dist/form-tool-C7760Hvm.js.map +1 -0
  18. package/dist/{html-tool-D4ay2h-U.js → html-tool-4zZO2hqE.js} +3 -3
  19. package/dist/{html-tool-D4ay2h-U.js.map → html-tool-4zZO2hqE.js.map} +1 -1
  20. package/dist/index-zy5NbC2E.js +4303 -0
  21. package/dist/index-zy5NbC2E.js.map +1 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +7 -5
  25. package/dist/mail-editor.d.ts +13 -2
  26. package/dist/mail-editor.d.ts.map +1 -1
  27. package/dist/{menu-tool-KvGDbaYD.js → menu-tool-Cu5D_VYs.js} +12 -11
  28. package/dist/menu-tool-Cu5D_VYs.js.map +1 -0
  29. package/dist/properties/property-panel.d.ts.map +1 -1
  30. package/dist/properties/widgets/index.d.ts +1 -0
  31. package/dist/properties/widgets/index.d.ts.map +1 -1
  32. package/dist/properties/widgets/number-unit-widget.d.ts +10 -0
  33. package/dist/properties/widgets/number-unit-widget.d.ts.map +1 -0
  34. package/dist/register-elements.d.ts.map +1 -1
  35. package/dist/sidebar/a11y-checker.d.ts +27 -0
  36. package/dist/sidebar/a11y-checker.d.ts.map +1 -0
  37. package/dist/sidebar/body-settings.d.ts +2 -0
  38. package/dist/sidebar/body-settings.d.ts.map +1 -1
  39. package/dist/sidebar/editor-sidebar.d.ts +5 -2
  40. package/dist/sidebar/editor-sidebar.d.ts.map +1 -1
  41. package/dist/{social-tool-B8Jg2yE-.js → social-tool-kPuP-4n6.js} +13 -12
  42. package/dist/social-tool-kPuP-4n6.js.map +1 -0
  43. package/dist/state/editor-store.d.ts +30 -28
  44. package/dist/state/editor-store.d.ts.map +1 -1
  45. package/dist/{table-tool-BzpD08dq.js → table-tool-CcWFvTSc.js} +14 -13
  46. package/dist/table-tool-CcWFvTSc.js.map +1 -0
  47. package/dist/timer-tool-CG1oul_Z.js +55 -0
  48. package/dist/timer-tool-CG1oul_Z.js.map +1 -0
  49. package/dist/tools/built-in/button-tool.d.ts.map +1 -1
  50. package/dist/tools/built-in/divider-tool.d.ts.map +1 -1
  51. package/dist/tools/built-in/heading-tool.d.ts.map +1 -1
  52. package/dist/tools/built-in/image-tool.d.ts.map +1 -1
  53. package/dist/tools/built-in/paragraph-tool.d.ts.map +1 -1
  54. package/dist/tools/built-in/shared-options.d.ts +105 -0
  55. package/dist/tools/built-in/shared-options.d.ts.map +1 -0
  56. package/dist/tools/built-in/text-tool.d.ts.map +1 -1
  57. package/dist/tools/helpers/index.d.ts +1 -1
  58. package/dist/tools/helpers/index.d.ts.map +1 -1
  59. package/dist/tools/helpers/value-extractor.d.ts +9 -0
  60. package/dist/tools/helpers/value-extractor.d.ts.map +1 -1
  61. package/dist/tools/tool-registry.d.ts.map +1 -1
  62. package/dist/{video-tool-CdGVmZxz.js → video-tool-CttMka8Z.js} +7 -6
  63. package/dist/video-tool-CttMka8Z.js.map +1 -0
  64. package/package.json +13 -26
  65. package/dist/form-tool-CduLiZgt.js.map +0 -1
  66. package/dist/index-BoKIXJKv.js +0 -3001
  67. package/dist/index-BoKIXJKv.js.map +0 -1
  68. package/dist/menu-tool-KvGDbaYD.js.map +0 -1
  69. package/dist/social-tool-B8Jg2yE-.js.map +0 -1
  70. package/dist/table-tool-BzpD08dq.js.map +0 -1
  71. package/dist/timer-tool-Ck1ERDW-.js +0 -54
  72. package/dist/timer-tool-Ck1ERDW-.js.map +0 -1
  73. package/dist/video-tool-CdGVmZxz.js.map +0 -1
@@ -0,0 +1,4303 @@
1
+ import { css as _, LitElement as T, nothing as v, html as d } from "lit";
2
+ import { property as x, customElement as S, state as E } from "lit/decorators.js";
3
+ import { unsafeHTML as ie } from "lit/directives/unsafe-html.js";
4
+ import { styleMap as He } from "lit/directives/style-map.js";
5
+ import { repeat as ye } from "lit/directives/repeat.js";
6
+ class B {
7
+ /**
8
+ * @param host - The Lit component that owns this controller
9
+ * @param channels - Which store channels to subscribe to
10
+ */
11
+ constructor(t, o) {
12
+ this.store = null, this.host = t, this.channels = o, t.addController(this);
13
+ }
14
+ /** Set or change the store reference. Re-subscribes automatically. */
15
+ setStore(t) {
16
+ this.store !== t && (this.unsub?.(), this.store = t, this.subscribe());
17
+ }
18
+ hostConnected() {
19
+ this.subscribe();
20
+ }
21
+ hostDisconnected() {
22
+ this.unsub?.(), this.unsub = void 0;
23
+ }
24
+ subscribe() {
25
+ this.store && (this.unsub = this.store.subscribeChannels(this.channels, () => {
26
+ this.host.requestUpdate();
27
+ }));
28
+ }
29
+ }
30
+ var Ve = Object.defineProperty, Fe = Object.getOwnPropertyDescriptor, xe = (e, t, o, r) => {
31
+ for (var i = r > 1 ? void 0 : r ? Fe(t, o) : t, n = e.length - 1, s; n >= 0; n--)
32
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
33
+ return r && i && Ve(t, o, i), i;
34
+ };
35
+ function ge(e) {
36
+ if (!e || e === "transparent" || e === "" || e === "none") return null;
37
+ const t = e.trim().toLowerCase(), o = {
38
+ white: "#ffffff",
39
+ black: "#000000",
40
+ red: "#ff0000",
41
+ blue: "#0000ff",
42
+ green: "#008000",
43
+ yellow: "#ffff00",
44
+ gray: "#808080",
45
+ grey: "#808080"
46
+ };
47
+ if (o[t]) return ge(o[t]);
48
+ if (t.startsWith("#")) {
49
+ let i = t.slice(1);
50
+ if (i.length === 3 && (i = i[0] + i[0] + i[1] + i[1] + i[2] + i[2]), i.length !== 6) return null;
51
+ const n = parseInt(i, 16);
52
+ return isNaN(n) ? null : { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
53
+ }
54
+ const r = t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
55
+ return r ? { r: +r[1], g: +r[2], b: +r[3] } : null;
56
+ }
57
+ function $e(e, t, o) {
58
+ const [r, i, n] = [e, t, o].map((s) => {
59
+ const a = s / 255;
60
+ return a <= 0.03928 ? a / 12.92 : Math.pow((a + 0.055) / 1.055, 2.4);
61
+ });
62
+ return 0.2126 * r + 0.7152 * i + 0.0722 * n;
63
+ }
64
+ function V(e, t) {
65
+ const o = ge(e), r = ge(t);
66
+ if (!o || !r) return null;
67
+ const i = $e(o.r, o.g, o.b), n = $e(r.r, r.g, r.b);
68
+ return (Math.max(i, n) + 0.05) / (Math.min(i, n) + 0.05);
69
+ }
70
+ function Le(e) {
71
+ if (typeof e != "string") return !1;
72
+ const t = e.trim().toLowerCase();
73
+ return t !== "" && t !== "transparent" && t !== "none" && t !== "inherit";
74
+ }
75
+ function Ce(...e) {
76
+ for (const t of e)
77
+ if (Le(t)) return t;
78
+ return "#ffffff";
79
+ }
80
+ function te(e, t = 0) {
81
+ return typeof e == "number" ? e : typeof e == "string" && parseInt(e, 10) || t;
82
+ }
83
+ function Ue(e) {
84
+ if (!e || e === "") return null;
85
+ const t = String(e);
86
+ if (t.endsWith("%")) return parseFloat(t) / 100;
87
+ const o = parseFloat(t);
88
+ return isNaN(o) ? null : o > 5 ? o / 100 : o;
89
+ }
90
+ let U = class extends T {
91
+ constructor() {
92
+ super(...arguments), this.storeCtrl = new B(this, ["design"]);
93
+ }
94
+ set store(e) {
95
+ this.storeCtrl.setStore(e);
96
+ }
97
+ get store() {
98
+ return this.storeCtrl.store;
99
+ }
100
+ checkAccessibility() {
101
+ return ve(this.store);
102
+ }
103
+ handleIssueClick(e) {
104
+ e && this.store.select(e);
105
+ }
106
+ handleIssueHover(e) {
107
+ this.store.hover(e ?? null);
108
+ }
109
+ handleFixPreheader(e) {
110
+ e.stopPropagation(), this.store.setActiveTab("body"), requestAnimationFrame(() => {
111
+ setTimeout(() => {
112
+ document.querySelector("mail-editor")?.shadowRoot?.querySelector("me-editor-sidebar")?.shadowRoot?.querySelector("me-body-settings")?.highlightPreheader?.();
113
+ }, 100);
114
+ });
115
+ }
116
+ handleFixHeading(e) {
117
+ e.stopPropagation();
118
+ const t = this.store.createRow([1]), r = this.store.addRow(t, 0).columns[0].id, i = this.toolRegistry.getDefaultValues("heading"), n = this.store.createContent("heading", i);
119
+ this.store.addContent(r, n), this.store.select(n.id);
120
+ }
121
+ render() {
122
+ const e = this.checkAccessibility(), t = e.filter((i) => i.severity === "error"), o = e.filter((i) => i.severity === "warning"), r = e.filter((i) => i.severity === "info");
123
+ return d`
124
+ <div class="summary">
125
+ ${t.length > 0 ? d`<span class="score-pill errors"><span class="score-dot error"></span>${t.length}</span>` : v}
126
+ ${o.length > 0 ? d`<span class="score-pill warnings"><span class="score-dot warning"></span>${o.length}</span>` : v}
127
+ ${r.length > 0 ? d`<span class="score-pill infos"><span class="score-dot info"></span>${r.length}</span>` : v}
128
+ ${t.length === 0 && o.length === 0 ? d`<span class="score-pill pass"><span class="score-dot pass"></span>Pass</span>` : v}
129
+ </div>
130
+
131
+ ${e.length === 0 ? d`
132
+ <div class="all-clear">
133
+ <div class="all-clear-icon">✓</div>
134
+ <div class="all-clear-text">Accessible</div>
135
+ <div class="all-clear-sub">No issues detected</div>
136
+ </div>
137
+ ` : d`
138
+ ${t.length > 0 ? d`
139
+ <div class="section-title">Errors</div>
140
+ <div class="issues-list">${t.map((i) => this.renderIssue(i))}</div>
141
+ ` : v}
142
+ ${o.length > 0 ? d`
143
+ <div class="section-title">Warnings</div>
144
+ <div class="issues-list">${o.map((i) => this.renderIssue(i))}</div>
145
+ ` : v}
146
+ ${r.length > 0 ? d`
147
+ <div class="section-title">Info</div>
148
+ <div class="issues-list">${r.map((i) => this.renderIssue(i))}</div>
149
+ ` : v}
150
+ `}
151
+ `;
152
+ }
153
+ renderIssue(e) {
154
+ return d`
155
+ <div class="issue ${e.severity}"
156
+ @click=${() => this.handleIssueClick(e.elementId)}
157
+ @mouseenter=${() => this.handleIssueHover(e.elementId)}
158
+ @mouseleave=${() => this.handleIssueHover(void 0)}>
159
+ <div class="issue-icon ${e.severity}">
160
+ ${e.severity === "error" ? "✕" : e.severity === "warning" ? "!" : "i"}
161
+ </div>
162
+ <div class="issue-body">
163
+ <div class="issue-rule">${e.rule}</div>
164
+ <div class="issue-msg">${e.message}</div>
165
+ ${e.element ? d`<div class="issue-element">${e.element}</div>` : v}
166
+ ${e.rule === "heading-structure" ? d`<button class="issue-fix" @click=${this.handleFixHeading}>+ Add heading</button>` : v}
167
+ ${e.rule === "preheader" ? d`<button class="issue-fix" @click=${this.handleFixPreheader}>Fix</button>` : v}
168
+ </div>
169
+ </div>
170
+ `;
171
+ }
172
+ };
173
+ U.styles = _`
174
+ :host {
175
+ display: flex;
176
+ flex-direction: column;
177
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
178
+ }
179
+
180
+ .summary {
181
+ display: flex;
182
+ flex-wrap: wrap;
183
+ gap: 6px;
184
+ margin-bottom: 12px;
185
+ }
186
+ .score-pill {
187
+ display: flex;
188
+ align-items: center;
189
+ gap: 4px;
190
+ padding: 3px 8px;
191
+ border-radius: 20px;
192
+ font-size: 11px;
193
+ font-weight: 600;
194
+ }
195
+ .score-pill.errors { background: #fef2f2; color: #dc2626; border: 1px solid #fecaca; }
196
+ .score-pill.warnings { background: #fffbeb; color: #d97706; border: 1px solid #fde68a; }
197
+ .score-pill.infos { background: #EDF5FF; color: #245A7F; border: 1px solid #bfdbfe; }
198
+ .score-pill.pass { background: #f0fdf4; color: #16a34a; border: 1px solid #bbf7d0; }
199
+ .score-dot { width: 6px; height: 6px; border-radius: 50%; }
200
+ .score-dot.error { background: #dc2626; }
201
+ .score-dot.warning { background: #d97706; }
202
+ .score-dot.info { background: #245A7F; }
203
+ .score-dot.pass { background: #16a34a; }
204
+
205
+ .section-title {
206
+ font-size: 10px; font-weight: 700; text-transform: uppercase;
207
+ letter-spacing: 0.06em; color: #245A7F;
208
+ padding: 6px 0 4px; margin-top: 8px;
209
+ border-bottom: 1px solid #EDF5FF;
210
+ }
211
+ .section-title:first-of-type { margin-top: 0; }
212
+
213
+ .issues-list {
214
+ display: flex;
215
+ flex-direction: column;
216
+ gap: 3px;
217
+ margin-top: 6px;
218
+ }
219
+ .issue {
220
+ display: flex;
221
+ gap: 8px;
222
+ padding: 6px 8px;
223
+ border-radius: 6px;
224
+ border: 1px solid #f3f4f6;
225
+ transition: all 150ms ease;
226
+ cursor: pointer;
227
+ }
228
+ .issue:hover { background: #f9fafb; border-color: #e5e7eb; }
229
+ .issue.error { border-left: 3px solid #dc2626; }
230
+ .issue.warning { border-left: 3px solid #d97706; }
231
+ .issue.info { border-left: 3px solid #5d768b; }
232
+ .issue-icon {
233
+ flex-shrink: 0;
234
+ width: 16px; height: 16px;
235
+ display: flex; align-items: center; justify-content: center;
236
+ font-size: 10px; font-weight: 700;
237
+ border-radius: 50%;
238
+ margin-top: 1px;
239
+ }
240
+ .issue-icon.error { background: #fef2f2; color: #dc2626; }
241
+ .issue-icon.warning { background: #fffbeb; color: #d97706; }
242
+ .issue-icon.info { background: #EDF5FF; color: #245A7F; }
243
+ .issue-body { flex: 1; min-width: 0; }
244
+ .issue-rule {
245
+ font-size: 9px; font-weight: 600; text-transform: uppercase;
246
+ letter-spacing: 0.04em; color: #9ca3af;
247
+ }
248
+ .issue-msg { font-size: 11px; color: #374151; line-height: 1.4; margin-top: 1px; }
249
+ .issue-element {
250
+ font-size: 10px; color: #5d768b; margin-top: 2px;
251
+ cursor: pointer;
252
+ }
253
+ .issue-element:hover { text-decoration: underline; }
254
+ .issue-fix {
255
+ display: inline-flex; align-items: center; gap: 3px;
256
+ margin-top: 4px; padding: 2px 8px;
257
+ background: #f0fdf4; color: #16a34a; border: 1px solid #bbf7d0;
258
+ border-radius: 4px; font-size: 10px; font-weight: 600;
259
+ cursor: pointer; transition: all 150ms ease;
260
+ }
261
+ .issue-fix:hover { background: #dcfce7; border-color: #86efac; }
262
+
263
+ .all-clear {
264
+ text-align: center;
265
+ padding: 24px 16px;
266
+ }
267
+ .all-clear-icon {
268
+ width: 36px; height: 36px; border-radius: 50%;
269
+ background: #f0fdf4; margin: 0 auto 8px;
270
+ display: flex; align-items: center; justify-content: center;
271
+ font-size: 18px; color: #16a34a;
272
+ }
273
+ .all-clear-text { font-size: 12px; font-weight: 600; color: #16a34a; }
274
+ .all-clear-sub { font-size: 11px; color: #9ca3af; margin-top: 4px; }
275
+ `;
276
+ xe([
277
+ x({ attribute: !1 })
278
+ ], U.prototype, "store", 1);
279
+ xe([
280
+ x({ attribute: !1 })
281
+ ], U.prototype, "toolRegistry", 2);
282
+ U = xe([
283
+ S("me-a11y-checker")
284
+ ], U);
285
+ function ve(e) {
286
+ const t = [], o = e.getDesign(), r = e.getBodyValues(), i = r.backgroundColor || "#ffffff", n = r.textColor || "#000000";
287
+ let s = !1;
288
+ const a = [];
289
+ for (const h of o.body.rows) {
290
+ const g = h.values.backgroundColor || "", b = h.values.columnsBackgroundColor || "";
291
+ for (const k of h.columns) {
292
+ const $ = Ce(k.values.backgroundColor, b, g, i);
293
+ for (const m of k.contents) {
294
+ const f = m.values, y = m.type, w = `${y} #${m.id.split("_").pop()}`;
295
+ if (y === "image") {
296
+ const C = f.alt || "";
297
+ (f.src || "") && !C.trim() ? t.push({ severity: "error", rule: "img-alt", message: "Missing alt text.", element: w, elementId: m.id }) : C && C.length > 125 && t.push({ severity: "warning", rule: "img-alt-length", message: `Alt text ${C.length} chars (max 125).`, element: w, elementId: m.id });
298
+ }
299
+ if (y === "text" || y === "heading" || y === "paragraph") {
300
+ const C = Le(f.color) ? f.color : n, A = Ce(f.backgroundColor, $), I = V(C, A);
301
+ if (I !== null) {
302
+ const Y = te(f.fontSize, 14), je = ["700", "800", "900"].includes(f.fontWeight || ""), ke = Y >= 18 || Y >= 14 && je ? 3 : 4.5;
303
+ I < ke && t.push({ severity: I < 3 ? "error" : "warning", rule: "color-contrast", message: `Ratio ${I.toFixed(1)}:1 (min ${ke}:1). "${C}" on "${A}".`, element: w, elementId: m.id });
304
+ }
305
+ const W = te(f.fontSize, 14);
306
+ y !== "heading" && W > 0 && W < 12 && t.push({ severity: "warning", rule: "font-size", message: `Font size ${W}px below 12px minimum.`, element: w, elementId: m.id });
307
+ const ee = Ue(f.lineHeight);
308
+ ee !== null && ee < 1.2 && y !== "heading" && t.push({ severity: "warning", rule: "line-height", message: `Line height ${String(f.lineHeight)} too tight (min 1.5x).`, element: w, elementId: m.id }), f.textAlign === "justify" && t.push({ severity: "warning", rule: "text-justify", message: "Justified text reduces readability.", element: w, elementId: m.id });
309
+ }
310
+ if (y === "button") {
311
+ const C = f.backgroundColor || "#3b82f6", A = f.textColor || "#ffffff", I = V(A, C);
312
+ I !== null && I < 4.5 && t.push({ severity: I < 3 ? "error" : "warning", rule: "color-contrast", message: `Button contrast ${I.toFixed(1)}:1 (min 4.5:1).`, element: w, elementId: m.id });
313
+ const W = V(C, $);
314
+ W !== null && W < 3 && t.push({ severity: "warning", rule: "btn-visibility", message: `Button blends with background (${W.toFixed(1)}:1).`, element: w, elementId: m.id }), (f.text || "").trim() || t.push({ severity: "error", rule: "link-text", message: "Button has no visible text.", element: w, elementId: m.id });
315
+ const ee = (f.buttonPadding || "10px 20px").split(/\s+/), Y = te(f.fontSize, 14) + te(ee[0], 10) * 2;
316
+ Y < 44 && t.push({ severity: "info", rule: "touch-target", message: `Button height ~${Y}px (min 44px).`, element: w, elementId: m.id });
317
+ }
318
+ if (y === "heading" && (s = !0, a.push(f.headingType || "h1")), y === "text" || y === "paragraph") {
319
+ const C = f.text || "", A = C.match(/<a[^>]*>(\s|&nbsp;)*<\/a>/gi);
320
+ A && t.push({ severity: "error", rule: "link-text", message: `${A.length} empty link(s).`, element: w, elementId: m.id });
321
+ const I = C.match(/<a[^>]*>(click here|here|link|read more)<\/a>/gi);
322
+ I && t.push({ severity: "warning", rule: "link-purpose", message: `${I.length} generic link text(s).`, element: w, elementId: m.id });
323
+ }
324
+ y === "social" && t.push({ severity: "info", rule: "social-alt", message: "Verify social icons have alt text.", element: w, elementId: m.id });
325
+ }
326
+ }
327
+ }
328
+ const c = o.body.rows.reduce((h, g) => h + g.columns.reduce((b, k) => b + k.contents.length, 0), 0);
329
+ if (c > 0 && !s && t.push({ severity: "warning", rule: "heading-structure", message: "No heading in email." }), a.length > 1) {
330
+ const h = a.map((g) => parseInt(g.replace("h", ""), 10)).filter((g) => !isNaN(g));
331
+ for (let g = 1; g < h.length; g++)
332
+ if (h[g] > h[g - 1] + 1) {
333
+ t.push({ severity: "warning", rule: "heading-skip", message: `Heading jumps h${h[g - 1]} → h${h[g]}.` });
334
+ break;
335
+ }
336
+ }
337
+ const l = V(n, i);
338
+ l !== null && l < 4.5 && t.push({ severity: "warning", rule: "color-contrast", message: `Body text contrast ${l.toFixed(1)}:1 (min 4.5:1).` });
339
+ const u = r.linkStyle?.linkColor;
340
+ if (u) {
341
+ const h = V(u, i);
342
+ h !== null && h < 4.5 && t.push({ severity: "warning", rule: "link-contrast", message: `Link contrast ${h.toFixed(1)}:1 (min 4.5:1).` });
343
+ const g = V(u, n);
344
+ g !== null && g < 3 && !r.linkStyle?.linkUnderline && t.push({ severity: "warning", rule: "link-distinguish", message: "Links not underlined and low contrast vs text." });
345
+ }
346
+ return (r.preheaderText || "").trim() || t.push({ severity: "info", rule: "preheader", message: "No preheader text set." }), c === 0 && t.push({ severity: "info", rule: "empty-email", message: "Email has no content." }), t.sort((h, g) => ({ error: 0, warning: 1, info: 2 })[h.severity] - { error: 0, warning: 1, info: 2 }[g.severity]), t;
347
+ }
348
+ function qe() {
349
+ const e = {};
350
+ return {
351
+ getCounters() {
352
+ return { ...e };
353
+ },
354
+ setCounters(t) {
355
+ for (const o of Object.keys(e))
356
+ delete e[o];
357
+ Object.assign(e, t);
358
+ },
359
+ next(t) {
360
+ const o = e[t] ?? 0;
361
+ return e[t] = o + 1, e[t];
362
+ }
363
+ };
364
+ }
365
+ class Ne {
366
+ constructor() {
367
+ this.listeners = /* @__PURE__ */ new Map();
368
+ }
369
+ /** Register a listener for an event */
370
+ on(t, o) {
371
+ this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(o);
372
+ }
373
+ /** Remove a specific listener */
374
+ off(t, o) {
375
+ this.listeners.get(t)?.delete(o);
376
+ }
377
+ /** Emit an event with a payload. Errors in listeners are caught and logged. */
378
+ emit(t, o) {
379
+ this.listeners.get(t)?.forEach((r) => {
380
+ try {
381
+ r(o);
382
+ } catch (i) {
383
+ console.error(`[emabuild] Error in "${t}" listener:`, i);
384
+ }
385
+ });
386
+ }
387
+ /** Remove all listeners, optionally scoped to a single event */
388
+ removeAllListeners(t) {
389
+ t ? this.listeners.delete(t) : this.listeners.clear();
390
+ }
391
+ }
392
+ class Ge {
393
+ constructor(t = 50) {
394
+ this.undoStack = [], this.redoStack = [], this.maxHistory = t;
395
+ }
396
+ /** Whether there are states to undo to */
397
+ get canUndo() {
398
+ return this.undoStack.length > 0;
399
+ }
400
+ /** Whether there are states to redo to */
401
+ get canRedo() {
402
+ return this.redoStack.length > 0;
403
+ }
404
+ /** Save current design to the undo stack before a mutation */
405
+ push(t) {
406
+ this.undoStack.push(structuredClone(t)), this.undoStack.length > this.maxHistory && this.undoStack.shift(), this.redoStack = [];
407
+ }
408
+ /** Restore the previous state, pushing current state to redo. Returns the restored design or undefined. */
409
+ undo(t) {
410
+ const o = this.undoStack.pop();
411
+ if (o)
412
+ return this.redoStack.push(structuredClone(t)), structuredClone(o);
413
+ }
414
+ /** Restore the next state, pushing current state to undo. Returns the restored design or undefined. */
415
+ redo(t) {
416
+ const o = this.redoStack.pop();
417
+ if (o)
418
+ return this.undoStack.push(structuredClone(t)), structuredClone(o);
419
+ }
420
+ /** Clear all history (e.g. when loading a new design) */
421
+ clear() {
422
+ this.undoStack = [], this.redoStack = [];
423
+ }
424
+ }
425
+ function Qe() {
426
+ return {
427
+ counters: { u_row: 0, u_column: 0 },
428
+ body: {
429
+ id: "u_body",
430
+ rows: [],
431
+ headers: [],
432
+ footers: [],
433
+ values: {
434
+ backgroundColor: "#e7e7e7",
435
+ contentAlign: "center",
436
+ contentVerticalAlign: "center",
437
+ contentWidth: "600px",
438
+ fontFamily: { label: "Arial", value: "arial,helvetica,sans-serif" },
439
+ textColor: "#000000",
440
+ linkStyle: {
441
+ body: !0,
442
+ linkColor: "#0000ee",
443
+ linkHoverColor: "#0000ee",
444
+ linkUnderline: !0,
445
+ linkHoverUnderline: !0
446
+ },
447
+ preheaderText: "",
448
+ popupPosition: "center",
449
+ popupWidth: "600px",
450
+ popupHeight: "auto",
451
+ borderRadius: "10px",
452
+ popupBackgroundColor: "#FFFFFF",
453
+ popupBackgroundImage: { url: "", fullWidth: !0, repeat: "no-repeat", center: !0, cover: !0 },
454
+ popupOverlay_backgroundColor: "rgba(0, 0, 0, 0.1)",
455
+ popupCloseButton_position: "top-right",
456
+ popupCloseButton_backgroundColor: "#DDDDDD",
457
+ popupCloseButton_iconColor: "#000000",
458
+ popupCloseButton_borderRadius: "0px",
459
+ popupCloseButton_margin: "0px",
460
+ popupCloseButton_action: {
461
+ name: "close_popup",
462
+ attrs: { onClick: "document.querySelector('.u-popup-container').style.display = 'none';" }
463
+ },
464
+ _meta: { htmlID: "u_body", htmlClassNames: "u_body" }
465
+ }
466
+ },
467
+ schemaVersion: 16
468
+ };
469
+ }
470
+ function Ye(e, t) {
471
+ const o = e.next("u_row"), r = t.map(() => {
472
+ const i = e.next("u_column");
473
+ return {
474
+ id: `u_column_${i}`,
475
+ contents: [],
476
+ values: {
477
+ backgroundColor: "",
478
+ padding: "0px",
479
+ border: {},
480
+ borderRadius: "0px",
481
+ _meta: { htmlID: `u_column_${i}`, htmlClassNames: "u_column" }
482
+ }
483
+ };
484
+ });
485
+ return {
486
+ id: `u_row_${o}`,
487
+ cells: t,
488
+ columns: r,
489
+ values: {
490
+ displayCondition: null,
491
+ columns: !1,
492
+ backgroundColor: "",
493
+ columnsBackgroundColor: "",
494
+ backgroundImage: { url: "", fullWidth: !0, repeat: !1, center: !0, cover: !1 },
495
+ padding: "0px",
496
+ anchor: "",
497
+ hideDesktop: !1,
498
+ hideMobile: !1,
499
+ _meta: { htmlID: `u_row_${o}`, htmlClassNames: "u_row" }
500
+ }
501
+ };
502
+ }
503
+ function Ke(e, t, o = {}) {
504
+ const r = e.next(`u_content_${t}`), i = `u_content_${t}_${r}`;
505
+ return {
506
+ id: i,
507
+ type: t,
508
+ values: {
509
+ containerPadding: "10px",
510
+ anchor: "",
511
+ hideDesktop: !1,
512
+ hideMobile: !1,
513
+ displayCondition: null,
514
+ _meta: { htmlID: i, htmlClassNames: `u_content_${t}` },
515
+ ...o
516
+ }
517
+ };
518
+ }
519
+ function de(e, t) {
520
+ return e.body.rows.find((o) => o.id === t);
521
+ }
522
+ function oe(e, t) {
523
+ for (const o of e.body.rows) {
524
+ const r = o.columns.find((i) => i.id === t);
525
+ if (r) return r;
526
+ }
527
+ }
528
+ function re(e, t) {
529
+ for (const o of e.body.rows)
530
+ for (const r of o.columns) {
531
+ const i = r.contents.find((n) => n.id === t);
532
+ if (i) return i;
533
+ }
534
+ }
535
+ function Je(e, t) {
536
+ for (const o of e.body.rows)
537
+ for (const r of o.columns)
538
+ if (r.contents.some((i) => i.id === t)) return r;
539
+ }
540
+ function Xe(e, t) {
541
+ for (const o of e.body.rows)
542
+ if (o.columns.some((r) => r.id === t)) return o;
543
+ }
544
+ function ce(e, t) {
545
+ return e.body.rows.findIndex((o) => o.id === t);
546
+ }
547
+ class Ze {
548
+ constructor() {
549
+ this.history = new Ge(), this.counterManager = qe(), this.channelSubscribers = /* @__PURE__ */ new Map(), this.events = new Ne(), this._mergeTags = [], this._a11yIssueIds = /* @__PURE__ */ new Set(), this._selectedId = null, this._hoveredId = null, this._viewMode = "desktop", this._activeTab = "content", this.design = Qe();
550
+ }
551
+ get a11yIssueIds() {
552
+ return this._a11yIssueIds;
553
+ }
554
+ setA11yIssueIds(t) {
555
+ this._a11yIssueIds = t;
556
+ }
557
+ // ── Subscriptions ──────────────────────────────────────────
558
+ /**
559
+ * Subscribe to specific channels only. The callback is invoked only
560
+ * when one of the listed channels fires. Returns an unsubscribe function.
561
+ *
562
+ * @example
563
+ * ```ts
564
+ * // Only re-render when the design changes, not on hover/selection
565
+ * store.subscribeChannels(['design'], () => this.requestUpdate());
566
+ * ```
567
+ */
568
+ subscribeChannels(t, o) {
569
+ for (const r of t) {
570
+ let i = this.channelSubscribers.get(r);
571
+ i || (i = /* @__PURE__ */ new Set(), this.channelSubscribers.set(r, i)), i.add(o);
572
+ }
573
+ return () => {
574
+ for (const r of t) {
575
+ const i = this.channelSubscribers.get(r);
576
+ i && (i.delete(o), i.size === 0 && this.channelSubscribers.delete(r));
577
+ }
578
+ };
579
+ }
580
+ /** @deprecated Use subscribeChannels instead */
581
+ subscribe(t) {
582
+ const o = ["design", "selection", "hover", "viewMode", "activeTab"];
583
+ return this.subscribeChannels(o, t);
584
+ }
585
+ /** Notify only subscribers of specific channels */
586
+ notifyChannels(...t) {
587
+ const o = /* @__PURE__ */ new Set();
588
+ for (const r of t) {
589
+ const i = this.channelSubscribers.get(r);
590
+ if (i) for (const n of i) o.add(n);
591
+ }
592
+ for (const r of o) r();
593
+ }
594
+ // ── Getters ────────────────────────────────────────────────
595
+ /** Get the full design document */
596
+ getDesign() {
597
+ return this.design;
598
+ }
599
+ /** Get the design body */
600
+ getBody() {
601
+ return this.design.body;
602
+ }
603
+ /** Get all rows */
604
+ getRows() {
605
+ return this.design.body.rows;
606
+ }
607
+ /** Get body-level values (background, fonts, etc.) */
608
+ getBodyValues() {
609
+ return this.design.body.values;
610
+ }
611
+ get selectedId() {
612
+ return this._selectedId;
613
+ }
614
+ get hoveredId() {
615
+ return this._hoveredId;
616
+ }
617
+ get viewMode() {
618
+ return this._viewMode;
619
+ }
620
+ get activeTab() {
621
+ return this._activeTab;
622
+ }
623
+ get mergeTags() {
624
+ return this._mergeTags;
625
+ }
626
+ get canUndo() {
627
+ return this.history.canUndo;
628
+ }
629
+ get canRedo() {
630
+ return this.history.canRedo;
631
+ }
632
+ // ── Design Loading ─────────────────────────────────────────
633
+ /** Load a design document, resetting history and selection */
634
+ loadDesign(t) {
635
+ 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 });
636
+ }
637
+ // ── Undo / Redo ────────────────────────────────────────────
638
+ undo() {
639
+ const t = this.history.undo(this.design);
640
+ t && (this.design = t, this.counterManager.setCounters(this.design.counters), this.notifyChannels("design"), this.emitUpdate("content_updated"));
641
+ }
642
+ redo() {
643
+ const t = this.history.redo(this.design);
644
+ t && (this.design = t, this.counterManager.setCounters(this.design.counters), this.notifyChannels("design"), this.emitUpdate("content_updated"));
645
+ }
646
+ // ── Selection / UI State ───────────────────────────────────
647
+ setMergeTags(t) {
648
+ this._mergeTags = t, this.notifyChannels("design");
649
+ }
650
+ select(t) {
651
+ this._selectedId = t, this.notifyChannels("selection");
652
+ }
653
+ hover(t) {
654
+ this._hoveredId = t, this.notifyChannels("hover");
655
+ }
656
+ setViewMode(t) {
657
+ this._viewMode = t, this.notifyChannels("viewMode");
658
+ }
659
+ setActiveTab(t) {
660
+ this._activeTab = t, this.notifyChannels("activeTab");
661
+ }
662
+ // ── Row Operations ─────────────────────────────────────────
663
+ /** Add a row at the given index (or at the end). Returns the inserted row. */
664
+ addRow(t, o) {
665
+ const r = structuredClone(t);
666
+ this.history.push(this.design);
667
+ const i = this.design.body.rows;
668
+ return o !== void 0 && o >= 0 && o <= i.length ? i.splice(o, 0, r) : i.push(r), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("row_added", r), r;
669
+ }
670
+ /** Remove a row by ID. Returns true if removed. */
671
+ removeRow(t) {
672
+ const o = ce(this.design, t);
673
+ return o === -1 ? !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"), !0);
674
+ }
675
+ /** Move a row from one index to another. Returns true if moved. */
676
+ moveRow(t, o) {
677
+ const r = this.design.body.rows;
678
+ if (t < 0 || t >= r.length || o < 0 || o >= r.length || t === o) return !1;
679
+ this.history.push(this.design);
680
+ const [i] = r.splice(t, 1);
681
+ return r.splice(o, 0, i), this.notifyChannels("design"), this.emitUpdate("row_reordered"), !0;
682
+ }
683
+ /** Duplicate a row, assigning fresh IDs to all nested elements */
684
+ duplicateRow(t) {
685
+ const o = de(this.design, t);
686
+ if (!o) return;
687
+ this.history.push(this.design);
688
+ const r = structuredClone(o), i = this.counterManager.next("u_row");
689
+ r.id = `u_row_${i}`, r.values._meta = { htmlID: r.id, htmlClassNames: "u_row" };
690
+ for (const s of r.columns) {
691
+ const a = this.counterManager.next("u_column");
692
+ s.id = `u_column_${a}`, s.values._meta = { htmlID: s.id, htmlClassNames: "u_column" };
693
+ for (const c of s.contents) {
694
+ const l = this.counterManager.next(`u_content_${c.type}`);
695
+ c.id = `u_content_${c.type}_${l}`, c.values._meta = { htmlID: c.id, htmlClassNames: `u_content_${c.type}` };
696
+ }
697
+ }
698
+ const n = ce(this.design, t);
699
+ return this.design.body.rows.splice(n + 1, 0, r), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("row_added", r), r;
700
+ }
701
+ /** Get the index of a row */
702
+ getRowIndex(t) {
703
+ return ce(this.design, t);
704
+ }
705
+ /** Update row-level values. Returns true if updated. */
706
+ updateRowValues(t, o) {
707
+ const r = de(this.design, t);
708
+ return r ? (this.history.push(this.design), Object.assign(r.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"), !0) : !1;
709
+ }
710
+ // ── Column Operations ──────────────────────────────────────
711
+ /** Update column-level values. Returns true if updated. */
712
+ updateColumnValues(t, o) {
713
+ const r = oe(this.design, t);
714
+ return r ? (this.history.push(this.design), Object.assign(r.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"), !0) : !1;
715
+ }
716
+ // ── Content Operations ─────────────────────────────────────
717
+ /** Add content to a column at the given index. Returns the inserted content. */
718
+ addContent(t, o, r) {
719
+ const i = oe(this.design, t);
720
+ if (!i) return;
721
+ const n = structuredClone(o);
722
+ return this.history.push(this.design), r !== void 0 && r >= 0 && r <= i.contents.length ? i.contents.splice(r, 0, n) : i.contents.push(n), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("content_added", n), n;
723
+ }
724
+ /** Remove a content block by ID. Returns true if removed. */
725
+ removeContent(t) {
726
+ for (const o of this.design.body.rows)
727
+ for (const r of o.columns) {
728
+ const i = r.contents.findIndex((n) => n.id === t);
729
+ if (i !== -1)
730
+ return this.history.push(this.design), r.contents.splice(i, 1), this._selectedId === t && (this._selectedId = null), this.notifyChannels("design"), this.emitUpdate("content_removed"), !0;
731
+ }
732
+ return !1;
733
+ }
734
+ /** Update content values by ID. Returns true if updated. */
735
+ updateContentValues(t, o) {
736
+ const r = re(this.design, t);
737
+ return r ? (this.history.push(this.design), Object.assign(r.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"), !0) : !1;
738
+ }
739
+ /** Move a content block to a different column at a given index. Returns true if moved. */
740
+ moveContent(t, o, r) {
741
+ if (!re(this.design, t)) return !1;
742
+ const n = oe(this.design, o);
743
+ if (!n) return !1;
744
+ this.history.push(this.design);
745
+ let s;
746
+ e: for (const c of this.design.body.rows)
747
+ for (const l of c.columns) {
748
+ const u = l.contents.findIndex((h) => h.id === t);
749
+ if (u !== -1) {
750
+ [s] = l.contents.splice(u, 1);
751
+ break e;
752
+ }
753
+ }
754
+ if (!s) return !1;
755
+ const a = Math.min(r, n.contents.length);
756
+ return n.contents.splice(a, 0, s), this.notifyChannels("design"), this.emitUpdate("content_reordered"), !0;
757
+ }
758
+ /** Duplicate a content block, inserting the copy right after the original */
759
+ duplicateContent(t) {
760
+ const o = re(this.design, t);
761
+ if (o)
762
+ for (const r of this.design.body.rows)
763
+ for (const i of r.columns) {
764
+ const n = i.contents.findIndex((s) => s.id === t);
765
+ if (n !== -1) {
766
+ this.history.push(this.design);
767
+ const s = structuredClone(o), a = this.counterManager.next(`u_content_${o.type}`);
768
+ return s.id = `u_content_${o.type}_${a}`, s.values._meta = { htmlID: s.id, htmlClassNames: `u_content_${o.type}` }, i.contents.splice(n + 1, 0, s), this.syncCounters(), this.notifyChannels("design"), this.emitUpdate("content_added", s), s;
769
+ }
770
+ }
771
+ }
772
+ // ── Body Values ────────────────────────────────────────────
773
+ /** Update body-level values (background, fonts, etc.) */
774
+ updateBodyValues(t) {
775
+ this.history.push(this.design), Object.assign(this.design.body.values, t), this.notifyChannels("design"), this.emitUpdate("body_updated");
776
+ }
777
+ // ── Lookups (delegate to design-lookup) ────────────────────
778
+ findRow(t) {
779
+ return de(this.design, t);
780
+ }
781
+ findColumn(t) {
782
+ return oe(this.design, t);
783
+ }
784
+ findContent(t) {
785
+ return re(this.design, t);
786
+ }
787
+ findParentColumn(t) {
788
+ return Je(this.design, t);
789
+ }
790
+ findParentRow(t) {
791
+ return Xe(this.design, t);
792
+ }
793
+ // ── Factory Methods (delegate to design-factory) ───────────
794
+ /** Create a new row with the given column layout */
795
+ createRow(t) {
796
+ const o = Ye(this.counterManager, t);
797
+ return this.syncCounters(), o;
798
+ }
799
+ /** Create a new content block for the given tool type */
800
+ createContent(t, o = {}) {
801
+ const r = Ke(this.counterManager, t, o);
802
+ return this.syncCounters(), r;
803
+ }
804
+ // ── Private Helpers ────────────────────────────────────────
805
+ syncCounters() {
806
+ this.design.counters = this.counterManager.getCounters();
807
+ }
808
+ emitUpdate(t, o) {
809
+ this.events.emit("design:updated", { type: t, item: o });
810
+ }
811
+ }
812
+ class et {
813
+ constructor() {
814
+ this.tools = /* @__PURE__ */ new Map(), this.lazyLoaders = /* @__PURE__ */ new Map(), this.lazyMeta = /* @__PURE__ */ new Map(), this.loadingPromises = /* @__PURE__ */ new Map();
815
+ }
816
+ /** Register a tool eagerly (available immediately) */
817
+ register(t) {
818
+ this.tools.set(t.name, t), this.lazyLoaders.delete(t.name), this.lazyMeta.delete(t.name);
819
+ }
820
+ /**
821
+ * Register a tool lazily. The tool's code is only loaded when first needed.
822
+ * Provide metadata (name, label, icon) so the tool can appear in the sidebar.
823
+ *
824
+ * @param meta - Display metadata for the sidebar palette
825
+ * @param loader - Async function that imports and returns the tool definition
826
+ *
827
+ * @example
828
+ * ```ts
829
+ * registry.registerLazy(
830
+ * { name: 'timer', label: 'Timer', icon: '<svg>...</svg>', position: 11 },
831
+ * () => import('./built-in/timer-tool.js').then(m => m.timerTool),
832
+ * );
833
+ * ```
834
+ */
835
+ registerLazy(t, o) {
836
+ this.tools.has(t.name) || (this.lazyMeta.set(t.name, t), this.lazyLoaders.set(t.name, o));
837
+ }
838
+ /** Get a tool by name. Returns undefined if not loaded yet (use ensureLoaded for lazy tools). */
839
+ get(t) {
840
+ return this.tools.get(t);
841
+ }
842
+ /** Check if a tool is registered (eager or lazy) */
843
+ has(t) {
844
+ return this.tools.has(t) || this.lazyLoaders.has(t);
845
+ }
846
+ /** Check if a tool is fully loaded and ready to render */
847
+ isLoaded(t) {
848
+ return this.tools.has(t);
849
+ }
850
+ /**
851
+ * Ensure a lazy tool is loaded. Returns the tool definition.
852
+ * If the tool is already loaded, returns it immediately.
853
+ * If it's being loaded, returns the in-flight promise.
854
+ */
855
+ async ensureLoaded(t) {
856
+ if (this.tools.has(t)) return this.tools.get(t);
857
+ if (this.loadingPromises.has(t)) return this.loadingPromises.get(t);
858
+ const o = this.lazyLoaders.get(t);
859
+ if (!o) return;
860
+ const r = o().then((i) => {
861
+ if (!i?.name || !i?.renderer)
862
+ throw new Error(`[ToolRegistry] Loaded tool "${t}" has invalid definition`);
863
+ return this.tools.set(t, i), this.lazyLoaders.delete(t), this.lazyMeta.delete(t), this.loadingPromises.delete(t), i;
864
+ }).catch((i) => {
865
+ this.loadingPromises.delete(t), console.error(`[ToolRegistry] Failed to load tool "${t}":`, i);
866
+ });
867
+ return this.loadingPromises.set(t, r), r;
868
+ }
869
+ /**
870
+ * Get all tools for display in the sidebar palette.
871
+ * Returns both loaded tools and lazy tool metadata, sorted by position.
872
+ */
873
+ getAll() {
874
+ return Array.from(this.tools.values()).sort((t, o) => (t.position ?? 0) - (o.position ?? 0));
875
+ }
876
+ /**
877
+ * Get all tool names and display metadata (including lazy tools not yet loaded).
878
+ * Used by the sidebar to show all available tools.
879
+ */
880
+ getAllMeta() {
881
+ const t = [];
882
+ for (const o of this.tools.values())
883
+ t.push({ name: o.name, label: o.label, icon: o.icon, position: o.position });
884
+ for (const o of this.lazyMeta.values())
885
+ t.push(o);
886
+ return t.sort((o, r) => (o.position ?? 0) - (r.position ?? 0));
887
+ }
888
+ /** Get default values for a tool. Loads lazily if needed (sync — returns empty if not loaded). */
889
+ getDefaultValues(t) {
890
+ const o = this.tools.get(t);
891
+ if (!o) return {};
892
+ const r = { ...o.defaultValues };
893
+ for (const i of Object.values(o.options))
894
+ for (const [n, s] of Object.entries(i.options))
895
+ n in r || (r[n] = s.defaultValue);
896
+ return r;
897
+ }
898
+ /** Get property groups for a tool */
899
+ getPropertyGroups(t) {
900
+ return this.tools.get(t)?.options ?? {};
901
+ }
902
+ }
903
+ const D = {
904
+ draggingContentId: null,
905
+ draggingRowId: null,
906
+ draggingElement: null,
907
+ startContentDrag(e, t) {
908
+ this.draggingContentId = e, this.draggingElement = t ?? null;
909
+ },
910
+ startRowDrag(e, t) {
911
+ this.draggingRowId = e, this.draggingElement = t ?? null;
912
+ },
913
+ reset() {
914
+ this.draggingElement && (this.draggingElement.style.opacity = "1", this.draggingElement = null), this.draggingContentId = null, this.draggingRowId = null;
915
+ }
916
+ };
917
+ function Ie(e) {
918
+ const t = document.createElement("div");
919
+ return Object.assign(t.style, {
920
+ position: "absolute",
921
+ left: "0",
922
+ right: "0",
923
+ height: "3px",
924
+ background: e,
925
+ borderRadius: "2px",
926
+ pointerEvents: "none",
927
+ zIndex: "1000",
928
+ display: "none",
929
+ boxShadow: `0 0 6px ${e}80`
930
+ }), t;
931
+ }
932
+ function _e(e, t, o, r, i = "4px") {
933
+ e.parentNode !== t && (e.remove(), t.appendChild(e));
934
+ const s = (t instanceof ShadowRoot ? t.host : t).getBoundingClientRect();
935
+ let a;
936
+ o.length === 0 || r === 0 ? a = o.length === 0 ? 0 : o[0].getBoundingClientRect().top - s.top : r >= o.length ? a = o[o.length - 1].getBoundingClientRect().bottom - s.top : a = o[r].getBoundingClientRect().top - s.top, Object.assign(e.style, {
937
+ display: "block",
938
+ top: `${a}px`,
939
+ left: i,
940
+ right: i,
941
+ width: "auto"
942
+ });
943
+ }
944
+ function F(e) {
945
+ e && (e.style.display = "none");
946
+ }
947
+ function fe(e, t) {
948
+ const o = (e instanceof ShadowRoot, e.children);
949
+ for (const r of Array.from(o)) {
950
+ const i = r;
951
+ t(i), i.shadowRoot && fe(i.shadowRoot, t), i.children?.length && fe(i, t);
952
+ }
953
+ }
954
+ function Te(e, t) {
955
+ const o = [];
956
+ return fe(e, (r) => {
957
+ r.matches?.(t) && o.push(r);
958
+ }), o;
959
+ }
960
+ class tt {
961
+ constructor(t, o, r) {
962
+ this.currentDrop = null, this.contentIndicator = null, this.rowIndicator = null, this.onDragOver = (i) => {
963
+ const n = i.dataTransfer?.types || [], s = n.includes("application/maileditor-tool"), a = n.includes("application/maileditor-layout"), c = n.includes("application/maileditor-content") || !!D.draggingContentId, l = n.includes("application/maileditor-row") || !!D.draggingRowId;
964
+ !s && !c && !a && !l || (i.preventDefault(), i.dataTransfer.dropEffect = s || a ? "copy" : "move", a || l ? (this.currentDrop = this.findRowDropTarget(i.clientY), F(this.contentIndicator), this.showRowIndicator()) : (this.currentDrop = this.findContentDropTarget(i.clientX, i.clientY), F(this.rowIndicator), this.showContentIndicator()));
965
+ }, this.onDrop = async (i) => {
966
+ i.preventDefault(), this.hideAllIndicators();
967
+ const n = this.currentDrop, s = i.dataTransfer?.getData("application/maileditor-row") || D.draggingRowId;
968
+ if (s) {
969
+ this.handleRowDrop(s, n), this.reset();
970
+ return;
971
+ }
972
+ const a = i.dataTransfer?.getData("application/maileditor-layout");
973
+ if (a) {
974
+ this.handleLayoutDrop(JSON.parse(a), n), this.reset();
975
+ return;
976
+ }
977
+ const c = i.dataTransfer?.getData("application/maileditor-tool");
978
+ if (c) {
979
+ await this.handleToolDrop(c, n), this.reset();
980
+ return;
981
+ }
982
+ const l = i.dataTransfer?.getData("application/maileditor-content") || D.draggingContentId;
983
+ l && this.handleContentDrop(l, n), this.reset();
984
+ }, this.onDragEnd = () => {
985
+ this.hideAllIndicators(), this.reset();
986
+ }, this.onDragLeave = (i) => {
987
+ const n = i.relatedTarget;
988
+ (!n || !this.root.contains(n)) && (this.hideAllIndicators(), this.currentDrop = null);
989
+ }, this.store = t, this.toolRegistry = o, this.root = r;
990
+ }
991
+ /** Attach all drag event listeners to the shadow root */
992
+ attach() {
993
+ 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 = Ie("#3b82f6"), this.rowIndicator = Ie("#8b5cf6");
994
+ }
995
+ /** Remove all event listeners and clean up indicators */
996
+ detach() {
997
+ 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();
998
+ }
999
+ // ── Drop Handlers ──────────────────────────────────────────
1000
+ handleRowDrop(t, o = this.currentDrop) {
1001
+ if (o?.type === "row" && o.rowIndex !== void 0) {
1002
+ const r = this.store.getRowIndex(t);
1003
+ if (r === -1) return;
1004
+ const i = o.rowIndex > r ? o.rowIndex - 1 : o.rowIndex;
1005
+ r !== i && this.store.moveRow(r, i);
1006
+ }
1007
+ }
1008
+ handleLayoutDrop(t, o = this.currentDrop) {
1009
+ const r = this.store.createRow(t), i = o?.type === "row" ? o.rowIndex : void 0;
1010
+ this.store.addRow(r, i);
1011
+ }
1012
+ async handleToolDrop(t, o) {
1013
+ if (await this.toolRegistry.ensureLoaded(t), o?.type === "content" && o.columnId) {
1014
+ const r = this.toolRegistry.getDefaultValues(t), i = this.store.createContent(t, r);
1015
+ this.store.addContent(o.columnId, i, o.contentIndex), this.store.select(i.id);
1016
+ } else {
1017
+ const r = this.store.createRow([1]);
1018
+ this.store.addRow(r);
1019
+ const i = this.toolRegistry.getDefaultValues(t), n = this.store.createContent(t, i);
1020
+ this.store.addContent(r.columns[0].id, n), this.store.select(n.id);
1021
+ }
1022
+ }
1023
+ handleContentDrop(t, o) {
1024
+ o?.type === "content" && o.columnId && (this.store.moveContent(t, o.columnId, o.contentIndex), this.store.select(t));
1025
+ }
1026
+ // ── Drop Target Detection ─────────────────────────────────
1027
+ findRowDropTarget(t) {
1028
+ const o = this.root.querySelector("me-editor-canvas");
1029
+ if (!o?.shadowRoot) return null;
1030
+ const r = Array.from(o.shadowRoot.querySelectorAll("me-row-renderer"));
1031
+ if (r.length === 0) return { type: "row", rowIndex: 0, y: 0 };
1032
+ let i = Math.abs(t - r[0].getBoundingClientRect().top), n = { type: "row", rowIndex: 0, y: r[0].getBoundingClientRect().top };
1033
+ for (let s = 0; s < r.length; s++) {
1034
+ const a = r[s].getBoundingClientRect().bottom, c = Math.abs(t - a);
1035
+ c < i && (i = c, n = { type: "row", rowIndex: s + 1, y: a });
1036
+ }
1037
+ return n;
1038
+ }
1039
+ findContentDropTarget(t, o) {
1040
+ const r = Te(this.root, "me-column-renderer");
1041
+ let i = null, n = 1 / 0;
1042
+ for (const s of r) {
1043
+ const a = s.dataset.columnId;
1044
+ if (!a || !s.shadowRoot) continue;
1045
+ const c = s.getBoundingClientRect();
1046
+ if (t < c.left || t > c.right) continue;
1047
+ const l = Array.from(s.shadowRoot.querySelectorAll("me-content-renderer"));
1048
+ if (l.length === 0) {
1049
+ const g = Math.abs(o - (c.top + c.height / 2));
1050
+ g < n && (n = g, i = { type: "content", columnId: a, contentIndex: 0, y: c.top + c.height / 2 });
1051
+ continue;
1052
+ }
1053
+ const u = l[0].getBoundingClientRect().top;
1054
+ let h = Math.abs(o - u);
1055
+ h < n && (n = h, i = { type: "content", columnId: a, contentIndex: 0, y: u });
1056
+ for (let g = 0; g < l.length; g++) {
1057
+ const b = l[g].getBoundingClientRect(), k = l[g + 1]?.getBoundingClientRect(), $ = k ? (b.bottom + k.top) / 2 : b.bottom;
1058
+ h = Math.abs(o - $), h < n && (n = h, i = { type: "content", columnId: a, contentIndex: g + 1, y: $ });
1059
+ }
1060
+ }
1061
+ return i;
1062
+ }
1063
+ // ── Indicator Positioning ──────────────────────────────────
1064
+ showContentIndicator() {
1065
+ if (!this.contentIndicator || !this.currentDrop?.columnId) {
1066
+ F(this.contentIndicator);
1067
+ return;
1068
+ }
1069
+ const o = Te(this.root, "me-column-renderer").find((i) => i.dataset.columnId === this.currentDrop.columnId);
1070
+ if (!o?.shadowRoot) return;
1071
+ const r = Array.from(o.shadowRoot.querySelectorAll("me-content-renderer"));
1072
+ _e(this.contentIndicator, o.shadowRoot, r, this.currentDrop.contentIndex ?? 0, "4px");
1073
+ }
1074
+ showRowIndicator() {
1075
+ if (!this.rowIndicator || !this.currentDrop) {
1076
+ F(this.rowIndicator);
1077
+ return;
1078
+ }
1079
+ const t = this.root.querySelector("me-editor-canvas"), o = t?.shadowRoot?.querySelector(".canvas-body");
1080
+ if (!o) return;
1081
+ const r = Array.from(t.shadowRoot.querySelectorAll("me-row-renderer"));
1082
+ _e(this.rowIndicator, o, r, this.currentDrop.rowIndex ?? 0, "0");
1083
+ }
1084
+ hideAllIndicators() {
1085
+ F(this.contentIndicator), F(this.rowIndicator);
1086
+ }
1087
+ reset() {
1088
+ this.currentDrop = null, D.reset();
1089
+ }
1090
+ }
1091
+ function p(e, t, o = "") {
1092
+ const r = e[t];
1093
+ return typeof r == "string" && r !== "" ? r : typeof r == "number" ? String(r) : o;
1094
+ }
1095
+ function Se(e) {
1096
+ return typeof e == "string" ? e : e && typeof e == "object" && "url" in e && e.url || "";
1097
+ }
1098
+ function Re(e) {
1099
+ if (e && typeof e == "object") {
1100
+ const t = e;
1101
+ return {
1102
+ width: typeof t.width == "number" ? t.width : void 0,
1103
+ maxWidth: typeof t.maxWidth == "string" ? t.maxWidth : void 0
1104
+ };
1105
+ }
1106
+ return {};
1107
+ }
1108
+ function ot(e) {
1109
+ const t = e.action;
1110
+ if (t && typeof t == "object") {
1111
+ const o = t.values;
1112
+ return {
1113
+ href: o?.href || "",
1114
+ target: o?.target || "_blank"
1115
+ };
1116
+ }
1117
+ return {
1118
+ href: p(e, "href"),
1119
+ target: p(e, "target", "_blank")
1120
+ };
1121
+ }
1122
+ function De(e, t = "") {
1123
+ const o = e.text;
1124
+ if (typeof o == "string" && o !== "") return o;
1125
+ const r = e.textJson;
1126
+ if (typeof r == "string")
1127
+ try {
1128
+ const i = JSON.parse(r), n = [], s = (a) => {
1129
+ typeof a.text == "string" && n.push(a.text), a.type === "linebreak" && n.push("<br/>");
1130
+ const c = a.children;
1131
+ c && c.forEach(s);
1132
+ };
1133
+ if (s(i.root || i), n.length > 0) return n.join("");
1134
+ } catch {
1135
+ }
1136
+ return t;
1137
+ }
1138
+ function be(e, t = "arial,helvetica,sans-serif") {
1139
+ const o = e.fontFamily;
1140
+ if (typeof o == "string" && o !== "") return o;
1141
+ if (o && typeof o == "object") {
1142
+ const r = o, i = r.value || t, n = r.url;
1143
+ if (n && typeof document < "u") {
1144
+ const s = `emabuild-font-${i.replace(/[^a-z]/gi, "")}`;
1145
+ if (!document.getElementById(s)) {
1146
+ const a = document.createElement("link");
1147
+ a.id = s, a.rel = "stylesheet", a.href = n, document.head.appendChild(a);
1148
+ }
1149
+ }
1150
+ return i;
1151
+ }
1152
+ return t;
1153
+ }
1154
+ function Pe(e) {
1155
+ const t = e.buttonColors;
1156
+ if (t && typeof t == "object") {
1157
+ const o = t;
1158
+ return {
1159
+ bg: o.backgroundColor || p(e, "backgroundColor", "#3b82f6"),
1160
+ color: o.color || p(e, "textColor", "#ffffff")
1161
+ };
1162
+ }
1163
+ return {
1164
+ bg: p(e, "backgroundColor", "#3b82f6"),
1165
+ color: p(e, "textColor", "#ffffff")
1166
+ };
1167
+ }
1168
+ function fo(e, t) {
1169
+ if (typeof e != "string") return t;
1170
+ try {
1171
+ return JSON.parse(e);
1172
+ } catch {
1173
+ return t;
1174
+ }
1175
+ }
1176
+ function N(e, t) {
1177
+ const { padding: o, align: r = "left", extraTdStyle: i = "" } = t;
1178
+ return `<table role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0">
1179
+ <tbody><tr><td style="${`padding:${o};font-family:arial,helvetica,sans-serif;${i}`}" align="${r}">
1180
+ ${e}
1181
+ </td></tr></tbody>
1182
+ </table>`;
1183
+ }
1184
+ function rt(e, t, o) {
1185
+ const { bgColor: r, textColor: i, fontSize: n, fontWeight: s, borderRadius: a } = o, c = parseInt(a) || 0;
1186
+ if (c <= 0) return "";
1187
+ const l = Math.round(c / 20 * 100);
1188
+ return `<!--[if mso]>
1189
+ <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="${l}%" stroke="f" fillcolor="${r}">
1190
+ <w:anchorlock/>
1191
+ <center style="color:${i};font-family:arial,helvetica,sans-serif;font-size:${n};font-weight:${s};">${e}</center>
1192
+ </v:roundrect>
1193
+ <![endif]-->`;
1194
+ }
1195
+ const it = [
1196
+ { label: "100%", value: "100%" },
1197
+ { label: "120%", value: "120%" },
1198
+ { label: "140%", value: "140%" },
1199
+ { label: "160%", value: "160%" },
1200
+ { label: "180%", value: "180%" },
1201
+ { label: "200%", value: "200%" }
1202
+ ], nt = [
1203
+ { label: "Normal", value: "400" },
1204
+ { label: "Medium", value: "500" },
1205
+ { label: "Semi Bold", value: "600" },
1206
+ { label: "Bold", value: "700" },
1207
+ { label: "Extra Bold", value: "800" }
1208
+ ], st = [
1209
+ { label: "Normal", value: "400" },
1210
+ { label: "Bold", value: "700" }
1211
+ ], at = [
1212
+ { label: "12px", value: "12px" },
1213
+ { label: "14px", value: "14px" },
1214
+ { label: "16px", value: "16px" },
1215
+ { label: "18px", value: "18px" },
1216
+ { label: "20px", value: "20px" },
1217
+ { label: "22px", value: "22px" },
1218
+ { label: "26px", value: "26px" },
1219
+ { label: "30px", value: "30px" },
1220
+ { label: "36px", value: "36px" },
1221
+ { label: "48px", value: "48px" },
1222
+ { label: "60px", value: "60px" }
1223
+ ], lt = [
1224
+ { label: "12px", value: "12px" },
1225
+ { label: "13px", value: "13px" },
1226
+ { label: "14px", value: "14px" },
1227
+ { label: "16px", value: "16px" },
1228
+ { label: "18px", value: "18px" },
1229
+ { label: "20px", value: "20px" }
1230
+ ], Be = (e = "140%") => ({
1231
+ label: "Line Height",
1232
+ defaultValue: e,
1233
+ widget: "dropdown",
1234
+ widgetParams: { options: [...it] }
1235
+ }), We = (e = "700", t = !1) => ({
1236
+ label: "Font Weight",
1237
+ defaultValue: e,
1238
+ widget: "dropdown",
1239
+ widgetParams: { options: [...t ? st : nt] }
1240
+ }), G = {
1241
+ title: "Spacing",
1242
+ options: {
1243
+ containerPadding: { label: "Padding", defaultValue: "10px", widget: "padding" }
1244
+ }
1245
+ }, ne = {
1246
+ title: "General",
1247
+ options: {
1248
+ anchor: { label: "Anchor", defaultValue: "", widget: "text" },
1249
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
1250
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
1251
+ }
1252
+ }, dt = {
1253
+ title: "General",
1254
+ options: {
1255
+ hideDesktop: { label: "Hide on Desktop", defaultValue: !1, widget: "toggle" },
1256
+ hideMobile: { label: "Hide on Mobile", defaultValue: !1, widget: "toggle" }
1257
+ }
1258
+ }, ct = {
1259
+ name: "text",
1260
+ label: "Text",
1261
+ 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>',
1262
+ supportedDisplayModes: ["email", "web"],
1263
+ position: 1,
1264
+ options: {
1265
+ text: {
1266
+ title: "Text",
1267
+ options: {
1268
+ text: {
1269
+ label: "Text Content",
1270
+ defaultValue: '<p style="font-size: 14px;">This is a new text block. Change the text.</p>',
1271
+ widget: "rich_text"
1272
+ }
1273
+ }
1274
+ },
1275
+ style: {
1276
+ title: "Style",
1277
+ options: {
1278
+ color: { label: "Text Color", defaultValue: "#000000", widget: "color_picker" },
1279
+ backgroundColor: { label: "Background Color", defaultValue: "", widget: "color_picker" },
1280
+ textAlign: { label: "Text Align", defaultValue: "left", widget: "alignment" },
1281
+ lineHeight: Be()
1282
+ }
1283
+ },
1284
+ spacing: G,
1285
+ general: ne
1286
+ },
1287
+ defaultValues: {
1288
+ text: '<p style="font-size: 14px;">This is a new text block. Change the text.</p>',
1289
+ color: "#000000",
1290
+ backgroundColor: "",
1291
+ lineHeight: "140%",
1292
+ containerPadding: "10px",
1293
+ textAlign: "left"
1294
+ },
1295
+ renderer: {
1296
+ renderEditor(e) {
1297
+ const t = p(e, "backgroundColor", "transparent"), o = p(e, "color", "inherit"), r = p(e, "lineHeight", "140%"), i = p(e, "textAlign", "left"), n = be(e), s = p(e, "text");
1298
+ return d`
1299
+ <div style="background-color:${t};color:${o};line-height:${r};text-align:${i};font-family:${n};">
1300
+ ${ie(s)}
1301
+ </div>
1302
+ `;
1303
+ },
1304
+ renderHtml(e) {
1305
+ const t = p(e, "containerPadding", "10px"), o = p(e, "backgroundColor"), r = p(e, "color", "#000000"), i = p(e, "lineHeight", "140%"), n = p(e, "textAlign", "left"), s = p(e, "text"), a = o ? `background-color:${o};` : "", c = `<div style="font-size:14px;color:${r};line-height:${i};text-align:${n};">${s}</div>`;
1306
+ return N(c, { padding: t, extraTdStyle: a });
1307
+ }
1308
+ }
1309
+ }, pt = {
1310
+ name: "heading",
1311
+ label: "Heading",
1312
+ 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>',
1313
+ supportedDisplayModes: ["email", "web"],
1314
+ position: 2,
1315
+ options: {
1316
+ text: {
1317
+ title: "Heading",
1318
+ options: {
1319
+ text: { label: "Text", defaultValue: "Heading", widget: "text" },
1320
+ headingType: {
1321
+ label: "Heading Type",
1322
+ defaultValue: "h1",
1323
+ widget: "dropdown",
1324
+ widgetParams: { options: [
1325
+ { label: "H1", value: "h1" },
1326
+ { label: "H2", value: "h2" },
1327
+ { label: "H3", value: "h3" },
1328
+ { label: "H4", value: "h4" }
1329
+ ] }
1330
+ }
1331
+ }
1332
+ },
1333
+ style: {
1334
+ title: "Style",
1335
+ options: {
1336
+ fontSize: {
1337
+ label: "Font Size",
1338
+ defaultValue: "22px",
1339
+ widget: "dropdown",
1340
+ widgetParams: { options: [...at] }
1341
+ },
1342
+ color: { label: "Text Color", defaultValue: "#000000", widget: "color_picker" },
1343
+ textAlign: { label: "Text Align", defaultValue: "left", widget: "alignment" },
1344
+ fontWeight: We(),
1345
+ lineHeight: Be(),
1346
+ letterSpacing: {
1347
+ label: "Letter Spacing",
1348
+ defaultValue: "0px",
1349
+ widget: "number_unit",
1350
+ widgetParams: { unit: "px", min: -5, max: 50, step: 0.1 }
1351
+ }
1352
+ }
1353
+ },
1354
+ spacing: G,
1355
+ general: ne
1356
+ },
1357
+ defaultValues: {
1358
+ text: "Heading",
1359
+ headingType: "h1",
1360
+ fontSize: "22px",
1361
+ color: "#000000",
1362
+ textAlign: "left",
1363
+ fontWeight: "700",
1364
+ lineHeight: "140%",
1365
+ letterSpacing: "0px",
1366
+ containerPadding: "10px"
1367
+ },
1368
+ renderer: {
1369
+ renderEditor(e) {
1370
+ const t = {
1371
+ padding: p(e, "containerPadding", "10px"),
1372
+ fontSize: p(e, "fontSize", "22px"),
1373
+ color: p(e, "color", "#000000"),
1374
+ textAlign: p(e, "textAlign", "left"),
1375
+ fontWeight: p(e, "fontWeight", "700"),
1376
+ lineHeight: p(e, "lineHeight", "140%"),
1377
+ letterSpacing: p(e, "letterSpacing", "normal"),
1378
+ fontFamily: be(e)
1379
+ }, o = De(e, "Heading");
1380
+ return d`<div style=${He(t)}>${ie(o)}</div>`;
1381
+ },
1382
+ renderHtml(e) {
1383
+ const t = p(e, "containerPadding", "10px"), o = p(e, "fontSize", "22px"), r = p(e, "color", "#000000"), i = p(e, "textAlign", "left"), n = p(e, "fontWeight", "700"), s = p(e, "lineHeight", "140%"), a = p(e, "letterSpacing", "normal"), c = be(e), l = p(e, "headingType", "h1"), u = De(e, "Heading"), h = `<${l} style="margin:0;font-size:${o};color:${r};text-align:${i};font-weight:${n};line-height:${s};letter-spacing:${a};font-family:${c};">${u}</${l}>`;
1384
+ return N(h, { padding: t });
1385
+ }
1386
+ }
1387
+ }, ut = {
1388
+ name: "paragraph",
1389
+ label: "Paragraph",
1390
+ 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>',
1391
+ supportedDisplayModes: ["email", "web"],
1392
+ position: 3,
1393
+ options: {
1394
+ text: {
1395
+ title: "Paragraph",
1396
+ options: {
1397
+ text: {
1398
+ label: "Text",
1399
+ 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>',
1400
+ widget: "rich_text"
1401
+ }
1402
+ }
1403
+ },
1404
+ style: {
1405
+ title: "Style",
1406
+ options: {
1407
+ color: { label: "Text Color", defaultValue: "#374151", widget: "color_picker" },
1408
+ textAlign: { label: "Text Align", defaultValue: "left", widget: "alignment" },
1409
+ lineHeight: { label: "Line Height", defaultValue: "160%", widget: "text" },
1410
+ letterSpacing: { label: "Letter Spacing", defaultValue: "normal", widget: "text" }
1411
+ }
1412
+ },
1413
+ spacing: G
1414
+ },
1415
+ defaultValues: {
1416
+ text: '<p style="font-size:14px;line-height:1.6;">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
1417
+ color: "#374151",
1418
+ lineHeight: "160%",
1419
+ letterSpacing: "normal",
1420
+ textAlign: "left",
1421
+ containerPadding: "10px"
1422
+ },
1423
+ renderer: {
1424
+ renderEditor(e) {
1425
+ const t = p(e, "color", "#374151"), o = p(e, "lineHeight", "160%"), r = p(e, "textAlign", "left");
1426
+ return d`<div style="color:${t};line-height:${o};text-align:${r};">${ie(p(e, "text"))}</div>`;
1427
+ },
1428
+ renderHtml(e) {
1429
+ const t = p(e, "containerPadding", "10px"), o = p(e, "color", "#374151"), r = p(e, "lineHeight", "160%"), i = p(e, "textAlign", "left"), n = p(e, "letterSpacing", "normal"), s = `<div style="font-size:14px;color:${o};line-height:${r};text-align:${i};letter-spacing:${n};word-wrap:break-word;">${p(e, "text")}</div>`;
1430
+ return N(s, { padding: t });
1431
+ }
1432
+ }
1433
+ }, ht = {
1434
+ name: "image",
1435
+ label: "Image",
1436
+ 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>',
1437
+ supportedDisplayModes: ["email", "web"],
1438
+ position: 3,
1439
+ options: {
1440
+ image: {
1441
+ title: "Image",
1442
+ options: {
1443
+ src: { label: "Image URL", defaultValue: "", widget: "text" },
1444
+ alt: { label: "Alt Text", defaultValue: "", widget: "text" },
1445
+ href: { label: "Link URL", defaultValue: "", widget: "text" },
1446
+ target: { label: "Link Target", defaultValue: "_blank", widget: "text" }
1447
+ }
1448
+ },
1449
+ style: {
1450
+ title: "Style",
1451
+ options: {
1452
+ width: {
1453
+ label: "Width",
1454
+ defaultValue: "100%",
1455
+ widget: "dropdown",
1456
+ widgetParams: { options: [
1457
+ { label: "Auto", value: "auto" },
1458
+ { label: "25%", value: "25%" },
1459
+ { label: "50%", value: "50%" },
1460
+ { label: "75%", value: "75%" },
1461
+ { label: "100%", value: "100%" }
1462
+ ] }
1463
+ },
1464
+ align: { label: "Align", defaultValue: "center", widget: "alignment" },
1465
+ borderRadius: { label: "Border Radius", defaultValue: "0px", widget: "text" }
1466
+ }
1467
+ },
1468
+ spacing: G,
1469
+ general: ne
1470
+ },
1471
+ defaultValues: {
1472
+ src: "https://placehold.co/600x200/e2e8f0/64748b?text=Drop+Image+Here",
1473
+ alt: "Image",
1474
+ href: "",
1475
+ target: "_blank",
1476
+ width: "100%",
1477
+ maxWidth: "100%",
1478
+ align: "center",
1479
+ borderRadius: "0px",
1480
+ containerPadding: "10px"
1481
+ },
1482
+ renderer: {
1483
+ renderEditor(e) {
1484
+ const t = Se(e.src), o = p(e, "alt"), i = Re(e.src).maxWidth || p(e, "width", "100%"), n = p(e, "borderRadius", "0px"), s = p(e, "textAlign", p(e, "align", "center"));
1485
+ return t ? d`<div style="text-align:${s};"><img src=${t} alt=${o} style="display:inline-block;max-width:100%;width:${i};border-radius:${n};border:0;" /></div>` : d`<div style="text-align:${s};"><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>`;
1486
+ },
1487
+ renderHtml(e, t) {
1488
+ const o = p(e, "containerPadding", "10px"), r = Se(e.src), i = p(e, "alt"), n = ot(e), s = Re(e.src), a = s.maxWidth || p(e, "width", "100%"), c = p(e, "borderRadius", "0px"), l = p(e, "textAlign", p(e, "align", "center"));
1489
+ let u;
1490
+ a.includes("%") ? u = Math.round(t.columnWidth * (parseFloat(a) / 100)) : a === "auto" ? u = s.width || t.columnWidth : u = parseInt(a) || t.columnWidth;
1491
+ const h = c !== "0px" ? `border-radius:${c};` : "", g = `<img align="${l}" border="0" src="${r}" alt="${i}" title="${i}" style="display:block;border:0;height:auto;width:100%;max-width:${u}px;${h}" width="${u}" />`, b = n.href ? `<a href="${n.href}" target="${n.target}" style="text-decoration:none;">${g}</a>` : g;
1492
+ return N(b, { padding: o, align: l });
1493
+ }
1494
+ }
1495
+ }, gt = {
1496
+ name: "button",
1497
+ label: "Button",
1498
+ 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>',
1499
+ supportedDisplayModes: ["email", "web"],
1500
+ position: 4,
1501
+ options: {
1502
+ button: {
1503
+ title: "Button",
1504
+ options: {
1505
+ text: { label: "Button Text", defaultValue: "Click Me", widget: "text" },
1506
+ href: { label: "Link URL", defaultValue: "#", widget: "text" },
1507
+ target: { label: "Target", defaultValue: "_blank", widget: "text" }
1508
+ }
1509
+ },
1510
+ style: {
1511
+ title: "Style",
1512
+ options: {
1513
+ backgroundColor: { label: "Button Color", defaultValue: "#3b82f6", widget: "color_picker" },
1514
+ textColor: { label: "Text Color", defaultValue: "#ffffff", widget: "color_picker" },
1515
+ fontSize: {
1516
+ label: "Font Size",
1517
+ defaultValue: "14px",
1518
+ widget: "dropdown",
1519
+ widgetParams: { options: [...lt] }
1520
+ },
1521
+ fontWeight: We("700", !0),
1522
+ borderRadius: { label: "Border Radius", defaultValue: "4px", widget: "text" },
1523
+ buttonWidth: {
1524
+ label: "Width",
1525
+ defaultValue: "auto",
1526
+ widget: "dropdown",
1527
+ widgetParams: { options: [
1528
+ { label: "Auto", value: "auto" },
1529
+ { label: "100%", value: "100%" },
1530
+ { label: "50%", value: "50%" }
1531
+ ] }
1532
+ },
1533
+ textAlign: { label: "Align", defaultValue: "center", widget: "alignment" },
1534
+ buttonPadding: { label: "Button Padding", defaultValue: "10px 20px", widget: "padding" },
1535
+ borderColor: { label: "Border Color", defaultValue: "", widget: "color_picker" },
1536
+ borderWidth: { label: "Border Width", defaultValue: "0px", widget: "text" }
1537
+ }
1538
+ },
1539
+ spacing: G,
1540
+ general: ne
1541
+ },
1542
+ defaultValues: {
1543
+ text: "Click Me",
1544
+ href: "#",
1545
+ target: "_blank",
1546
+ backgroundColor: "#3b82f6",
1547
+ textColor: "#ffffff",
1548
+ fontSize: "14px",
1549
+ fontWeight: "700",
1550
+ borderRadius: "4px",
1551
+ buttonWidth: "auto",
1552
+ textAlign: "center",
1553
+ buttonPadding: "10px 20px",
1554
+ borderColor: "",
1555
+ borderWidth: "0px",
1556
+ containerPadding: "10px"
1557
+ },
1558
+ renderer: {
1559
+ renderEditor(e) {
1560
+ const { bg: t, color: o } = Pe(e), r = p(e, "fontSize", "14px"), i = p(e, "fontWeight", "700"), n = p(e, "borderRadius", "4px"), s = p(e, "buttonPadding", p(e, "padding", "10px 20px")), a = p(e, "text", "Click Me"), c = p(e, "textAlign", "center"), l = p(e, "buttonWidth", "auto"), u = p(e, "borderWidth", "0px"), h = p(e, "borderColor", t), g = u !== "0px" ? `border:${u} solid ${h};` : "border:none;", b = l === "auto" ? "display:inline-block;" : `display:block;width:${l};`;
1561
+ return d`
1562
+ <div style="text-align:${c};">
1563
+ <a style="${b}background-color:${t};color:${o};font-size:${r};font-weight:${i};border-radius:${n};padding:${s};text-decoration:none;text-align:center;${g}cursor:pointer;font-family:arial,helvetica,sans-serif;">${a}</a>
1564
+ </div>
1565
+ `;
1566
+ },
1567
+ renderHtml(e) {
1568
+ const t = p(e, "containerPadding", "10px"), { bg: o, color: r } = Pe(e), i = p(e, "fontSize", "14px"), n = p(e, "fontWeight", "700"), s = p(e, "borderRadius", "4px"), a = p(e, "buttonPadding", p(e, "padding", "10px 20px")), c = p(e, "text", "Click Me"), l = p(e, "textAlign", "center"), u = p(e, "href", "#"), h = p(e, "target", "_blank"), g = p(e, "borderWidth", "0px"), b = p(e, "borderColor", o), k = g !== "0px" ? `border:${g} solid ${b};` : "border:none;", $ = rt(c, u, { bgColor: o, textColor: r, fontSize: i, fontWeight: n, borderRadius: s }), m = $ ? `${$}
1569
+ <!--[if !mso]><!-->` : "<!--[if !mso]><!-->", y = `<div align="${l}">
1570
+ ${m}
1571
+ <a href="${u}" target="${h}" style="display:inline-block;text-decoration:none;text-align:center;color:${r};background-color:${o};border-radius:${s};font-size:${i};font-weight:${n};padding:${a};font-family:arial,helvetica,sans-serif;${k}mso-border-alt:none;"><span style="line-height:120%;">${c}</span></a>
1572
+ <!--<![endif]-->
1573
+ </div>`;
1574
+ return N(y, { padding: t, align: l });
1575
+ }
1576
+ }
1577
+ }, ft = {
1578
+ name: "divider",
1579
+ label: "Divider",
1580
+ 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>',
1581
+ supportedDisplayModes: ["email", "web"],
1582
+ position: 5,
1583
+ options: {
1584
+ style: {
1585
+ title: "Style",
1586
+ options: {
1587
+ borderTopWidth: { label: "Width", defaultValue: "1px", widget: "text" },
1588
+ borderTopStyle: {
1589
+ label: "Style",
1590
+ defaultValue: "solid",
1591
+ widget: "dropdown",
1592
+ widgetParams: { options: [
1593
+ { label: "Solid", value: "solid" },
1594
+ { label: "Dashed", value: "dashed" },
1595
+ { label: "Dotted", value: "dotted" },
1596
+ { label: "Double", value: "double" }
1597
+ ] }
1598
+ },
1599
+ borderTopColor: { label: "Color", defaultValue: "#cccccc", widget: "color_picker" },
1600
+ width: { label: "Line Width", defaultValue: "100%", widget: "text" }
1601
+ }
1602
+ },
1603
+ spacing: G,
1604
+ general: dt
1605
+ },
1606
+ defaultValues: {
1607
+ borderTopWidth: "1px",
1608
+ borderTopStyle: "solid",
1609
+ borderTopColor: "#cccccc",
1610
+ width: "100%",
1611
+ containerPadding: "10px"
1612
+ },
1613
+ renderer: {
1614
+ renderEditor(e) {
1615
+ p(e, "containerPadding", "10px");
1616
+ const t = p(e, "width", "100%"), o = `${p(e, "borderTopWidth", "1px")} ${p(e, "borderTopStyle", "solid")} ${p(e, "borderTopColor", "#cccccc")}`;
1617
+ return d`<div><div style="border-top:${o};width:${t};margin:0 auto;"></div></div>`;
1618
+ },
1619
+ renderHtml(e) {
1620
+ const t = p(e, "containerPadding", "10px"), o = p(e, "width", "100%"), r = `${p(e, "borderTopWidth", "1px")} ${p(e, "borderTopStyle", "solid")} ${p(e, "borderTopColor", "#cccccc")}`, i = `<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="${o}" style="border-collapse:collapse;border-top:${r};"><tbody><tr><td style="font-size:0;line-height:0;">&nbsp;</td></tr></tbody></table>`;
1621
+ return N(i, { padding: t, align: "center" });
1622
+ }
1623
+ }
1624
+ }, bt = [
1625
+ ct,
1626
+ pt,
1627
+ ut,
1628
+ ht,
1629
+ gt,
1630
+ ft
1631
+ ], Ee = [
1632
+ {
1633
+ 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 },
1634
+ loader: () => import("./html-tool-4zZO2hqE.js").then((e) => e.htmlTool)
1635
+ },
1636
+ {
1637
+ 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 },
1638
+ loader: () => import("./social-tool-kPuP-4n6.js").then((e) => e.socialTool)
1639
+ },
1640
+ {
1641
+ 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 },
1642
+ loader: () => import("./menu-tool-Cu5D_VYs.js").then((e) => e.menuTool)
1643
+ },
1644
+ {
1645
+ 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 },
1646
+ loader: () => import("./video-tool-CttMka8Z.js").then((e) => e.videoTool)
1647
+ },
1648
+ {
1649
+ 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 },
1650
+ loader: () => import("./timer-tool-CG1oul_Z.js").then((e) => e.timerTool)
1651
+ },
1652
+ {
1653
+ 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 },
1654
+ loader: () => import("./table-tool-CcWFvTSc.js").then((e) => e.tableTool)
1655
+ },
1656
+ {
1657
+ 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 },
1658
+ loader: () => import("./form-tool-C7760Hvm.js").then((e) => e.formTool)
1659
+ }
1660
+ ];
1661
+ function mt(e, t, o) {
1662
+ const r = o.backgroundColor || "#e7e7e7", i = o.contentWidth || "600px", n = o.fontFamily?.value || "arial,helvetica,sans-serif", s = o.textColor || "#000000", a = o.preheaderText || "" || "&zwnj;", c = `<div style="display:none;font-size:1px;color:${r};line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">${a}${"&zwnj;&nbsp;".repeat(80)}</div>`;
1663
+ return `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1664
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
1665
+ <head>
1666
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
1667
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1668
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
1669
+ <meta name="x-apple-disable-message-reformatting">
1670
+ <meta name="format-detection" content="telephone=no,address=no,email=no,date=no,url=no">
1671
+ <meta name="color-scheme" content="light dark">
1672
+ <meta name="supported-color-schemes" content="light dark">
1673
+ <title></title>
1674
+ <!--[if mso]>
1675
+ <noscript><xml>
1676
+ <o:OfficeDocumentSettings>
1677
+ <o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch>
1678
+ </o:OfficeDocumentSettings>
1679
+ </xml></noscript>
1680
+ <style type="text/css">
1681
+ table, td, th { font-family: ${n} !important; }
1682
+ </style>
1683
+ <![endif]-->
1684
+ <!--[if !mso]><!-->
1685
+ <style type="text/css">
1686
+ ${t}
1687
+ </style>
1688
+ <!--<![endif]-->
1689
+ <style type="text/css">
1690
+ body { margin: 0; padding: 0; word-break: normal; }
1691
+ table, tr, td { vertical-align: top; border-collapse: collapse; }
1692
+ p { margin: 0; }
1693
+ a[x-apple-data-detectors='true'] { color: inherit !important; text-decoration: none !important; }
1694
+ </style>
1695
+ </head>
1696
+ <body class="clean-body u_body" style="margin:0;padding:0;-webkit-text-size-adjust:100%;background-color:${r};color:${s};">
1697
+ ${c}
1698
+ <table id="u_body" role="presentation" style="border-collapse:collapse;border-spacing:0;margin:0 auto;background-color:${r};width:100%;" cellpadding="0" cellspacing="0" border="0">
1699
+ <tbody>
1700
+ <tr>
1701
+ <td style="vertical-align:top;">
1702
+ <!--[if (mso)|(IE)]><table width="${parseInt(i)}" align="center" cellpadding="0" cellspacing="0" border="0"><tr><td><![endif]-->
1703
+ ${e}
1704
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
1705
+ </td>
1706
+ </tr>
1707
+ </tbody>
1708
+ </table>
1709
+ </body>
1710
+ </html>`;
1711
+ }
1712
+ function yt(e, t, o) {
1713
+ const r = parseInt(t.contentWidth || "600"), i = e.values.backgroundColor || "", n = e.values.columnsBackgroundColor || "", s = e.values.padding || "0px", a = e.cells.reduce((m, f) => m + f, 0), c = i ? `background-color:${i};` : "", l = e.values.backgroundImage;
1714
+ let u = "";
1715
+ if (l?.url) {
1716
+ const m = l.repeat === !0 || l.repeat === "repeat" ? "repeat" : "no-repeat", f = l.cover === !0 ? "cover" : l.fullWidth === !0 ? "100% auto" : "auto", y = l.center !== !1 ? "center top" : "left top";
1717
+ u = `background-image:url('${l.url}');background-repeat:${m};background-position:${y};background-size:${f};`;
1718
+ }
1719
+ const h = e.columns.length > 1, g = e.columns.map((m, f) => {
1720
+ const y = Math.round(e.cells[f] / a * r);
1721
+ return { colHtml: xt(m, y, n, t, o), colWidthPx: y };
1722
+ });
1723
+ let b;
1724
+ if (h) {
1725
+ const m = g.map(
1726
+ ({ colHtml: f, colWidthPx: y }) => `<!--[if (mso)|(IE)]><td align="center" width="${y}" style="width:${y}px;padding:0px;" valign="top"><![endif]-->${f}<!--[if (mso)|(IE)]></td><![endif]-->`
1727
+ );
1728
+ b = `<!--[if (mso)|(IE)]><table role="presentation" width="${r}" cellpadding="0" cellspacing="0" border="0"><tr><![endif]-->${m.join("")}<!--[if (mso)|(IE)]></tr></table><![endif]-->`;
1729
+ } else
1730
+ b = g.map(({ colHtml: m }) => m).join("");
1731
+ const k = e.values.hideDesktop ? " u_hide_desktop" : "", $ = e.values.hideMobile ? " u_hide_mobile" : "";
1732
+ return `<div class="u_row${k}${$}" style="padding:${s};${c}${u}">
1733
+ <div style="margin:0 auto;max-width:${r}px;${h ? "font-size:0;" : ""}text-align:center;">${b}</div>
1734
+ </div>`;
1735
+ }
1736
+ function xt(e, t, o, r, i) {
1737
+ const n = e.values.backgroundColor || o || "", s = e.values.padding || "0px", a = e.values.borderRadius || "0px", c = n ? `background-color:${n};` : "", l = e.contents.map((u) => {
1738
+ const h = i.get(u.type);
1739
+ if (!h) return `<!-- unknown tool: ${u.type} -->`;
1740
+ const g = {
1741
+ columnWidth: t,
1742
+ displayMode: "email",
1743
+ contentWidth: parseInt(r.contentWidth || "600"),
1744
+ bodyValues: r
1745
+ };
1746
+ let b = h(u.values, g);
1747
+ const k = !!u.values.hideDesktop, $ = !!u.values.hideMobile;
1748
+ return (k || $) && (b = `<div class="${[k && "u_hide_desktop", $ && "u_hide_mobile"].filter(Boolean).join(" ")}">${b}</div>`), b;
1749
+ }).join(`
1750
+ `);
1751
+ return `<div class="u_column" style="display:inline-block;vertical-align:top;width:${t}px;max-width:${t}px;font-size:14px;text-align:left;">
1752
+ <div style="width:100%;${c}${a !== "0px" ? `border-radius:${a};` : ""}">
1753
+ <div style="padding:${s};">
1754
+ ${l || "&nbsp;"}
1755
+ </div>
1756
+ </div>
1757
+ </div>`;
1758
+ }
1759
+ function vt(e) {
1760
+ return `
1761
+ @media only screen and (min-width: ${e + 20}px) {
1762
+ .u_row .u_column { display: inline-block !important; }
1763
+ }
1764
+
1765
+ @media only screen and (max-width: ${e + 20}px) {
1766
+ .u_row .u_column {
1767
+ display: block !important;
1768
+ width: 100% !important;
1769
+ max-width: 100% !important;
1770
+ }
1771
+ .u_row {
1772
+ width: 100% !important;
1773
+ }
1774
+ }
1775
+
1776
+ @media only screen and (max-width: 620px) {
1777
+ .u_row-container {
1778
+ max-width: 100% !important;
1779
+ padding-left: 0 !important;
1780
+ padding-right: 0 !important;
1781
+ }
1782
+ }
1783
+
1784
+ @media (prefers-color-scheme: dark) {
1785
+ /* Dark mode overrides — add per-client rules as needed */
1786
+ }
1787
+
1788
+ /* Outlook dark mode */
1789
+ [data-ogsb] body,
1790
+ [data-ogsb] table,
1791
+ [data-ogsb] td {
1792
+ /* Preserve original colors */
1793
+ }
1794
+
1795
+ .u_hide_desktop { display: block !important; }
1796
+ .u_hide_mobile { display: block !important; }
1797
+
1798
+ @media only screen and (max-width: ${e + 20}px) {
1799
+ .u_hide_desktop { display: block !important; }
1800
+ .u_hide_mobile { display: none !important; }
1801
+ }
1802
+
1803
+ @media only screen and (min-width: ${e + 21}px) {
1804
+ .u_hide_desktop { display: none !important; }
1805
+ .u_hide_mobile { display: block !important; }
1806
+ }`;
1807
+ }
1808
+ const wt = [
1809
+ "box-sizing",
1810
+ "overflow-wrap",
1811
+ "word-break",
1812
+ "word-wrap",
1813
+ "outline",
1814
+ "cursor",
1815
+ "transition",
1816
+ "animation",
1817
+ "transform",
1818
+ "z-index",
1819
+ "display:\\s*flex",
1820
+ "display:\\s*grid",
1821
+ "gap"
1822
+ ], kt = new RegExp(
1823
+ `(?:;\\s*|^\\s*)(${wt.join("|")})\\s*:[^;]*;?`,
1824
+ "gi"
1825
+ ), $t = /var\(--[^)]*\)/gi;
1826
+ function Ct(e) {
1827
+ return e.replace(/style="([^"]*)"/gi, (t, o) => {
1828
+ let r = o;
1829
+ return r = r.replace(kt, ""), r = r.replace($t, "inherit"), r = r.replace(/;\s*;/g, ";").replace(/^\s*;\s*/, "").replace(/;\s*$/, "").trim(), r ? `style="${r}"` : "";
1830
+ });
1831
+ }
1832
+ function It(e, t, o) {
1833
+ const r = e.body.values, i = parseInt(r.contentWidth || "600"), n = e.body.rows.map((g) => yt(g, r, t)).join(`
1834
+ `), s = vt(i), a = Ct(n);
1835
+ let c = mt(a, s, r);
1836
+ if (o?.mergeTags)
1837
+ for (const [g, b] of Object.entries(o.mergeTags))
1838
+ c = c.replaceAll(`{{${g}}}`, b);
1839
+ const l = c.match(/<body[^>]*>([\s\S]*)<\/body>/i), u = c.match(/<style[^>]*>([\s\S]*?)<\/style>/gi), h = [];
1840
+ return r.fontFamily?.url && h.push(r.fontFamily.url), {
1841
+ design: structuredClone(e),
1842
+ html: c,
1843
+ chunks: {
1844
+ body: l?.[1] ?? n,
1845
+ css: u?.map((g) => g.replace(/<\/?style[^>]*>/gi, "")).join(`
1846
+ `) ?? s,
1847
+ fonts: h,
1848
+ js: ""
1849
+ }
1850
+ };
1851
+ }
1852
+ function _t(e) {
1853
+ return typeof e == "number" ? e : typeof e == "string" && parseInt(e, 10) || 0;
1854
+ }
1855
+ function Tt(e) {
1856
+ return typeof e == "string" ? e.includes("px") ? e : e + "px" : typeof e == "number" ? e + "px" : "0px";
1857
+ }
1858
+ function me(e) {
1859
+ return e ? {
1860
+ url: e.url || "",
1861
+ fullWidth: e.fullWidth ?? !0,
1862
+ repeat: e.repeat ?? !1,
1863
+ center: e.position === "center" || e.center === !0,
1864
+ cover: e.size === "cover" || e.cover === !0
1865
+ } : { url: "", fullWidth: !0, repeat: !1, center: !0, cover: !1 };
1866
+ }
1867
+ function pe(e) {
1868
+ return {
1869
+ url: e.url || "",
1870
+ fullWidth: e.fullWidth,
1871
+ repeat: e.repeat,
1872
+ size: e.cover ? "cover" : "custom",
1873
+ position: e.center ? "center" : "top left"
1874
+ };
1875
+ }
1876
+ function St(e, t) {
1877
+ const o = { ...t };
1878
+ if (e === "image") {
1879
+ if (o.src && typeof o.src == "object") {
1880
+ const r = o.src;
1881
+ o.src = r.url || "", r.width && (o.maxWidth = r.width + "px");
1882
+ }
1883
+ if (o.altText !== void 0 && o.alt === void 0 && (o.alt = o.altText, delete o.altText), o.action && typeof o.action == "object") {
1884
+ const r = o.action;
1885
+ o.href = r.values?.href || "", o.target = r.values?.target || "_blank", delete o.action;
1886
+ }
1887
+ }
1888
+ if (e === "button") {
1889
+ if (o.href && typeof o.href == "object") {
1890
+ const r = o.href;
1891
+ o.href = r.values?.href || "", o.target = r.values?.target || "_blank";
1892
+ }
1893
+ if (o.buttonColors && typeof o.buttonColors == "object") {
1894
+ const r = o.buttonColors;
1895
+ o.backgroundColor = r.backgroundColor || o.backgroundColor, o.textColor = r.color || o.textColor, delete o.buttonColors;
1896
+ }
1897
+ if (o.size && typeof o.size == "object") {
1898
+ const r = o.size;
1899
+ o.buttonWidth = r.autoWidth ? "auto" : r.width ? Tt(r.width) : "auto", delete o.size;
1900
+ }
1901
+ if (o.padding !== void 0 && o.buttonPadding === void 0 && (o.buttonPadding = o.padding), o.border && typeof o.border == "object") {
1902
+ const r = o.border;
1903
+ o.borderColor = r.borderTopColor || "", o.borderWidth = r.borderTopWidth || "0px", delete o.border;
1904
+ }
1905
+ typeof o.fontWeight == "number" && (o.fontWeight = String(o.fontWeight));
1906
+ }
1907
+ if (e === "heading" && typeof o.fontWeight == "number" && (o.fontWeight = String(o.fontWeight)), e === "divider" && o.border && typeof o.border == "object") {
1908
+ const r = o.border;
1909
+ o.borderTopWidth = r.borderTopWidth || "1px", o.borderTopStyle = r.borderTopStyle || "solid", o.borderTopColor = r.borderTopColor || "#cccccc", delete o.border;
1910
+ }
1911
+ if (e === "menu") {
1912
+ if (o.menu && typeof o.menu == "object") {
1913
+ const r = o.menu;
1914
+ Array.isArray(r.items) && (o.items = JSON.stringify(r.items.map((i) => ({
1915
+ text: i.text || "",
1916
+ href: i.link?.values?.href || "#"
1917
+ })))), o.menu.separator && (o.separator = o.menu.separator), delete o.menu;
1918
+ }
1919
+ o.linkColor && !o.color && (o.color = o.linkColor);
1920
+ }
1921
+ return o;
1922
+ }
1923
+ function Rt(e, t) {
1924
+ const o = { ...t };
1925
+ if (e === "image") {
1926
+ const r = typeof o.src == "string" ? o.src : "";
1927
+ o.src = {
1928
+ url: r,
1929
+ width: _t(o.maxWidth) || null,
1930
+ height: null,
1931
+ autoWidth: !0
1932
+ }, o.alt !== void 0 && (o.altText = o.alt, delete o.alt), (o.href !== void 0 || o.target !== void 0) && (o.action = {
1933
+ name: "web",
1934
+ values: { href: o.href || "", target: o.target || "_blank" }
1935
+ }, delete o.href, delete o.target), delete o.maxWidth;
1936
+ }
1937
+ if (e === "button" && (typeof o.href == "string" && (o.href = {
1938
+ name: "web",
1939
+ values: { href: o.href, target: o.target || "_blank" }
1940
+ }, delete o.target), o.buttonColors = {
1941
+ color: o.textColor || "#ffffff",
1942
+ backgroundColor: o.backgroundColor || "#3b82f6",
1943
+ hoverColor: o.textColor || "#ffffff",
1944
+ hoverBackgroundColor: o.backgroundColor || "#3b82f6"
1945
+ }, o.buttonWidth !== void 0 && (o.size = {
1946
+ autoWidth: o.buttonWidth === "auto",
1947
+ width: o.buttonWidth === "auto" ? "100%" : o.buttonWidth
1948
+ }, delete o.buttonWidth), o.buttonPadding !== void 0 && (o.padding = o.buttonPadding, delete o.buttonPadding), (o.borderColor !== void 0 || o.borderWidth !== void 0) && (o.border = {
1949
+ borderTopWidth: o.borderWidth || "0px",
1950
+ borderTopStyle: "solid",
1951
+ borderTopColor: o.borderColor || "",
1952
+ borderRightWidth: o.borderWidth || "0px",
1953
+ borderRightStyle: "solid",
1954
+ borderRightColor: o.borderColor || "",
1955
+ borderBottomWidth: o.borderWidth || "0px",
1956
+ borderBottomStyle: "solid",
1957
+ borderBottomColor: o.borderColor || "",
1958
+ borderLeftWidth: o.borderWidth || "0px",
1959
+ borderLeftStyle: "solid",
1960
+ borderLeftColor: o.borderColor || ""
1961
+ }, delete o.borderColor, delete o.borderWidth), typeof o.fontWeight == "string" && (o.fontWeight = parseInt(o.fontWeight, 10) || 400)), e === "heading" && typeof o.fontWeight == "string" && (o.fontWeight = parseInt(o.fontWeight, 10) || 400), e === "divider" && (o.border = {
1962
+ borderTopWidth: o.borderTopWidth || "1px",
1963
+ borderTopStyle: o.borderTopStyle || "solid",
1964
+ borderTopColor: o.borderTopColor || "#cccccc"
1965
+ }, delete o.borderTopWidth, delete o.borderTopStyle, delete o.borderTopColor), e === "menu") {
1966
+ if (typeof o.items == "string") {
1967
+ try {
1968
+ const r = JSON.parse(o.items);
1969
+ o.menu = {
1970
+ items: r.map((i, n) => ({
1971
+ key: String(n),
1972
+ text: i.text || "",
1973
+ link: {
1974
+ name: "web",
1975
+ values: { href: i.href || "#", target: "_blank" }
1976
+ }
1977
+ }))
1978
+ };
1979
+ } catch {
1980
+ }
1981
+ delete o.items;
1982
+ }
1983
+ o.color && !o.linkColor && (o.linkColor = o.color, o.textColor = o.color);
1984
+ }
1985
+ return o;
1986
+ }
1987
+ function ue(e) {
1988
+ const t = e.values || {};
1989
+ t.backgroundImage && typeof t.backgroundImage == "object" && (t.backgroundImage = me(t.backgroundImage)), t.hideMobile === void 0 && (t.hideMobile = !1);
1990
+ const o = (e.columns || []).map((r) => Dt(r));
1991
+ return {
1992
+ id: e.id,
1993
+ cells: e.cells,
1994
+ columns: o,
1995
+ values: t
1996
+ };
1997
+ }
1998
+ function Dt(e) {
1999
+ const t = (e.contents || []).map((o) => {
2000
+ const r = o.type, i = St(r, o.values || {});
2001
+ return { id: o.id, type: r, values: i };
2002
+ });
2003
+ return {
2004
+ id: e.id,
2005
+ contents: t,
2006
+ values: e.values || {}
2007
+ };
2008
+ }
2009
+ function Pt(e) {
2010
+ const t = e.body || {}, o = t.values || {};
2011
+ if (typeof o.contentWidth == "number" && (o.contentWidth = o.contentWidth + "px"), o.backgroundImage && typeof o.backgroundImage == "object" && (o.backgroundImage = me(o.backgroundImage)), o.popupBackgroundImage && typeof o.popupBackgroundImage == "object" && (o.popupBackgroundImage = me(o.popupBackgroundImage)), o.linkStyle && typeof o.linkStyle == "object") {
2012
+ const a = o.linkStyle;
2013
+ delete a.inherit;
2014
+ }
2015
+ t.id || (t.id = "u_body");
2016
+ const r = (t.rows || []).map(ue), i = (t.headers || []).map(ue), n = (t.footers || []).map(ue);
2017
+ return {
2018
+ counters: At(r, i, n),
2019
+ body: {
2020
+ id: t.id || "u_body",
2021
+ rows: r,
2022
+ headers: i,
2023
+ footers: n,
2024
+ values: o
2025
+ },
2026
+ schemaVersion: 16
2027
+ };
2028
+ }
2029
+ function Et(e) {
2030
+ const t = { ...e.body.values };
2031
+ typeof t.contentWidth == "string" && (t.contentWidth = parseInt(t.contentWidth, 10) || 600), t.backgroundImage && typeof t.backgroundImage == "object" && (t.backgroundImage = pe(t.backgroundImage)), t.popupBackgroundImage && typeof t.popupBackgroundImage == "object" && (t.popupBackgroundImage = pe(t.popupBackgroundImage));
2032
+ const o = (r) => {
2033
+ const i = { ...r.values };
2034
+ return i.backgroundImage && typeof i.backgroundImage == "object" && (i.backgroundImage = pe(i.backgroundImage)), i.selectable === void 0 && (i.selectable = !0), i.draggable === void 0 && (i.draggable = !0), i.duplicatable === void 0 && (i.duplicatable = !0), i.deletable === void 0 && (i.deletable = !0), {
2035
+ id: r.id,
2036
+ cells: r.cells,
2037
+ columns: r.columns.map((n) => ({
2038
+ id: n.id,
2039
+ contents: n.contents.map((s) => {
2040
+ const a = s.type === "paragraph" ? "text" : s.type, c = Rt(a, { ...s.values });
2041
+ return c.selectable === void 0 && (c.selectable = !0), c.draggable === void 0 && (c.draggable = !0), c.duplicatable === void 0 && (c.duplicatable = !0), c.deletable === void 0 && (c.deletable = !0), { id: s.id, type: a, values: c };
2042
+ }),
2043
+ values: n.values
2044
+ })),
2045
+ values: i
2046
+ };
2047
+ };
2048
+ return {
2049
+ counters: e.counters,
2050
+ body: {
2051
+ id: e.body.id,
2052
+ rows: e.body.rows.map(o),
2053
+ headers: e.body.headers.map(o),
2054
+ footers: e.body.footers.map(o),
2055
+ values: t
2056
+ },
2057
+ schemaVersion: 12
2058
+ // Unlayer uses version 12
2059
+ };
2060
+ }
2061
+ function At(...e) {
2062
+ const t = {}, o = (r) => {
2063
+ const i = r.match(/^(.+?)(\d+)$/);
2064
+ if (i) {
2065
+ const n = i[1].replace(/_$/, ""), s = parseInt(i[2], 10);
2066
+ t[n] = Math.max(t[n] || 0, s);
2067
+ }
2068
+ };
2069
+ for (const r of e)
2070
+ for (const i of r) {
2071
+ o(i.id);
2072
+ for (const n of i.columns) {
2073
+ o(n.id);
2074
+ for (const s of n.contents)
2075
+ o(s.id);
2076
+ }
2077
+ }
2078
+ return t;
2079
+ }
2080
+ var Mt = Object.defineProperty, zt = Object.getOwnPropertyDescriptor, se = (e, t, o, r) => {
2081
+ for (var i = r > 1 ? void 0 : r ? zt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2082
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2083
+ return r && i && Mt(t, o, i), i;
2084
+ };
2085
+ let O = class extends T {
2086
+ constructor() {
2087
+ super(...arguments), this.visible = !1, this.mergeTags = [], this.mergeDropdownOpen = !1, this._outsideClickHandler = (e) => {
2088
+ if (!this.mergeDropdownOpen) return;
2089
+ e.composedPath().includes(this) || (this.mergeDropdownOpen = !1);
2090
+ };
2091
+ }
2092
+ connectedCallback() {
2093
+ super.connectedCallback(), document.addEventListener("mousedown", this._outsideClickHandler, !0);
2094
+ }
2095
+ disconnectedCallback() {
2096
+ super.disconnectedCallback(), document.removeEventListener("mousedown", this._outsideClickHandler, !0);
2097
+ }
2098
+ exec(e, t) {
2099
+ document.execCommand(e, !1, t), this.requestUpdate();
2100
+ }
2101
+ isActive(e) {
2102
+ try {
2103
+ return document.queryCommandState(e);
2104
+ } catch {
2105
+ return !1;
2106
+ }
2107
+ }
2108
+ /** Position the toolbar above a given element */
2109
+ positionAbove(e) {
2110
+ const t = e.getBoundingClientRect();
2111
+ this.style.left = `${t.left + t.width / 2}px`, this.style.top = `${t.top - 8}px`, this.style.transform = "translate(-50%, -100%)", this.classList.add("visible");
2112
+ }
2113
+ hide() {
2114
+ this.classList.remove("visible"), this.mergeDropdownOpen = !1;
2115
+ }
2116
+ insertMergeTag(e) {
2117
+ document.execCommand("insertHTML", !1, e), this.mergeDropdownOpen = !1, this.requestUpdate();
2118
+ }
2119
+ toggleMergeDropdown(e) {
2120
+ e.preventDefault(), this.mergeDropdownOpen = !this.mergeDropdownOpen;
2121
+ }
2122
+ handleLink() {
2123
+ if (this.isActive("createLink"))
2124
+ this.exec("unlink");
2125
+ else {
2126
+ const e = prompt("Enter URL:");
2127
+ e && this.exec("createLink", e);
2128
+ }
2129
+ }
2130
+ render() {
2131
+ return d`
2132
+ <div class="toolbar" @mousedown=${(e) => e.preventDefault()}>
2133
+ <button class="btn ${this.isActive("bold") ? "active" : ""}"
2134
+ @click=${() => this.exec("bold")} title="Bold (Ctrl+B)">
2135
+ <strong>B</strong>
2136
+ </button>
2137
+ <button class="btn ${this.isActive("italic") ? "active" : ""}"
2138
+ @click=${() => this.exec("italic")} title="Italic (Ctrl+I)">
2139
+ <em>I</em>
2140
+ </button>
2141
+ <button class="btn ${this.isActive("underline") ? "active" : ""}"
2142
+ @click=${() => this.exec("underline")} title="Underline (Ctrl+U)">
2143
+ <u>U</u>
2144
+ </button>
2145
+ <button class="btn ${this.isActive("strikeThrough") ? "active" : ""}"
2146
+ @click=${() => this.exec("strikeThrough")} title="Strikethrough">
2147
+ <s>S</s>
2148
+ </button>
2149
+ <div class="separator"></div>
2150
+ <button class="btn ${this.isActive("createLink") ? "active" : ""}"
2151
+ @click=${this.handleLink} title="Link">
2152
+ <svg viewBox="0 0 24 24"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
2153
+ </button>
2154
+ <div class="separator"></div>
2155
+ <button class="btn" @click=${() => this.exec("justifyLeft")} title="Align Left">
2156
+ <svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><line x1="3" y1="18" x2="18" y2="18"/></svg>
2157
+ </button>
2158
+ <button class="btn" @click=${() => this.exec("justifyCenter")} title="Align Center">
2159
+ <svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/></svg>
2160
+ </button>
2161
+ <button class="btn" @click=${() => this.exec("justifyRight")} title="Align Right">
2162
+ <svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="9" y1="12" x2="21" y2="12"/><line x1="6" y1="18" x2="21" y2="18"/></svg>
2163
+ </button>
2164
+ ${this.mergeTags.length > 0 ? d`
2165
+ <div class="separator"></div>
2166
+ <div class="merge-wrap">
2167
+ <button class="btn ${this.mergeDropdownOpen ? "active" : ""}"
2168
+ @click=${this.toggleMergeDropdown} title="Insert Merge Tag">
2169
+ <span style="font-size:13px;font-weight:700;letter-spacing:-0.5px;">{x}</span>
2170
+ </button>
2171
+ ${this.mergeDropdownOpen ? d`
2172
+ <div class="merge-dropdown" @mousedown=${(e) => e.preventDefault()}>
2173
+ ${this.mergeTags.map((e) => d`
2174
+ <div class="merge-group-name">${e.name}</div>
2175
+ ${Object.entries(e.mergeTags).map(([t, o]) => d`
2176
+ <button class="merge-item" @click=${() => this.insertMergeTag(o.value)}>
2177
+ ${o.name}
2178
+ </button>
2179
+ `)}
2180
+ `)}
2181
+ </div>
2182
+ ` : v}
2183
+ </div>
2184
+ ` : v}
2185
+ </div>
2186
+ `;
2187
+ }
2188
+ };
2189
+ O.styles = _`
2190
+ :host {
2191
+ position: fixed;
2192
+ z-index: 10000;
2193
+ display: none;
2194
+ }
2195
+ :host(.visible) {
2196
+ display: block;
2197
+ animation: fadeIn 0.15s ease;
2198
+ }
2199
+ @keyframes fadeIn {
2200
+ from { opacity: 0; transform: translateY(4px); }
2201
+ to { opacity: 1; transform: translateY(0); }
2202
+ }
2203
+ .toolbar {
2204
+ display: flex;
2205
+ align-items: center;
2206
+ gap: 2px;
2207
+ padding: 4px 6px;
2208
+ background: #1e293b;
2209
+ border-radius: 10px;
2210
+ box-shadow: 0 8px 24px rgba(0,0,0,0.2);
2211
+ }
2212
+ .btn {
2213
+ width: 32px;
2214
+ height: 32px;
2215
+ display: flex;
2216
+ align-items: center;
2217
+ justify-content: center;
2218
+ background: none;
2219
+ border: none;
2220
+ color: var(--me-grey-300);
2221
+ cursor: pointer;
2222
+ border-radius: 6px;
2223
+ font-size: 14px;
2224
+ font-weight: 600;
2225
+ transition: all 0.1s ease;
2226
+ padding: 0;
2227
+ }
2228
+ .btn:hover { background: rgba(255,255,255,0.08); color: white; }
2229
+ .btn.active { background: rgba(93,118,139,0.4); color: white; }
2230
+ .separator {
2231
+ width: 1px;
2232
+ height: 20px;
2233
+ background: #334155;
2234
+ margin: 0 2px;
2235
+ }
2236
+ .btn svg {
2237
+ width: 16px;
2238
+ height: 16px;
2239
+ stroke: currentColor;
2240
+ fill: none;
2241
+ stroke-width: 2;
2242
+ stroke-linecap: round;
2243
+ stroke-linejoin: round;
2244
+ }
2245
+ /* Merge tag dropdown */
2246
+ .merge-wrap { position: relative; }
2247
+ .merge-dropdown {
2248
+ position: absolute;
2249
+ top: calc(100% + 6px);
2250
+ left: 50%;
2251
+ transform: translateX(-50%);
2252
+ background: white;
2253
+ border: 1px solid var(--me-grey-200);
2254
+ border-radius: 8px;
2255
+ box-shadow: 0 8px 24px rgba(0,0,0,0.15);
2256
+ min-width: 200px;
2257
+ max-height: 260px;
2258
+ overflow-y: auto;
2259
+ z-index: 10;
2260
+ padding: 4px 0;
2261
+ }
2262
+ .merge-group-name {
2263
+ padding: 6px 12px 2px;
2264
+ font-size: 10px;
2265
+ font-weight: 700;
2266
+ text-transform: uppercase;
2267
+ letter-spacing: 0.05em;
2268
+ color: var(--me-grey-500);
2269
+ font-family: sans-serif;
2270
+ }
2271
+ .merge-item {
2272
+ display: block;
2273
+ width: 100%;
2274
+ padding: 6px 12px;
2275
+ background: none;
2276
+ border: none;
2277
+ color: var(--me-grey-600);
2278
+ font-size: 13px;
2279
+ text-align: left;
2280
+ cursor: pointer;
2281
+ white-space: nowrap;
2282
+ }
2283
+ .merge-item:hover {
2284
+ background: var(--me-blue-50);
2285
+ color: var(--me-grey-900);
2286
+ }
2287
+ `;
2288
+ se([
2289
+ x({ type: Boolean })
2290
+ ], O.prototype, "visible", 2);
2291
+ se([
2292
+ x({ attribute: !1 })
2293
+ ], O.prototype, "mergeTags", 2);
2294
+ se([
2295
+ E()
2296
+ ], O.prototype, "mergeDropdownOpen", 2);
2297
+ O = se([
2298
+ S("me-inline-toolbar")
2299
+ ], O);
2300
+ var Lt = Object.defineProperty, Bt = Object.getOwnPropertyDescriptor, J = (e, t, o, r) => {
2301
+ for (var i = r > 1 ? void 0 : r ? Bt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2302
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2303
+ return r && i && Lt(t, o, i), i;
2304
+ };
2305
+ const Ae = /* @__PURE__ */ new Set(["text", "heading", "paragraph"]);
2306
+ function Me(e) {
2307
+ return e === "html" ? "html" : "text";
2308
+ }
2309
+ let M = class extends T {
2310
+ constructor() {
2311
+ super(...arguments), this.storeCtrl = new B(this, ["design", "selection", "viewMode"]), this.editing = !1, this.toolbar = null, this.editableEl = null, this.handleInlineInput = () => {
2312
+ this.showToolbar();
2313
+ }, this.handleInlineBlur = (e) => {
2314
+ const t = e.relatedTarget;
2315
+ t && (t.closest("me-inline-toolbar") || this.toolbar?.contains(t)) || setTimeout(() => {
2316
+ document.activeElement !== this.editableEl && !this.toolbar?.matches(":hover") && this.stopEditing();
2317
+ }, 150);
2318
+ }, this.handleOverlayBlur = (e) => {
2319
+ const t = e.relatedTarget;
2320
+ t && (t.closest("me-inline-toolbar") || this.toolbar?.contains(t)) || setTimeout(() => {
2321
+ document.activeElement !== this.editableEl && !this.toolbar?.matches(":hover") && this.stopEditing();
2322
+ }, 200);
2323
+ }, this.handleInlineKeydown = (e) => {
2324
+ e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this.stopEditing());
2325
+ }, this.hoverUnsub = null;
2326
+ }
2327
+ set store(e) {
2328
+ this.storeCtrl.setStore(e);
2329
+ }
2330
+ get store() {
2331
+ return this.storeCtrl.store;
2332
+ }
2333
+ // ── Event handlers ───────────────────────────────────────
2334
+ handleClick(e) {
2335
+ e.stopPropagation(), this.editing || this.store.select(this.content.id);
2336
+ }
2337
+ handleDblClick(e) {
2338
+ e.stopPropagation(), Ae.has(this.content.type) && this.startEditing();
2339
+ }
2340
+ handleMouseEnter() {
2341
+ this.classList.add("hovered"), this.store.hover(this.content.id);
2342
+ }
2343
+ handleMouseLeave() {
2344
+ this.classList.remove("hovered"), this.store.hover(null);
2345
+ }
2346
+ handleDelete(e) {
2347
+ e.stopPropagation(), this.store.removeContent(this.content.id);
2348
+ }
2349
+ handleDuplicate(e) {
2350
+ e.stopPropagation(), this.store.duplicateContent(this.content.id);
2351
+ }
2352
+ /** Called from the drag handle only (not the whole block) */
2353
+ handleDragStart(e) {
2354
+ e.stopPropagation(), e.dataTransfer.setData("application/maileditor-content", this.content.id), e.dataTransfer.effectAllowed = "move", this.style.opacity = "0.4", D.startContentDrag(this.content.id, this);
2355
+ }
2356
+ handleDragEnd() {
2357
+ D.reset();
2358
+ }
2359
+ // ── Inline editing ───────────────────────────────────────
2360
+ startEditing() {
2361
+ this.editing = !0, this.classList.add("editing"), this.storeCtrl.hostDisconnected();
2362
+ const e = this.getBoundingClientRect(), t = this.getInlineStyles(this.content.values), o = Me(this.content.type), r = this.content.values[o] || "", i = document.createElement("div");
2363
+ i.contentEditable = "true", i.innerHTML = r, Object.assign(i.style, {
2364
+ position: "fixed",
2365
+ left: e.left + "px",
2366
+ top: e.top + "px",
2367
+ width: e.width + "px",
2368
+ minHeight: e.height + "px",
2369
+ zIndex: "9999",
2370
+ background: "white",
2371
+ boxShadow: "0 0 0 2px #8b5cf6, 0 4px 16px rgba(0,0,0,0.15)",
2372
+ borderRadius: "2px",
2373
+ outline: "none",
2374
+ boxSizing: "border-box"
2375
+ }), t.split(";").forEach((a) => {
2376
+ const [c, l] = a.split(":").map((u) => u?.trim());
2377
+ c && l && i.style.setProperty(c, l);
2378
+ }), i.addEventListener("keydown", this.handleInlineKeydown), i.addEventListener("blur", this.handleOverlayBlur), document.body.appendChild(i), this.editableEl = i, i.focus();
2379
+ const n = window.getSelection(), s = document.createRange();
2380
+ s.selectNodeContents(i), s.collapse(!1), n?.removeAllRanges(), n?.addRange(s), this.showToolbar();
2381
+ }
2382
+ stopEditing() {
2383
+ this.editing && (this.saveInlineContent(), this.editableEl && (this.editableEl.removeEventListener("keydown", this.handleInlineKeydown), this.editableEl.removeEventListener("blur", this.handleOverlayBlur), this.editableEl.remove()), this.editing = !1, this.classList.remove("editing"), this.editableEl = null, this.storeCtrl.hostConnected(), this.requestUpdate(), this.toolbar?.hide());
2384
+ }
2385
+ saveInlineContent() {
2386
+ if (!this.editableEl) return;
2387
+ const e = this.editableEl.innerHTML, t = Me(this.content.type), o = this.content.values[t];
2388
+ e !== o && this.store.updateContentValues(this.content.id, { [t]: e });
2389
+ }
2390
+ showToolbar() {
2391
+ this.toolbar || (this.toolbar = document.createElement("me-inline-toolbar"), document.body.appendChild(this.toolbar)), this.toolbar.mergeTags = this.store.mergeTags, this.editableEl && this.toolbar.positionAbove(this.editableEl);
2392
+ }
2393
+ // ── Lifecycle ────────────────────────────────────────────
2394
+ connectedCallback() {
2395
+ super.connectedCallback(), this.store && (this.hoverUnsub = this.store.subscribeChannels(["hover"], () => {
2396
+ this.store.hoveredId === this.content?.id ? this.classList.add("hovered") : this.matches(":hover") || this.classList.remove("hovered");
2397
+ }));
2398
+ }
2399
+ disconnectedCallback() {
2400
+ super.disconnectedCallback(), this.editing && this.stopEditing(), this.hoverUnsub?.(), this.toolbar?.remove(), this.toolbar = null;
2401
+ }
2402
+ // ── Render ───────────────────────────────────────────────
2403
+ render() {
2404
+ if (!this.store) return d``;
2405
+ const e = this.store.selectedId === this.content.id, t = this.store.viewMode, o = !!this.content.values.hideDesktop, r = !!this.content.values.hideMobile, i = t === "desktop" && o || t === "mobile" && r, n = this.store.a11yIssueIds.has(this.content.id);
2406
+ this.classList.toggle("selected", e && !this.editing), this.classList.toggle("a11y-issue", n), this.classList.toggle("hidden-in-view", i), this.removeAttribute("draggable"), this.dataset.contentId = this.content.id, this.editing && !e && this.stopEditing();
2407
+ const s = this.toolRegistry.get(this.content.type);
2408
+ if (!s && this.toolRegistry.has(this.content.type))
2409
+ return this.toolRegistry.ensureLoaded(this.content.type).then(() => this.requestUpdate()), d`<div style="padding:16px;text-align:center;color:#9ca3af;font-size:13px;">Loading ${this.content.type}...</div>`;
2410
+ const a = o ? "Hidden on desktop" : r ? "Hidden on mobile" : "", c = Ae.has(this.content.type), l = d`
2411
+ <button class="drag-handle" draggable="true" title="Drag to move"
2412
+ @dragstart=${(g) => this.handleDragStart(g)}
2413
+ @dragend=${() => this.handleDragEnd()}
2414
+ @mousedown=${(g) => g.stopPropagation()}>
2415
+ <svg viewBox="0 0 16 16"><circle cx="5" cy="3" r="1.5"/><circle cx="11" cy="3" r="1.5"/><circle cx="5" cy="8" r="1.5"/><circle cx="11" cy="8" r="1.5"/><circle cx="5" cy="13" r="1.5"/><circle cx="11" cy="13" r="1.5"/></svg>
2416
+ </button>
2417
+ `, u = s?.renderer.renderEditor(this.content.values, {
2418
+ isSelected: e,
2419
+ isHovered: this.classList.contains("hovered"),
2420
+ columnWidth: 600,
2421
+ displayMode: "email"
2422
+ });
2423
+ if (this.editing && c)
2424
+ return d`${l}<div class="content-wrapper" style="visibility:hidden;">${u}</div>`;
2425
+ const h = this.content.values.containerPadding || "0px";
2426
+ return d`
2427
+ ${i ? d`<div class="hidden-badge">${a}</div>` : ""}
2428
+ ${l}
2429
+ <div class="action-bar">
2430
+ <span class="action-bar-label">${this.content.type}</span>
2431
+ <button class="action-btn" @click=${this.handleDuplicate} title="Duplicate">&#9851;</button>
2432
+ <button class="action-btn" @click=${this.handleDelete} title="Delete">&#10005;</button>
2433
+ </div>
2434
+ <div class="content-wrapper" style="padding:${h};"
2435
+ @click=${this.handleClick}
2436
+ @dblclick=${this.handleDblClick}
2437
+ @mouseenter=${this.handleMouseEnter}
2438
+ @mouseleave=${this.handleMouseLeave}>
2439
+ ${u ?? d`<div style="padding:10px;color:#999;font-style:italic;">Unknown tool: ${this.content.type}</div>`}
2440
+ </div>
2441
+ `;
2442
+ }
2443
+ /** Build inline CSS for the contenteditable area based on content values */
2444
+ getInlineStyles(e) {
2445
+ const t = [], o = (h, g = "") => {
2446
+ const b = e[h];
2447
+ return typeof b == "string" ? b : typeof b == "number" ? String(b) : g;
2448
+ };
2449
+ t.push(`padding:${o("containerPadding", "10px")}`);
2450
+ const r = o("backgroundColor");
2451
+ r && t.push(`background-color:${r}`);
2452
+ const i = o("color");
2453
+ i && t.push(`color:${i}`);
2454
+ const n = o("fontSize");
2455
+ n && t.push(`font-size:${n}`);
2456
+ const s = o("fontWeight");
2457
+ s && t.push(`font-weight:${s}`);
2458
+ const a = o("lineHeight", "140%");
2459
+ t.push(`line-height:${a}`);
2460
+ const c = o("textAlign");
2461
+ c && t.push(`text-align:${c}`);
2462
+ const l = o("letterSpacing");
2463
+ l && l !== "normal" && t.push(`letter-spacing:${l}`);
2464
+ const u = e.fontFamily;
2465
+ return typeof u == "string" ? t.push(`font-family:${u}`) : u && typeof u == "object" && t.push(`font-family:${u.value || "inherit"}`), t.push("word-break:break-word", "outline:none", "min-height:1em"), t.join(";");
2466
+ }
2467
+ };
2468
+ M.styles = _`
2469
+ :host {
2470
+ display: block; position: relative;
2471
+ transition: outline 0.15s ease, transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
2472
+ }
2473
+ :host(.selected) { outline: 2px solid var(--me-primary); outline-offset: -1px; box-shadow: 0 0 0 4px var(--me-primary-10); }
2474
+ :host(.hovered:not(.selected)) { outline: 2px dashed var(--me-primary-30); outline-offset: -1px; box-shadow: 0 0 0 4px var(--me-primary-5); }
2475
+ :host(.hovered.a11y-issue) {
2476
+ outline: 2px solid var(--me-danger) !important; outline-offset: -1px;
2477
+ animation: a11yPulse 1s ease-in-out infinite;
2478
+ }
2479
+ @keyframes a11yPulse {
2480
+ 0%, 100% { box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.15); }
2481
+ 50% { box-shadow: 0 0 0 6px rgba(220, 38, 38, 0.25); }
2482
+ }
2483
+ :host(.editing) { outline: 2px solid #32769B; outline-offset: -1px; }
2484
+ :host(.just-dropped) {
2485
+ animation: dropIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
2486
+ }
2487
+ :host(.hidden-in-view) { opacity: 0.3; position: relative; }
2488
+ .hidden-badge {
2489
+ position: absolute; top: 4px; right: 4px; z-index: 5;
2490
+ background: #f59e0b; color: white; font-size: 10px; font-weight: 600;
2491
+ padding: 2px 6px; border-radius: 3px; font-family: sans-serif;
2492
+ pointer-events: none;
2493
+ }
2494
+ @keyframes dropIn {
2495
+ 0% { opacity: 0; transform: scale(0.92) translateY(-8px); }
2496
+ 100% { opacity: 1; transform: scale(1) translateY(0); }
2497
+ }
2498
+ /* Drag handle — straddles the right border, vertically centered */
2499
+ .drag-handle {
2500
+ display: none;
2501
+ position: absolute;
2502
+ top: 50%;
2503
+ right: -12px;
2504
+ transform: translateY(-50%);
2505
+ width: 24px;
2506
+ height: 24px;
2507
+ background: var(--me-primary);
2508
+ color: white;
2509
+ border: 2px solid white;
2510
+ border-radius: 50%;
2511
+ cursor: grab;
2512
+ z-index: 20;
2513
+ align-items: center;
2514
+ justify-content: center;
2515
+ padding: 0;
2516
+ box-shadow: 0 1px 4px rgba(0,0,0,0.2);
2517
+ transition: background 0.15s ease, transform 0.15s ease;
2518
+ }
2519
+ .drag-handle:hover {
2520
+ background: var(--me-primary-dark);
2521
+ transform: translateY(-50%) scale(1.15);
2522
+ }
2523
+ .drag-handle:active { cursor: grabbing; }
2524
+ .drag-handle svg {
2525
+ width: 12px; height: 12px; fill: currentColor; stroke: none;
2526
+ }
2527
+ :host(.selected) .drag-handle,
2528
+ :host(.hovered) .drag-handle { display: flex; }
2529
+ :host(.editing) .drag-handle { display: none; }
2530
+ /* Action bar */
2531
+ .action-bar {
2532
+ display: none; position: absolute; top: -28px; right: 4px;
2533
+ background: var(--me-primary); border-radius: 6px; padding: 2px; gap: 2px; z-index: 10;
2534
+ align-items: center;
2535
+ }
2536
+ :host(.selected:not(.editing)) .action-bar { display: flex; }
2537
+ .action-bar-label {
2538
+ font-size: 10px; color: rgba(255,255,255,0.6); font-weight: 600;
2539
+ text-transform: uppercase; letter-spacing: 0.03em;
2540
+ padding: 0 4px;
2541
+ }
2542
+ .action-btn {
2543
+ background: none; border: none; color: white; cursor: pointer;
2544
+ padding: 2px 6px; font-size: 12px; line-height: 1; border-radius: 2px;
2545
+ }
2546
+ .action-btn:hover { background: rgba(255,255,255,0.15); }
2547
+ .content-wrapper { position: relative; cursor: default; box-sizing: border-box; }
2548
+ /* Reset paragraph margins in user content to match email rendering.
2549
+ Override inline margin from external editors (e.g. margin: 1.25em 0px). */
2550
+ .content-wrapper p { margin: 0 !important; }
2551
+ .inline-editable {
2552
+ outline: none; cursor: text; min-height: 1em;
2553
+ }
2554
+ .inline-editable:focus { outline: none; }
2555
+ `;
2556
+ J([
2557
+ x({ attribute: !1 })
2558
+ ], M.prototype, "content", 2);
2559
+ J([
2560
+ x({ attribute: !1 })
2561
+ ], M.prototype, "store", 1);
2562
+ J([
2563
+ x({ attribute: !1 })
2564
+ ], M.prototype, "toolRegistry", 2);
2565
+ J([
2566
+ E()
2567
+ ], M.prototype, "editing", 2);
2568
+ M = J([
2569
+ S("me-content-renderer")
2570
+ ], M);
2571
+ var Wt = Object.defineProperty, Ot = Object.getOwnPropertyDescriptor, X = (e, t, o, r) => {
2572
+ for (var i = r > 1 ? void 0 : r ? Ot(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2573
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2574
+ return r && i && Wt(t, o, i), i;
2575
+ };
2576
+ let z = class extends T {
2577
+ constructor() {
2578
+ super(...arguments), this.storeCtrl = new B(this, ["design"]), this.widthPercent = 100;
2579
+ }
2580
+ set store(e) {
2581
+ this.storeCtrl.setStore(e);
2582
+ }
2583
+ get store() {
2584
+ return this.storeCtrl.store;
2585
+ }
2586
+ render() {
2587
+ const e = this.column.values.padding || "0px", t = this.column.values.backgroundColor || "transparent", o = this.column.contents;
2588
+ return this.dataset.columnId = this.column.id, this.style.width = `${this.widthPercent}%`, this.style.padding = e, this.style.backgroundColor = t, this.style.verticalAlign = "top", this.style.boxSizing = "border-box", o.length === 0 ? d`
2589
+ <div class="empty-column" data-column-id=${this.column.id}>
2590
+ Drag content here
2591
+ </div>
2592
+ ` : d`
2593
+ ${ye(o, (r) => r.id, (r) => d`
2594
+ <me-content-renderer
2595
+ .content=${r}
2596
+ .store=${this.store}
2597
+ .toolRegistry=${this.toolRegistry}
2598
+ ></me-content-renderer>
2599
+ `)}
2600
+ `;
2601
+ }
2602
+ };
2603
+ z.styles = _`
2604
+ :host {
2605
+ display: block;
2606
+ min-height: 40px;
2607
+ position: relative;
2608
+ }
2609
+ .empty-column {
2610
+ display: flex;
2611
+ align-items: center;
2612
+ justify-content: center;
2613
+ min-height: 60px;
2614
+ border: 2px dashed #d1d5db;
2615
+ border-radius: 4px;
2616
+ color: #9ca3af;
2617
+ font-size: 13px;
2618
+ font-family: sans-serif;
2619
+ margin: 4px;
2620
+ }
2621
+ .drop-indicator {
2622
+ height: 3px;
2623
+ background: #3b82f6;
2624
+ border-radius: 2px;
2625
+ margin: 0 4px;
2626
+ opacity: 0;
2627
+ transition: opacity 0.15s ease;
2628
+ }
2629
+ .drop-indicator.active {
2630
+ opacity: 1;
2631
+ }
2632
+ `;
2633
+ X([
2634
+ x({ attribute: !1 })
2635
+ ], z.prototype, "column", 2);
2636
+ X([
2637
+ x({ attribute: !1 })
2638
+ ], z.prototype, "store", 1);
2639
+ X([
2640
+ x({ attribute: !1 })
2641
+ ], z.prototype, "toolRegistry", 2);
2642
+ X([
2643
+ x({ type: Number })
2644
+ ], z.prototype, "widthPercent", 2);
2645
+ z = X([
2646
+ S("me-column-renderer")
2647
+ ], z);
2648
+ var jt = Object.defineProperty, Ht = Object.getOwnPropertyDescriptor, ae = (e, t, o, r) => {
2649
+ for (var i = r > 1 ? void 0 : r ? Ht(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2650
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2651
+ return r && i && jt(t, o, i), i;
2652
+ };
2653
+ let j = class extends T {
2654
+ constructor() {
2655
+ super(...arguments), this.storeCtrl = new B(this, ["design", "viewMode"]), this.handleDragStart = (e) => {
2656
+ e.stopPropagation(), e.dataTransfer.setData("application/maileditor-row", this.row.id), e.dataTransfer.effectAllowed = "move", this.style.opacity = "0.4", D.startRowDrag(this.row.id, this);
2657
+ }, this.handleDragEnd = () => {
2658
+ D.reset();
2659
+ };
2660
+ }
2661
+ set store(e) {
2662
+ this.storeCtrl.setStore(e);
2663
+ }
2664
+ get store() {
2665
+ return this.storeCtrl.store;
2666
+ }
2667
+ handleMoveUp(e) {
2668
+ e.stopPropagation();
2669
+ const t = this.store.getRowIndex(this.row.id);
2670
+ t > 0 && this.store.moveRow(t, t - 1);
2671
+ }
2672
+ handleMoveDown(e) {
2673
+ e.stopPropagation();
2674
+ const t = this.store.getRowIndex(this.row.id), o = this.store.getRows().length;
2675
+ t < o - 1 && this.store.moveRow(t, t + 1);
2676
+ }
2677
+ handleDuplicate(e) {
2678
+ e.stopPropagation(), this.store.duplicateRow(this.row.id);
2679
+ }
2680
+ handleDelete(e) {
2681
+ e.stopPropagation(), this.store.removeRow(this.row.id);
2682
+ }
2683
+ render() {
2684
+ if (!this.store) return d``;
2685
+ const { row: e, store: t, toolRegistry: o } = this, r = e.values.backgroundColor || "transparent", i = e.values.columnsBackgroundColor || "transparent", n = e.values.padding || "0px", s = e.cells.reduce((f, y) => f + y, 0), a = e.values.backgroundImage, c = typeof a == "object" && a?.url ? a.url : "";
2686
+ let l = "";
2687
+ if (c) {
2688
+ const f = a.repeat === !0 || a.repeat === "repeat" ? "repeat" : "no-repeat", y = a.cover === !0 ? "cover" : a.fullWidth === !0 ? "100% auto" : "auto", w = a.center !== !1 ? "center" : "top left";
2689
+ l = `background-image:url('${c}');background-size:${y};background-position:${w};background-repeat:${f};`;
2690
+ }
2691
+ const u = t.viewMode, h = !!e.values.hideDesktop, g = !!e.values.hideMobile, b = u === "desktop" && h || u === "mobile" && g, k = h ? "Hidden on desktop" : g ? "Hidden on mobile" : "";
2692
+ this.classList.toggle("hidden-in-view", b), this.removeAttribute("draggable"), this.dataset.rowId = e.id;
2693
+ const $ = t.getRowIndex(e.id), m = t.getRows().length;
2694
+ return d`
2695
+ ${b ? d`<div class="row-hidden-badge">${k}</div>` : ""}
2696
+ <button class="drag-handle" draggable="true" title="Drag to reorder"
2697
+ @dragstart=${this.handleDragStart}
2698
+ @dragend=${this.handleDragEnd}
2699
+ @mousedown=${(f) => f.stopPropagation()}>
2700
+ <svg viewBox="0 0 16 16"><circle cx="5" cy="3" r="1.5"/><circle cx="11" cy="3" r="1.5"/><circle cx="5" cy="8" r="1.5"/><circle cx="11" cy="8" r="1.5"/><circle cx="5" cy="13" r="1.5"/><circle cx="11" cy="13" r="1.5"/></svg>
2701
+ </button>
2702
+ <div class="action-bar">
2703
+ <span class="action-bar-label">Row</span>
2704
+ ${$ > 0 ? d`
2705
+ <button class="action-btn" @click=${this.handleMoveUp} title="Move Up">
2706
+ <svg viewBox="0 0 24 24"><path d="M12 19V5"/><path d="m5 12 7-7 7 7"/></svg>
2707
+ </button>
2708
+ ` : ""}
2709
+ ${$ < m - 1 ? d`
2710
+ <button class="action-btn" @click=${this.handleMoveDown} title="Move Down">
2711
+ <svg viewBox="0 0 24 24"><path d="M12 5v14"/><path d="m19 12-7 7-7-7"/></svg>
2712
+ </button>
2713
+ ` : ""}
2714
+ <div class="action-separator"></div>
2715
+ <button class="action-btn danger" @click=${this.handleDelete} title="Delete Row">
2716
+ <svg viewBox="0 0 24 24"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
2717
+ </button>
2718
+ </div>
2719
+ <div
2720
+ class="row-wrapper"
2721
+ style="background-color:${r};padding:${n};${l}"
2722
+ >
2723
+ ${ye(e.columns, (f) => f.id, (f, y) => {
2724
+ const w = e.cells[y] / s * 100;
2725
+ return d`
2726
+ <me-column-renderer
2727
+ .column=${f}
2728
+ .store=${t}
2729
+ .toolRegistry=${o}
2730
+ .widthPercent=${w}
2731
+ style="background-color:${i};"
2732
+ ></me-column-renderer>
2733
+ `;
2734
+ })}
2735
+ </div>
2736
+ `;
2737
+ }
2738
+ };
2739
+ j.styles = _`
2740
+ :host {
2741
+ display: block;
2742
+ position: relative;
2743
+ transition: opacity 0.2s ease;
2744
+ }
2745
+ :host(.hidden-in-view) { opacity: 0.3; }
2746
+ .row-hidden-badge {
2747
+ position: absolute; top: 4px; left: 4px; z-index: 5;
2748
+ background: #f59e0b; color: white; font-size: 10px; font-weight: 600;
2749
+ padding: 2px 6px; border-radius: 3px; font-family: sans-serif;
2750
+ pointer-events: none;
2751
+ }
2752
+ .row-wrapper {
2753
+ display: flex;
2754
+ flex-wrap: nowrap;
2755
+ position: relative;
2756
+ min-height: 30px;
2757
+ transition: box-shadow 0.15s ease;
2758
+ }
2759
+ :host(:hover) .row-wrapper {
2760
+ box-shadow: inset 0 0 0 2px var(--me-primary-30);
2761
+ }
2762
+
2763
+ /* Drop-in animation for newly added rows */
2764
+ :host(.just-added) {
2765
+ animation: rowSlideIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
2766
+ }
2767
+ @keyframes rowSlideIn {
2768
+ 0% { opacity: 0; transform: translateY(-10px) scaleY(0.95); }
2769
+ 100% { opacity: 1; transform: translateY(0) scaleY(1); }
2770
+ }
2771
+
2772
+ /* ── Drag handle — right side, vertically centered ── */
2773
+ .drag-handle {
2774
+ display: none;
2775
+ position: absolute;
2776
+ right: -12px;
2777
+ top: 50%;
2778
+ transform: translateY(-50%);
2779
+ width: 24px;
2780
+ height: 24px;
2781
+ background: var(--me-primary);
2782
+ color: white;
2783
+ border: 2px solid white;
2784
+ border-radius: 50%;
2785
+ cursor: grab;
2786
+ z-index: 20;
2787
+ align-items: center;
2788
+ justify-content: center;
2789
+ padding: 0;
2790
+ box-shadow: 0 1px 4px rgba(0,0,0,0.2);
2791
+ transition: background 0.15s ease, transform 0.15s ease;
2792
+ }
2793
+ .drag-handle:hover {
2794
+ background: var(--me-primary-dark);
2795
+ transform: translateY(-50%) scale(1.15);
2796
+ }
2797
+ .drag-handle:active { cursor: grabbing; }
2798
+ .drag-handle svg {
2799
+ width: 12px; height: 12px; fill: currentColor; stroke: none;
2800
+ }
2801
+ :host(:hover) .drag-handle { display: flex; }
2802
+
2803
+ /* ── Action bar — top-right ── */
2804
+ .action-bar {
2805
+ display: none;
2806
+ position: absolute;
2807
+ top: -28px;
2808
+ right: 4px;
2809
+ background: var(--me-primary);
2810
+ border-radius: 6px;
2811
+ padding: 2px;
2812
+ gap: 2px;
2813
+ z-index: 10;
2814
+ align-items: center;
2815
+ }
2816
+ :host(:hover) .action-bar { display: flex; }
2817
+ .action-bar-label {
2818
+ font-size: 10px; color: rgba(255,255,255,0.6); font-weight: 600;
2819
+ text-transform: uppercase; letter-spacing: 0.03em;
2820
+ padding: 0 4px;
2821
+ }
2822
+ .action-btn {
2823
+ background: none;
2824
+ border: none;
2825
+ color: white;
2826
+ cursor: pointer;
2827
+ padding: 2px 6px;
2828
+ font-size: 12px;
2829
+ line-height: 1;
2830
+ border-radius: 2px;
2831
+ display: flex;
2832
+ align-items: center;
2833
+ justify-content: center;
2834
+ }
2835
+ .action-btn:hover { background: rgba(255,255,255,0.15); }
2836
+ .action-btn.danger:hover { background: rgba(239,68,68,0.5); }
2837
+ .action-btn svg {
2838
+ width: 14px;
2839
+ height: 14px;
2840
+ stroke: currentColor;
2841
+ fill: none;
2842
+ stroke-width: 2;
2843
+ stroke-linecap: round;
2844
+ stroke-linejoin: round;
2845
+ }
2846
+ .action-separator {
2847
+ width: 1px;
2848
+ background: rgba(255,255,255,0.3);
2849
+ margin: 2px 1px;
2850
+ }
2851
+ `;
2852
+ ae([
2853
+ x({ attribute: !1 })
2854
+ ], j.prototype, "row", 2);
2855
+ ae([
2856
+ x({ attribute: !1 })
2857
+ ], j.prototype, "store", 1);
2858
+ ae([
2859
+ x({ attribute: !1 })
2860
+ ], j.prototype, "toolRegistry", 2);
2861
+ j = ae([
2862
+ S("me-row-renderer")
2863
+ ], j);
2864
+ var Vt = Object.defineProperty, Ft = Object.getOwnPropertyDescriptor, Z = (e, t, o, r) => {
2865
+ for (var i = r > 1 ? void 0 : r ? Ft(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2866
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2867
+ return r && i && Vt(t, o, i), i;
2868
+ };
2869
+ let L = class extends T {
2870
+ constructor() {
2871
+ super(...arguments), this.storeCtrl = new B(this, ["design", "viewMode"]), this.quickAddIndex = null, this.quickAddPos = { x: 0, y: 0 }, this.boundCloseQuickAdd = this.closeQuickAdd.bind(this);
2872
+ }
2873
+ set store(e) {
2874
+ this.storeCtrl.setStore(e);
2875
+ }
2876
+ get store() {
2877
+ return this.storeCtrl.store;
2878
+ }
2879
+ connectedCallback() {
2880
+ super.connectedCallback(), document.addEventListener("click", this.boundCloseQuickAdd);
2881
+ }
2882
+ disconnectedCallback() {
2883
+ super.disconnectedCallback(), document.removeEventListener("click", this.boundCloseQuickAdd);
2884
+ }
2885
+ handleCanvasClick() {
2886
+ this.store.select(null);
2887
+ }
2888
+ setViewMode(e) {
2889
+ this.store.setViewMode(e);
2890
+ }
2891
+ // ── Quick-add methods ──────────────────────────────────────
2892
+ openQuickAdd(e, t) {
2893
+ e.stopPropagation();
2894
+ const r = e.currentTarget.getBoundingClientRect();
2895
+ this.quickAddPos = {
2896
+ x: r.left + r.width / 2,
2897
+ y: r.bottom + 6
2898
+ }, this.quickAddIndex = t;
2899
+ }
2900
+ closeQuickAdd() {
2901
+ this.quickAddIndex !== null && (this.quickAddIndex = null);
2902
+ }
2903
+ async quickAddTool(e, t) {
2904
+ await this.toolRegistry.ensureLoaded(e);
2905
+ const o = this.toolRegistry.getDefaultValues(e), r = this.store.createRow([1]), n = this.store.addRow(r, t).columns[0].id, s = this.store.createContent(e, o);
2906
+ this.store.addContent(n, s), this.quickAddIndex = null;
2907
+ }
2908
+ quickAddLayout(e, t) {
2909
+ const o = this.store.createRow(e);
2910
+ this.store.addRow(o, t), this.quickAddIndex = null;
2911
+ }
2912
+ renderRowGap(e) {
2913
+ return d`
2914
+ <div class="row-gap">
2915
+ <button
2916
+ class="add-btn"
2917
+ @click=${(t) => this.openQuickAdd(t, e)}
2918
+ title="Add row"
2919
+ >+</button>
2920
+ </div>
2921
+ `;
2922
+ }
2923
+ renderQuickAddMenu() {
2924
+ if (this.quickAddIndex === null) return "";
2925
+ const e = this.quickAddIndex, t = this.quickAddPos.x, o = this.quickAddPos.y;
2926
+ return d`
2927
+ <div
2928
+ class="quick-add-menu"
2929
+ style="position:fixed;left:${t}px;top:${o}px;transform:translateX(-50%)"
2930
+ @click=${(i) => i.stopPropagation()}
2931
+ >
2932
+ <div class="quick-tools">
2933
+ <button @click=${() => this.quickAddTool("text", e)} title="Text">T</button>
2934
+ <button @click=${() => this.quickAddTool("heading", e)} title="Heading">H</button>
2935
+ <button @click=${() => this.quickAddTool("image", e)} title="Image">
2936
+ <svg width="16" height="16" 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"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
2937
+ </button>
2938
+ <button @click=${() => this.quickAddTool("button", e)} title="Button">
2939
+ <svg width="16" height="16" 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="3"/></svg>
2940
+ </button>
2941
+ <button @click=${() => this.quickAddTool("divider", e)} title="Divider">
2942
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="12" x2="21" y2="12"/></svg>
2943
+ </button>
2944
+ </div>
2945
+ <div class="quick-separator"></div>
2946
+ <div class="quick-layouts">
2947
+ ${[
2948
+ { cells: [1], label: "100%" },
2949
+ { cells: [1, 1], label: "50/50" },
2950
+ { cells: [1, 1, 1], label: "33/33/33" },
2951
+ { cells: [2, 1], label: "66/33" },
2952
+ { cells: [1, 2], label: "33/66" },
2953
+ { cells: [1, 1, 1, 1], label: "25x4" }
2954
+ ].map(
2955
+ (i) => {
2956
+ const n = i.cells.reduce((s, a) => s + a, 0);
2957
+ return d`
2958
+ <button
2959
+ @click=${() => this.quickAddLayout(i.cells, e)}
2960
+ title=${i.label}
2961
+ >
2962
+ ${i.cells.map((s) => d`<div class="ql-col" style="--col-flex:${s / n}"></div>`)}
2963
+ </button>
2964
+ `;
2965
+ }
2966
+ )}
2967
+ </div>
2968
+ </div>
2969
+ `;
2970
+ }
2971
+ render() {
2972
+ const e = this.store.getRows(), t = this.store.getBodyValues(), o = t.contentWidth || "600px", r = t.backgroundColor || "#e7e7e7", i = this.store.viewMode, n = i === "mobile" ? "375px" : o;
2973
+ return d`
2974
+ <div class="view-toggle">
2975
+ <button
2976
+ class="view-btn ${i === "desktop" ? "active" : ""}"
2977
+ @click=${() => this.setViewMode("desktop")}
2978
+ >Desktop</button>
2979
+ <button
2980
+ class="view-btn ${i === "mobile" ? "active" : ""}"
2981
+ @click=${() => this.setViewMode("mobile")}
2982
+ >Mobile</button>
2983
+ </div>
2984
+
2985
+ <div class="canvas-bg" style="background-color:${r};" @click=${this.handleCanvasClick}>
2986
+ <div
2987
+ class="canvas-body"
2988
+ style="max-width:${n};"
2989
+ >
2990
+ ${e.length === 0 ? d`
2991
+ <div class="empty-canvas">
2992
+ <div class="empty-icon">&#9776;</div>
2993
+ <div>Drag a content block here</div>
2994
+ </div>
2995
+ ${this.renderRowGap(0)}
2996
+ ` : d`
2997
+ ${this.renderRowGap(0)}
2998
+ ${ye(e, (s) => s.id, (s, a) => d`
2999
+ <me-row-renderer
3000
+ .row=${s}
3001
+ .store=${this.store}
3002
+ .toolRegistry=${this.toolRegistry}
3003
+ ></me-row-renderer>
3004
+ ${this.renderRowGap(a + 1)}
3005
+ `)}
3006
+ `}
3007
+ </div>
3008
+ </div>
3009
+ ${this.renderQuickAddMenu()}
3010
+ `;
3011
+ }
3012
+ };
3013
+ L.styles = _`
3014
+ :host {
3015
+ display: block;
3016
+ flex: 1;
3017
+ overflow-y: auto;
3018
+ background: var(--me-grey-100);
3019
+ }
3020
+ /* Full-width body background — mirrors the email <body> */
3021
+ .canvas-bg {
3022
+ min-height: 100%;
3023
+ padding: 0 20px 20px;
3024
+ }
3025
+ .canvas-body {
3026
+ margin: 0 auto;
3027
+ background: #ffffff;
3028
+ min-height: 200px;
3029
+ position: relative;
3030
+ }
3031
+ .empty-canvas {
3032
+ display: flex;
3033
+ flex-direction: column;
3034
+ align-items: center;
3035
+ justify-content: center;
3036
+ min-height: 300px;
3037
+ color: var(--me-grey-400);
3038
+ font-family: sans-serif;
3039
+ font-size: 14px;
3040
+ gap: 8px;
3041
+ }
3042
+ .empty-icon {
3043
+ font-size: 40px;
3044
+ opacity: 0.4;
3045
+ }
3046
+ .view-toggle {
3047
+ display: flex;
3048
+ justify-content: center;
3049
+ margin: 8px 0 12px;
3050
+ gap: 4px;
3051
+ }
3052
+ .view-btn {
3053
+ padding: 6px 16px;
3054
+ border: 1px solid var(--me-grey-200);
3055
+ background: white;
3056
+ cursor: pointer;
3057
+ font-size: 11px;
3058
+ font-weight: 600;
3059
+ font-family: sans-serif;
3060
+ color: var(--me-grey-700);
3061
+ transition: all 0.15s ease;
3062
+ }
3063
+ .view-btn:hover { background: var(--me-grey-50); }
3064
+ .view-btn:first-child { border-radius: 8px 0 0 8px; }
3065
+ .view-btn:last-child { border-radius: 0 8px 8px 0; }
3066
+ .view-btn.active {
3067
+ background: var(--me-primary);
3068
+ border-color: var(--me-primary);
3069
+ color: white;
3070
+ }
3071
+
3072
+ /* ── Quick-add row gaps ─────────────────────────── */
3073
+ .row-gap {
3074
+ height: 20px;
3075
+ position: relative;
3076
+ display: flex;
3077
+ align-items: center;
3078
+ justify-content: center;
3079
+ z-index: 2;
3080
+ }
3081
+ .row-gap .add-btn {
3082
+ opacity: 0;
3083
+ width: 24px;
3084
+ height: 24px;
3085
+ border-radius: 50%;
3086
+ border: none;
3087
+ background: var(--me-primary);
3088
+ color: white;
3089
+ font-size: 16px;
3090
+ line-height: 1;
3091
+ cursor: pointer;
3092
+ display: flex;
3093
+ align-items: center;
3094
+ justify-content: center;
3095
+ transition: opacity 0.15s, transform 0.15s;
3096
+ padding: 0;
3097
+ font-family: sans-serif;
3098
+ }
3099
+ .row-gap:hover .add-btn {
3100
+ opacity: 1;
3101
+ }
3102
+ .row-gap .add-btn:hover {
3103
+ transform: scale(1.1);
3104
+ }
3105
+ .row-gap::before {
3106
+ content: '';
3107
+ position: absolute;
3108
+ left: 5%;
3109
+ right: 5%;
3110
+ top: 50%;
3111
+ height: 2px;
3112
+ background: transparent;
3113
+ border-radius: 1px;
3114
+ transition: background 0.2s ease;
3115
+ }
3116
+ .row-gap:hover::before {
3117
+ background: rgba(93, 118, 139, 0.2);
3118
+ }
3119
+
3120
+ /* ── Quick-add floating menu ───────────────────── */
3121
+ .quick-add-menu {
3122
+ background: white;
3123
+ border: 1px solid var(--me-grey-200);
3124
+ border-radius: 10px;
3125
+ box-shadow: 0 4px 20px rgba(0,0,0,0.12);
3126
+ padding: 8px;
3127
+ z-index: 100;
3128
+ animation: qaFadeIn 0.12s ease-out;
3129
+ font-family: sans-serif;
3130
+ }
3131
+ @keyframes qaFadeIn {
3132
+ from { opacity: 0; transform: scale(0.95); }
3133
+ to { opacity: 1; transform: scale(1); }
3134
+ }
3135
+ .quick-tools {
3136
+ display: flex;
3137
+ gap: 4px;
3138
+ }
3139
+ .quick-tools button {
3140
+ width: 36px;
3141
+ height: 36px;
3142
+ border: none;
3143
+ border-radius: 8px;
3144
+ background: var(--me-grey-50);
3145
+ cursor: pointer;
3146
+ font-size: 14px;
3147
+ font-family: sans-serif;
3148
+ color: var(--me-grey-700);
3149
+ display: flex;
3150
+ align-items: center;
3151
+ justify-content: center;
3152
+ transition: background 0.12s, color 0.12s;
3153
+ }
3154
+ .quick-tools button:hover {
3155
+ background: var(--me-primary);
3156
+ color: white;
3157
+ }
3158
+ .quick-separator {
3159
+ height: 1px;
3160
+ background: var(--me-grey-200);
3161
+ margin: 6px 0;
3162
+ }
3163
+ .quick-layouts {
3164
+ display: flex;
3165
+ gap: 4px;
3166
+ }
3167
+ .quick-layouts button {
3168
+ flex: 1;
3169
+ height: 28px;
3170
+ border: 1px solid var(--me-grey-200);
3171
+ border-radius: 6px;
3172
+ background: white;
3173
+ cursor: pointer;
3174
+ padding: 3px 4px;
3175
+ display: flex;
3176
+ gap: 2px;
3177
+ align-items: stretch;
3178
+ transition: border-color 0.12s;
3179
+ }
3180
+ .quick-layouts button:hover {
3181
+ border-color: var(--me-primary);
3182
+ }
3183
+ .quick-layouts button .ql-col {
3184
+ background: var(--me-grey-300);
3185
+ border-radius: 2px;
3186
+ flex-grow: var(--col-flex, 1);
3187
+ transition: background 0.12s;
3188
+ }
3189
+ .quick-layouts button:hover .ql-col {
3190
+ background: var(--me-primary);
3191
+ }
3192
+ `;
3193
+ Z([
3194
+ x({ attribute: !1 })
3195
+ ], L.prototype, "store", 1);
3196
+ Z([
3197
+ x({ attribute: !1 })
3198
+ ], L.prototype, "toolRegistry", 2);
3199
+ Z([
3200
+ E()
3201
+ ], L.prototype, "quickAddIndex", 2);
3202
+ Z([
3203
+ E()
3204
+ ], L.prototype, "quickAddPos", 2);
3205
+ L = Z([
3206
+ S("me-editor-canvas")
3207
+ ], L);
3208
+ var Ut = Object.defineProperty, qt = Object.getOwnPropertyDescriptor, Oe = (e, t, o, r) => {
3209
+ for (var i = r > 1 ? void 0 : r ? qt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3210
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3211
+ return r && i && Ut(t, o, i), i;
3212
+ };
3213
+ const he = [
3214
+ // System / email-safe fonts
3215
+ { label: "Arial", value: "arial,helvetica,sans-serif", url: "" },
3216
+ { label: "Helvetica", value: "helvetica,sans-serif", url: "" },
3217
+ { label: "Georgia", value: "georgia,serif", url: "" },
3218
+ { label: "Times New Roman", value: "'times new roman',times,serif", url: "" },
3219
+ { label: "Trebuchet MS", value: "trebuchet ms,helvetica,sans-serif", url: "" },
3220
+ { label: "Verdana", value: "verdana,geneva,sans-serif", url: "" },
3221
+ { label: "Courier New", value: "'courier new',courier,monospace", url: "" },
3222
+ // Google Fonts
3223
+ { label: "Lato", value: "'Lato',sans-serif", url: "https://fonts.googleapis.com/css?family=Lato:400,700" },
3224
+ { label: "Montserrat", value: "'Montserrat',sans-serif", url: "https://fonts.googleapis.com/css?family=Montserrat:400,700" },
3225
+ { label: "Old Standard TT", value: "'Old Standard TT',serif", url: "https://fonts.googleapis.com/css?family=Old+Standard+TT:400,700" },
3226
+ { label: "Open Sans", value: "'Open Sans',sans-serif", url: "https://fonts.googleapis.com/css?family=Open+Sans:400,700" },
3227
+ { label: "Pacifico", value: "'Pacifico',cursive", url: "https://fonts.googleapis.com/css?family=Pacifico:400" },
3228
+ { label: "Playfair Display", value: "'Playfair Display',serif", url: "https://fonts.googleapis.com/css?family=Playfair+Display:400,700" },
3229
+ { label: "Raleway", value: "'Raleway',sans-serif", url: "https://fonts.googleapis.com/css?family=Raleway:400,700" },
3230
+ { label: "Roboto", value: "'Roboto',sans-serif", url: "https://fonts.googleapis.com/css?family=Roboto:400,700" },
3231
+ { label: "Rubik", value: "'Rubik',sans-serif", url: "https://fonts.googleapis.com/css?family=Rubik:400,700" },
3232
+ { label: "Source Sans Pro", value: "'Source Sans Pro',sans-serif", url: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" }
3233
+ ];
3234
+ let K = class extends T {
3235
+ constructor() {
3236
+ super(...arguments), this.storeCtrl = new B(this, ["design"]);
3237
+ }
3238
+ set store(e) {
3239
+ this.storeCtrl.setStore(e);
3240
+ }
3241
+ get store() {
3242
+ return this.storeCtrl.store;
3243
+ }
3244
+ /** Scroll to preheader field, focus it, and pulse highlight */
3245
+ highlightPreheader() {
3246
+ const e = this.shadowRoot?.getElementById("preheader-field"), t = this.shadowRoot?.getElementById("preheader-input");
3247
+ e && (e.scrollIntoView({ behavior: "smooth", block: "center" }), e.classList.add("highlight"), t?.focus(), setTimeout(() => e.classList.remove("highlight"), 5e3));
3248
+ }
3249
+ update_(e, t) {
3250
+ this.store.updateBodyValues({ [e]: t });
3251
+ }
3252
+ updateLinkStyle(e, t) {
3253
+ const o = this.store.getBodyValues().linkStyle;
3254
+ this.store.updateBodyValues({ linkStyle: { ...o, [e]: t } });
3255
+ }
3256
+ updateFontFamily(e) {
3257
+ const t = he.find((r) => r.value === e), o = { label: t?.label || e, value: e };
3258
+ if (t?.url) {
3259
+ o.url = t.url;
3260
+ const r = `emabuild-font-${e.replace(/[^a-z]/gi, "")}`;
3261
+ if (!document.getElementById(r)) {
3262
+ const i = document.createElement("link");
3263
+ i.id = r, i.rel = "stylesheet", i.href = t.url, document.head.appendChild(i);
3264
+ }
3265
+ }
3266
+ this.store.updateBodyValues({ fontFamily: o });
3267
+ }
3268
+ render() {
3269
+ const e = this.store.getBodyValues();
3270
+ return d`
3271
+ ${this.renderColorField("Background Color", e.backgroundColor || "#e7e7e7", (t) => this.update_("backgroundColor", t))}
3272
+
3273
+ <p class="section-title" style="margin-top:16px;">Content</p>
3274
+ <div class="field">
3275
+ <label class="field-label">Content Width (px)</label>
3276
+ <input class="input" type="number" .value=${parseInt(e.contentWidth || "600")} min="320" max="960" step="10"
3277
+ @change=${(t) => this.update_("contentWidth", t.target.value + "px")} />
3278
+ </div>
3279
+ <div class="field">
3280
+ <label class="field-label">Content Align</label>
3281
+ <div class="align-group">
3282
+ ${["left", "center", "right"].map((t) => d`
3283
+ <button class="align-btn ${e.contentAlign === t ? "active" : ""}"
3284
+ @click=${() => this.update_("contentAlign", t)}>${t}</button>
3285
+ `)}
3286
+ </div>
3287
+ </div>
3288
+
3289
+ <p class="section-title" style="margin-top:16px;">Typography</p>
3290
+ <div class="field">
3291
+ <label class="field-label">Font Family</label>
3292
+ <select class="input" @change=${(t) => this.updateFontFamily(t.target.value)}>
3293
+ <optgroup label="System Fonts">
3294
+ ${he.filter((t) => !t.url).map((t) => d`<option value=${t.value} ?selected=${e.fontFamily?.value === t.value}>${t.label}</option>`)}
3295
+ </optgroup>
3296
+ <optgroup label="Google Fonts">
3297
+ ${he.filter((t) => !!t.url).map((t) => d`<option value=${t.value} ?selected=${e.fontFamily?.value === t.value}>${t.label}</option>`)}
3298
+ </optgroup>
3299
+ </select>
3300
+ </div>
3301
+ ${this.renderColorField("Text Color", e.textColor || "#000000", (t) => this.update_("textColor", t))}
3302
+
3303
+ <p class="section-title" style="margin-top:16px;">Links</p>
3304
+ ${this.renderColorField("Link Color", e.linkStyle?.linkColor || "#0000ee", (t) => this.updateLinkStyle("linkColor", t))}
3305
+ <div class="field">
3306
+ <label style="display:flex;align-items:center;gap:8px;font-size:12px;color:#6b7280;cursor:pointer;">
3307
+ <input type="checkbox" .checked=${e.linkStyle?.linkUnderline ?? !0}
3308
+ @change=${(t) => this.updateLinkStyle("linkUnderline", t.target.checked)} />
3309
+ Underline Links
3310
+ </label>
3311
+ </div>
3312
+
3313
+ <p class="section-title" style="margin-top:16px;">Email</p>
3314
+ <div class="field" id="preheader-field">
3315
+ <label class="field-label">Preheader Text</label>
3316
+ <textarea class="input" id="preheader-input" .value=${e.preheaderText || ""} placeholder="Preview text shown in inbox..."
3317
+ style="min-height:60px;resize:vertical;font-family:inherit;"
3318
+ @change=${(t) => this.update_("preheaderText", t.target.value)}></textarea>
3319
+ </div>
3320
+ `;
3321
+ }
3322
+ /** Reusable color field (swatch + hex input) */
3323
+ renderColorField(e, t, o) {
3324
+ return d`
3325
+ <div class="field">
3326
+ <label class="field-label">${e}</label>
3327
+ <div class="color-row">
3328
+ <input class="color-swatch" type="color" .value=${t} @input=${(r) => o(r.target.value)} />
3329
+ <input class="input" type="text" .value=${t} style="flex:1;" @change=${(r) => o(r.target.value)} />
3330
+ </div>
3331
+ </div>
3332
+ `;
3333
+ }
3334
+ };
3335
+ K.styles = _`
3336
+ :host { display: block; }
3337
+ .section-title {
3338
+ font-size: 11px; font-weight: 600; text-transform: uppercase;
3339
+ color: #9ca3af; letter-spacing: 0.05em; margin: 0 0 8px 0;
3340
+ }
3341
+ .field { margin-bottom: 12px; }
3342
+ .field-label { display: block; font-size: 12px; color: #6b7280; margin-bottom: 4px; }
3343
+ .input {
3344
+ width: 100%; padding: 5px 8px; border: 1px solid #d1d5db; border-radius: 4px;
3345
+ font-size: 12px; box-sizing: border-box;
3346
+ }
3347
+ .input:focus { outline: none; border-color: #3b82f6; }
3348
+ .color-row { display: flex; gap: 6px; align-items: center; }
3349
+ .color-swatch {
3350
+ width: 32px; height: 32px; border: 1px solid #d1d5db; border-radius: 4px;
3351
+ padding: 0; cursor: pointer;
3352
+ }
3353
+ .align-group { display: flex; gap: 2px; }
3354
+ .align-btn {
3355
+ flex: 1; padding: 5px; border: 1px solid #d1d5db; background: white;
3356
+ border-radius: 4px; cursor: pointer; font-size: 11px; color: #6b7280;
3357
+ }
3358
+ .align-btn.active { border-color: #3b82f6; background: #eff6ff; color: #3b82f6; }
3359
+ .field.highlight textarea {
3360
+ animation: preheaderPulse 0.6s ease-in-out 4;
3361
+ border-color: #dc2626;
3362
+ }
3363
+ @keyframes preheaderPulse {
3364
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
3365
+ 50% { box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.2); }
3366
+ }
3367
+ `;
3368
+ Oe([
3369
+ x({ attribute: !1 })
3370
+ ], K.prototype, "store", 1);
3371
+ K = Oe([
3372
+ S("me-body-settings")
3373
+ ], K);
3374
+ var Nt = Object.defineProperty, Gt = Object.getOwnPropertyDescriptor, le = (e, t, o, r) => {
3375
+ for (var i = r > 1 ? void 0 : r ? Gt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3376
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3377
+ return r && i && Nt(t, o, i), i;
3378
+ };
3379
+ const ze = {
3380
+ text: { label: "Text", tools: ["text", "heading", "paragraph"] },
3381
+ media: { label: "Media", tools: ["image", "video"] },
3382
+ actions: { label: "Actions", tools: ["button", "social", "menu"] },
3383
+ structure: { label: "Structure", tools: ["divider", "html", "timer", "table", "form"] }
3384
+ };
3385
+ let H = class extends T {
3386
+ constructor() {
3387
+ super(...arguments), this.storeCtrl = new B(this, ["activeTab", "design"]), this.searchQuery = "";
3388
+ }
3389
+ set store(e) {
3390
+ this.storeCtrl.setStore(e);
3391
+ }
3392
+ get store() {
3393
+ return this.storeCtrl.store;
3394
+ }
3395
+ getA11ySeverities() {
3396
+ const e = ve(this.store);
3397
+ return {
3398
+ errors: e.some((t) => t.severity === "error"),
3399
+ warnings: e.some((t) => t.severity === "warning"),
3400
+ infos: e.some((t) => t.severity === "info")
3401
+ };
3402
+ }
3403
+ handleDragStart(e, t) {
3404
+ e.dataTransfer.setData("application/maileditor-tool", t), e.dataTransfer.effectAllowed = "copy";
3405
+ }
3406
+ handleLayoutDragStart(e, t) {
3407
+ e.dataTransfer.setData("application/maileditor-layout", JSON.stringify(t)), e.dataTransfer.effectAllowed = "copy";
3408
+ }
3409
+ addRowWithLayout(e) {
3410
+ const t = this.store.createRow(e);
3411
+ this.store.addRow(t);
3412
+ }
3413
+ render() {
3414
+ const e = this.store.activeTab;
3415
+ return d`
3416
+ <div class="tabs">
3417
+ <button class="tab ${e === "content" ? "active" : ""}"
3418
+ @click=${() => this.store.setActiveTab("content")}>Elements</button>
3419
+ <button class="tab ${e === "body" ? "active" : ""}"
3420
+ @click=${() => this.store.setActiveTab("body")}>Body</button>
3421
+ <button class="tab ${e === "a11y" ? "active" : ""}"
3422
+ @click=${() => this.store.setActiveTab("a11y")}>A11y${this.renderA11yBadge()}</button>
3423
+ </div>
3424
+
3425
+ ${e === "content" ? this.renderElementsTab() : ""}
3426
+ ${e === "body" ? d`<div class="tab-content" style="padding-top:12px;">${this.renderBodyTab()}</div>` : ""}
3427
+ ${e === "a11y" ? d`<div class="tab-content" style="padding-top:12px;"><me-a11y-checker .store=${this.store} .toolRegistry=${this.toolRegistry}></me-a11y-checker></div>` : ""}
3428
+ `;
3429
+ }
3430
+ renderElementsTab() {
3431
+ const e = this.toolRegistry.getAllMeta(), t = this.searchQuery.toLowerCase().trim(), o = /* @__PURE__ */ new Map();
3432
+ for (const l of e) o.set(l.name, l);
3433
+ const r = (l) => !t || l.label.toLowerCase().includes(t) || l.name.toLowerCase().includes(t);
3434
+ let i = !1;
3435
+ const n = Object.entries(ze).map(([, l]) => {
3436
+ const u = l.tools.map((h) => o.get(h)).filter((h) => !!h && r(h));
3437
+ return u.length > 0 && (i = !0), { label: l.label, tools: u };
3438
+ }), s = new Set(Object.values(ze).flatMap((l) => l.tools)), a = e.filter((l) => !s.has(l.name) && r(l));
3439
+ a.length > 0 && (i = !0);
3440
+ const c = !t || "layout".includes(t) || "row".includes(t) || "column".includes(t);
3441
+ return d`
3442
+ <div class="search-wrap">
3443
+ <input class="search-input"
3444
+ type="text"
3445
+ placeholder="Search elements..."
3446
+ .value=${this.searchQuery}
3447
+ @input=${(l) => {
3448
+ this.searchQuery = l.target.value;
3449
+ }}
3450
+ />
3451
+ </div>
3452
+ <div class="tab-content">
3453
+ ${n.map(
3454
+ (l) => l.tools.length === 0 ? v : d`
3455
+ <div class="category">
3456
+ <div class="category-title">${l.label}</div>
3457
+ <div class="tool-grid">
3458
+ ${l.tools.map((u) => this.renderToolItem(u))}
3459
+ </div>
3460
+ </div>
3461
+ `
3462
+ )}
3463
+ ${a.length > 0 ? d`
3464
+ <div class="category">
3465
+ <div class="category-title">Custom</div>
3466
+ <div class="tool-grid">
3467
+ ${a.map((l) => this.renderToolItem(l))}
3468
+ </div>
3469
+ </div>
3470
+ ` : ""}
3471
+ ${c ? d`
3472
+ <div class="layout-section">
3473
+ <div class="category-title">Rows</div>
3474
+ <div class="layout-grid">
3475
+ ${this.renderLayoutOption([1], "100%")}
3476
+ ${this.renderLayoutOption([1, 1], "50/50")}
3477
+ ${this.renderLayoutOption([1, 1, 1], "33/33/33")}
3478
+ ${this.renderLayoutOption([2, 1], "66/33")}
3479
+ ${this.renderLayoutOption([1, 2], "33/66")}
3480
+ ${this.renderLayoutOption([1, 1, 1, 1], "25x4")}
3481
+ </div>
3482
+ </div>
3483
+ ` : ""}
3484
+ ${!i && !c ? d`
3485
+ <div class="no-results">No elements match "${this.searchQuery}"</div>
3486
+ ` : ""}
3487
+ </div>
3488
+ `;
3489
+ }
3490
+ renderA11yBadge() {
3491
+ const { errors: e, warnings: t, infos: o } = this.getA11ySeverities();
3492
+ return !e && !t && !o ? v : d`<span class="tab-badge">${e ? d`<span class="tab-dot error"></span>` : v}${t ? d`<span class="tab-dot warning"></span>` : v}${o ? d`<span class="tab-dot info"></span>` : v}</span>`;
3493
+ }
3494
+ renderToolItem(e) {
3495
+ return d`
3496
+ <div class="tool-item"
3497
+ draggable="true"
3498
+ @dragstart=${(t) => this.handleDragStart(t, e.name)}>
3499
+ <div class="tool-icon">${ie(e.icon)}</div>
3500
+ <span>${e.label}</span>
3501
+ </div>
3502
+ `;
3503
+ }
3504
+ renderLayoutOption(e, t) {
3505
+ const o = e.reduce((r, i) => r + i, 0);
3506
+ return d`
3507
+ <div class="layout-item" draggable="true"
3508
+ @click=${() => this.addRowWithLayout(e)}
3509
+ @dragstart=${(r) => this.handleLayoutDragStart(r, e)}
3510
+ title=${t}>
3511
+ ${e.map((r) => d`<div class="layout-col" style="width:${r / o * 100}%;"></div>`)}
3512
+ </div>
3513
+ `;
3514
+ }
3515
+ renderBodyTab() {
3516
+ return d`<me-body-settings .store=${this.store}></me-body-settings>`;
3517
+ }
3518
+ };
3519
+ H.styles = _`
3520
+ :host {
3521
+ display: flex;
3522
+ flex-direction: column;
3523
+ width: 280px;
3524
+ min-width: 280px;
3525
+ background: #ffffff;
3526
+ border-right: 1px solid var(--me-grey-100);
3527
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
3528
+ overflow-y: auto;
3529
+ transition: width 200ms ease, min-width 200ms ease;
3530
+ position: relative;
3531
+ }
3532
+ :host(.collapsed) {
3533
+ width: 0; min-width: 0; overflow: hidden; border-right: none;
3534
+ }
3535
+
3536
+ /* ── Tabs ── */
3537
+ .tabs {
3538
+ display: flex;
3539
+ border-bottom: 1px solid var(--me-grey-200);
3540
+ background: #ffffff;
3541
+ flex-shrink: 0;
3542
+ }
3543
+ .tab {
3544
+ flex: 1; padding: 10px 8px; border: none; background: none;
3545
+ cursor: pointer; font-size: 11px; font-weight: 600;
3546
+ text-transform: uppercase; letter-spacing: 0.05em;
3547
+ color: var(--me-grey-500); text-align: center;
3548
+ transition: all 150ms ease; border-bottom: 2px solid transparent;
3549
+ }
3550
+ .tab:hover { color: var(--me-grey-700); background: var(--me-grey-100); }
3551
+ .tab.active { color: var(--me-primary); border-bottom-color: var(--me-primary); }
3552
+
3553
+ /* ── Search ── */
3554
+ .search-wrap {
3555
+ padding: 10px 12px 6px;
3556
+ flex-shrink: 0;
3557
+ }
3558
+ .search-input {
3559
+ width: 100%;
3560
+ border: 1px solid var(--me-grey-200);
3561
+ border-radius: 8px;
3562
+ padding: 6px 10px 6px 30px;
3563
+ font-size: 12px;
3564
+ color: var(--me-grey-700);
3565
+ background: var(--me-grey-50) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") 10px center no-repeat;
3566
+ outline: none;
3567
+ transition: all 150ms ease;
3568
+ box-sizing: border-box;
3569
+ }
3570
+ .search-input::placeholder { color: var(--me-grey-400); }
3571
+ .search-input:focus {
3572
+ border-color: var(--me-primary);
3573
+ background-color: #fff;
3574
+ box-shadow: 0 0 0 2px rgba(93,118,139,0.15);
3575
+ }
3576
+
3577
+ /* ── Scrollable content ── */
3578
+ .tab-content {
3579
+ padding: 0 12px 16px;
3580
+ flex: 1;
3581
+ overflow-y: auto;
3582
+ }
3583
+
3584
+ /* ── Category groups ── */
3585
+ .category {
3586
+ margin-top: 12px;
3587
+ }
3588
+ .category-title {
3589
+ font-size: 10px;
3590
+ font-weight: 700;
3591
+ text-transform: uppercase;
3592
+ color: var(--me-blue-600);
3593
+ letter-spacing: 0.06em;
3594
+ margin: 0 0 6px 2px;
3595
+ padding: 4px 0;
3596
+ border-bottom: 1px solid var(--me-blue-50);
3597
+ }
3598
+
3599
+ /* ── Tool grid (2 columns) ── */
3600
+ .tool-grid {
3601
+ display: grid;
3602
+ grid-template-columns: 1fr 1fr;
3603
+ gap: 4px;
3604
+ }
3605
+ .tool-item {
3606
+ display: flex;
3607
+ flex-direction: row;
3608
+ align-items: center;
3609
+ gap: 6px;
3610
+ padding: 6px 8px;
3611
+ border: 1px solid transparent;
3612
+ border-radius: 8px;
3613
+ cursor: grab;
3614
+ background: transparent;
3615
+ transition: all 150ms ease;
3616
+ font-size: 11px;
3617
+ color: var(--me-grey-600);
3618
+ }
3619
+ .tool-item:hover {
3620
+ border-color: var(--me-grey-200);
3621
+ background: var(--me-grey-50);
3622
+ }
3623
+ .tool-item:hover .tool-icon { color: var(--me-primary); }
3624
+ .tool-item:active { cursor: grabbing; background: var(--me-primary-5); }
3625
+ .tool-icon {
3626
+ width: 18px; height: 18px;
3627
+ display: flex; align-items: center; justify-content: center;
3628
+ color: var(--me-grey-400);
3629
+ transition: color 150ms ease;
3630
+ flex-shrink: 0;
3631
+ }
3632
+ .tool-icon svg { width: 18px; height: 18px; }
3633
+
3634
+ /* ── Layout presets ── */
3635
+ .layout-section { margin-top: 14px; }
3636
+ .layout-grid {
3637
+ display: grid;
3638
+ grid-template-columns: 1fr 1fr 1fr;
3639
+ gap: 6px;
3640
+ }
3641
+ .layout-item {
3642
+ display: flex; align-items: center; justify-content: center;
3643
+ gap: 2px; padding: 8px 4px;
3644
+ border: 1px solid var(--me-grey-200); border-radius: 8px;
3645
+ cursor: pointer; background: white;
3646
+ transition: all 150ms ease;
3647
+ }
3648
+ .layout-item:hover { border-color: var(--me-primary); background: var(--me-primary-5); }
3649
+ .layout-item:hover .layout-col { background: var(--me-primary); }
3650
+ .layout-item:active { background: var(--me-primary-10); }
3651
+ .layout-col {
3652
+ height: 18px; background: var(--me-grey-300); border-radius: 2px;
3653
+ transition: background 150ms ease;
3654
+ }
3655
+
3656
+ /* ── A11y tab badge ── */
3657
+ .tab-badge {
3658
+ display: inline-flex;
3659
+ gap: 3px;
3660
+ margin-left: 4px;
3661
+ vertical-align: middle;
3662
+ }
3663
+ .tab-dot {
3664
+ width: 6px; height: 6px; border-radius: 50%;
3665
+ }
3666
+ .tab-dot.error { background: var(--me-danger); }
3667
+ .tab-dot.warning { background: var(--me-warning); }
3668
+ .tab-dot.info { background: var(--me-blue-600); }
3669
+
3670
+ /* ── No results ── */
3671
+ .no-results {
3672
+ text-align: center; color: var(--me-grey-400); font-size: 12px;
3673
+ padding: 24px 0;
3674
+ }
3675
+ `;
3676
+ le([
3677
+ x({ attribute: !1 })
3678
+ ], H.prototype, "store", 1);
3679
+ le([
3680
+ x({ attribute: !1 })
3681
+ ], H.prototype, "toolRegistry", 2);
3682
+ le([
3683
+ E()
3684
+ ], H.prototype, "searchQuery", 2);
3685
+ H = le([
3686
+ S("me-editor-sidebar")
3687
+ ], H);
3688
+ function Qt(e, t, o) {
3689
+ const r = e && /^#[0-9a-fA-F]{3,8}$/.test(e) ? e : "#000000";
3690
+ return d`
3691
+ <div class="prop-row">
3692
+ <label class="prop-label">${o}</label>
3693
+ <div class="prop-color">
3694
+ <input class="color-swatch" type="color" .value=${r}
3695
+ @input=${(i) => t(i.target.value)} />
3696
+ <input class="prop-input" type="text" .value=${e ?? ""} style="flex:1;"
3697
+ @change=${(i) => t(i.target.value)} />
3698
+ </div>
3699
+ </div>
3700
+ `;
3701
+ }
3702
+ function Yt(e, t, o, r) {
3703
+ const i = r?.options || [];
3704
+ return d`
3705
+ <div class="prop-row">
3706
+ <label class="prop-label">${o}</label>
3707
+ <select class="prop-input" @change=${(n) => t(n.target.value)}>
3708
+ ${i.map((n) => d`<option value=${n.value} ?selected=${e === n.value}>${n.label}</option>`)}
3709
+ </select>
3710
+ </div>
3711
+ `;
3712
+ }
3713
+ function Kt(e, t, o) {
3714
+ return d`
3715
+ <div class="prop-row">
3716
+ <label class="prop-label">${o}</label>
3717
+ <div style="display:flex;gap:2px;">
3718
+ ${["left", "center", "right"].map((r) => d`
3719
+ <button
3720
+ style="flex:1;padding:6px;border:1px solid ${e === r ? "#3b82f6" : "#d1d5db"};background:${e === r ? "#eff6ff" : "white"};border-radius:4px;cursor:pointer;font-size:11px;text-transform:capitalize;color:${e === r ? "#3b82f6" : "#6b7280"};"
3721
+ @click=${() => t(r)}
3722
+ >${r}</button>
3723
+ `)}
3724
+ </div>
3725
+ </div>
3726
+ `;
3727
+ }
3728
+ function Jt(e) {
3729
+ const t = (e || "0px").split(/\s+/).map((s) => parseInt(s) || 0), o = t[0], r = t[1] ?? o, i = t[2] ?? o, n = t[3] ?? r;
3730
+ return [o, r, i, n];
3731
+ }
3732
+ function Xt(e, t, o, r) {
3733
+ return e === t && t === o && o === r ? `${e}px` : e === o && t === r ? `${e}px ${t}px` : `${e}px ${t}px ${o}px ${r}px`;
3734
+ }
3735
+ function Zt(e, t, o) {
3736
+ const [r, i, n, s] = Jt(e), a = (l, u, h, g) => t(Xt(l, u, h, g));
3737
+ return d`
3738
+ <div class="prop-row">
3739
+ <label class="prop-label">${o}</label>
3740
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:4px;">
3741
+ ${[
3742
+ { label: "T", val: r, change: (l) => a(l, i, n, s) },
3743
+ { label: "R", val: i, change: (l) => a(r, l, n, s) },
3744
+ { label: "B", val: n, change: (l) => a(r, i, l, s) },
3745
+ { label: "L", val: s, change: (l) => a(r, i, n, l) }
3746
+ ].map((l) => d`
3747
+ <div style="display:flex;align-items:center;gap:4px;">
3748
+ <span style="font-size:10px;color:#9ca3af;width:12px;">${l.label}</span>
3749
+ <input type="number" .value=${l.val} min="0"
3750
+ @change=${(u) => l.change(parseInt(u.target.value) || 0)}
3751
+ style="flex:1;padding:4px 6px;border:1px solid #d1d5db;border-radius:3px;font-size:12px;width:50px;" />
3752
+ </div>
3753
+ `)}
3754
+ </div>
3755
+ </div>
3756
+ `;
3757
+ }
3758
+ function eo(e, t, o) {
3759
+ return d`
3760
+ <div class="prop-row">
3761
+ <div class="prop-toggle">
3762
+ <input type="checkbox" .checked=${!!e}
3763
+ @change=${(r) => t(r.target.checked)} />
3764
+ <label class="prop-label" style="margin:0;">${o}</label>
3765
+ </div>
3766
+ </div>
3767
+ `;
3768
+ }
3769
+ function to(e, t, o) {
3770
+ return d`
3771
+ <div class="prop-row">
3772
+ <label class="prop-label">${o}</label>
3773
+ <input class="prop-input" type="text" .value=${e ?? ""}
3774
+ @change=${(r) => t(r.target.value)} />
3775
+ </div>
3776
+ `;
3777
+ }
3778
+ function oo(e, t, o) {
3779
+ return d`
3780
+ <div class="prop-row">
3781
+ <label class="prop-label">${o}</label>
3782
+ <textarea class="prop-input"
3783
+ style="min-height:100px;font-family:'SF Mono',Menlo,monospace;font-size:12px;"
3784
+ .value=${e ?? ""}
3785
+ @change=${(r) => t(r.target.value)}
3786
+ ></textarea>
3787
+ </div>
3788
+ `;
3789
+ }
3790
+ function ro(e, t, o, r) {
3791
+ const i = r?.unit || "px", n = r?.min ?? 0, s = r?.max ?? 100, a = r?.step ?? 0.1, c = parseFloat(e) || 0, l = (u) => {
3792
+ const h = parseFloat(u.target.value) || 0;
3793
+ t(`${h}${i}`);
3794
+ };
3795
+ return d`
3796
+ <div class="prop-row">
3797
+ <label class="prop-label">${o}</label>
3798
+ <div style="display:flex;align-items:center;gap:4px;">
3799
+ <input
3800
+ type="number"
3801
+ .value=${String(c)}
3802
+ min=${n}
3803
+ max=${s}
3804
+ step=${a}
3805
+ @input=${l}
3806
+ style="flex:1;padding:6px 8px;border:1px solid #d1d5db;border-radius:4px;font-size:13px;color:#111827;"
3807
+ />
3808
+ <span style="font-size:12px;color:#9ca3af;min-width:20px;">${i}</span>
3809
+ </div>
3810
+ </div>
3811
+ `;
3812
+ }
3813
+ var io = Object.defineProperty, no = Object.getOwnPropertyDescriptor, we = (e, t, o, r) => {
3814
+ for (var i = r > 1 ? void 0 : r ? no(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3815
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3816
+ return r && i && io(t, o, i), i;
3817
+ };
3818
+ let q = class extends T {
3819
+ constructor() {
3820
+ super(...arguments), this.storeCtrl = new B(this, ["design", "selection"]);
3821
+ }
3822
+ set store(e) {
3823
+ this.storeCtrl.setStore(e);
3824
+ }
3825
+ get store() {
3826
+ return this.storeCtrl.store;
3827
+ }
3828
+ /** Create a change handler bound to a specific content ID and property key */
3829
+ onChange(e, t) {
3830
+ return (o) => {
3831
+ this.store.updateContentValues(e, { [t]: o });
3832
+ };
3833
+ }
3834
+ render() {
3835
+ const e = this.store.selectedId, t = e ? this.store.findContent(e) : void 0;
3836
+ if (this.classList.toggle("hidden", !t), !t)
3837
+ return d``;
3838
+ const o = this.toolRegistry.get(t.type);
3839
+ return o ? d`
3840
+ <div class="header">
3841
+ <p class="header-title">${o.label}</p>
3842
+ <p class="header-type">${t.type}</p>
3843
+ </div>
3844
+ ${Object.entries(o.options).map(([, r]) => this.renderGroup(t, r))}
3845
+ ` : d`<div class="no-selection">Unknown tool: ${t.type}</div>`;
3846
+ }
3847
+ renderGroup(e, t) {
3848
+ return d`
3849
+ <div class="group">
3850
+ <div class="group-title">${t.title}</div>
3851
+ <div class="group-body">
3852
+ ${Object.entries(t.options).map(
3853
+ ([o, r]) => this.renderWidget(e, o, r)
3854
+ )}
3855
+ </div>
3856
+ </div>
3857
+ `;
3858
+ }
3859
+ /** Delegate to the correct widget function based on the property's widget type */
3860
+ renderWidget(e, t, o) {
3861
+ const r = e.values[t] ?? o.defaultValue, i = this.onChange(e.id, t);
3862
+ switch (o.widget) {
3863
+ case "color_picker":
3864
+ return Qt(r, i, o.label);
3865
+ case "toggle":
3866
+ return eo(r, i, o.label);
3867
+ case "rich_text":
3868
+ return oo(r, i, o.label);
3869
+ case "dropdown":
3870
+ return Yt(r, i, o.label, o.widgetParams);
3871
+ case "alignment":
3872
+ return Kt(r, i, o.label);
3873
+ case "padding":
3874
+ return Zt(r, i, o.label);
3875
+ case "number_unit":
3876
+ return ro(r, i, o.label, o.widgetParams);
3877
+ case "text":
3878
+ default:
3879
+ return to(r, i, o.label);
3880
+ }
3881
+ }
3882
+ };
3883
+ q.styles = _`
3884
+ :host {
3885
+ display: flex; flex-direction: column; width: 280px; min-width: 280px;
3886
+ background: #fff; border-left: 1px solid var(--me-grey-100);
3887
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
3888
+ overflow-y: auto;
3889
+ transition: width 200ms ease, min-width 200ms ease, opacity 200ms ease;
3890
+ }
3891
+ :host(.hidden) {
3892
+ width: 0; min-width: 0; opacity: 0; overflow: hidden; border-left: none;
3893
+ }
3894
+
3895
+ /* ── Panel header ── */
3896
+ .header {
3897
+ padding: 10px 12px; border-bottom: 1px solid var(--me-grey-100); background: #fff;
3898
+ flex-shrink: 0;
3899
+ }
3900
+ .header-title {
3901
+ font-size: 12px; font-weight: 700; color: var(--me-grey-900); margin: 0;
3902
+ }
3903
+ .header-type {
3904
+ font-size: 10px; color: var(--me-grey-400); text-transform: uppercase;
3905
+ letter-spacing: 0.03em; margin: 2px 0 0 0;
3906
+ }
3907
+
3908
+ /* ── Empty state ── */
3909
+ .no-selection {
3910
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
3911
+ flex: 1; color: var(--me-grey-400); font-size: 12px; gap: 8px; padding: 40px 16px; text-align: center;
3912
+ }
3913
+
3914
+ /* ── Property groups ── */
3915
+ .group { padding: 0 12px 4px; }
3916
+ .group-title {
3917
+ padding: 8px 0 4px; font-size: 10px; font-weight: 700; color: var(--me-blue-600);
3918
+ cursor: default; user-select: none;
3919
+ display: flex; align-items: center; justify-content: space-between;
3920
+ text-transform: uppercase; letter-spacing: 0.06em;
3921
+ border-bottom: 1px solid var(--me-blue-50);
3922
+ margin-bottom: 8px;
3923
+ }
3924
+ .group-body { display: flex; flex-direction: column; gap: 8px; padding-bottom: 4px; }
3925
+
3926
+ /* ── Property rows ── */
3927
+ .prop-row { margin-bottom: 0; display: flex; flex-direction: column; gap: 4px; }
3928
+ .prop-label {
3929
+ display: block; font-size: 11px; font-weight: 500; color: var(--me-grey-600);
3930
+ letter-spacing: 0.01em;
3931
+ }
3932
+
3933
+ /* ── Inputs & selects ── */
3934
+ .prop-input {
3935
+ width: 100%; padding: 6px 10px; border: 1px solid var(--me-grey-200); border-radius: 8px;
3936
+ font-size: 12px; color: var(--me-grey-700); background: #fff; box-sizing: border-box;
3937
+ transition: border-color 150ms ease, box-shadow 150ms ease;
3938
+ }
3939
+ .prop-input:focus {
3940
+ outline: none; border-color: var(--me-primary);
3941
+ box-shadow: 0 0 0 2px var(--me-primary-30);
3942
+ }
3943
+ select.prop-input {
3944
+ appearance: none; padding-right: 28px;
3945
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
3946
+ background-repeat: no-repeat; background-position: right 8px center;
3947
+ }
3948
+ textarea.prop-input { min-height: 80px; resize: vertical; font-family: monospace; }
3949
+
3950
+ /* ── Toggle ── */
3951
+ .prop-toggle { display: flex; align-items: center; gap: 8px; }
3952
+
3953
+ /* ── Color picker ── */
3954
+ .prop-color { display: flex; align-items: center; gap: 8px; }
3955
+ .color-swatch {
3956
+ width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--me-grey-200);
3957
+ cursor: pointer; padding: 0; transition: border-color 150ms ease;
3958
+ }
3959
+ .color-swatch:hover { border-color: var(--me-primary); }
3960
+ `;
3961
+ we([
3962
+ x({ attribute: !1 })
3963
+ ], q.prototype, "store", 1);
3964
+ we([
3965
+ x({ attribute: !1 })
3966
+ ], q.prototype, "toolRegistry", 2);
3967
+ q = we([
3968
+ S("me-property-panel")
3969
+ ], q);
3970
+ var so = Object.defineProperty, ao = Object.getOwnPropertyDescriptor, Q = (e, t, o, r) => {
3971
+ for (var i = r > 1 ? void 0 : r ? ao(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3972
+ (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3973
+ return r && i && so(t, o, i), i;
3974
+ };
3975
+ let P = class extends T {
3976
+ constructor() {
3977
+ super(...arguments), this.options = {}, this.store = new Ze(), this.toolRegistry = new et(), this.dragManager = null, this.callbacks = /* @__PURE__ */ new Map(), this.unsubscribe = null, this.sidebarCollapsed = !1, this.a11yHasErrors = !1, this.a11yHasWarnings = !1, this.a11yHasInfos = !1, this.a11yDebounceTimer = null, this._handleKeydown = (e) => {
3978
+ const t = e.metaKey || e.ctrlKey, r = e.composedPath().some((i) => {
3979
+ const n = i, s = n?.tagName;
3980
+ return !!(s === "INPUT" || s === "TEXTAREA" || s === "SELECT" || n?.isContentEditable);
3981
+ });
3982
+ r && !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 && !r ? (e.preventDefault(), this.store.removeContent(this.store.selectedId)) : e.key === "Escape" && this.store.select(null));
3983
+ };
3984
+ }
3985
+ updateA11yState() {
3986
+ this.a11yDebounceTimer && clearTimeout(this.a11yDebounceTimer), this.a11yDebounceTimer = setTimeout(() => {
3987
+ const e = ve(this.store);
3988
+ this.a11yHasErrors = e.some((o) => o.severity === "error"), this.a11yHasWarnings = e.some((o) => o.severity === "warning"), this.a11yHasInfos = e.some((o) => o.severity === "info");
3989
+ const t = /* @__PURE__ */ new Set();
3990
+ for (const o of e)
3991
+ o.elementId && (o.severity === "error" || o.severity === "warning") && t.add(o.elementId);
3992
+ this.store.setA11yIssueIds(t);
3993
+ }, 300);
3994
+ }
3995
+ toggleSidebar() {
3996
+ this.sidebarCollapsed = !this.sidebarCollapsed, this.shadowRoot?.querySelector("me-editor-sidebar")?.classList.toggle("collapsed", this.sidebarCollapsed);
3997
+ }
3998
+ connectedCallback() {
3999
+ super.connectedCallback(), this.registerBuiltInTools(), this.applyOptions(), this.setAttribute("tabindex", "0"), this.addEventListener("keydown", this._handleKeydown);
4000
+ }
4001
+ firstUpdated() {
4002
+ this.dragManager = new tt(this.store, this.toolRegistry, this.shadowRoot), this.dragManager.attach(), this.store.events.on("design:loaded", (e) => {
4003
+ this.dispatchEvent(new CustomEvent("design:loaded", { detail: e, bubbles: !0, composed: !0 }));
4004
+ }), this.store.events.on("design:updated", (e) => {
4005
+ this.dispatchEvent(new CustomEvent("design:updated", { detail: e, bubbles: !0, composed: !0 }));
4006
+ }), this.unsubscribe = this.store.subscribeChannels(["design"], () => this.updateA11yState()), this.updateA11yState(), this.dispatchEvent(new CustomEvent("editor:ready", { bubbles: !0, composed: !0 })), this.preloadLazyTools();
4007
+ }
4008
+ disconnectedCallback() {
4009
+ super.disconnectedCallback(), this.dragManager?.detach(), this.unsubscribe?.(), this.store.events.removeAllListeners(), this.removeEventListener("keydown", this._handleKeydown);
4010
+ }
4011
+ // ----------------------------------------------------------
4012
+ // Public API — public API
4013
+ // ----------------------------------------------------------
4014
+ loadDesign(e) {
4015
+ this.store.loadDesign(e);
4016
+ }
4017
+ /** Load an Unlayer design JSON, converting it to Emabuild format */
4018
+ loadUnlayerDesign(e) {
4019
+ this.store.loadDesign(Pt(e));
4020
+ }
4021
+ saveDesign(e) {
4022
+ e(structuredClone(this.store.getDesign()));
4023
+ }
4024
+ /** Save the design as Unlayer-compatible JSON */
4025
+ saveUnlayerDesign(e) {
4026
+ e(Et(this.store.getDesign()));
4027
+ }
4028
+ exportHtml(e, t) {
4029
+ const o = this.store.getDesign(), r = /* @__PURE__ */ new Set();
4030
+ for (const n of o.body.rows)
4031
+ for (const s of n.columns)
4032
+ for (const a of s.contents)
4033
+ r.add(a.type);
4034
+ const i = Array.from(r).filter((n) => !this.toolRegistry.isLoaded(n)).map((n) => this.toolRegistry.ensureLoaded(n));
4035
+ i.length > 0 ? Promise.all(i).then(() => this.doExport(o, e, t)) : this.doExport(o, e, t);
4036
+ }
4037
+ doExport(e, t, o) {
4038
+ const r = /* @__PURE__ */ new Map();
4039
+ for (const i of this.toolRegistry.getAll())
4040
+ r.set(i.name, (n, s) => i.renderer.renderHtml(n, s));
4041
+ t(It(e, r, o));
4042
+ }
4043
+ async exportHtmlAsync(e) {
4044
+ return new Promise((t) => this.exportHtml(t, e));
4045
+ }
4046
+ registerTool(e) {
4047
+ this.toolRegistry.register(e), this.requestUpdate();
4048
+ }
4049
+ registerPropertyEditor(e, t) {
4050
+ }
4051
+ registerTab(e) {
4052
+ }
4053
+ registerCallback(e, t) {
4054
+ this.callbacks.set(e, t);
4055
+ }
4056
+ setMergeTags(e) {
4057
+ this.store.setMergeTags(e);
4058
+ }
4059
+ undo() {
4060
+ this.store.undo();
4061
+ }
4062
+ redo() {
4063
+ this.store.redo();
4064
+ }
4065
+ setBodyValues(e) {
4066
+ this.store.updateBodyValues(e);
4067
+ }
4068
+ // ----------------------------------------------------------
4069
+ // Internal
4070
+ // ----------------------------------------------------------
4071
+ /**
4072
+ * Preload lazy tools during browser idle time.
4073
+ * Uses requestIdleCallback to avoid blocking the main thread.
4074
+ * Falls back to setTimeout(1000) for browsers without idle callback support.
4075
+ */
4076
+ preloadLazyTools() {
4077
+ const e = window.requestIdleCallback ?? ((t) => setTimeout(t, 1e3));
4078
+ for (const { meta: t } of Ee)
4079
+ e(() => {
4080
+ this.toolRegistry.ensureLoaded(t.name);
4081
+ });
4082
+ }
4083
+ registerBuiltInTools() {
4084
+ for (const e of bt)
4085
+ this.toolRegistry.register(e);
4086
+ for (const { meta: e, loader: t } of Ee)
4087
+ this.toolRegistry.registerLazy(e, t);
4088
+ }
4089
+ applyOptions() {
4090
+ if (this.options.design && this.store.loadDesign(this.options.design), this.options.mergeTags) {
4091
+ const e = this.options.mergeTags, t = Array.isArray(e) ? e : Object.values(e);
4092
+ this.store.setMergeTags(t);
4093
+ }
4094
+ }
4095
+ render() {
4096
+ return d`
4097
+ <me-editor-sidebar
4098
+ .store=${this.store}
4099
+ .toolRegistry=${this.toolRegistry}
4100
+ ></me-editor-sidebar>
4101
+ <button class="sidebar-toggle ${this.sidebarCollapsed ? "collapsed" : ""}"
4102
+ @click=${this.toggleSidebar}
4103
+ title="${this.sidebarCollapsed ? "Show tools" : "Hide tools"}"
4104
+ style="left:${this.sidebarCollapsed ? "10px" : "290px"}">
4105
+ ${this.sidebarCollapsed ? d`<svg viewBox="0 0 24 24"><path d="M13 18l-6-6 6-6"/><path d="M19 18l-6-6 6-6"/></svg>` : d`<svg viewBox="0 0 24 24"><path d="M15 18l-6-6 6-6"/></svg>`}
4106
+ </button>
4107
+ ${this.sidebarCollapsed && (this.a11yHasErrors || this.a11yHasWarnings || this.a11yHasInfos) ? d`
4108
+ <div class="a11y-dots">
4109
+ ${this.a11yHasErrors ? d`<div class="a11y-dot error"></div>` : v}
4110
+ ${this.a11yHasWarnings ? d`<div class="a11y-dot warning"></div>` : v}
4111
+ ${this.a11yHasInfos ? d`<div class="a11y-dot info"></div>` : v}
4112
+ </div>
4113
+ ` : v}
4114
+ <me-editor-canvas
4115
+ .store=${this.store}
4116
+ .toolRegistry=${this.toolRegistry}
4117
+ ></me-editor-canvas>
4118
+ <me-property-panel
4119
+ .store=${this.store}
4120
+ .toolRegistry=${this.toolRegistry}
4121
+ ></me-property-panel>
4122
+ `;
4123
+ }
4124
+ };
4125
+ P.styles = _`
4126
+ :host {
4127
+ /* ── Design tokens ── */
4128
+ --me-primary: #5d768b;
4129
+ --me-primary-dark: #4a6070;
4130
+ --me-primary-5: rgba(93,118,139,0.05);
4131
+ --me-primary-10: rgba(93,118,139,0.1);
4132
+ --me-primary-30: rgba(93,118,139,0.3);
4133
+
4134
+ --me-grey-900: #111827;
4135
+ --me-grey-700: #374151;
4136
+ --me-grey-600: #4b5563;
4137
+ --me-grey-500: #6b7280;
4138
+ --me-grey-400: #9ca3af;
4139
+ --me-grey-300: #d1d5db;
4140
+ --me-grey-200: #e5e7eb;
4141
+ --me-grey-100: #f3f4f6;
4142
+ --me-grey-50: #f9fafb;
4143
+
4144
+ --me-blue-50: #EDF5FF;
4145
+ --me-blue-600: #245A7F;
4146
+
4147
+ --me-danger: #dc2626;
4148
+ --me-warning: #d97706;
4149
+ --me-success: #16a34a;
4150
+
4151
+ --me-radius-sm: 6px;
4152
+ --me-radius: 8px;
4153
+ --me-radius-lg: 10px;
4154
+
4155
+ --me-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4156
+ --me-transition: 150ms ease;
4157
+
4158
+ /* ── Layout ── */
4159
+ display: flex;
4160
+ width: 100%;
4161
+ height: 100%;
4162
+ flex: 1;
4163
+ min-height: 500px;
4164
+ font-family: var(--me-font);
4165
+ color: var(--me-grey-900);
4166
+ box-sizing: border-box;
4167
+ overflow: hidden;
4168
+ position: relative;
4169
+ }
4170
+ * { box-sizing: border-box; }
4171
+ .sidebar-toggle {
4172
+ position: absolute;
4173
+ top: 50%;
4174
+ transform: translateY(-50%);
4175
+ left: 10px;
4176
+ width: 28px;
4177
+ height: 28px;
4178
+ border-radius: var(--me-radius);
4179
+ border: 1px solid var(--me-grey-200);
4180
+ background: white;
4181
+ cursor: pointer;
4182
+ display: flex;
4183
+ align-items: center;
4184
+ justify-content: center;
4185
+ z-index: 40;
4186
+ box-shadow: 0 1px 4px rgba(0,0,0,0.08);
4187
+ transition: all var(--me-transition);
4188
+ padding: 0;
4189
+ color: var(--me-grey-500);
4190
+ }
4191
+ .sidebar-toggle:hover {
4192
+ background: var(--me-grey-50);
4193
+ color: var(--me-primary);
4194
+ box-shadow: 0 2px 8px rgba(0,0,0,0.12);
4195
+ }
4196
+ .sidebar-toggle svg {
4197
+ width: 14px;
4198
+ height: 14px;
4199
+ stroke: currentColor;
4200
+ fill: none;
4201
+ stroke-width: 2;
4202
+ stroke-linecap: round;
4203
+ stroke-linejoin: round;
4204
+ transition: transform 200ms ease;
4205
+ }
4206
+ .sidebar-toggle.collapsed {
4207
+ width: 20px;
4208
+ height: 20px;
4209
+ border: none;
4210
+ background: transparent;
4211
+ box-shadow: none;
4212
+ color: var(--me-primary);
4213
+ animation: pulse-hint 2s ease-in-out infinite;
4214
+ }
4215
+ .sidebar-toggle.collapsed:hover {
4216
+ background: transparent;
4217
+ color: var(--me-primary-dark);
4218
+ animation: none;
4219
+ transform: translateY(-50%) scale(1.2);
4220
+ }
4221
+ .sidebar-toggle.collapsed svg {
4222
+ width: 22px;
4223
+ height: 22px;
4224
+ transform: rotate(180deg);
4225
+ }
4226
+ @keyframes pulse-hint {
4227
+ 0%, 100% { opacity: 0.5; }
4228
+ 50% { opacity: 1; }
4229
+ }
4230
+
4231
+ /* ── A11y dots when sidebar collapsed ── */
4232
+ .a11y-dots {
4233
+ position: absolute;
4234
+ left: 14px;
4235
+ top: calc(50% + 18px);
4236
+ display: flex;
4237
+ flex-direction: column;
4238
+ gap: 6px;
4239
+ z-index: 40;
4240
+ }
4241
+ .a11y-dot {
4242
+ width: 8px; height: 8px; border-radius: 50%;
4243
+ }
4244
+ .a11y-dot.error { background: #dc2626; animation: pulse-e 1.8s ease-in-out infinite; }
4245
+ .a11y-dot.warning { background: #d97706; animation: pulse-w 2.3s ease-in-out infinite; }
4246
+ .a11y-dot.info { background: #5d768b; animation: pulse-i 2.7s ease-in-out infinite; }
4247
+ @keyframes pulse-e {
4248
+ 0%, 100% { opacity: 0.4; transform: scale(0.85); }
4249
+ 50% { opacity: 1; transform: scale(1.1); }
4250
+ }
4251
+ @keyframes pulse-w {
4252
+ 0%, 100% { opacity: 0.35; transform: scale(0.9); }
4253
+ 60% { opacity: 1; transform: scale(1.15); }
4254
+ }
4255
+ @keyframes pulse-i {
4256
+ 0%, 100% { opacity: 0.3; transform: scale(0.9); }
4257
+ 40% { opacity: 0.9; transform: scale(1.05); }
4258
+ }
4259
+ `;
4260
+ Q([
4261
+ x({ type: Object })
4262
+ ], P.prototype, "options", 2);
4263
+ Q([
4264
+ E()
4265
+ ], P.prototype, "sidebarCollapsed", 2);
4266
+ Q([
4267
+ E()
4268
+ ], P.prototype, "a11yHasErrors", 2);
4269
+ Q([
4270
+ E()
4271
+ ], P.prototype, "a11yHasWarnings", 2);
4272
+ Q([
4273
+ E()
4274
+ ], P.prototype, "a11yHasInfos", 2);
4275
+ P = Q([
4276
+ S("mail-editor")
4277
+ ], P);
4278
+ function R(e, t) {
4279
+ customElements.get(e) || customElements.define(e, t);
4280
+ }
4281
+ R("mail-editor", P);
4282
+ R("me-editor-canvas", L);
4283
+ R("me-row-renderer", j);
4284
+ R("me-column-renderer", z);
4285
+ R("me-content-renderer", M);
4286
+ R("me-editor-sidebar", H);
4287
+ R("me-body-settings", K);
4288
+ R("me-property-panel", q);
4289
+ R("me-inline-toolbar", O);
4290
+ R("me-a11y-checker", U);
4291
+ const bo = customElements.get("mail-editor") !== void 0;
4292
+ export {
4293
+ bo as E,
4294
+ P as M,
4295
+ et as T,
4296
+ Ze as a,
4297
+ N as e,
4298
+ Pt as f,
4299
+ fo as j,
4300
+ p as s,
4301
+ Et as t
4302
+ };
4303
+ //# sourceMappingURL=index-zy5NbC2E.js.map