@emabuild/core 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/canvas/column-renderer.d.ts.map +1 -1
  2. package/dist/canvas/content-renderer.d.ts.map +1 -1
  3. package/dist/canvas/editor-canvas.d.ts +2 -0
  4. package/dist/canvas/editor-canvas.d.ts.map +1 -1
  5. package/dist/canvas/row-renderer.d.ts.map +1 -1
  6. package/dist/{form-tool-C7760Hvm.js → form-tool-a_WVnfC2.js} +2 -2
  7. package/dist/{form-tool-C7760Hvm.js.map → form-tool-a_WVnfC2.js.map} +1 -1
  8. package/dist/{html-tool-4zZO2hqE.js → html-tool-RhawxTfJ.js} +2 -2
  9. package/dist/{html-tool-4zZO2hqE.js.map → html-tool-RhawxTfJ.js.map} +1 -1
  10. package/dist/{index-zy5NbC2E.js → index-CLXq1CZC.js} +336 -203
  11. package/dist/index-CLXq1CZC.js.map +1 -0
  12. package/dist/index.js +1 -1
  13. package/dist/mail-editor.d.ts.map +1 -1
  14. package/dist/{menu-tool-Cu5D_VYs.js → menu-tool-BkQwnMyx.js} +2 -2
  15. package/dist/{menu-tool-Cu5D_VYs.js.map → menu-tool-BkQwnMyx.js.map} +1 -1
  16. package/dist/properties/property-panel.d.ts.map +1 -1
  17. package/dist/properties/widgets/image-upload-widget.d.ts +4 -0
  18. package/dist/properties/widgets/image-upload-widget.d.ts.map +1 -0
  19. package/dist/properties/widgets/index.d.ts +1 -0
  20. package/dist/properties/widgets/index.d.ts.map +1 -1
  21. package/dist/sidebar/editor-sidebar.d.ts.map +1 -1
  22. package/dist/{social-tool-kPuP-4n6.js → social-tool-CUjd50d7.js} +2 -2
  23. package/dist/{social-tool-kPuP-4n6.js.map → social-tool-CUjd50d7.js.map} +1 -1
  24. package/dist/state/editor-store.d.ts +6 -1
  25. package/dist/state/editor-store.d.ts.map +1 -1
  26. package/dist/{table-tool-CcWFvTSc.js → table-tool-Bi0-Rvry.js} +2 -2
  27. package/dist/{table-tool-CcWFvTSc.js.map → table-tool-Bi0-Rvry.js.map} +1 -1
  28. package/dist/{timer-tool-CG1oul_Z.js → timer-tool-CwBZNCmI.js} +2 -2
  29. package/dist/{timer-tool-CG1oul_Z.js.map → timer-tool-CwBZNCmI.js.map} +1 -1
  30. package/dist/tools/built-in/button-tool.d.ts.map +1 -1
  31. package/dist/{video-tool-CttMka8Z.js → video-tool-C8evvYgp.js} +2 -2
  32. package/dist/{video-tool-CttMka8Z.js.map → video-tool-C8evvYgp.js.map} +1 -1
  33. package/package.json +26 -13
  34. package/dist/index-zy5NbC2E.js.map +0 -1
@@ -1,6 +1,6 @@
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";
1
+ import { css as _, LitElement as T, nothing as x, html as d } from "lit";
2
+ import { property as v, customElement as S, state as E } from "lit/decorators.js";
3
+ import { unsafeHTML as J } from "lit/directives/unsafe-html.js";
4
4
  import { styleMap as He } from "lit/directives/style-map.js";
5
5
  import { repeat as ye } from "lit/directives/repeat.js";
6
6
  class B {
@@ -67,17 +67,17 @@ function V(e, t) {
67
67
  const i = $e(o.r, o.g, o.b), n = $e(r.r, r.g, r.b);
68
68
  return (Math.max(i, n) + 0.05) / (Math.min(i, n) + 0.05);
69
69
  }
70
- function Le(e) {
70
+ function ze(e) {
71
71
  if (typeof e != "string") return !1;
72
72
  const t = e.trim().toLowerCase();
73
73
  return t !== "" && t !== "transparent" && t !== "none" && t !== "inherit";
74
74
  }
75
75
  function Ce(...e) {
76
76
  for (const t of e)
77
- if (Le(t)) return t;
77
+ if (ze(t)) return t;
78
78
  return "#ffffff";
79
79
  }
80
- function te(e, t = 0) {
80
+ function oe(e, t = 0) {
81
81
  return typeof e == "number" ? e : typeof e == "string" && parseInt(e, 10) || t;
82
82
  }
83
83
  function Ue(e) {
@@ -122,10 +122,10 @@ let U = class extends T {
122
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
123
  return d`
124
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}
125
+ ${t.length > 0 ? d`<span class="score-pill errors"><span class="score-dot error"></span>${t.length}</span>` : x}
126
+ ${o.length > 0 ? d`<span class="score-pill warnings"><span class="score-dot warning"></span>${o.length}</span>` : x}
127
+ ${r.length > 0 ? d`<span class="score-pill infos"><span class="score-dot info"></span>${r.length}</span>` : x}
128
+ ${t.length === 0 && o.length === 0 ? d`<span class="score-pill pass"><span class="score-dot pass"></span>Pass</span>` : x}
129
129
  </div>
130
130
 
131
131
  ${e.length === 0 ? d`
@@ -138,15 +138,15 @@ let U = class extends T {
138
138
  ${t.length > 0 ? d`
139
139
  <div class="section-title">Errors</div>
140
140
  <div class="issues-list">${t.map((i) => this.renderIssue(i))}</div>
141
- ` : v}
141
+ ` : x}
142
142
  ${o.length > 0 ? d`
143
143
  <div class="section-title">Warnings</div>
144
144
  <div class="issues-list">${o.map((i) => this.renderIssue(i))}</div>
145
- ` : v}
145
+ ` : x}
146
146
  ${r.length > 0 ? d`
147
147
  <div class="section-title">Info</div>
148
148
  <div class="issues-list">${r.map((i) => this.renderIssue(i))}</div>
149
- ` : v}
149
+ ` : x}
150
150
  `}
151
151
  `;
152
152
  }
@@ -162,9 +162,9 @@ let U = class extends T {
162
162
  <div class="issue-body">
163
163
  <div class="issue-rule">${e.rule}</div>
164
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}
165
+ ${e.element ? d`<div class="issue-element">${e.element}</div>` : x}
166
+ ${e.rule === "heading-structure" ? d`<button class="issue-fix" @click=${this.handleFixHeading}>+ Add heading</button>` : x}
167
+ ${e.rule === "preheader" ? d`<button class="issue-fix" @click=${this.handleFixPreheader}>Fix</button>` : x}
168
168
  </div>
169
169
  </div>
170
170
  `;
@@ -274,10 +274,10 @@ U.styles = _`
274
274
  .all-clear-sub { font-size: 11px; color: #9ca3af; margin-top: 4px; }
275
275
  `;
276
276
  xe([
277
- x({ attribute: !1 })
277
+ v({ attribute: !1 })
278
278
  ], U.prototype, "store", 1);
279
279
  xe([
280
- x({ attribute: !1 })
280
+ v({ attribute: !1 })
281
281
  ], U.prototype, "toolRegistry", 2);
282
282
  U = xe([
283
283
  S("me-a11y-checker")
@@ -297,23 +297,23 @@ function ve(e) {
297
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
298
  }
299
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);
300
+ const C = ze(f.color) ? f.color : n, A = Ce(f.backgroundColor, $), I = V(C, A);
301
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;
302
+ const Q = oe(f.fontSize, 14), Oe = ["700", "800", "900"].includes(f.fontWeight || ""), ke = Q >= 18 || Q >= 14 && Oe ? 3 : 4.5;
303
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
304
  }
305
- const W = te(f.fontSize, 14);
305
+ const W = oe(f.fontSize, 14);
306
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 });
307
+ const te = Ue(f.lineHeight);
308
+ te !== null && te < 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
309
  }
310
310
  if (y === "button") {
311
311
  const C = f.backgroundColor || "#3b82f6", A = f.textColor || "#ffffff", I = V(A, C);
312
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
313
  const W = V(C, $);
314
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 });
315
+ const te = (f.buttonPadding || "10px 20px").split(/\s+/), Q = oe(f.fontSize, 14) + oe(te[0], 10) * 2;
316
+ Q < 44 && t.push({ severity: "info", rule: "touch-target", message: `Button height ~${Q}px (min 44px).`, element: w, elementId: m.id });
317
317
  }
318
318
  if (y === "heading" && (s = !0, a.push(f.headingType || "h1")), y === "text" || y === "paragraph") {
319
319
  const C = f.text || "", A = C.match(/<a[^>]*>(\s|&nbsp;)*<\/a>/gi);
@@ -422,7 +422,7 @@ class Ge {
422
422
  this.undoStack = [], this.redoStack = [];
423
423
  }
424
424
  }
425
- function Qe() {
425
+ function Ye() {
426
426
  return {
427
427
  counters: { u_row: 0, u_column: 0 },
428
428
  body: {
@@ -467,7 +467,7 @@ function Qe() {
467
467
  schemaVersion: 16
468
468
  };
469
469
  }
470
- function Ye(e, t) {
470
+ function Qe(e, t) {
471
471
  const o = e.next("u_row"), r = t.map(() => {
472
472
  const i = e.next("u_column");
473
473
  return {
@@ -519,13 +519,13 @@ function Ke(e, t, o = {}) {
519
519
  function de(e, t) {
520
520
  return e.body.rows.find((o) => o.id === t);
521
521
  }
522
- function oe(e, t) {
522
+ function re(e, t) {
523
523
  for (const o of e.body.rows) {
524
524
  const r = o.columns.find((i) => i.id === t);
525
525
  if (r) return r;
526
526
  }
527
527
  }
528
- function re(e, t) {
528
+ function ie(e, t) {
529
529
  for (const o of e.body.rows)
530
530
  for (const r of o.columns) {
531
531
  const i = r.contents.find((n) => n.id === t);
@@ -546,7 +546,13 @@ function ce(e, t) {
546
546
  }
547
547
  class Ze {
548
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();
549
+ this.history = new Ge(), this.counterManager = qe(), this.channelSubscribers = /* @__PURE__ */ new Map(), this.events = new Ne(), this._mergeTags = [], this._callbacks = /* @__PURE__ */ new Map(), this._a11yIssueIds = /* @__PURE__ */ new Set(), this._selectedId = null, this._hoveredId = null, this._viewMode = "desktop", this._activeTab = "content", this.pendingChannels = /* @__PURE__ */ new Set(), this.rafId = null, this.design = Ye();
550
+ }
551
+ setCallback(t, o) {
552
+ this._callbacks.set(t, o);
553
+ }
554
+ getCallback(t) {
555
+ return this._callbacks.get(t);
550
556
  }
551
557
  get a11yIssueIds() {
552
558
  return this._a11yIssueIds;
@@ -582,14 +588,18 @@ class Ze {
582
588
  const o = ["design", "selection", "hover", "viewMode", "activeTab"];
583
589
  return this.subscribeChannels(o, t);
584
590
  }
585
- /** Notify only subscribers of specific channels */
586
591
  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();
592
+ for (const o of t) this.pendingChannels.add(o);
593
+ this.rafId === null && (this.rafId = requestAnimationFrame(() => {
594
+ this.rafId = null;
595
+ const o = /* @__PURE__ */ new Set();
596
+ for (const r of this.pendingChannels) {
597
+ const i = this.channelSubscribers.get(r);
598
+ if (i) for (const n of i) o.add(n);
599
+ }
600
+ this.pendingChannels.clear();
601
+ for (const r of o) r();
602
+ }));
593
603
  }
594
604
  // ── Getters ────────────────────────────────────────────────
595
605
  /** Get the full design document */
@@ -651,7 +661,9 @@ class Ze {
651
661
  this._selectedId = t, this.notifyChannels("selection");
652
662
  }
653
663
  hover(t) {
654
- this._hoveredId = t, this.notifyChannels("hover");
664
+ this._hoveredId = t;
665
+ const o = this.channelSubscribers.get("hover");
666
+ if (o) for (const r of o) r();
655
667
  }
656
668
  setViewMode(t) {
657
669
  this._viewMode = t, this.notifyChannels("viewMode");
@@ -710,13 +722,13 @@ class Ze {
710
722
  // ── Column Operations ──────────────────────────────────────
711
723
  /** Update column-level values. Returns true if updated. */
712
724
  updateColumnValues(t, o) {
713
- const r = oe(this.design, t);
725
+ const r = re(this.design, t);
714
726
  return r ? (this.history.push(this.design), Object.assign(r.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"), !0) : !1;
715
727
  }
716
728
  // ── Content Operations ─────────────────────────────────────
717
729
  /** Add content to a column at the given index. Returns the inserted content. */
718
730
  addContent(t, o, r) {
719
- const i = oe(this.design, t);
731
+ const i = re(this.design, t);
720
732
  if (!i) return;
721
733
  const n = structuredClone(o);
722
734
  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;
@@ -733,13 +745,13 @@ class Ze {
733
745
  }
734
746
  /** Update content values by ID. Returns true if updated. */
735
747
  updateContentValues(t, o) {
736
- const r = re(this.design, t);
748
+ const r = ie(this.design, t);
737
749
  return r ? (this.history.push(this.design), Object.assign(r.values, o), this.notifyChannels("design"), this.emitUpdate("content_updated"), !0) : !1;
738
750
  }
739
751
  /** Move a content block to a different column at a given index. Returns true if moved. */
740
752
  moveContent(t, o, r) {
741
- if (!re(this.design, t)) return !1;
742
- const n = oe(this.design, o);
753
+ if (!ie(this.design, t)) return !1;
754
+ const n = re(this.design, o);
743
755
  if (!n) return !1;
744
756
  this.history.push(this.design);
745
757
  let s;
@@ -757,7 +769,7 @@ class Ze {
757
769
  }
758
770
  /** Duplicate a content block, inserting the copy right after the original */
759
771
  duplicateContent(t) {
760
- const o = re(this.design, t);
772
+ const o = ie(this.design, t);
761
773
  if (o)
762
774
  for (const r of this.design.body.rows)
763
775
  for (const i of r.columns) {
@@ -779,10 +791,10 @@ class Ze {
779
791
  return de(this.design, t);
780
792
  }
781
793
  findColumn(t) {
782
- return oe(this.design, t);
794
+ return re(this.design, t);
783
795
  }
784
796
  findContent(t) {
785
- return re(this.design, t);
797
+ return ie(this.design, t);
786
798
  }
787
799
  findParentColumn(t) {
788
800
  return Je(this.design, t);
@@ -793,7 +805,7 @@ class Ze {
793
805
  // ── Factory Methods (delegate to design-factory) ───────────
794
806
  /** Create a new row with the given column layout */
795
807
  createRow(t) {
796
- const o = Ye(this.counterManager, t);
808
+ const o = Qe(this.counterManager, t);
797
809
  return this.syncCounters(), o;
798
810
  }
799
811
  /** Create a new content block for the given tool type */
@@ -1165,7 +1177,7 @@ function Pe(e) {
1165
1177
  color: p(e, "textColor", "#ffffff")
1166
1178
  };
1167
1179
  }
1168
- function fo(e, t) {
1180
+ function bo(e, t) {
1169
1181
  if (typeof e != "string") return t;
1170
1182
  try {
1171
1183
  return JSON.parse(e);
@@ -1297,7 +1309,7 @@ const it = [
1297
1309
  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
1310
  return d`
1299
1311
  <div style="background-color:${t};color:${o};line-height:${r};text-align:${i};font-family:${n};">
1300
- ${ie(s)}
1312
+ ${J(s)}
1301
1313
  </div>
1302
1314
  `;
1303
1315
  },
@@ -1377,7 +1389,7 @@ const it = [
1377
1389
  letterSpacing: p(e, "letterSpacing", "normal"),
1378
1390
  fontFamily: be(e)
1379
1391
  }, o = De(e, "Heading");
1380
- return d`<div style=${He(t)}>${ie(o)}</div>`;
1392
+ return d`<div style=${He(t)}>${J(o)}</div>`;
1381
1393
  },
1382
1394
  renderHtml(e) {
1383
1395
  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}>`;
@@ -1423,7 +1435,7 @@ const it = [
1423
1435
  renderer: {
1424
1436
  renderEditor(e) {
1425
1437
  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>`;
1438
+ return d`<div style="color:${t};line-height:${o};text-align:${r};">${J(p(e, "text"))}</div>`;
1427
1439
  },
1428
1440
  renderHtml(e) {
1429
1441
  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>`;
@@ -1440,7 +1452,7 @@ const it = [
1440
1452
  image: {
1441
1453
  title: "Image",
1442
1454
  options: {
1443
- src: { label: "Image URL", defaultValue: "", widget: "text" },
1455
+ src: { label: "Image URL", defaultValue: "", widget: "image_upload" },
1444
1456
  alt: { label: "Alt Text", defaultValue: "", widget: "text" },
1445
1457
  href: { label: "Link URL", defaultValue: "", widget: "text" },
1446
1458
  target: { label: "Link Target", defaultValue: "_blank", widget: "text" }
@@ -1560,7 +1572,7 @@ const it = [
1560
1572
  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
1573
  return d`
1562
1574
  <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>
1575
+ <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;">${J(a)}</a>
1564
1576
  </div>
1565
1577
  `;
1566
1578
  },
@@ -1631,31 +1643,31 @@ const it = [
1631
1643
  ], Ee = [
1632
1644
  {
1633
1645
  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)
1646
+ loader: () => import("./html-tool-RhawxTfJ.js").then((e) => e.htmlTool)
1635
1647
  },
1636
1648
  {
1637
1649
  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)
1650
+ loader: () => import("./social-tool-CUjd50d7.js").then((e) => e.socialTool)
1639
1651
  },
1640
1652
  {
1641
1653
  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)
1654
+ loader: () => import("./menu-tool-BkQwnMyx.js").then((e) => e.menuTool)
1643
1655
  },
1644
1656
  {
1645
1657
  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)
1658
+ loader: () => import("./video-tool-C8evvYgp.js").then((e) => e.videoTool)
1647
1659
  },
1648
1660
  {
1649
1661
  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)
1662
+ loader: () => import("./timer-tool-CwBZNCmI.js").then((e) => e.timerTool)
1651
1663
  },
1652
1664
  {
1653
1665
  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)
1666
+ loader: () => import("./table-tool-Bi0-Rvry.js").then((e) => e.tableTool)
1655
1667
  },
1656
1668
  {
1657
1669
  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)
1670
+ loader: () => import("./form-tool-a_WVnfC2.js").then((e) => e.formTool)
1659
1671
  }
1660
1672
  ];
1661
1673
  function mt(e, t, o) {
@@ -2077,12 +2089,12 @@ function At(...e) {
2077
2089
  }
2078
2090
  return t;
2079
2091
  }
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--)
2092
+ var Mt = Object.defineProperty, Lt = Object.getOwnPropertyDescriptor, se = (e, t, o, r) => {
2093
+ for (var i = r > 1 ? void 0 : r ? Lt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2082
2094
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2083
2095
  return r && i && Mt(t, o, i), i;
2084
2096
  };
2085
- let O = class extends T {
2097
+ let j = class extends T {
2086
2098
  constructor() {
2087
2099
  super(...arguments), this.visible = !1, this.mergeTags = [], this.mergeDropdownOpen = !1, this._outsideClickHandler = (e) => {
2088
2100
  if (!this.mergeDropdownOpen) return;
@@ -2179,14 +2191,14 @@ let O = class extends T {
2179
2191
  `)}
2180
2192
  `)}
2181
2193
  </div>
2182
- ` : v}
2194
+ ` : x}
2183
2195
  </div>
2184
- ` : v}
2196
+ ` : x}
2185
2197
  </div>
2186
2198
  `;
2187
2199
  }
2188
2200
  };
2189
- O.styles = _`
2201
+ j.styles = _`
2190
2202
  :host {
2191
2203
  position: fixed;
2192
2204
  z-index: 10000;
@@ -2286,21 +2298,21 @@ O.styles = _`
2286
2298
  }
2287
2299
  `;
2288
2300
  se([
2289
- x({ type: Boolean })
2290
- ], O.prototype, "visible", 2);
2301
+ v({ type: Boolean })
2302
+ ], j.prototype, "visible", 2);
2291
2303
  se([
2292
- x({ attribute: !1 })
2293
- ], O.prototype, "mergeTags", 2);
2304
+ v({ attribute: !1 })
2305
+ ], j.prototype, "mergeTags", 2);
2294
2306
  se([
2295
2307
  E()
2296
- ], O.prototype, "mergeDropdownOpen", 2);
2297
- O = se([
2308
+ ], j.prototype, "mergeDropdownOpen", 2);
2309
+ j = se([
2298
2310
  S("me-inline-toolbar")
2299
- ], O);
2300
- var Lt = Object.defineProperty, Bt = Object.getOwnPropertyDescriptor, J = (e, t, o, r) => {
2311
+ ], j);
2312
+ var zt = Object.defineProperty, Bt = Object.getOwnPropertyDescriptor, X = (e, t, o, r) => {
2301
2313
  for (var i = r > 1 ? void 0 : r ? Bt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2302
2314
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2303
- return r && i && Lt(t, o, i), i;
2315
+ return r && i && zt(t, o, i), i;
2304
2316
  };
2305
2317
  const Ae = /* @__PURE__ */ new Set(["text", "heading", "paragraph"]);
2306
2318
  function Me(e) {
@@ -2344,17 +2356,27 @@ let M = class extends T {
2344
2356
  this.classList.remove("hovered"), this.store.hover(null);
2345
2357
  }
2346
2358
  handleDelete(e) {
2347
- e.stopPropagation(), this.store.removeContent(this.content.id);
2359
+ e.stopPropagation(), this.classList.add("removing");
2360
+ const t = this.content.id;
2361
+ this.addEventListener("animationend", () => this.store.removeContent(t), { once: !0 });
2348
2362
  }
2349
2363
  handleDuplicate(e) {
2350
- e.stopPropagation(), this.store.duplicateContent(this.content.id);
2364
+ e.stopPropagation();
2365
+ const t = this.store.duplicateContent(this.content.id);
2366
+ t && requestAnimationFrame(() => {
2367
+ const o = this.parentElement;
2368
+ if (o?.shadowRoot) {
2369
+ const r = o.shadowRoot.querySelector(`[data-content-id="${t.id}"]`);
2370
+ r?.classList.add("just-duplicated"), setTimeout(() => r?.classList.remove("just-duplicated"), 600);
2371
+ }
2372
+ });
2351
2373
  }
2352
2374
  /** Called from the drag handle only (not the whole block) */
2353
2375
  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);
2376
+ e.stopPropagation(), e.dataTransfer.setData("application/maileditor-content", this.content.id), e.dataTransfer.effectAllowed = "move", this.style.opacity = "0.4", this.style.transform = "scale(0.97)", D.startContentDrag(this.content.id, this);
2355
2377
  }
2356
2378
  handleDragEnd() {
2357
- D.reset();
2379
+ this.style.transform = "", D.reset();
2358
2380
  }
2359
2381
  // ── Inline editing ───────────────────────────────────────
2360
2382
  startEditing() {
@@ -2392,7 +2414,7 @@ let M = class extends T {
2392
2414
  }
2393
2415
  // ── Lifecycle ────────────────────────────────────────────
2394
2416
  connectedCallback() {
2395
- super.connectedCallback(), this.store && (this.hoverUnsub = this.store.subscribeChannels(["hover"], () => {
2417
+ super.connectedCallback(), this.classList.add("just-dropped"), setTimeout(() => this.classList.remove("just-dropped"), 400), this.store && (this.hoverUnsub = this.store.subscribeChannels(["hover"], () => {
2396
2418
  this.store.hoveredId === this.content?.id ? this.classList.add("hovered") : this.matches(":hover") || this.classList.remove("hovered");
2397
2419
  }));
2398
2420
  }
@@ -2428,7 +2450,7 @@ let M = class extends T {
2428
2450
  ${l}
2429
2451
  <div class="action-bar">
2430
2452
  <span class="action-bar-label">${this.content.type}</span>
2431
- <button class="action-btn" @click=${this.handleDuplicate} title="Duplicate">&#9851;</button>
2453
+ <button class="action-btn" @click=${this.handleDuplicate} title="Duplicate">&#10697;</button>
2432
2454
  <button class="action-btn" @click=${this.handleDelete} title="Delete">&#10005;</button>
2433
2455
  </div>
2434
2456
  <div class="content-wrapper" style="padding:${h};"
@@ -2484,6 +2506,20 @@ M.styles = _`
2484
2506
  :host(.just-dropped) {
2485
2507
  animation: dropIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
2486
2508
  }
2509
+ :host(.just-duplicated) {
2510
+ animation: duplicateFlash 0.5s ease-out;
2511
+ }
2512
+ @keyframes duplicateFlash {
2513
+ 0% { background: var(--me-primary-10, rgba(93,118,139,0.1)); transform: scale(1.01); }
2514
+ 100% { background: transparent; transform: scale(1); }
2515
+ }
2516
+ :host(.removing) {
2517
+ animation: fadeRemove 0.25s ease-out forwards;
2518
+ pointer-events: none;
2519
+ }
2520
+ @keyframes fadeRemove {
2521
+ to { opacity: 0; transform: scale(0.96) translateY(-4px); height: 0; margin: 0; padding: 0; overflow: hidden; }
2522
+ }
2487
2523
  :host(.hidden-in-view) { opacity: 0.3; position: relative; }
2488
2524
  .hidden-badge {
2489
2525
  position: absolute; top: 4px; right: 4px; z-index: 5;
@@ -2553,27 +2589,27 @@ M.styles = _`
2553
2589
  }
2554
2590
  .inline-editable:focus { outline: none; }
2555
2591
  `;
2556
- J([
2557
- x({ attribute: !1 })
2592
+ X([
2593
+ v({ attribute: !1 })
2558
2594
  ], M.prototype, "content", 2);
2559
- J([
2560
- x({ attribute: !1 })
2595
+ X([
2596
+ v({ attribute: !1 })
2561
2597
  ], M.prototype, "store", 1);
2562
- J([
2563
- x({ attribute: !1 })
2598
+ X([
2599
+ v({ attribute: !1 })
2564
2600
  ], M.prototype, "toolRegistry", 2);
2565
- J([
2601
+ X([
2566
2602
  E()
2567
2603
  ], M.prototype, "editing", 2);
2568
- M = J([
2604
+ M = X([
2569
2605
  S("me-content-renderer")
2570
2606
  ], 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--)
2607
+ var Wt = Object.defineProperty, jt = Object.getOwnPropertyDescriptor, Z = (e, t, o, r) => {
2608
+ for (var i = r > 1 ? void 0 : r ? jt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2573
2609
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2574
2610
  return r && i && Wt(t, o, i), i;
2575
2611
  };
2576
- let z = class extends T {
2612
+ let L = class extends T {
2577
2613
  constructor() {
2578
2614
  super(...arguments), this.storeCtrl = new B(this, ["design"]), this.widthPercent = 100;
2579
2615
  }
@@ -2600,7 +2636,7 @@ let z = class extends T {
2600
2636
  `;
2601
2637
  }
2602
2638
  };
2603
- z.styles = _`
2639
+ L.styles = _`
2604
2640
  :host {
2605
2641
  display: block;
2606
2642
  min-height: 40px;
@@ -2611,12 +2647,17 @@ z.styles = _`
2611
2647
  align-items: center;
2612
2648
  justify-content: center;
2613
2649
  min-height: 60px;
2614
- border: 2px dashed #d1d5db;
2615
- border-radius: 4px;
2616
- color: #9ca3af;
2617
- font-size: 13px;
2650
+ border: 2px dashed var(--me-grey-300, #d1d5db);
2651
+ border-radius: 8px;
2652
+ color: var(--me-grey-400, #9ca3af);
2653
+ font-size: 12px;
2618
2654
  font-family: sans-serif;
2619
2655
  margin: 4px;
2656
+ animation: emptyBreath 3s ease-in-out infinite;
2657
+ }
2658
+ @keyframes emptyBreath {
2659
+ 0%, 100% { border-color: var(--me-grey-300, #d1d5db); opacity: 0.6; }
2660
+ 50% { border-color: var(--me-primary, #5d768b); opacity: 1; }
2620
2661
  }
2621
2662
  .drop-indicator {
2622
2663
  height: 3px;
@@ -2630,32 +2671,32 @@ z.styles = _`
2630
2671
  opacity: 1;
2631
2672
  }
2632
2673
  `;
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([
2674
+ Z([
2675
+ v({ attribute: !1 })
2676
+ ], L.prototype, "column", 2);
2677
+ Z([
2678
+ v({ attribute: !1 })
2679
+ ], L.prototype, "store", 1);
2680
+ Z([
2681
+ v({ attribute: !1 })
2682
+ ], L.prototype, "toolRegistry", 2);
2683
+ Z([
2684
+ v({ type: Number })
2685
+ ], L.prototype, "widthPercent", 2);
2686
+ L = Z([
2646
2687
  S("me-column-renderer")
2647
- ], z);
2648
- var jt = Object.defineProperty, Ht = Object.getOwnPropertyDescriptor, ae = (e, t, o, r) => {
2688
+ ], L);
2689
+ var Ot = Object.defineProperty, Ht = Object.getOwnPropertyDescriptor, ae = (e, t, o, r) => {
2649
2690
  for (var i = r > 1 ? void 0 : r ? Ht(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2650
2691
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2651
- return r && i && jt(t, o, i), i;
2692
+ return r && i && Ot(t, o, i), i;
2652
2693
  };
2653
- let j = class extends T {
2694
+ let O = class extends T {
2654
2695
  constructor() {
2655
2696
  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);
2697
+ e.stopPropagation(), e.dataTransfer.setData("application/maileditor-row", this.row.id), e.dataTransfer.effectAllowed = "move", this.style.opacity = "0.4", this.style.transform = "scale(0.98)", D.startRowDrag(this.row.id, this);
2657
2698
  }, this.handleDragEnd = () => {
2658
- D.reset();
2699
+ this.style.transform = "", D.reset();
2659
2700
  };
2660
2701
  }
2661
2702
  set store(e) {
@@ -2678,7 +2719,9 @@ let j = class extends T {
2678
2719
  e.stopPropagation(), this.store.duplicateRow(this.row.id);
2679
2720
  }
2680
2721
  handleDelete(e) {
2681
- e.stopPropagation(), this.store.removeRow(this.row.id);
2722
+ e.stopPropagation(), this.classList.add("removing");
2723
+ const t = this.row.id;
2724
+ this.addEventListener("animationend", () => this.store.removeRow(t), { once: !0 });
2682
2725
  }
2683
2726
  render() {
2684
2727
  if (!this.store) return d``;
@@ -2736,13 +2779,20 @@ let j = class extends T {
2736
2779
  `;
2737
2780
  }
2738
2781
  };
2739
- j.styles = _`
2782
+ O.styles = _`
2740
2783
  :host {
2741
2784
  display: block;
2742
2785
  position: relative;
2743
- transition: opacity 0.2s ease;
2786
+ transition: opacity 0.2s ease, transform 0.25s ease;
2744
2787
  }
2745
2788
  :host(.hidden-in-view) { opacity: 0.3; }
2789
+ :host(.removing) {
2790
+ animation: rowRemove 0.25s ease-out forwards;
2791
+ pointer-events: none;
2792
+ }
2793
+ @keyframes rowRemove {
2794
+ to { opacity: 0; transform: scaleY(0.8); height: 0; margin: 0; overflow: hidden; }
2795
+ }
2746
2796
  .row-hidden-badge {
2747
2797
  position: absolute; top: 4px; left: 4px; z-index: 5;
2748
2798
  background: #f59e0b; color: white; font-size: 10px; font-weight: 600;
@@ -2850,23 +2900,23 @@ j.styles = _`
2850
2900
  }
2851
2901
  `;
2852
2902
  ae([
2853
- x({ attribute: !1 })
2854
- ], j.prototype, "row", 2);
2903
+ v({ attribute: !1 })
2904
+ ], O.prototype, "row", 2);
2855
2905
  ae([
2856
- x({ attribute: !1 })
2857
- ], j.prototype, "store", 1);
2906
+ v({ attribute: !1 })
2907
+ ], O.prototype, "store", 1);
2858
2908
  ae([
2859
- x({ attribute: !1 })
2860
- ], j.prototype, "toolRegistry", 2);
2861
- j = ae([
2909
+ v({ attribute: !1 })
2910
+ ], O.prototype, "toolRegistry", 2);
2911
+ O = ae([
2862
2912
  S("me-row-renderer")
2863
- ], j);
2864
- var Vt = Object.defineProperty, Ft = Object.getOwnPropertyDescriptor, Z = (e, t, o, r) => {
2913
+ ], O);
2914
+ var Vt = Object.defineProperty, Ft = Object.getOwnPropertyDescriptor, ee = (e, t, o, r) => {
2865
2915
  for (var i = r > 1 ? void 0 : r ? Ft(t, o) : t, n = e.length - 1, s; n >= 0; n--)
2866
2916
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
2867
2917
  return r && i && Vt(t, o, i), i;
2868
2918
  };
2869
- let L = class extends T {
2919
+ let z = class extends T {
2870
2920
  constructor() {
2871
2921
  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
2922
  }
@@ -2885,6 +2935,11 @@ let L = class extends T {
2885
2935
  handleCanvasClick() {
2886
2936
  this.store.select(null);
2887
2937
  }
2938
+ /** Flash the canvas border to confirm undo/redo */
2939
+ flashUndo() {
2940
+ const e = this.shadowRoot?.querySelector(".canvas-body");
2941
+ e && (e.classList.add("undo-flash"), e.addEventListener("animationend", () => e.classList.remove("undo-flash"), { once: !0 }));
2942
+ }
2888
2943
  setViewMode(e) {
2889
2944
  this.store.setViewMode(e);
2890
2945
  }
@@ -2989,8 +3044,19 @@ let L = class extends T {
2989
3044
  >
2990
3045
  ${e.length === 0 ? d`
2991
3046
  <div class="empty-canvas">
2992
- <div class="empty-icon">&#9776;</div>
2993
- <div>Drag a content block here</div>
3047
+ <div class="empty-icon">
3048
+ <svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
3049
+ </div>
3050
+ <div class="empty-title">Start building your email</div>
3051
+ <div class="empty-sub">Drag elements from the sidebar, use the + button, or start with a template</div>
3052
+ <div class="empty-actions">
3053
+ <button class="empty-action primary" @click=${() => this.quickAddTool("heading", 0)}>Add Heading</button>
3054
+ <button class="empty-action" @click=${() => this.quickAddTool("text", 0)}>Add Text</button>
3055
+ <button class="empty-action" @click=${() => this.quickAddLayout([1, 1], 0)}>2 Columns</button>
3056
+ </div>
3057
+ <div class="empty-shortcut">
3058
+ <kbd>Ctrl</kbd>+<kbd>Z</kbd> undo · <kbd>Ctrl</kbd>+<kbd>D</kbd> duplicate · <kbd>Del</kbd> remove
3059
+ </div>
2994
3060
  </div>
2995
3061
  ${this.renderRowGap(0)}
2996
3062
  ` : d`
@@ -3010,7 +3076,7 @@ let L = class extends T {
3010
3076
  `;
3011
3077
  }
3012
3078
  };
3013
- L.styles = _`
3079
+ z.styles = _`
3014
3080
  :host {
3015
3081
  display: block;
3016
3082
  flex: 1;
@@ -3027,21 +3093,48 @@ L.styles = _`
3027
3093
  background: #ffffff;
3028
3094
  min-height: 200px;
3029
3095
  position: relative;
3096
+ transition: max-width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
3097
+ }
3098
+ .canvas-body.undo-flash {
3099
+ animation: undoFlash 0.3s ease-out;
3100
+ }
3101
+ @keyframes undoFlash {
3102
+ 0% { box-shadow: inset 0 0 0 2px var(--me-primary-30, rgba(93,118,139,0.3)); }
3103
+ 100% { box-shadow: none; }
3030
3104
  }
3031
3105
  .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;
3106
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
3107
+ min-height: 300px; color: var(--me-grey-400); font-family: sans-serif; gap: 12px;
3108
+ padding: 40px 20px; text-align: center;
3041
3109
  }
3042
3110
  .empty-icon {
3043
- font-size: 40px;
3044
- opacity: 0.4;
3111
+ width: 56px; height: 56px; border-radius: 50%;
3112
+ background: var(--me-primary-5, rgba(93,118,139,0.05));
3113
+ display: flex; align-items: center; justify-content: center;
3114
+ animation: emptyPulse 3s ease-in-out infinite;
3115
+ }
3116
+ .empty-icon svg { width: 24px; height: 24px; stroke: var(--me-primary); fill: none; stroke-width: 1.5; }
3117
+ @keyframes emptyPulse {
3118
+ 0%, 100% { opacity: 0.6; transform: scale(0.95); }
3119
+ 50% { opacity: 1; transform: scale(1); }
3120
+ }
3121
+ .empty-title { font-size: 14px; font-weight: 600; color: var(--me-grey-600); }
3122
+ .empty-sub { font-size: 12px; color: var(--me-grey-400); max-width: 240px; line-height: 1.5; }
3123
+ .empty-actions { display: flex; gap: 8px; margin-top: 8px; }
3124
+ .empty-action {
3125
+ padding: 6px 14px; border-radius: var(--me-radius, 8px); border: 1px solid var(--me-grey-200);
3126
+ background: white; color: var(--me-grey-600); font-size: 11px; font-weight: 600;
3127
+ cursor: pointer; transition: all var(--me-transition, 150ms ease); font-family: sans-serif;
3128
+ }
3129
+ .empty-action:hover { border-color: var(--me-primary); color: var(--me-primary); background: var(--me-primary-5); }
3130
+ .empty-action.primary { background: var(--me-primary); color: white; border-color: var(--me-primary); }
3131
+ .empty-action.primary:hover { background: var(--me-primary-dark, #4a6070); }
3132
+ .empty-shortcut {
3133
+ font-size: 10px; color: var(--me-grey-300); margin-top: 12px; font-family: sans-serif;
3134
+ }
3135
+ .empty-shortcut kbd {
3136
+ background: var(--me-grey-100); border: 1px solid var(--me-grey-200);
3137
+ border-radius: 3px; padding: 1px 4px; font-size: 10px; font-family: monospace;
3045
3138
  }
3046
3139
  .view-toggle {
3047
3140
  display: flex;
@@ -3190,22 +3283,22 @@ L.styles = _`
3190
3283
  background: var(--me-primary);
3191
3284
  }
3192
3285
  `;
3193
- Z([
3194
- x({ attribute: !1 })
3195
- ], L.prototype, "store", 1);
3196
- Z([
3197
- x({ attribute: !1 })
3198
- ], L.prototype, "toolRegistry", 2);
3199
- Z([
3286
+ ee([
3287
+ v({ attribute: !1 })
3288
+ ], z.prototype, "store", 1);
3289
+ ee([
3290
+ v({ attribute: !1 })
3291
+ ], z.prototype, "toolRegistry", 2);
3292
+ ee([
3200
3293
  E()
3201
- ], L.prototype, "quickAddIndex", 2);
3202
- Z([
3294
+ ], z.prototype, "quickAddIndex", 2);
3295
+ ee([
3203
3296
  E()
3204
- ], L.prototype, "quickAddPos", 2);
3205
- L = Z([
3297
+ ], z.prototype, "quickAddPos", 2);
3298
+ z = ee([
3206
3299
  S("me-editor-canvas")
3207
- ], L);
3208
- var Ut = Object.defineProperty, qt = Object.getOwnPropertyDescriptor, Oe = (e, t, o, r) => {
3300
+ ], z);
3301
+ var Ut = Object.defineProperty, qt = Object.getOwnPropertyDescriptor, je = (e, t, o, r) => {
3209
3302
  for (var i = r > 1 ? void 0 : r ? qt(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3210
3303
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3211
3304
  return r && i && Ut(t, o, i), i;
@@ -3365,10 +3458,10 @@ K.styles = _`
3365
3458
  50% { box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.2); }
3366
3459
  }
3367
3460
  `;
3368
- Oe([
3369
- x({ attribute: !1 })
3461
+ je([
3462
+ v({ attribute: !1 })
3370
3463
  ], K.prototype, "store", 1);
3371
- K = Oe([
3464
+ K = je([
3372
3465
  S("me-body-settings")
3373
3466
  ], K);
3374
3467
  var Nt = Object.defineProperty, Gt = Object.getOwnPropertyDescriptor, le = (e, t, o, r) => {
@@ -3376,7 +3469,7 @@ var Nt = Object.defineProperty, Gt = Object.getOwnPropertyDescriptor, le = (e, t
3376
3469
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3377
3470
  return r && i && Nt(t, o, i), i;
3378
3471
  };
3379
- const ze = {
3472
+ const Le = {
3380
3473
  text: { label: "Text", tools: ["text", "heading", "paragraph"] },
3381
3474
  media: { label: "Media", tools: ["image", "video"] },
3382
3475
  actions: { label: "Actions", tools: ["button", "social", "menu"] },
@@ -3432,10 +3525,10 @@ let H = class extends T {
3432
3525
  for (const l of e) o.set(l.name, l);
3433
3526
  const r = (l) => !t || l.label.toLowerCase().includes(t) || l.name.toLowerCase().includes(t);
3434
3527
  let i = !1;
3435
- const n = Object.entries(ze).map(([, l]) => {
3528
+ const n = Object.entries(Le).map(([, l]) => {
3436
3529
  const u = l.tools.map((h) => o.get(h)).filter((h) => !!h && r(h));
3437
3530
  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));
3531
+ }), s = new Set(Object.values(Le).flatMap((l) => l.tools)), a = e.filter((l) => !s.has(l.name) && r(l));
3439
3532
  a.length > 0 && (i = !0);
3440
3533
  const c = !t || "layout".includes(t) || "row".includes(t) || "column".includes(t);
3441
3534
  return d`
@@ -3451,7 +3544,7 @@ let H = class extends T {
3451
3544
  </div>
3452
3545
  <div class="tab-content">
3453
3546
  ${n.map(
3454
- (l) => l.tools.length === 0 ? v : d`
3547
+ (l) => l.tools.length === 0 ? x : d`
3455
3548
  <div class="category">
3456
3549
  <div class="category-title">${l.label}</div>
3457
3550
  <div class="tool-grid">
@@ -3489,14 +3582,14 @@ let H = class extends T {
3489
3582
  }
3490
3583
  renderA11yBadge() {
3491
3584
  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>`;
3585
+ return !e && !t && !o ? x : d`<span class="tab-badge">${e ? d`<span class="tab-dot error"></span>` : x}${t ? d`<span class="tab-dot warning"></span>` : x}${o ? d`<span class="tab-dot info"></span>` : x}</span>`;
3493
3586
  }
3494
3587
  renderToolItem(e) {
3495
3588
  return d`
3496
3589
  <div class="tool-item"
3497
3590
  draggable="true"
3498
3591
  @dragstart=${(t) => this.handleDragStart(t, e.name)}>
3499
- <div class="tool-icon">${ie(e.icon)}</div>
3592
+ <div class="tool-icon">${J(e.icon)}</div>
3500
3593
  <span>${e.label}</span>
3501
3594
  </div>
3502
3595
  `;
@@ -3579,6 +3672,11 @@ H.styles = _`
3579
3672
  padding: 0 12px 16px;
3580
3673
  flex: 1;
3581
3674
  overflow-y: auto;
3675
+ animation: tabFadeIn 0.2s ease-out;
3676
+ }
3677
+ @keyframes tabFadeIn {
3678
+ from { opacity: 0; transform: translateY(4px); }
3679
+ to { opacity: 1; transform: translateY(0); }
3582
3680
  }
3583
3681
 
3584
3682
  /* ── Category groups ── */
@@ -3674,10 +3772,10 @@ H.styles = _`
3674
3772
  }
3675
3773
  `;
3676
3774
  le([
3677
- x({ attribute: !1 })
3775
+ v({ attribute: !1 })
3678
3776
  ], H.prototype, "store", 1);
3679
3777
  le([
3680
- x({ attribute: !1 })
3778
+ v({ attribute: !1 })
3681
3779
  ], H.prototype, "toolRegistry", 2);
3682
3780
  le([
3683
3781
  E()
@@ -3685,7 +3783,7 @@ le([
3685
3783
  H = le([
3686
3784
  S("me-editor-sidebar")
3687
3785
  ], H);
3688
- function Qt(e, t, o) {
3786
+ function Yt(e, t, o) {
3689
3787
  const r = e && /^#[0-9a-fA-F]{3,8}$/.test(e) ? e : "#000000";
3690
3788
  return d`
3691
3789
  <div class="prop-row">
@@ -3699,7 +3797,7 @@ function Qt(e, t, o) {
3699
3797
  </div>
3700
3798
  `;
3701
3799
  }
3702
- function Yt(e, t, o, r) {
3800
+ function Qt(e, t, o, r) {
3703
3801
  const i = r?.options || [];
3704
3802
  return d`
3705
3803
  <div class="prop-row">
@@ -3810,10 +3908,41 @@ function ro(e, t, o, r) {
3810
3908
  </div>
3811
3909
  `;
3812
3910
  }
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--)
3911
+ function io(e, t, o, r) {
3912
+ const i = () => {
3913
+ r && r({
3914
+ done: (n) => {
3915
+ n?.url && t(n.url);
3916
+ }
3917
+ });
3918
+ };
3919
+ return d`
3920
+ <div class="prop-row">
3921
+ <label class="prop-label">${o}</label>
3922
+ ${e ? d`
3923
+ <div style="margin-bottom:6px;border-radius:6px;overflow:hidden;border:1px solid var(--me-grey-200,#e5e7eb);background:var(--me-grey-50,#f9fafb);">
3924
+ <img src=${e} alt="Preview" style="display:block;width:100%;max-height:120px;object-fit:cover;" />
3925
+ </div>
3926
+ ` : x}
3927
+ <div style="display:flex;gap:4px;">
3928
+ <input class="prop-input" type="text" .value=${e ?? ""} placeholder="https://..."
3929
+ style="flex:1;${r ? "border-radius:8px 0 0 8px;" : ""}"
3930
+ @change=${(n) => t(n.target.value)} />
3931
+ ${r ? d`
3932
+ <button @click=${i}
3933
+ style="padding:0 10px;border:1px solid var(--me-grey-200,#e5e7eb);border-left:none;border-radius:0 8px 8px 0;background:var(--me-grey-50,#f9fafb);cursor:pointer;color:var(--me-grey-600,#4b5563);font-size:11px;font-weight:600;transition:all 150ms ease;white-space:nowrap;"
3934
+ title="Upload image">
3935
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle;"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
3936
+ </button>
3937
+ ` : x}
3938
+ </div>
3939
+ </div>
3940
+ `;
3941
+ }
3942
+ var no = Object.defineProperty, so = Object.getOwnPropertyDescriptor, we = (e, t, o, r) => {
3943
+ for (var i = r > 1 ? void 0 : r ? so(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3815
3944
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3816
- return r && i && io(t, o, i), i;
3945
+ return r && i && no(t, o, i), i;
3817
3946
  };
3818
3947
  let q = class extends T {
3819
3948
  constructor() {
@@ -3861,19 +3990,21 @@ let q = class extends T {
3861
3990
  const r = e.values[t] ?? o.defaultValue, i = this.onChange(e.id, t);
3862
3991
  switch (o.widget) {
3863
3992
  case "color_picker":
3864
- return Qt(r, i, o.label);
3993
+ return Yt(r, i, o.label);
3865
3994
  case "toggle":
3866
3995
  return eo(r, i, o.label);
3867
3996
  case "rich_text":
3868
3997
  return oo(r, i, o.label);
3869
3998
  case "dropdown":
3870
- return Yt(r, i, o.label, o.widgetParams);
3999
+ return Qt(r, i, o.label, o.widgetParams);
3871
4000
  case "alignment":
3872
4001
  return Kt(r, i, o.label);
3873
4002
  case "padding":
3874
4003
  return Zt(r, i, o.label);
3875
4004
  case "number_unit":
3876
4005
  return ro(r, i, o.label, o.widgetParams);
4006
+ case "image_upload":
4007
+ return io(r, i, o.label, this.store.getCallback("image"));
3877
4008
  case "text":
3878
4009
  default:
3879
4010
  return to(r, i, o.label);
@@ -3959,27 +4090,29 @@ q.styles = _`
3959
4090
  .color-swatch:hover { border-color: var(--me-primary); }
3960
4091
  `;
3961
4092
  we([
3962
- x({ attribute: !1 })
4093
+ v({ attribute: !1 })
3963
4094
  ], q.prototype, "store", 1);
3964
4095
  we([
3965
- x({ attribute: !1 })
4096
+ v({ attribute: !1 })
3966
4097
  ], q.prototype, "toolRegistry", 2);
3967
4098
  q = we([
3968
4099
  S("me-property-panel")
3969
4100
  ], 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--)
4101
+ var ao = Object.defineProperty, lo = Object.getOwnPropertyDescriptor, Y = (e, t, o, r) => {
4102
+ for (var i = r > 1 ? void 0 : r ? lo(t, o) : t, n = e.length - 1, s; n >= 0; n--)
3972
4103
  (s = e[n]) && (i = (r ? s(t, o, i) : s(i)) || i);
3973
- return r && i && so(t, o, i), i;
4104
+ return r && i && ao(t, o, i), i;
3974
4105
  };
3975
4106
  let P = class extends T {
3976
4107
  constructor() {
3977
4108
  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);
4109
+ const t = e.metaKey || e.ctrlKey, r = e.composedPath().some((n) => {
4110
+ const s = n, a = s?.tagName;
4111
+ return !!(a === "INPUT" || a === "TEXTAREA" || a === "SELECT" || s?.isContentEditable);
3981
4112
  });
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));
4113
+ if (r && !t) return;
4114
+ const i = this.shadowRoot?.querySelector("me-editor-canvas");
4115
+ t && e.key === "z" && !e.shiftKey ? (e.preventDefault(), this.store.undo(), i?.flashUndo?.()) : t && (e.key === "y" || e.key === "z" && e.shiftKey) ? (e.preventDefault(), this.store.redo(), i?.flashUndo?.()) : t && e.key === "d" && !e.shiftKey && this.store.selectedId && !r ? (e.preventDefault(), this.store.duplicateContent(this.store.selectedId)) : (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
4116
  };
3984
4117
  }
3985
4118
  updateA11yState() {
@@ -4051,7 +4184,7 @@ let P = class extends T {
4051
4184
  registerTab(e) {
4052
4185
  }
4053
4186
  registerCallback(e, t) {
4054
- this.callbacks.set(e, t);
4187
+ this.callbacks.set(e, t), this.store.setCallback(e, t);
4055
4188
  }
4056
4189
  setMergeTags(e) {
4057
4190
  this.store.setMergeTags(e);
@@ -4106,11 +4239,11 @@ let P = class extends T {
4106
4239
  </button>
4107
4240
  ${this.sidebarCollapsed && (this.a11yHasErrors || this.a11yHasWarnings || this.a11yHasInfos) ? d`
4108
4241
  <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}
4242
+ ${this.a11yHasErrors ? d`<div class="a11y-dot error"></div>` : x}
4243
+ ${this.a11yHasWarnings ? d`<div class="a11y-dot warning"></div>` : x}
4244
+ ${this.a11yHasInfos ? d`<div class="a11y-dot info"></div>` : x}
4112
4245
  </div>
4113
- ` : v}
4246
+ ` : x}
4114
4247
  <me-editor-canvas
4115
4248
  .store=${this.store}
4116
4249
  .toolRegistry=${this.toolRegistry}
@@ -4257,47 +4390,47 @@ P.styles = _`
4257
4390
  40% { opacity: 0.9; transform: scale(1.05); }
4258
4391
  }
4259
4392
  `;
4260
- Q([
4261
- x({ type: Object })
4393
+ Y([
4394
+ v({ type: Object })
4262
4395
  ], P.prototype, "options", 2);
4263
- Q([
4396
+ Y([
4264
4397
  E()
4265
4398
  ], P.prototype, "sidebarCollapsed", 2);
4266
- Q([
4399
+ Y([
4267
4400
  E()
4268
4401
  ], P.prototype, "a11yHasErrors", 2);
4269
- Q([
4402
+ Y([
4270
4403
  E()
4271
4404
  ], P.prototype, "a11yHasWarnings", 2);
4272
- Q([
4405
+ Y([
4273
4406
  E()
4274
4407
  ], P.prototype, "a11yHasInfos", 2);
4275
- P = Q([
4408
+ P = Y([
4276
4409
  S("mail-editor")
4277
4410
  ], P);
4278
4411
  function R(e, t) {
4279
4412
  customElements.get(e) || customElements.define(e, t);
4280
4413
  }
4281
4414
  R("mail-editor", P);
4282
- R("me-editor-canvas", L);
4283
- R("me-row-renderer", j);
4284
- R("me-column-renderer", z);
4415
+ R("me-editor-canvas", z);
4416
+ R("me-row-renderer", O);
4417
+ R("me-column-renderer", L);
4285
4418
  R("me-content-renderer", M);
4286
4419
  R("me-editor-sidebar", H);
4287
4420
  R("me-body-settings", K);
4288
4421
  R("me-property-panel", q);
4289
- R("me-inline-toolbar", O);
4422
+ R("me-inline-toolbar", j);
4290
4423
  R("me-a11y-checker", U);
4291
- const bo = customElements.get("mail-editor") !== void 0;
4424
+ const mo = customElements.get("mail-editor") !== void 0;
4292
4425
  export {
4293
- bo as E,
4426
+ mo as E,
4294
4427
  P as M,
4295
4428
  et as T,
4296
4429
  Ze as a,
4297
4430
  N as e,
4298
4431
  Pt as f,
4299
- fo as j,
4432
+ bo as j,
4300
4433
  p as s,
4301
4434
  Et as t
4302
4435
  };
4303
- //# sourceMappingURL=index-zy5NbC2E.js.map
4436
+ //# sourceMappingURL=index-CLXq1CZC.js.map