best-email-builder 0.13.0 → 0.14.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 (47) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/ai-server.js +3 -3
  3. package/dist/ai.js +6 -6
  4. package/dist/builder.js +10 -8
  5. package/dist/{chunk-G7G3TRWG.js → chunk-2ZRGQFX6.js} +684 -700
  6. package/dist/chunk-2ZRGQFX6.js.map +1 -0
  7. package/dist/{chunk-UGF3YJ64.js → chunk-7JJ4EZAZ.js} +2 -2
  8. package/dist/{chunk-LSOR4OII.js → chunk-NEEOZR5C.js} +68 -68
  9. package/dist/chunk-NEEOZR5C.js.map +1 -0
  10. package/dist/{chunk-6QTSXJG4.js → chunk-O2A2DPFJ.js} +3 -3
  11. package/dist/{chunk-JJ56652Y.js → chunk-OTE7BRKU.js} +9 -5
  12. package/dist/chunk-OTE7BRKU.js.map +1 -0
  13. package/dist/{chunk-2KOI5SWV.js → chunk-PCSKVVSZ.js} +2 -2
  14. package/dist/{chunk-A4KF7NMP.js → chunk-R3DWMSSR.js} +2 -2
  15. package/dist/{chunk-Q5UPFM7J.js → chunk-SAYIBNH5.js} +3 -3
  16. package/dist/{chunk-Q5UPFM7J.js.map → chunk-SAYIBNH5.js.map} +1 -1
  17. package/dist/{chunk-ZTUW25BG.js → chunk-SYEUC7I2.js} +24 -21
  18. package/dist/chunk-SYEUC7I2.js.map +1 -0
  19. package/dist/{chunk-Q2ZUJFOY.js → chunk-VHTV32EW.js} +2 -2
  20. package/dist/{chunk-XF25DLD4.js → chunk-XXUYQ5BX.js} +3 -3
  21. package/dist/index.js +12 -10
  22. package/dist/index.js.map +1 -1
  23. package/dist/library.js +5 -5
  24. package/dist/server.js +7 -5
  25. package/dist/server.js.map +1 -1
  26. package/dist/styles.css +1 -1
  27. package/dist/types/builder.d.ts +1 -1
  28. package/dist/types/core/constants.d.ts +1 -1
  29. package/dist/types/engine/NativeAdapter.d.ts +1 -1
  30. package/dist/types/features/variables/VariablePicker.d.ts +2 -2
  31. package/dist/types/features/variables/VariablesBar.d.ts +10 -5
  32. package/dist/types/features/variables/catalog.d.ts +15 -1
  33. package/dist/types/index.d.ts +1 -1
  34. package/dist/types/server/index.d.ts +1 -1
  35. package/dist/types/ui/primitives/searchShortcut.d.ts +1 -1
  36. package/package.json +1 -1
  37. package/dist/chunk-G7G3TRWG.js.map +0 -1
  38. package/dist/chunk-JJ56652Y.js.map +0 -1
  39. package/dist/chunk-LSOR4OII.js.map +0 -1
  40. package/dist/chunk-ZTUW25BG.js.map +0 -1
  41. package/dist/types/features/variables/VariablesMenu.d.ts +0 -18
  42. /package/dist/{chunk-UGF3YJ64.js.map → chunk-7JJ4EZAZ.js.map} +0 -0
  43. /package/dist/{chunk-6QTSXJG4.js.map → chunk-O2A2DPFJ.js.map} +0 -0
  44. /package/dist/{chunk-2KOI5SWV.js.map → chunk-PCSKVVSZ.js.map} +0 -0
  45. /package/dist/{chunk-A4KF7NMP.js.map → chunk-R3DWMSSR.js.map} +0 -0
  46. /package/dist/{chunk-Q2ZUJFOY.js.map → chunk-VHTV32EW.js.map} +0 -0
  47. /package/dist/{chunk-XF25DLD4.js.map → chunk-XXUYQ5BX.js.map} +0 -0
@@ -6,17 +6,17 @@ import {
6
6
  useLayoutWidth,
7
7
  useSearchShortcut,
8
8
  withThumbnailImages
9
- } from "./chunk-LSOR4OII.js";
9
+ } from "./chunk-NEEOZR5C.js";
10
10
  import {
11
11
  BRAND_NOTES,
12
12
  countImagesWithoutPicture,
13
13
  logoWidthFor
14
- } from "./chunk-Q2ZUJFOY.js";
14
+ } from "./chunk-VHTV32EW.js";
15
15
  import {
16
16
  cleanRichText,
17
17
  escapeText,
18
18
  textOfHtml
19
- } from "./chunk-UGF3YJ64.js";
19
+ } from "./chunk-7JJ4EZAZ.js";
20
20
  import {
21
21
  Button,
22
22
  Dialog,
@@ -51,7 +51,7 @@ import {
51
51
  createHttpStorage,
52
52
  useT,
53
53
  useUi
54
- } from "./chunk-6QTSXJG4.js";
54
+ } from "./chunk-O2A2DPFJ.js";
55
55
  import {
56
56
  DEFAULT_BUTTON_URL,
57
57
  EMAIL_BUILDER_VERSION,
@@ -94,10 +94,10 @@ import {
94
94
  setAttributes,
95
95
  setContent,
96
96
  toProject
97
- } from "./chunk-Q5UPFM7J.js";
97
+ } from "./chunk-SAYIBNH5.js";
98
98
  import {
99
99
  isSafeUrl
100
- } from "./chunk-A4KF7NMP.js";
100
+ } from "./chunk-R3DWMSSR.js";
101
101
  import {
102
102
  CUSTOM_GROUP,
103
103
  DEFAULT_VARIABLES,
@@ -110,7 +110,7 @@ import {
110
110
  tokenOf,
111
111
  translatorFor,
112
112
  validateCustomVariable
113
- } from "./chunk-ZTUW25BG.js";
113
+ } from "./chunk-SYEUC7I2.js";
114
114
 
115
115
  // src/core/events.js
116
116
  function createEmitter({ onError } = {}) {
@@ -1113,7 +1113,7 @@ function createStarterMjml({ sender = {}, buttonUrl = DEFAULT_BUTTON_URL, t = id
1113
1113
  `<mj-section background-color="${PALETTE.surface}" padding-top="8px" padding-bottom="28px">`,
1114
1114
  "<mj-column>",
1115
1115
  `<mj-text ${TEXT} font-size="24px" line-height="32px" font-weight="bold" ${SIDE}>${escapeXml2(t("Your headline"))}</mj-text>`,
1116
- `<mj-text ${TEXT} font-size="15px" line-height="24px" ${SIDE}>${escapeXml2(t("Hello {name},", { name: "{{contact.firstname}}" }))}<br /><br />${escapeXml2(t("Your text."))}</mj-text>`,
1116
+ `<mj-text ${TEXT} font-size="15px" line-height="24px" ${SIDE}>${escapeXml2(t("Hello,"))}<br /><br />${escapeXml2(t("Your text."))}</mj-text>`,
1117
1117
  `<mj-button href="${escapeXml2(buttonUrl)}" background-color="${PALETTE.navy}" color="${PALETTE.white}" font-family="${FONT_STACK}" font-size="15px" font-weight="bold" border-radius="6px" inner-padding="12px 28px" align="left" ${SIDE}>${escapeXml2(t("Learn more"))}</mj-button>`,
1118
1118
  "</mj-column>",
1119
1119
  "</mj-section>",
@@ -1223,7 +1223,7 @@ var TEMPLATE_GALLERY = [
1223
1223
  create: ({ sender, t }) => email(
1224
1224
  header(sender, t) + section(
1225
1225
  column(
1226
- heading(esc(t("Welcome, {name}!", { name: "{{contact.firstname}}" })), { size: 28 }) + paragraph(esc(t("Thank you for joining us. Here is how to get the most out of your account.")))
1226
+ heading(esc(t("Welcome aboard!")), { size: 28 }) + paragraph(esc(t("Thank you for joining us. Here is how to get the most out of your account.")))
1227
1227
  ),
1228
1228
  { top: 16, bottom: 8 }
1229
1229
  ) + section(
@@ -1438,112 +1438,20 @@ var versionsFeature = {
1438
1438
  };
1439
1439
 
1440
1440
  // src/features/variables/VariablesBar.jsx
1441
- import { useId, useState as useState2 } from "react";
1442
- import { Braces, ChevronDown } from "lucide-react";
1443
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1444
- function VariablesBar({ context }) {
1445
- const { editor, ready, variables } = context;
1446
- const { t, notify } = useUi();
1447
- const [hovered, setHovered] = useState2(false);
1448
- const [open, setOpen] = useState2(false);
1449
- const listId = useId();
1450
- const fields = variables.filter((v) => v.kind !== "link");
1451
- if (!fields.length) return null;
1452
- const expanded = hovered || open;
1453
- const insert = (variable) => {
1454
- if (!editor.insertText(tokenOf(variable))) notify("info", t("Select a text or a button first."));
1455
- };
1456
- return /* @__PURE__ */ jsx2("div", { className: "eb:relative eb:z-10 eb:h-6 eb:shrink-0", "data-testid": "eb-variables-bar", children: /* @__PURE__ */ jsxs2(
1457
- "div",
1458
- {
1459
- className: cn(
1460
- "eb:absolute eb:inset-x-0 eb:top-0 eb:border-b eb:border-border eb:bg-background eb:transition-shadow",
1461
- expanded && "eb:shadow-md"
1462
- ),
1463
- "data-expanded": expanded,
1464
- onMouseEnter: () => setHovered(true),
1465
- onMouseLeave: () => setHovered(false),
1466
- onKeyDown: (e) => e.key === "Escape" && open && setOpen(false),
1467
- onMouseDown: (e) => e.preventDefault(),
1468
- children: [
1469
- /* @__PURE__ */ jsxs2(
1470
- "button",
1471
- {
1472
- type: "button",
1473
- "aria-expanded": expanded,
1474
- "aria-controls": listId,
1475
- onClick: () => setOpen((value) => !value),
1476
- className: "eb:flex eb:h-6 eb:w-full eb:items-center eb:gap-1.5 eb:px-3 eb:text-[11px] eb:font-medium eb:text-foreground-lighter eb:outline-none eb:hover:text-foreground eb:focus-visible:ring-2 eb:focus-visible:ring-ring/40 eb:focus-visible:ring-inset",
1477
- children: [
1478
- /* @__PURE__ */ jsx2(Braces, { className: "eb:size-3", "aria-hidden": "true" }),
1479
- t("Personalization fields"),
1480
- /* @__PURE__ */ jsx2("span", { className: "eb:text-foreground-muted", children: fields.length }),
1481
- /* @__PURE__ */ jsx2(ChevronDown, { className: cn("eb:ml-auto eb:size-3.5 eb:transition-transform", expanded && "eb:rotate-180"), "aria-hidden": "true" })
1482
- ]
1483
- }
1484
- ),
1485
- /* @__PURE__ */ jsx2(
1486
- "div",
1487
- {
1488
- id: listId,
1489
- className: cn(
1490
- "eb:grid eb:transition-[grid-template-rows,visibility] eb:duration-200 eb:ease-out",
1491
- expanded ? "eb:visible eb:grid-rows-[1fr]" : "eb:invisible eb:grid-rows-[0fr]"
1492
- ),
1493
- children: /* @__PURE__ */ jsx2("div", { className: "eb:min-h-0 eb:overflow-hidden", children: /* @__PURE__ */ jsx2(
1494
- "div",
1495
- {
1496
- role: "group",
1497
- "aria-label": t("Personalization fields"),
1498
- className: "eb:flex eb:max-h-24 eb:flex-wrap eb:gap-1 eb:overflow-y-auto eb:px-3 eb:pt-0.5 eb:pb-2",
1499
- children: fields.map((variable) => /* @__PURE__ */ jsx2(
1500
- TooltipWrap,
1501
- {
1502
- label: /* @__PURE__ */ jsx2("code", { className: "eb:font-mono", children: tokenOf(variable) }),
1503
- delayDuration: 100,
1504
- hoverable: false,
1505
- children: /* @__PURE__ */ jsx2(
1506
- "button",
1507
- {
1508
- type: "button",
1509
- disabled: !ready,
1510
- "data-variable": variable.key,
1511
- onMouseEnter: () => editor.previewText(tokenOf(variable)),
1512
- onMouseLeave: () => editor.clearPreview(),
1513
- onFocus: () => editor.previewText(tokenOf(variable)),
1514
- onBlur: () => editor.clearPreview(),
1515
- onClick: () => insert(variable),
1516
- className: "eb:inline-flex eb:h-5.5 eb:items-center eb:rounded-full eb:border eb:border-border eb:bg-surface-75 eb:px-2 eb:text-[11px] eb:font-medium eb:text-foreground eb:transition-colors eb:outline-none eb:hover:border-primary/50 eb:hover:bg-primary/5 eb:hover:text-primary eb:focus-visible:ring-2 eb:focus-visible:ring-ring/50 eb:disabled:opacity-50",
1517
- children: variable.custom ? variable.label : t(variable.label)
1518
- }
1519
- )
1520
- },
1521
- variable.key
1522
- ))
1523
- }
1524
- ) })
1525
- }
1526
- )
1527
- ]
1528
- }
1529
- ) });
1530
- }
1531
-
1532
- // src/features/variables/VariablesMenu.jsx
1533
- import { useState as useState5 } from "react";
1534
- import { Braces as Braces3 } from "lucide-react";
1441
+ import { Fragment, useId, useState as useState3 } from "react";
1442
+ import { Braces as Braces2, ChevronDown, Link2, Pencil, Plus } from "lucide-react";
1535
1443
 
1536
1444
  // src/features/variables/VariableDialog.jsx
1537
- import { useEffect, useMemo, useState as useState3 } from "react";
1538
- import { Braces as Braces2, Loader2, Trash2 } from "lucide-react";
1539
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1445
+ import { useEffect, useMemo, useState as useState2 } from "react";
1446
+ import { Braces, Loader2, Trash2 } from "lucide-react";
1447
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1540
1448
  function VariableDialog({ open, onOpenChange, variable = null, initialLabel = "", variables, storage, onSaved, onDeleted }) {
1541
1449
  const { t, notify, confirm } = useUi();
1542
1450
  const editing = Boolean(variable);
1543
- const [form, setForm] = useState3({ label: "", key: "", group: "", sample: "", fallback: "" });
1544
- const [keyTouched, setKeyTouched] = useState3(false);
1545
- const [errors, setErrors] = useState3({});
1546
- const [busy, setBusy] = useState3(false);
1451
+ const [form, setForm] = useState2({ label: "", key: "", group: "", sample: "", fallback: "" });
1452
+ const [keyTouched, setKeyTouched] = useState2(false);
1453
+ const [errors, setErrors] = useState2({});
1454
+ const [busy, setBusy] = useState2(false);
1547
1455
  useEffect(() => {
1548
1456
  if (!open) return;
1549
1457
  setForm(
@@ -1610,9 +1518,9 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
1610
1518
  setBusy(false);
1611
1519
  }
1612
1520
  };
1613
- const field = (name, label, props = {}, hint = null) => /* @__PURE__ */ jsxs3("div", { className: "eb:space-y-1.5", children: [
1614
- /* @__PURE__ */ jsx3(Label, { htmlFor: `eb-var-${name}`, children: label }),
1615
- /* @__PURE__ */ jsx3(
1521
+ const field = (name, label, props = {}, hint = null) => /* @__PURE__ */ jsxs2("div", { className: "eb:space-y-1.5", children: [
1522
+ /* @__PURE__ */ jsx2(Label, { htmlFor: `eb-var-${name}`, children: label }),
1523
+ /* @__PURE__ */ jsx2(
1616
1524
  Input,
1617
1525
  {
1618
1526
  id: `eb-var-${name}`,
@@ -1623,23 +1531,23 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
1623
1531
  ...props
1624
1532
  }
1625
1533
  ),
1626
- (errors[name] || hint) && /* @__PURE__ */ jsx3("p", { id: `eb-var-${name}-hint`, className: errors[name] ? "eb:text-[12px] eb:text-destructive" : "eb:text-[11px] eb:text-foreground-muted", children: errors[name] || hint })
1534
+ (errors[name] || hint) && /* @__PURE__ */ jsx2("p", { id: `eb-var-${name}-hint`, className: errors[name] ? "eb:text-[12px] eb:text-destructive" : "eb:text-[11px] eb:text-foreground-muted", children: errors[name] || hint })
1627
1535
  ] });
1628
- return /* @__PURE__ */ jsx3(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs3(
1536
+ return /* @__PURE__ */ jsx2(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs2(
1629
1537
  DialogContent,
1630
1538
  {
1631
1539
  className: "eb:sm:max-w-[440px]",
1632
1540
  onMouseDown: (e) => e.stopPropagation(),
1633
1541
  onCloseAutoFocus: (e) => e.preventDefault(),
1634
1542
  children: [
1635
- /* @__PURE__ */ jsx3(DialogHeader, { children: /* @__PURE__ */ jsxs3("div", { className: "eb:flex eb:items-center eb:gap-3", children: [
1636
- /* @__PURE__ */ jsx3("span", { className: "eb:flex eb:size-10 eb:shrink-0 eb:items-center eb:justify-center eb:rounded-lg2 eb:bg-primary/10 eb:text-primary", children: /* @__PURE__ */ jsx3(Braces2, { className: "eb:size-5" }) }),
1637
- /* @__PURE__ */ jsxs3("div", { children: [
1638
- /* @__PURE__ */ jsx3(DialogTitle, { className: "eb:text-base eb:font-normal", children: editing ? t("Edit variable") : t("New variable") }),
1639
- /* @__PURE__ */ jsx3(DialogDescription, { className: "eb:text-[13px]", children: t("Available in every template.") })
1543
+ /* @__PURE__ */ jsx2(DialogHeader, { children: /* @__PURE__ */ jsxs2("div", { className: "eb:flex eb:items-center eb:gap-3", children: [
1544
+ /* @__PURE__ */ jsx2("span", { className: "eb:flex eb:size-10 eb:shrink-0 eb:items-center eb:justify-center eb:rounded-lg2 eb:bg-primary/10 eb:text-primary", children: /* @__PURE__ */ jsx2(Braces, { className: "eb:size-5" }) }),
1545
+ /* @__PURE__ */ jsxs2("div", { children: [
1546
+ /* @__PURE__ */ jsx2(DialogTitle, { className: "eb:text-base eb:font-normal", children: editing ? t("Edit variable") : t("New variable") }),
1547
+ /* @__PURE__ */ jsx2(DialogDescription, { className: "eb:text-[13px]", children: t("Available in every template.") })
1640
1548
  ] })
1641
1549
  ] }) }),
1642
- /* @__PURE__ */ jsxs3("form", { onSubmit: submit, className: "eb:space-y-3", noValidate: true, children: [
1550
+ /* @__PURE__ */ jsxs2("form", { onSubmit: submit, className: "eb:space-y-3", noValidate: true, children: [
1643
1551
  field("label", t("Name"), { autoFocus: true, maxLength: VARIABLE_LIMITS.label, placeholder: t("Order number") }),
1644
1552
  field(
1645
1553
  "key",
@@ -1647,9 +1555,9 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
1647
1555
  { disabled: editing, maxLength: VARIABLE_LIMITS.key, className: "eb:font-mono eb:text-[12px]" },
1648
1556
  form.key ? `{{${form.key}}}` : null
1649
1557
  ),
1650
- /* @__PURE__ */ jsxs3("div", { className: "eb:space-y-1.5", children: [
1651
- /* @__PURE__ */ jsx3(Label, { htmlFor: "eb-var-group", children: t("Group") }),
1652
- /* @__PURE__ */ jsx3(
1558
+ /* @__PURE__ */ jsxs2("div", { className: "eb:space-y-1.5", children: [
1559
+ /* @__PURE__ */ jsx2(Label, { htmlFor: "eb-var-group", children: t("Group") }),
1560
+ /* @__PURE__ */ jsx2(
1653
1561
  Input,
1654
1562
  {
1655
1563
  id: "eb-var-group",
@@ -1660,21 +1568,21 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
1660
1568
  placeholder: t(CUSTOM_GROUP)
1661
1569
  }
1662
1570
  ),
1663
- /* @__PURE__ */ jsx3("datalist", { id: "eb-var-groups", children: groups.map((g) => /* @__PURE__ */ jsx3("option", { value: g }, g)) })
1571
+ /* @__PURE__ */ jsx2("datalist", { id: "eb-var-groups", children: groups.map((g) => /* @__PURE__ */ jsx2("option", { value: g }, g)) })
1664
1572
  ] }),
1665
- /* @__PURE__ */ jsxs3("div", { className: "eb:grid eb:grid-cols-2 eb:gap-3", children: [
1573
+ /* @__PURE__ */ jsxs2("div", { className: "eb:grid eb:grid-cols-2 eb:gap-3", children: [
1666
1574
  field("sample", t("Sample value"), { maxLength: VARIABLE_LIMITS.sample, placeholder: "CMD-1042" }, t("Preview and tests")),
1667
1575
  field("fallback", t("Value if empty"), { maxLength: VARIABLE_LIMITS.fallback }, t("When a recipient has none"))
1668
1576
  ] }),
1669
- /* @__PURE__ */ jsxs3("div", { className: "eb:flex eb:items-center eb:gap-2 eb:pt-1", children: [
1670
- editing && /* @__PURE__ */ jsxs3(Button, { variant: "ghost", className: "eb:text-destructive eb:hover:text-destructive", onClick: remove, disabled: busy, children: [
1671
- /* @__PURE__ */ jsx3(Trash2, {}),
1577
+ /* @__PURE__ */ jsxs2("div", { className: "eb:flex eb:items-center eb:gap-2 eb:pt-1", children: [
1578
+ editing && /* @__PURE__ */ jsxs2(Button, { variant: "ghost", className: "eb:text-destructive eb:hover:text-destructive", onClick: remove, disabled: busy, children: [
1579
+ /* @__PURE__ */ jsx2(Trash2, {}),
1672
1580
  t("Delete")
1673
1581
  ] }),
1674
- /* @__PURE__ */ jsxs3("div", { className: "eb:ml-auto eb:flex eb:gap-2", children: [
1675
- /* @__PURE__ */ jsx3(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: t("Cancel") }),
1676
- /* @__PURE__ */ jsxs3(Button, { type: "submit", disabled: busy, children: [
1677
- busy && /* @__PURE__ */ jsx3(Loader2, { className: "eb:animate-spin" }),
1582
+ /* @__PURE__ */ jsxs2("div", { className: "eb:ml-auto eb:flex eb:gap-2", children: [
1583
+ /* @__PURE__ */ jsx2(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: t("Cancel") }),
1584
+ /* @__PURE__ */ jsxs2(Button, { type: "submit", disabled: busy, children: [
1585
+ busy && /* @__PURE__ */ jsx2(Loader2, { className: "eb:animate-spin" }),
1678
1586
  editing ? t("Save") : t("Create")
1679
1587
  ] })
1680
1588
  ] })
@@ -1685,199 +1593,137 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
1685
1593
  ) });
1686
1594
  }
1687
1595
 
1688
- // src/features/variables/VariablePicker.jsx
1689
- import { useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState4 } from "react";
1690
- import { Pencil, Plus, Search } from "lucide-react";
1691
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1692
- function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, filter }) {
1693
- const t = useT();
1694
- const [query, setQuery] = useState4("");
1695
- const [active, setActive] = useState4(0);
1696
- const listRef = useRef(null);
1697
- const searchRef = useRef(
1698
- /** @type {HTMLInputElement|null} */
1699
- null
1700
- );
1701
- useSearchShortcut(searchRef);
1702
- const matches = useMemo2(() => {
1703
- const q = query.trim().toLowerCase();
1704
- return variables.filter((v) => filter ? filter(v) : true).filter(
1705
- (v) => !q || t(v.label).toLowerCase().includes(q) || v.key.toLowerCase().includes(q) || t(v.group).toLowerCase().includes(q)
1706
- );
1707
- }, [variables, query, filter, t]);
1708
- const groups = useMemo2(() => [...new Set(matches.map((v) => v.group))], [matches]);
1709
- const ordered = useMemo2(() => groups.flatMap((g) => matches.filter((v) => v.group === g)), [groups, matches]);
1710
- useEffect2(() => setActive(0), [query]);
1711
- useEffect2(() => {
1712
- listRef.current?.querySelector('[data-active="true"]')?.scrollIntoView({ block: "nearest" });
1713
- }, [active]);
1714
- const onKeyDown = (e) => {
1715
- if (e.key === "ArrowDown") {
1716
- e.preventDefault();
1717
- setActive((i) => Math.min(i + 1, ordered.length - 1));
1718
- } else if (e.key === "ArrowUp") {
1719
- e.preventDefault();
1720
- setActive((i) => Math.max(i - 1, 0));
1721
- } else if (e.key === "Enter") {
1722
- e.preventDefault();
1723
- if (ordered[active]) onPick(ordered[active]);
1724
- else if (onCreate && query.trim()) onCreate(query.trim());
1725
- }
1596
+ // src/features/variables/VariablesBar.jsx
1597
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1598
+ var BADGE = "eb:inline-flex eb:h-5.5 eb:items-center eb:gap-1 eb:rounded-full eb:border eb:border-border eb:bg-surface-75 eb:px-2 eb:text-[11px] eb:font-medium eb:text-foreground eb:transition-colors eb:outline-none eb:hover:border-primary/50 eb:hover:bg-primary/5 eb:hover:text-primary eb:focus-visible:ring-2 eb:focus-visible:ring-ring/50 eb:disabled:opacity-50";
1599
+ function VariablesBar({ context }) {
1600
+ const { editor, ready, variables, storage, canManageVariables, reloadVariables } = context;
1601
+ const { t, notify } = useUi();
1602
+ const [hovered, setHovered] = useState3(false);
1603
+ const [open, setOpen] = useState3(false);
1604
+ const [dialog, setDialog] = useState3(null);
1605
+ const listId = useId();
1606
+ if (!variables.length && !canManageVariables) return null;
1607
+ const expanded = hovered || open;
1608
+ const fields = variables.filter((v) => v.kind !== "link");
1609
+ const links = variables.filter((v) => v.kind === "link");
1610
+ const insert = (variable) => {
1611
+ const done = variable.kind === "link" ? editor.insertLink(tokenOf(variable), t("Unsubscribe")) : editor.insertText(tokenOf(variable));
1612
+ if (!done) notify("info", t("Select a text or a button first."));
1726
1613
  };
1727
- return /* @__PURE__ */ jsxs4("div", { className: "eb:flex eb:max-h-[min(440px,70vh)] eb:flex-col", "data-testid": "variable-picker", children: [
1728
- /* @__PURE__ */ jsxs4("div", { className: "eb:relative eb:border-b eb:border-border eb:p-2", children: [
1729
- /* @__PURE__ */ jsx4(Search, { className: "eb:pointer-events-none eb:absolute eb:top-1/2 eb:left-4 eb:size-3.5 eb:-translate-y-1/2 eb:text-foreground-muted" }),
1730
- /* @__PURE__ */ jsx4(
1731
- "input",
1732
- {
1733
- ref: searchRef,
1734
- autoFocus: true,
1735
- value: query,
1736
- onChange: (e) => setQuery(e.target.value),
1737
- onKeyDown,
1738
- placeholder: t("Search variables\u2026"),
1739
- "aria-label": t("Search variables\u2026"),
1740
- "aria-keyshortcuts": SEARCH_KEYS,
1741
- className: "eb:h-8 eb:w-full eb:rounded-md eb:bg-surface-75 eb:pr-14 eb:pl-7 eb:text-[13px] eb:text-foreground eb:outline-none eb:placeholder:text-foreground-muted eb:focus-visible:ring-2 eb:focus-visible:ring-ring/40"
1742
- }
1743
- ),
1744
- /* @__PURE__ */ jsx4(SearchKeyHint, { className: "eb:absolute eb:top-1/2 eb:right-4 eb:-translate-y-1/2" })
1745
- ] }),
1746
- /* @__PURE__ */ jsxs4("div", { ref: listRef, role: "listbox", "aria-label": t("Variables"), className: "eb:min-h-0 eb:flex-1 eb:overflow-y-auto eb:p-1", children: [
1747
- ordered.length === 0 && /* @__PURE__ */ jsxs4("div", { className: "eb:px-2 eb:py-3 eb:text-center eb:text-[12px] eb:text-foreground-muted", children: [
1748
- /* @__PURE__ */ jsx4("p", { children: t("No variable found.") }),
1749
- onCreate && query.trim() && /* @__PURE__ */ jsxs4(
1750
- "button",
1751
- {
1752
- type: "button",
1753
- onClick: () => onCreate(query.trim()),
1754
- className: "eb:mt-2 eb:inline-flex eb:items-center eb:gap-1 eb:rounded-md eb:px-2 eb:py-1 eb:text-[12px] eb:font-medium eb:text-primary eb:hover:bg-accent",
1755
- children: [
1756
- /* @__PURE__ */ jsx4(Plus, { className: "eb:size-3.5" }),
1757
- t("Create \u201C{name}\u201D", { name: query.trim() })
1758
- ]
1759
- }
1760
- )
1761
- ] }),
1762
- groups.map((group) => /* @__PURE__ */ jsxs4("div", { role: "group", "aria-label": t(group), children: [
1763
- /* @__PURE__ */ jsx4("p", { className: "eb:px-2 eb:pt-2 eb:pb-1 eb:text-[11px] eb:text-foreground-muted", children: t(group) }),
1764
- ordered.filter((v) => v.group === group).map((variable) => {
1765
- const index = ordered.indexOf(variable);
1766
- return /* @__PURE__ */ jsxs4(
1767
- "div",
1768
- {
1769
- "data-active": index === active,
1770
- className: cn(
1771
- "eb:group/var eb:flex eb:items-center eb:gap-1 eb:rounded-md",
1772
- index === active ? "eb:bg-accent eb:text-accent-foreground" : "eb:hover:bg-accent/60"
1773
- ),
1774
- onMouseEnter: () => setActive(index),
1775
- children: [
1776
- /* @__PURE__ */ jsxs4(
1777
- "button",
1778
- {
1779
- type: "button",
1780
- role: "option",
1781
- "aria-selected": index === active,
1782
- "data-variable": variable.key,
1783
- onClick: () => onPick(variable),
1784
- className: "eb:flex eb:min-w-0 eb:flex-1 eb:items-center eb:gap-2 eb:px-2 eb:py-1.5 eb:text-left eb:text-[13px]",
1785
- title: variable.description || void 0,
1786
- children: [
1787
- /* @__PURE__ */ jsx4("span", { className: "eb:min-w-0 eb:flex-1 eb:truncate", children: variable.custom ? variable.label : t(variable.label) }),
1788
- /* @__PURE__ */ jsx4("code", { className: "eb:shrink-0 eb:font-mono eb:text-[10.5px] eb:text-foreground-muted", children: tokenOf(variable) })
1789
- ]
1790
- }
1791
- ),
1792
- onEdit && variable.custom && /* @__PURE__ */ jsx4(
1793
- "button",
1794
- {
1795
- type: "button",
1796
- "aria-label": t("Edit \u201C{name}\u201D", { name: variable.label }),
1797
- title: t("Edit"),
1798
- onClick: () => onEdit(variable),
1799
- className: "eb:mr-1 eb:flex eb:size-6 eb:shrink-0 eb:items-center eb:justify-center eb:rounded-md eb:text-foreground-muted eb:opacity-0 eb:group-hover/var:opacity-100 eb:hover:bg-background eb:hover:text-foreground eb:focus-visible:opacity-100",
1800
- children: /* @__PURE__ */ jsx4(Pencil, { className: "eb:size-3" })
1801
- }
1802
- )
1803
- ]
1804
- },
1805
- variable.key
1806
- );
1807
- })
1808
- ] }, group))
1809
- ] }),
1810
- onCreate && /* @__PURE__ */ jsx4("div", { className: "eb:border-t eb:border-border eb:p-1", children: /* @__PURE__ */ jsxs4(
1614
+ const badge = (variable) => {
1615
+ const link2 = variable.kind === "link";
1616
+ const label = variable.custom ? variable.label : t(variable.label);
1617
+ const editable = canManageVariables && variable.custom;
1618
+ const button2 = /* @__PURE__ */ jsxs3(
1811
1619
  "button",
1812
1620
  {
1813
1621
  type: "button",
1814
- onClick: () => onCreate(query.trim()),
1815
- className: "eb:flex eb:w-full eb:items-center eb:gap-2 eb:rounded-md eb:px-2 eb:py-1.5 eb:text-left eb:text-[13px] eb:font-medium eb:text-primary eb:hover:bg-accent",
1622
+ disabled: !ready,
1623
+ "data-variable": variable.key,
1624
+ onMouseEnter: link2 ? void 0 : () => editor.previewText(tokenOf(variable)),
1625
+ onMouseLeave: link2 ? void 0 : () => editor.clearPreview(),
1626
+ onFocus: link2 ? void 0 : () => editor.previewText(tokenOf(variable)),
1627
+ onBlur: link2 ? void 0 : () => editor.clearPreview(),
1628
+ onClick: () => insert(variable),
1629
+ className: cn(BADGE, editable && "eb:rounded-r-none eb:border-r-0 eb:pr-1.5"),
1816
1630
  children: [
1817
- /* @__PURE__ */ jsx4(Plus, { className: "eb:size-4" }),
1818
- t("New variable")
1631
+ link2 && /* @__PURE__ */ jsx3(Link2, { className: "eb:size-3", "aria-hidden": "true" }),
1632
+ label
1819
1633
  ]
1820
1634
  }
1821
- ) })
1822
- ] });
1823
- }
1824
-
1825
- // src/features/variables/VariablesMenu.jsx
1826
- import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1827
- function VariablesMenu({ context }) {
1828
- const { editor, ready, variables, storage, canManageVariables, reloadVariables } = context;
1829
- const { t, notify } = useUi();
1830
- const [open, setOpen] = useState5(false);
1831
- const [dialog, setDialog] = useState5(null);
1832
- const insert = (variable) => {
1833
- setOpen(false);
1834
- const done = variable.kind === "link" ? editor.insertLink(tokenOf(variable), t("Unsubscribe")) : editor.insertText(tokenOf(variable));
1835
- if (!done) notify("info", t("Select a text or a button first."));
1836
- return done;
1837
- };
1838
- const manage = canManageVariables ? {
1839
- onCreate: (label) => {
1840
- setOpen(false);
1841
- setDialog({ variable: null, label });
1842
- },
1843
- onEdit: (variable) => {
1844
- setOpen(false);
1845
- setDialog({ variable, label: "" });
1846
- }
1847
- } : {};
1848
- return /* @__PURE__ */ jsxs5(Fragment, { children: [
1849
- /* @__PURE__ */ jsxs5(Popover, { open, onOpenChange: setOpen, children: [
1850
- /* @__PURE__ */ jsx5(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
1851
- Button,
1852
- {
1853
- variant: "outline",
1854
- size: "sm-compact",
1855
- disabled: !ready,
1856
- onPointerDown: (e) => e.pointerType === "mouse" && e.preventDefault(),
1857
- children: [
1858
- /* @__PURE__ */ jsx5(Braces3, {}),
1859
- t("Variables")
1860
- ]
1861
- }
1862
- ) }),
1863
- /* @__PURE__ */ jsx5(
1864
- PopoverContent,
1635
+ );
1636
+ const tip = /* @__PURE__ */ jsx3(TooltipWrap, { label: /* @__PURE__ */ jsx3("code", { className: "eb:font-mono", children: tokenOf(variable) }), delayDuration: 100, hoverable: false, children: button2 });
1637
+ if (!editable) return /* @__PURE__ */ jsx3(Fragment, { children: tip }, variable.key);
1638
+ return /* @__PURE__ */ jsxs3("span", { className: "eb:inline-flex", children: [
1639
+ tip,
1640
+ /* @__PURE__ */ jsx3(
1641
+ "button",
1865
1642
  {
1866
- align: "end",
1867
- className: "eb:w-80 eb:p-0",
1868
- onCloseAutoFocus: (e) => e.preventDefault(),
1869
- onMouseDown: (e) => e.stopPropagation(),
1870
- children: /* @__PURE__ */ jsx5(VariablePicker, { variables, onPick: insert, ...manage })
1643
+ type: "button",
1644
+ "aria-label": t("Edit \u201C{name}\u201D", { name: variable.label }),
1645
+ title: t("Edit"),
1646
+ onClick: () => setDialog({ variable }),
1647
+ className: cn(BADGE, "eb:rounded-l-none eb:px-1.5 eb:text-foreground-muted"),
1648
+ children: /* @__PURE__ */ jsx3(Pencil, { className: "eb:size-2.5", "aria-hidden": "true" })
1871
1649
  }
1872
1650
  )
1873
- ] }),
1874
- canManageVariables && /* @__PURE__ */ jsx5(
1651
+ ] }, variable.key);
1652
+ };
1653
+ return /* @__PURE__ */ jsxs3("div", { className: "eb:relative eb:z-10 eb:h-6 eb:shrink-0", "data-testid": "eb-variables-bar", children: [
1654
+ /* @__PURE__ */ jsxs3(
1655
+ "div",
1656
+ {
1657
+ className: cn(
1658
+ "eb:absolute eb:inset-x-0 eb:top-0 eb:border-b eb:border-border eb:bg-background eb:transition-shadow",
1659
+ expanded && "eb:shadow-md"
1660
+ ),
1661
+ "data-expanded": expanded,
1662
+ onMouseEnter: () => setHovered(true),
1663
+ onMouseLeave: () => setHovered(false),
1664
+ onKeyDown: (e) => e.key === "Escape" && open && setOpen(false),
1665
+ onMouseDown: (e) => e.preventDefault(),
1666
+ children: [
1667
+ /* @__PURE__ */ jsxs3(
1668
+ "button",
1669
+ {
1670
+ type: "button",
1671
+ "aria-expanded": expanded,
1672
+ "aria-controls": listId,
1673
+ onClick: () => setOpen((value) => !value),
1674
+ className: "eb:flex eb:h-6 eb:w-full eb:items-center eb:gap-1.5 eb:px-3 eb:text-[11px] eb:font-medium eb:text-foreground-lighter eb:outline-none eb:hover:text-foreground eb:focus-visible:ring-2 eb:focus-visible:ring-ring/40 eb:focus-visible:ring-inset",
1675
+ children: [
1676
+ /* @__PURE__ */ jsx3(Braces2, { className: "eb:size-3", "aria-hidden": "true" }),
1677
+ t("Email provider variables"),
1678
+ fields.length > 0 && /* @__PURE__ */ jsx3("span", { className: "eb:text-foreground-muted", children: fields.length }),
1679
+ /* @__PURE__ */ jsx3(ChevronDown, { className: cn("eb:ml-auto eb:size-3.5 eb:transition-transform", expanded && "eb:rotate-180"), "aria-hidden": "true" })
1680
+ ]
1681
+ }
1682
+ ),
1683
+ /* @__PURE__ */ jsx3(
1684
+ "div",
1685
+ {
1686
+ id: listId,
1687
+ className: cn(
1688
+ "eb:grid eb:transition-[grid-template-rows,visibility] eb:duration-200 eb:ease-out",
1689
+ expanded ? "eb:visible eb:grid-rows-[1fr]" : "eb:invisible eb:grid-rows-[0fr]"
1690
+ ),
1691
+ children: /* @__PURE__ */ jsx3("div", { className: "eb:min-h-0 eb:overflow-hidden", children: /* @__PURE__ */ jsxs3(
1692
+ "div",
1693
+ {
1694
+ role: "group",
1695
+ "aria-label": t("Email provider variables"),
1696
+ className: "eb:flex eb:max-h-24 eb:flex-wrap eb:items-center eb:gap-1 eb:overflow-y-auto eb:px-3 eb:pt-0.5 eb:pb-2",
1697
+ children: [
1698
+ fields.map(badge),
1699
+ !fields.length && /* @__PURE__ */ jsx3("span", { className: "eb:text-[11px] eb:text-foreground-muted", children: t("No variables yet.") }),
1700
+ canManageVariables && /* @__PURE__ */ jsx3(TooltipWrap, { label: t("New variable"), delayDuration: 100, hoverable: false, children: /* @__PURE__ */ jsx3(
1701
+ "button",
1702
+ {
1703
+ type: "button",
1704
+ disabled: !ready,
1705
+ "aria-label": t("New variable"),
1706
+ onClick: () => setDialog({}),
1707
+ className: cn(BADGE, "eb:w-5.5 eb:justify-center eb:border-dashed eb:bg-transparent eb:px-0 eb:text-primary"),
1708
+ children: /* @__PURE__ */ jsx3(Plus, { className: "eb:size-3.5", "aria-hidden": "true" })
1709
+ }
1710
+ ) }),
1711
+ links.length > 0 && /* @__PURE__ */ jsx3("span", { className: "eb:mx-1 eb:h-3.5 eb:w-px eb:bg-border", "aria-hidden": "true" }),
1712
+ links.map(badge)
1713
+ ]
1714
+ }
1715
+ ) })
1716
+ }
1717
+ )
1718
+ ]
1719
+ }
1720
+ ),
1721
+ canManageVariables && /* @__PURE__ */ jsx3(
1875
1722
  VariableDialog,
1876
1723
  {
1877
1724
  open: Boolean(dialog),
1878
1725
  onOpenChange: (next) => !next && setDialog(null),
1879
1726
  variable: dialog?.variable || null,
1880
- initialLabel: dialog?.label || "",
1881
1727
  variables,
1882
1728
  storage,
1883
1729
  onSaved: async (variable, created) => {
@@ -1906,7 +1752,6 @@ var variablesFeature = {
1906
1752
  id: "variables",
1907
1753
  label: "Variables",
1908
1754
  order: 10,
1909
- toolbar: VariablesMenu,
1910
1755
  canvasBar: VariablesBar
1911
1756
  };
1912
1757
 
@@ -1920,9 +1765,9 @@ var previewFeature = {
1920
1765
  };
1921
1766
 
1922
1767
  // src/features/test-email/TestEmailButton.jsx
1923
- import { useState as useState6 } from "react";
1768
+ import { useState as useState4 } from "react";
1924
1769
  import { CheckCircle2, Loader2 as Loader22, Send, XCircle } from "lucide-react";
1925
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1770
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1926
1771
  var KEY = "best-email-builder:test-addresses";
1927
1772
  function readAddresses(fallback) {
1928
1773
  try {
@@ -1940,10 +1785,10 @@ function rememberAddresses(value) {
1940
1785
  function TestEmailButton({ context }) {
1941
1786
  const { editor, ready, meta, storage, testRecipients = [] } = context;
1942
1787
  const { t, notify } = useUi();
1943
- const [open, setOpen] = useState6(false);
1944
- const [addresses, setAddresses] = useState6("");
1945
- const [sending, setSending] = useState6(false);
1946
- const [report, setReport] = useState6(null);
1788
+ const [open, setOpen] = useState4(false);
1789
+ const [addresses, setAddresses] = useState4("");
1790
+ const [sending, setSending] = useState4(false);
1791
+ const [report, setReport] = useState4(null);
1947
1792
  const emails = addresses.split(/[,;\s]+/).map((a) => a.trim()).filter(Boolean);
1948
1793
  const send = async () => {
1949
1794
  if (!emails.length) return;
@@ -1966,8 +1811,8 @@ function TestEmailButton({ context }) {
1966
1811
  setSending(false);
1967
1812
  }
1968
1813
  };
1969
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
1970
- /* @__PURE__ */ jsxs6(
1814
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1815
+ /* @__PURE__ */ jsxs4(
1971
1816
  Button,
1972
1817
  {
1973
1818
  variant: "outline",
@@ -1979,22 +1824,22 @@ function TestEmailButton({ context }) {
1979
1824
  setOpen(true);
1980
1825
  },
1981
1826
  children: [
1982
- /* @__PURE__ */ jsx6(Send, {}),
1827
+ /* @__PURE__ */ jsx4(Send, {}),
1983
1828
  t("Test")
1984
1829
  ]
1985
1830
  }
1986
1831
  ),
1987
- /* @__PURE__ */ jsx6(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "eb:sm:max-w-[460px]", children: [
1988
- /* @__PURE__ */ jsx6(DialogHeader, { children: /* @__PURE__ */ jsxs6("div", { className: "eb:flex eb:items-center eb:gap-3", children: [
1989
- /* @__PURE__ */ jsx6("span", { className: "eb:flex eb:size-10 eb:shrink-0 eb:items-center eb:justify-center eb:rounded-lg2 eb:bg-primary/10 eb:text-primary", children: /* @__PURE__ */ jsx6(Send, { className: "eb:size-5" }) }),
1990
- /* @__PURE__ */ jsxs6("div", { children: [
1991
- /* @__PURE__ */ jsx6(DialogTitle, { className: "eb:text-base eb:font-normal", children: t("Send a test") }),
1992
- /* @__PURE__ */ jsx6(DialogDescription, { className: "eb:text-[13px]", children: t("The email on screen, to reviewers\u2019 addresses.") })
1832
+ /* @__PURE__ */ jsx4(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs4(DialogContent, { className: "eb:sm:max-w-[460px]", children: [
1833
+ /* @__PURE__ */ jsx4(DialogHeader, { children: /* @__PURE__ */ jsxs4("div", { className: "eb:flex eb:items-center eb:gap-3", children: [
1834
+ /* @__PURE__ */ jsx4("span", { className: "eb:flex eb:size-10 eb:shrink-0 eb:items-center eb:justify-center eb:rounded-lg2 eb:bg-primary/10 eb:text-primary", children: /* @__PURE__ */ jsx4(Send, { className: "eb:size-5" }) }),
1835
+ /* @__PURE__ */ jsxs4("div", { children: [
1836
+ /* @__PURE__ */ jsx4(DialogTitle, { className: "eb:text-base eb:font-normal", children: t("Send a test") }),
1837
+ /* @__PURE__ */ jsx4(DialogDescription, { className: "eb:text-[13px]", children: t("The email on screen, to reviewers\u2019 addresses.") })
1993
1838
  ] })
1994
1839
  ] }) }),
1995
- /* @__PURE__ */ jsxs6("div", { className: "eb:space-y-2", children: [
1996
- /* @__PURE__ */ jsx6(Label, { htmlFor: "eb-test-addresses", children: t("Addresses") }),
1997
- /* @__PURE__ */ jsx6(
1840
+ /* @__PURE__ */ jsxs4("div", { className: "eb:space-y-2", children: [
1841
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "eb-test-addresses", children: t("Addresses") }),
1842
+ /* @__PURE__ */ jsx4(
1998
1843
  Textarea,
1999
1844
  {
2000
1845
  id: "eb-test-addresses",
@@ -2005,20 +1850,20 @@ function TestEmailButton({ context }) {
2005
1850
  }
2006
1851
  )
2007
1852
  ] }),
2008
- report && /* @__PURE__ */ jsxs6("ul", { className: "eb:space-y-1", "aria-label": t("Results"), children: [
2009
- report.results.map((r) => /* @__PURE__ */ jsxs6("li", { className: "eb:flex eb:items-start eb:gap-1.5 eb:text-[12px] eb:text-foreground", children: [
2010
- r.ok ? /* @__PURE__ */ jsx6(CheckCircle2, { className: "eb:mt-0.5 eb:size-3.5 eb:shrink-0 eb:text-success", "aria-hidden": "true" }) : /* @__PURE__ */ jsx6(XCircle, { className: "eb:mt-0.5 eb:size-3.5 eb:shrink-0 eb:text-destructive", "aria-hidden": "true" }),
2011
- /* @__PURE__ */ jsxs6("span", { className: "eb:min-w-0 eb:break-all", children: [
1853
+ report && /* @__PURE__ */ jsxs4("ul", { className: "eb:space-y-1", "aria-label": t("Results"), children: [
1854
+ report.results.map((r) => /* @__PURE__ */ jsxs4("li", { className: "eb:flex eb:items-start eb:gap-1.5 eb:text-[12px] eb:text-foreground", children: [
1855
+ r.ok ? /* @__PURE__ */ jsx4(CheckCircle2, { className: "eb:mt-0.5 eb:size-3.5 eb:shrink-0 eb:text-success", "aria-hidden": "true" }) : /* @__PURE__ */ jsx4(XCircle, { className: "eb:mt-0.5 eb:size-3.5 eb:shrink-0 eb:text-destructive", "aria-hidden": "true" }),
1856
+ /* @__PURE__ */ jsxs4("span", { className: "eb:min-w-0 eb:break-all", children: [
2012
1857
  r.email,
2013
1858
  r.error ? ` \u2014 ${r.error}` : ""
2014
1859
  ] })
2015
1860
  ] }, r.email)),
2016
- report.invalid.map((email2) => /* @__PURE__ */ jsx6("li", { className: "eb:text-[12px] eb:text-foreground-muted", children: t("Ignored (invalid): {email}", { email: email2 }) }, `invalid-${email2}`))
1861
+ report.invalid.map((email2) => /* @__PURE__ */ jsx4("li", { className: "eb:text-[12px] eb:text-foreground-muted", children: t("Ignored (invalid): {email}", { email: email2 }) }, `invalid-${email2}`))
2017
1862
  ] }),
2018
- /* @__PURE__ */ jsxs6("div", { className: "eb:flex eb:justify-end eb:gap-2", children: [
2019
- /* @__PURE__ */ jsx6(Button, { variant: "outline", onClick: () => setOpen(false), children: t("Close") }),
2020
- /* @__PURE__ */ jsxs6(Button, { onClick: send, disabled: sending || !emails.length, children: [
2021
- sending ? /* @__PURE__ */ jsx6(Loader22, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx6(Send, {}),
1863
+ /* @__PURE__ */ jsxs4("div", { className: "eb:flex eb:justify-end eb:gap-2", children: [
1864
+ /* @__PURE__ */ jsx4(Button, { variant: "outline", onClick: () => setOpen(false), children: t("Close") }),
1865
+ /* @__PURE__ */ jsxs4(Button, { onClick: send, disabled: sending || !emails.length, children: [
1866
+ sending ? /* @__PURE__ */ jsx4(Loader22, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx4(Send, {}),
2022
1867
  t("Send")
2023
1868
  ] })
2024
1869
  ] })
@@ -2036,9 +1881,9 @@ var testEmailFeature = {
2036
1881
  };
2037
1882
 
2038
1883
  // src/features/templates/TemplateGallery.jsx
2039
- import { useEffect as useEffect3, useMemo as useMemo3, useState as useState7 } from "react";
2040
- import { LayoutTemplate, Search as Search2, X } from "lucide-react";
2041
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1884
+ import { useEffect as useEffect2, useMemo as useMemo2, useState as useState5 } from "react";
1885
+ import { LayoutTemplate, Search, X } from "lucide-react";
1886
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2042
1887
  var THUMBNAIL_SCALE = 0.38;
2043
1888
  var EMAIL_WIDTH = 600;
2044
1889
  var FADE_LINE = "eb:block eb:overflow-hidden eb:whitespace-nowrap eb:[mask-image:linear-gradient(to_right,#000_calc(100%-2.5rem),transparent)]";
@@ -2046,12 +1891,12 @@ var NO_SCROLLBAR = "<style>html,body{overflow:hidden!important;scrollbar-width:n
2046
1891
  var withoutScrollbar = (html) => !html ? html : /<\/head>/i.test(html) ? html.replace(/<\/head>/i, `${NO_SCROLLBAR}</head>`) : NO_SCROLLBAR + html;
2047
1892
  var fold = (text) => String(text || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
2048
1893
  function Thumbnail({ html, title }) {
2049
- return /* @__PURE__ */ jsx7(
1894
+ return /* @__PURE__ */ jsx5(
2050
1895
  "div",
2051
1896
  {
2052
1897
  className: "eb:relative eb:h-[220px] eb:shrink-0 eb:overflow-hidden eb:rounded-md eb:border eb:border-border eb:bg-surface-75",
2053
1898
  "aria-hidden": "true",
2054
- children: /* @__PURE__ */ jsx7(
1899
+ children: /* @__PURE__ */ jsx5(
2055
1900
  "iframe",
2056
1901
  {
2057
1902
  title,
@@ -2073,11 +1918,11 @@ function Thumbnail({ html, title }) {
2073
1918
  function TemplateGalleryButton({ context }) {
2074
1919
  const { editor, ready, templates, isDirty, markDirty, template, setMeta } = context;
2075
1920
  const { t, confirm, notify } = useUi();
2076
- const [open, setOpen] = useState7(false);
2077
- const [query, setQuery] = useState7("");
2078
- const [chosen, setChosen] = useState7(() => /* @__PURE__ */ new Set());
2079
- const [rendered, setRendered] = useState7({});
2080
- useEffect3(() => {
1921
+ const [open, setOpen] = useState5(false);
1922
+ const [query, setQuery] = useState5("");
1923
+ const [chosen, setChosen] = useState5(() => /* @__PURE__ */ new Set());
1924
+ const [rendered, setRendered] = useState5({});
1925
+ useEffect2(() => {
2081
1926
  if (!open || !ready) return void 0;
2082
1927
  let alive = true;
2083
1928
  Promise.all(
@@ -2095,12 +1940,12 @@ function TemplateGalleryButton({ context }) {
2095
1940
  alive = false;
2096
1941
  };
2097
1942
  }, [open, ready, templates, editor]);
2098
- const cards = useMemo3(
1943
+ const cards = useMemo2(
2099
1944
  () => open ? templates.map((entry) => ({ ...entry, tags: entry.tags || [], html: rendered[entry.id] ?? "" })) : [],
2100
1945
  [open, templates, rendered]
2101
1946
  );
2102
- const tags = useMemo3(() => [...new Set(templates.flatMap((entry) => entry.tags || []))], [templates]);
2103
- const shown = useMemo3(() => {
1947
+ const tags = useMemo2(() => [...new Set(templates.flatMap((entry) => entry.tags || []))], [templates]);
1948
+ const shown = useMemo2(() => {
2104
1949
  const q = fold(query.trim());
2105
1950
  return cards.filter(
2106
1951
  (card) => (chosen.size === 0 || card.tags.some((tag) => chosen.has(tag))) && (!q || [card.name, card.description, ...card.tags].some((field) => fold(field).includes(q)))
@@ -2133,8 +1978,8 @@ function TemplateGalleryButton({ context }) {
2133
1978
  setOpen(false);
2134
1979
  notify("success", t("\u201C{name}\u201D template applied.", { name: entry.name }));
2135
1980
  };
2136
- return /* @__PURE__ */ jsxs7(Fragment3, { children: [
2137
- /* @__PURE__ */ jsxs7(
1981
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
1982
+ /* @__PURE__ */ jsxs5(
2138
1983
  Button,
2139
1984
  {
2140
1985
  variant: "outline",
@@ -2146,12 +1991,12 @@ function TemplateGalleryButton({ context }) {
2146
1991
  setOpen(true);
2147
1992
  },
2148
1993
  children: [
2149
- /* @__PURE__ */ jsx7(LayoutTemplate, {}),
1994
+ /* @__PURE__ */ jsx5(LayoutTemplate, {}),
2150
1995
  t("Templates")
2151
1996
  ]
2152
1997
  }
2153
1998
  ),
2154
- /* @__PURE__ */ jsx7(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs7(
1999
+ /* @__PURE__ */ jsx5(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs5(
2155
2000
  DialogContent,
2156
2001
  {
2157
2002
  className: "eb:flex eb:h-[min(48rem,calc(100dvh-2rem))] eb:flex-col eb:sm:max-w-4xl",
@@ -2163,14 +2008,14 @@ function TemplateGalleryButton({ context }) {
2163
2008
  }
2164
2009
  },
2165
2010
  children: [
2166
- /* @__PURE__ */ jsxs7(DialogHeader, { children: [
2167
- /* @__PURE__ */ jsx7(DialogTitle, { children: t("Start from a template") }),
2168
- /* @__PURE__ */ jsx7(DialogDescription, { children: t("Picking a template replaces the email being edited.") })
2011
+ /* @__PURE__ */ jsxs5(DialogHeader, { children: [
2012
+ /* @__PURE__ */ jsx5(DialogTitle, { children: t("Start from a template") }),
2013
+ /* @__PURE__ */ jsx5(DialogDescription, { children: t("Picking a template replaces the email being edited.") })
2169
2014
  ] }),
2170
- /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:shrink-0 eb:flex-col eb:gap-3", children: [
2171
- /* @__PURE__ */ jsxs7("div", { className: "eb:relative", children: [
2172
- /* @__PURE__ */ jsx7(Search2, { className: "eb:pointer-events-none eb:absolute eb:top-1/2 eb:left-2.5 eb:size-3.5 eb:-translate-y-1/2 eb:text-foreground-muted" }),
2173
- /* @__PURE__ */ jsx7(
2015
+ /* @__PURE__ */ jsxs5("div", { className: "eb:flex eb:shrink-0 eb:flex-col eb:gap-3", children: [
2016
+ /* @__PURE__ */ jsxs5("div", { className: "eb:relative", children: [
2017
+ /* @__PURE__ */ jsx5(Search, { className: "eb:pointer-events-none eb:absolute eb:top-1/2 eb:left-2.5 eb:size-3.5 eb:-translate-y-1/2 eb:text-foreground-muted" }),
2018
+ /* @__PURE__ */ jsx5(
2174
2019
  Input,
2175
2020
  {
2176
2021
  type: "search",
@@ -2181,20 +2026,20 @@ function TemplateGalleryButton({ context }) {
2181
2026
  className: "eb:pr-8 eb:pl-8 eb:[&::-webkit-search-cancel-button]:hidden"
2182
2027
  }
2183
2028
  ),
2184
- query && /* @__PURE__ */ jsx7(
2029
+ query && /* @__PURE__ */ jsx5(
2185
2030
  "button",
2186
2031
  {
2187
2032
  type: "button",
2188
2033
  onClick: () => setQuery(""),
2189
2034
  "aria-label": t("Clear the search"),
2190
2035
  className: "eb:absolute eb:top-1/2 eb:right-2.5 eb:-translate-y-1/2 eb:cursor-pointer",
2191
- children: /* @__PURE__ */ jsx7(X, { className: "eb:size-3.5 eb:text-foreground-muted eb:hover:text-foreground" })
2036
+ children: /* @__PURE__ */ jsx5(X, { className: "eb:size-3.5 eb:text-foreground-muted eb:hover:text-foreground" })
2192
2037
  }
2193
2038
  )
2194
2039
  ] }),
2195
- tags.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:items-start eb:gap-1.5", children: [
2196
- /* @__PURE__ */ jsx7("div", { role: "group", "aria-label": t("Filter by tag"), className: "eb:flex eb:min-w-0 eb:flex-1 eb:flex-wrap eb:gap-1.5", "data-testid": "eb-gallery-tags", children: tags.map((tag) => /* @__PURE__ */ jsx7(FilterChip, { pressed: chosen.has(tag), onClick: () => toggle(tag), children: tag }, tag)) }),
2197
- /* @__PURE__ */ jsx7(
2040
+ tags.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "eb:flex eb:items-start eb:gap-1.5", children: [
2041
+ /* @__PURE__ */ jsx5("div", { role: "group", "aria-label": t("Filter by tag"), className: "eb:flex eb:min-w-0 eb:flex-1 eb:flex-wrap eb:gap-1.5", "data-testid": "eb-gallery-tags", children: tags.map((tag) => /* @__PURE__ */ jsx5(FilterChip, { pressed: chosen.has(tag), onClick: () => toggle(tag), children: tag }, tag)) }),
2042
+ /* @__PURE__ */ jsx5(
2198
2043
  FilterReset,
2199
2044
  {
2200
2045
  label: t("Clear the tag filters"),
@@ -2205,7 +2050,7 @@ function TemplateGalleryButton({ context }) {
2205
2050
  )
2206
2051
  ] })
2207
2052
  ] }),
2208
- /* @__PURE__ */ jsx7("div", { className: "eb:-m-1 eb:min-h-0 eb:flex-1 eb:overflow-y-auto eb:p-1", children: shown.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "eb:m-0 eb:py-10 eb:text-center eb:text-[13px] eb:text-foreground-muted", children: t("Nothing matches \u201C{query}\u201D.", { query: query.trim() }) }) : /* @__PURE__ */ jsx7("ul", { className: "eb:m-0 eb:grid eb:list-none eb:grid-cols-1 eb:gap-3 eb:p-0 eb:sm:grid-cols-2 eb:md:grid-cols-3", children: shown.map((card) => /* @__PURE__ */ jsx7("li", { className: "eb:min-w-0", children: /* @__PURE__ */ jsxs7(
2053
+ /* @__PURE__ */ jsx5("div", { className: "eb:-m-1 eb:min-h-0 eb:flex-1 eb:overflow-y-auto eb:p-1", children: shown.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "eb:m-0 eb:py-10 eb:text-center eb:text-[13px] eb:text-foreground-muted", children: t("Nothing matches \u201C{query}\u201D.", { query: query.trim() }) }) : /* @__PURE__ */ jsx5("ul", { className: "eb:m-0 eb:grid eb:list-none eb:grid-cols-1 eb:gap-3 eb:p-0 eb:sm:grid-cols-2 eb:md:grid-cols-3", children: shown.map((card) => /* @__PURE__ */ jsx5("li", { className: "eb:min-w-0", children: /* @__PURE__ */ jsxs5(
2209
2054
  "button",
2210
2055
  {
2211
2056
  type: "button",
@@ -2214,10 +2059,10 @@ function TemplateGalleryButton({ context }) {
2214
2059
  title: card.description,
2215
2060
  className: "eb:group eb:flex eb:h-full eb:w-full eb:flex-col eb:gap-2 eb:rounded-lg2 eb:border eb:border-border eb:bg-background eb:p-2 eb:text-left eb:transition-colors eb:hover:border-primary/50 eb:hover:bg-primary/5 eb:focus-visible:outline-none eb:focus-visible:ring-2 eb:focus-visible:ring-ring/50",
2216
2061
  children: [
2217
- /* @__PURE__ */ jsx7(Thumbnail, { html: card.html, title: card.name }),
2218
- /* @__PURE__ */ jsxs7("span", { className: "eb:block eb:min-w-0 eb:px-1", children: [
2219
- /* @__PURE__ */ jsx7("span", { className: cn(FADE_LINE, "eb:text-[13px] eb:font-medium eb:text-foreground"), children: card.name }),
2220
- /* @__PURE__ */ jsx7("span", { className: cn(FADE_LINE, "eb:text-[12px] eb:text-foreground-muted"), children: card.description })
2062
+ /* @__PURE__ */ jsx5(Thumbnail, { html: card.html, title: card.name }),
2063
+ /* @__PURE__ */ jsxs5("span", { className: "eb:block eb:min-w-0 eb:px-1", children: [
2064
+ /* @__PURE__ */ jsx5("span", { className: cn(FADE_LINE, "eb:text-[13px] eb:font-medium eb:text-foreground"), children: card.name }),
2065
+ /* @__PURE__ */ jsx5("span", { className: cn(FADE_LINE, "eb:text-[12px] eb:text-foreground-muted"), children: card.description })
2221
2066
  ] })
2222
2067
  ]
2223
2068
  }
@@ -2238,14 +2083,14 @@ var templatesFeature = {
2238
2083
  };
2239
2084
 
2240
2085
  // src/features/brand/BrandButton.jsx
2241
- import { useEffect as useEffect4, useRef as useRef2, useState as useState9 } from "react";
2086
+ import { useEffect as useEffect3, useRef, useState as useState7 } from "react";
2242
2087
  import { Globe, ImageOff, Loader2 as Loader23, Palette, Trash2 as Trash22, TriangleAlert, Upload, WandSparkles } from "lucide-react";
2243
2088
 
2244
2089
  // src/ui/primitives/color-picker.jsx
2245
- import { useState as useState8 } from "react";
2090
+ import { useState as useState6 } from "react";
2246
2091
  import { HexAlphaColorPicker } from "react-colorful";
2247
2092
  import { Check } from "lucide-react";
2248
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2093
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2249
2094
  var PRESET_COLORS = [
2250
2095
  "#8B5CF6",
2251
2096
  "#A78BFA",
@@ -2276,20 +2121,20 @@ function normalizeHex(v) {
2276
2121
  }
2277
2122
  function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
2278
2123
  const t = useT();
2279
- const [open, setOpen] = useState8(false);
2124
+ const [open, setOpen] = useState6(false);
2280
2125
  const valid = isValidHex(value);
2281
2126
  const normalized = valid ? normalizeHex(value) : "";
2282
2127
  const emit = (hex) => onChange(normalizeHex(hex));
2283
- return /* @__PURE__ */ jsxs8("div", { className: cn("eb:flex eb:gap-2", className), children: [
2284
- /* @__PURE__ */ jsxs8(Popover, { open, onOpenChange: setOpen, children: [
2285
- /* @__PURE__ */ jsx8(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx8(
2128
+ return /* @__PURE__ */ jsxs6("div", { className: cn("eb:flex eb:gap-2", className), children: [
2129
+ /* @__PURE__ */ jsxs6(Popover, { open, onOpenChange: setOpen, children: [
2130
+ /* @__PURE__ */ jsx6(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(
2286
2131
  "button",
2287
2132
  {
2288
2133
  type: "button",
2289
2134
  "aria-label": t("Pick a colour"),
2290
2135
  title: t("Pick a colour"),
2291
2136
  className: "eb-checker eb:relative eb:h-8 eb:w-[44px] eb:shrink-0 eb:overflow-hidden eb:rounded-lg2 eb:shadow-sm eb:ring-1 eb:ring-black/10 eb:ring-inset eb:transition-transform eb:hover:scale-[1.04]",
2292
- children: /* @__PURE__ */ jsx8(
2137
+ children: /* @__PURE__ */ jsx6(
2293
2138
  "span",
2294
2139
  {
2295
2140
  className: "eb:absolute eb:inset-0",
@@ -2299,18 +2144,18 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
2299
2144
  )
2300
2145
  }
2301
2146
  ) }),
2302
- /* @__PURE__ */ jsxs8(PopoverContent, { align: "start", className: "eb:w-64 eb:space-y-3 eb:p-3", children: [
2303
- /* @__PURE__ */ jsx8("div", { className: "eb-picker", children: /* @__PURE__ */ jsx8(HexAlphaColorPicker, { color: valid ? value : FALLBACK_COLOR, onChange: emit }) }),
2304
- /* @__PURE__ */ jsxs8("div", { className: "eb:flex eb:items-center eb:gap-2", children: [
2305
- /* @__PURE__ */ jsx8(
2147
+ /* @__PURE__ */ jsxs6(PopoverContent, { align: "start", className: "eb:w-64 eb:space-y-3 eb:p-3", children: [
2148
+ /* @__PURE__ */ jsx6("div", { className: "eb-picker", children: /* @__PURE__ */ jsx6(HexAlphaColorPicker, { color: valid ? value : FALLBACK_COLOR, onChange: emit }) }),
2149
+ /* @__PURE__ */ jsxs6("div", { className: "eb:flex eb:items-center eb:gap-2", children: [
2150
+ /* @__PURE__ */ jsx6(
2306
2151
  "span",
2307
2152
  {
2308
2153
  className: "eb-checker eb:relative eb:size-8 eb:shrink-0 eb:overflow-hidden eb:rounded-lg2 eb:ring-1 eb:ring-black/10 eb:ring-inset",
2309
2154
  "aria-hidden": true,
2310
- children: /* @__PURE__ */ jsx8("span", { className: "eb:absolute eb:inset-0", style: { backgroundColor: valid ? value : "transparent" } })
2155
+ children: /* @__PURE__ */ jsx6("span", { className: "eb:absolute eb:inset-0", style: { backgroundColor: valid ? value : "transparent" } })
2311
2156
  }
2312
2157
  ),
2313
- /* @__PURE__ */ jsx8(
2158
+ /* @__PURE__ */ jsx6(
2314
2159
  Input,
2315
2160
  {
2316
2161
  value: value || "",
@@ -2322,7 +2167,7 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
2322
2167
  }
2323
2168
  )
2324
2169
  ] }),
2325
- /* @__PURE__ */ jsx8("div", { className: "eb:grid eb:grid-cols-6 eb:gap-1.5 eb:border-t eb:border-border eb:pt-2.5", children: PRESET_COLORS.map((c) => /* @__PURE__ */ jsx8(
2170
+ /* @__PURE__ */ jsx6("div", { className: "eb:grid eb:grid-cols-6 eb:gap-1.5 eb:border-t eb:border-border eb:pt-2.5", children: PRESET_COLORS.map((c) => /* @__PURE__ */ jsx6(
2326
2171
  "button",
2327
2172
  {
2328
2173
  type: "button",
@@ -2331,13 +2176,13 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
2331
2176
  "aria-label": c,
2332
2177
  className: "eb:relative eb:size-6 eb:rounded-lg2 eb:ring-1 eb:ring-black/10 eb:ring-inset eb:transition-transform eb:hover:scale-110",
2333
2178
  style: { backgroundColor: c },
2334
- children: normalized === c && /* @__PURE__ */ jsx8(Check, { className: "eb:absolute eb:inset-0 eb:m-auto eb:size-3.5 eb:text-white eb:drop-shadow-[0_1px_1px_rgba(0,0,0,0.6)]" })
2179
+ children: normalized === c && /* @__PURE__ */ jsx6(Check, { className: "eb:absolute eb:inset-0 eb:m-auto eb:size-3.5 eb:text-white eb:drop-shadow-[0_1px_1px_rgba(0,0,0,0.6)]" })
2335
2180
  },
2336
2181
  c
2337
2182
  )) })
2338
2183
  ] })
2339
2184
  ] }),
2340
- /* @__PURE__ */ jsx8(
2185
+ /* @__PURE__ */ jsx6(
2341
2186
  Input,
2342
2187
  {
2343
2188
  id,
@@ -2352,7 +2197,7 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
2352
2197
  }
2353
2198
 
2354
2199
  // src/features/brand/BrandButton.jsx
2355
- import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2200
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2356
2201
  var toForm = (brand) => ({
2357
2202
  name: brand.name || "",
2358
2203
  logoUrl: brand.logoUrl || "",
@@ -2366,31 +2211,31 @@ var isLogoUrl = (url) => !url || url.startsWith("/") || /^https:\/\//i.test(url)
2366
2211
  function BrandButton({ context }) {
2367
2212
  const { editor, ready, storage, brand, setBrand, hostSender } = context;
2368
2213
  const { t, notify } = useUi();
2369
- const [open, setOpen] = useState9(false);
2370
- const [form, setForm] = useState9(() => toForm(brand || {}));
2371
- const [applyNow, setApplyNow] = useState9(true);
2372
- const [reading, setReading] = useState9(false);
2373
- const [readError, setReadError] = useState9("");
2374
- const [notes, setNotes] = useState9(
2214
+ const [open, setOpen] = useState7(false);
2215
+ const [form, setForm] = useState7(() => toForm(brand || {}));
2216
+ const [applyNow, setApplyNow] = useState7(true);
2217
+ const [reading, setReading] = useState7(false);
2218
+ const [readError, setReadError] = useState7("");
2219
+ const [notes, setNotes] = useState7(
2375
2220
  /** @type {string[]} */
2376
2221
  []
2377
2222
  );
2378
- const [uploading, setUploading] = useState9(false);
2379
- const [saving, setSaving] = useState9(false);
2380
- const [error, setError] = useState9("");
2381
- const abortRef = useRef2(
2223
+ const [uploading, setUploading] = useState7(false);
2224
+ const [saving, setSaving] = useState7(false);
2225
+ const [error, setError] = useState7("");
2226
+ const abortRef = useRef(
2382
2227
  /** @type {AbortController|null} */
2383
2228
  null
2384
2229
  );
2385
- const fileRef = useRef2(
2230
+ const fileRef = useRef(
2386
2231
  /** @type {HTMLInputElement|null} */
2387
2232
  null
2388
2233
  );
2389
2234
  const canRead = typeof storage.importBrand === "function";
2390
2235
  const canUpload = typeof storage.uploadImage === "function";
2391
- useEffect4(() => () => abortRef.current?.abort(), []);
2236
+ useEffect3(() => () => abortRef.current?.abort(), []);
2392
2237
  const logoUrl = form.logoUrl;
2393
- useEffect4(() => {
2238
+ useEffect3(() => {
2394
2239
  if (!logoUrl || !isLogoUrl(logoUrl)) return void 0;
2395
2240
  let live = true;
2396
2241
  const image = new Image();
@@ -2499,11 +2344,11 @@ function BrandButton({ context }) {
2499
2344
  }
2500
2345
  };
2501
2346
  const swatch = brand?.primary;
2502
- return /* @__PURE__ */ jsxs9(Fragment4, { children: [
2503
- /* @__PURE__ */ jsxs9(Button, { variant: "outline", size: "sm-compact", disabled: !ready, onClick: openDialog, "data-testid": "eb-brand-button", children: [
2504
- /* @__PURE__ */ jsx9(Palette, {}),
2347
+ return /* @__PURE__ */ jsxs7(Fragment4, { children: [
2348
+ /* @__PURE__ */ jsxs7(Button, { variant: "outline", size: "sm-compact", disabled: !ready, onClick: openDialog, "data-testid": "eb-brand-button", children: [
2349
+ /* @__PURE__ */ jsx7(Palette, {}),
2505
2350
  t("Brand"),
2506
- swatch && /* @__PURE__ */ jsx9(
2351
+ swatch && /* @__PURE__ */ jsx7(
2507
2352
  "span",
2508
2353
  {
2509
2354
  "aria-hidden": "true",
@@ -2512,18 +2357,18 @@ function BrandButton({ context }) {
2512
2357
  }
2513
2358
  )
2514
2359
  ] }),
2515
- /* @__PURE__ */ jsx9(Dialog, { open, onOpenChange: close, children: /* @__PURE__ */ jsxs9(
2360
+ /* @__PURE__ */ jsx7(Dialog, { open, onOpenChange: close, children: /* @__PURE__ */ jsxs7(
2516
2361
  DialogContent,
2517
2362
  {
2518
2363
  className: "eb:flex eb:max-h-[calc(100dvh-2rem)] eb:flex-col eb:gap-0 eb:p-0 eb:sm:max-w-2xl",
2519
2364
  "data-testid": "eb-brand",
2520
2365
  children: [
2521
- /* @__PURE__ */ jsxs9(DialogHeader, { className: "eb:gap-1.5 eb:px-6 eb:pt-6 eb:pb-4", children: [
2522
- /* @__PURE__ */ jsx9(DialogTitle, { children: t("Your brand") }),
2523
- /* @__PURE__ */ jsx9(DialogDescription, { children: t("Set it once: new emails, templates and blocks take your logo, colors and font.") })
2366
+ /* @__PURE__ */ jsxs7(DialogHeader, { className: "eb:gap-1.5 eb:px-6 eb:pt-6 eb:pb-4", children: [
2367
+ /* @__PURE__ */ jsx7(DialogTitle, { children: t("Your brand") }),
2368
+ /* @__PURE__ */ jsx7(DialogDescription, { children: t("Set it once: new emails, templates and blocks take your logo, colors and font.") })
2524
2369
  ] }),
2525
- /* @__PURE__ */ jsxs9("div", { className: "eb:min-h-0 eb:flex-1 eb:overflow-y-auto eb:border-y eb:border-border eb:px-6 eb:py-5", children: [
2526
- canRead && /* @__PURE__ */ jsxs9(
2370
+ /* @__PURE__ */ jsxs7("div", { className: "eb:min-h-0 eb:flex-1 eb:overflow-y-auto eb:border-y eb:border-border eb:px-6 eb:py-5", children: [
2371
+ canRead && /* @__PURE__ */ jsxs7(
2527
2372
  "form",
2528
2373
  {
2529
2374
  className: "eb:mb-5 eb:flex eb:flex-col eb:gap-1.5",
@@ -2532,11 +2377,11 @@ function BrandButton({ context }) {
2532
2377
  readWebsite();
2533
2378
  },
2534
2379
  children: [
2535
- /* @__PURE__ */ jsx9(Label, { htmlFor: "eb-brand-website", children: t("Your website") }),
2536
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-2 eb:sm:flex-row", children: [
2537
- /* @__PURE__ */ jsxs9("div", { className: "eb:relative eb:min-w-0 eb:flex-1", children: [
2538
- /* @__PURE__ */ jsx9(Globe, { className: "eb:pointer-events-none eb:absolute eb:top-1/2 eb:left-2.5 eb:size-3.5 eb:-translate-y-1/2 eb:text-foreground-muted", "aria-hidden": "true" }),
2539
- /* @__PURE__ */ jsx9(
2380
+ /* @__PURE__ */ jsx7(Label, { htmlFor: "eb-brand-website", children: t("Your website") }),
2381
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-2 eb:sm:flex-row", children: [
2382
+ /* @__PURE__ */ jsxs7("div", { className: "eb:relative eb:min-w-0 eb:flex-1", children: [
2383
+ /* @__PURE__ */ jsx7(Globe, { className: "eb:pointer-events-none eb:absolute eb:top-1/2 eb:left-2.5 eb:size-3.5 eb:-translate-y-1/2 eb:text-foreground-muted", "aria-hidden": "true" }),
2384
+ /* @__PURE__ */ jsx7(
2540
2385
  Input,
2541
2386
  {
2542
2387
  id: "eb-brand-website",
@@ -2550,28 +2395,28 @@ function BrandButton({ context }) {
2550
2395
  }
2551
2396
  )
2552
2397
  ] }),
2553
- /* @__PURE__ */ jsxs9(Button, { type: "submit", size: "sm", disabled: reading || !form.website.trim(), children: [
2554
- reading ? /* @__PURE__ */ jsx9(Loader23, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx9(WandSparkles, {}),
2398
+ /* @__PURE__ */ jsxs7(Button, { type: "submit", size: "sm", disabled: reading || !form.website.trim(), children: [
2399
+ reading ? /* @__PURE__ */ jsx7(Loader23, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx7(WandSparkles, {}),
2555
2400
  t("Get my brand")
2556
2401
  ] })
2557
2402
  ] }),
2558
- reading ? /* @__PURE__ */ jsx9("p", { role: "status", className: "eb:text-[12px] eb:text-foreground-muted", children: t("Reading the website\u2026") }) : readError ? /* @__PURE__ */ jsxs9("p", { role: "alert", className: "eb:flex eb:items-start eb:gap-1.5 eb:text-[12px] eb:text-destructive", children: [
2559
- /* @__PURE__ */ jsx9(TriangleAlert, { className: "eb:mt-px eb:size-3.5 eb:shrink-0", "aria-hidden": "true" }),
2403
+ reading ? /* @__PURE__ */ jsx7("p", { role: "status", className: "eb:text-[12px] eb:text-foreground-muted", children: t("Reading the website\u2026") }) : readError ? /* @__PURE__ */ jsxs7("p", { role: "alert", className: "eb:flex eb:items-start eb:gap-1.5 eb:text-[12px] eb:text-destructive", children: [
2404
+ /* @__PURE__ */ jsx7(TriangleAlert, { className: "eb:mt-px eb:size-3.5 eb:shrink-0", "aria-hidden": "true" }),
2560
2405
  readError
2561
- ] }) : notes.length ? /* @__PURE__ */ jsx9("ul", { className: "eb:flex eb:flex-col eb:gap-1 eb:text-[12px] eb:text-foreground-muted", "data-testid": "eb-brand-notes", children: notes.map((note) => /* @__PURE__ */ jsx9("li", { children: t(BRAND_NOTES[note]) }, note)) }) : /* @__PURE__ */ jsx9("p", { className: "eb:text-[12px] eb:text-foreground-muted", children: t("The logo, colors and font are read from it. You can change them before saving.") })
2406
+ ] }) : notes.length ? /* @__PURE__ */ jsx7("ul", { className: "eb:flex eb:flex-col eb:gap-1 eb:text-[12px] eb:text-foreground-muted", "data-testid": "eb-brand-notes", children: notes.map((note) => /* @__PURE__ */ jsx7("li", { children: t(BRAND_NOTES[note]) }, note)) }) : /* @__PURE__ */ jsx7("p", { className: "eb:text-[12px] eb:text-foreground-muted", children: t("The logo, colors and font are read from it. You can change them before saving.") })
2562
2407
  ]
2563
2408
  }
2564
2409
  ),
2565
- /* @__PURE__ */ jsxs9("div", { className: "eb:grid eb:gap-6 eb:sm:grid-cols-[minmax(0,1fr)_220px]", children: [
2566
- /* @__PURE__ */ jsxs9("fieldset", { disabled: reading, className: "eb:m-0 eb:flex eb:min-w-0 eb:flex-col eb:gap-4 eb:border-0 eb:p-0", children: [
2567
- /* @__PURE__ */ jsx9("legend", { className: "eb:sr-only", children: t("Your brand") }),
2568
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2569
- /* @__PURE__ */ jsx9(Label, { htmlFor: "eb-brand-logo", children: t("Logo") }),
2570
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:items-center eb:gap-3", children: [
2571
- /* @__PURE__ */ jsx9("div", { className: "eb-checker eb:flex eb:h-12 eb:w-24 eb:shrink-0 eb:items-center eb:justify-center eb:overflow-hidden eb:rounded-lg2 eb:ring-1 eb:ring-border eb:ring-inset", children: form.logoUrl && !logoInvalid ? /* @__PURE__ */ jsx9("img", { src: form.logoUrl, alt: t("Logo"), className: "eb:max-h-10 eb:max-w-20 eb:object-contain" }) : /* @__PURE__ */ jsx9(ImageOff, { className: "eb:size-4 eb:text-foreground-muted", "aria-hidden": "true" }) }),
2572
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-wrap eb:gap-2", children: [
2573
- canUpload && /* @__PURE__ */ jsxs9(Fragment4, { children: [
2574
- /* @__PURE__ */ jsx9(
2410
+ /* @__PURE__ */ jsxs7("div", { className: "eb:grid eb:gap-6 eb:sm:grid-cols-[minmax(0,1fr)_220px]", children: [
2411
+ /* @__PURE__ */ jsxs7("fieldset", { disabled: reading, className: "eb:m-0 eb:flex eb:min-w-0 eb:flex-col eb:gap-4 eb:border-0 eb:p-0", children: [
2412
+ /* @__PURE__ */ jsx7("legend", { className: "eb:sr-only", children: t("Your brand") }),
2413
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2414
+ /* @__PURE__ */ jsx7(Label, { htmlFor: "eb-brand-logo", children: t("Logo") }),
2415
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:items-center eb:gap-3", children: [
2416
+ /* @__PURE__ */ jsx7("div", { className: "eb-checker eb:flex eb:h-12 eb:w-24 eb:shrink-0 eb:items-center eb:justify-center eb:overflow-hidden eb:rounded-lg2 eb:ring-1 eb:ring-border eb:ring-inset", children: form.logoUrl && !logoInvalid ? /* @__PURE__ */ jsx7("img", { src: form.logoUrl, alt: t("Logo"), className: "eb:max-h-10 eb:max-w-20 eb:object-contain" }) : /* @__PURE__ */ jsx7(ImageOff, { className: "eb:size-4 eb:text-foreground-muted", "aria-hidden": "true" }) }),
2417
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-wrap eb:gap-2", children: [
2418
+ canUpload && /* @__PURE__ */ jsxs7(Fragment4, { children: [
2419
+ /* @__PURE__ */ jsx7(
2575
2420
  "input",
2576
2421
  {
2577
2422
  ref: fileRef,
@@ -2584,18 +2429,18 @@ function BrandButton({ context }) {
2584
2429
  onChange: pickLogo
2585
2430
  }
2586
2431
  ),
2587
- /* @__PURE__ */ jsxs9(Button, { type: "button", variant: "outline", size: "sm", disabled: uploading, onClick: () => fileRef.current?.click(), children: [
2588
- uploading ? /* @__PURE__ */ jsx9(Loader23, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx9(Upload, {}),
2432
+ /* @__PURE__ */ jsxs7(Button, { type: "button", variant: "outline", size: "sm", disabled: uploading, onClick: () => fileRef.current?.click(), children: [
2433
+ uploading ? /* @__PURE__ */ jsx7(Loader23, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx7(Upload, {}),
2589
2434
  t("Upload")
2590
2435
  ] })
2591
2436
  ] }),
2592
- form.logoUrl && /* @__PURE__ */ jsxs9(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => set({ logoUrl: "", logoWidth: 0 }), children: [
2593
- /* @__PURE__ */ jsx9(Trash22, {}),
2437
+ form.logoUrl && /* @__PURE__ */ jsxs7(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => set({ logoUrl: "", logoWidth: 0 }), children: [
2438
+ /* @__PURE__ */ jsx7(Trash22, {}),
2594
2439
  t("Remove")
2595
2440
  ] })
2596
2441
  ] })
2597
2442
  ] }),
2598
- /* @__PURE__ */ jsx9(
2443
+ /* @__PURE__ */ jsx7(
2599
2444
  Input,
2600
2445
  {
2601
2446
  id: "eb-brand-logo",
@@ -2606,11 +2451,11 @@ function BrandButton({ context }) {
2606
2451
  className: "eb:text-[12px]"
2607
2452
  }
2608
2453
  ),
2609
- logoInvalid && /* @__PURE__ */ jsx9("p", { className: "eb:text-[12px] eb:text-destructive", children: t("An https:// address is required") })
2454
+ logoInvalid && /* @__PURE__ */ jsx7("p", { className: "eb:text-[12px] eb:text-destructive", children: t("An https:// address is required") })
2610
2455
  ] }),
2611
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2612
- /* @__PURE__ */ jsx9(Label, { htmlFor: "eb-brand-name", children: t("Company name") }),
2613
- /* @__PURE__ */ jsx9(
2456
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2457
+ /* @__PURE__ */ jsx7(Label, { htmlFor: "eb-brand-name", children: t("Company name") }),
2458
+ /* @__PURE__ */ jsx7(
2614
2459
  Input,
2615
2460
  {
2616
2461
  id: "eb-brand-name",
@@ -2621,36 +2466,36 @@ function BrandButton({ context }) {
2621
2466
  }
2622
2467
  )
2623
2468
  ] }),
2624
- /* @__PURE__ */ jsxs9("div", { className: "eb:grid eb:gap-4 eb:sm:grid-cols-2", children: [
2625
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2626
- /* @__PURE__ */ jsx9(Label, { htmlFor: "eb-brand-primary", children: t("Main color") }),
2627
- /* @__PURE__ */ jsx9(ColorPicker, { id: "eb-brand-primary", value: form.primary, onChange: (primary) => set({ primary }), placeholder: PALETTE.navy }),
2628
- /* @__PURE__ */ jsx9("p", { className: "eb:text-[11px] eb:text-foreground-muted", children: t("Buttons, banners, links") })
2469
+ /* @__PURE__ */ jsxs7("div", { className: "eb:grid eb:gap-4 eb:sm:grid-cols-2", children: [
2470
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2471
+ /* @__PURE__ */ jsx7(Label, { htmlFor: "eb-brand-primary", children: t("Main color") }),
2472
+ /* @__PURE__ */ jsx7(ColorPicker, { id: "eb-brand-primary", value: form.primary, onChange: (primary) => set({ primary }), placeholder: PALETTE.navy }),
2473
+ /* @__PURE__ */ jsx7("p", { className: "eb:text-[11px] eb:text-foreground-muted", children: t("Buttons, banners, links") })
2629
2474
  ] }),
2630
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2631
- /* @__PURE__ */ jsx9(Label, { htmlFor: "eb-brand-heading", children: t("Headings color") }),
2632
- /* @__PURE__ */ jsx9(ColorPicker, { id: "eb-brand-heading", value: form.heading, onChange: (heading2) => set({ heading: heading2 }), placeholder: PALETTE.navy })
2475
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2476
+ /* @__PURE__ */ jsx7(Label, { htmlFor: "eb-brand-heading", children: t("Headings color") }),
2477
+ /* @__PURE__ */ jsx7(ColorPicker, { id: "eb-brand-heading", value: form.heading, onChange: (heading2) => set({ heading: heading2 }), placeholder: PALETTE.navy })
2633
2478
  ] })
2634
2479
  ] }),
2635
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2636
- /* @__PURE__ */ jsx9(Label, { htmlFor: "eb-brand-font", children: t("Font") }),
2637
- /* @__PURE__ */ jsxs9(Select, { value: form.font || FONT_STACK, onValueChange: (font) => set({ font }), children: [
2638
- /* @__PURE__ */ jsx9(SelectTrigger, { id: "eb-brand-font", children: /* @__PURE__ */ jsx9(SelectValue, {}) }),
2639
- /* @__PURE__ */ jsx9(SelectContent, { children: FONT_OPTIONS.map((option) => /* @__PURE__ */ jsx9(SelectItem, { value: option.value, children: /* @__PURE__ */ jsx9("span", { style: { fontFamily: option.value }, children: option.label }) }, option.value)) })
2480
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2481
+ /* @__PURE__ */ jsx7(Label, { htmlFor: "eb-brand-font", children: t("Font") }),
2482
+ /* @__PURE__ */ jsxs7(Select, { value: form.font || FONT_STACK, onValueChange: (font) => set({ font }), children: [
2483
+ /* @__PURE__ */ jsx7(SelectTrigger, { id: "eb-brand-font", children: /* @__PURE__ */ jsx7(SelectValue, {}) }),
2484
+ /* @__PURE__ */ jsx7(SelectContent, { children: FONT_OPTIONS.map((option) => /* @__PURE__ */ jsx7(SelectItem, { value: option.value, children: /* @__PURE__ */ jsx7("span", { style: { fontFamily: option.value }, children: option.label }) }, option.value)) })
2640
2485
  ] })
2641
2486
  ] })
2642
2487
  ] }),
2643
- /* @__PURE__ */ jsx9(BrandPreview, { brand: draft, fallbackName: hostSender?.name || t("Your company") })
2488
+ /* @__PURE__ */ jsx7(BrandPreview, { brand: draft, fallbackName: hostSender?.name || t("Your company") })
2644
2489
  ] })
2645
2490
  ] }),
2646
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-3 eb:px-6 eb:pt-3 eb:pb-6", children: [
2647
- error && /* @__PURE__ */ jsxs9("p", { role: "alert", className: "eb:flex eb:items-start eb:gap-1.5 eb:text-[12px] eb:text-destructive", children: [
2648
- /* @__PURE__ */ jsx9(TriangleAlert, { className: "eb:mt-px eb:size-3.5 eb:shrink-0", "aria-hidden": "true" }),
2491
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-3 eb:px-6 eb:pt-3 eb:pb-6", children: [
2492
+ error && /* @__PURE__ */ jsxs7("p", { role: "alert", className: "eb:flex eb:items-start eb:gap-1.5 eb:text-[12px] eb:text-destructive", children: [
2493
+ /* @__PURE__ */ jsx7(TriangleAlert, { className: "eb:mt-px eb:size-3.5 eb:shrink-0", "aria-hidden": "true" }),
2649
2494
  error
2650
2495
  ] }),
2651
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-3 eb:sm:flex-row eb:sm:items-center", children: [
2652
- /* @__PURE__ */ jsxs9("label", { className: "eb:flex eb:cursor-pointer eb:items-center eb:gap-2 eb:text-[13px] eb:sm:mr-auto", children: [
2653
- /* @__PURE__ */ jsx9(
2496
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-3 eb:sm:flex-row eb:sm:items-center", children: [
2497
+ /* @__PURE__ */ jsxs7("label", { className: "eb:flex eb:cursor-pointer eb:items-center eb:gap-2 eb:text-[13px] eb:sm:mr-auto", children: [
2498
+ /* @__PURE__ */ jsx7(
2654
2499
  "input",
2655
2500
  {
2656
2501
  type: "checkbox",
@@ -2662,10 +2507,10 @@ function BrandButton({ context }) {
2662
2507
  ),
2663
2508
  t("Also apply to this email")
2664
2509
  ] }),
2665
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:justify-end eb:gap-2", children: [
2666
- /* @__PURE__ */ jsx9(Button, { variant: "outline", size: "sm", onClick: () => close(false), children: t("Cancel") }),
2667
- /* @__PURE__ */ jsxs9(Button, { size: "sm", onClick: save, disabled: saving || reading || uploading || logoInvalid, "data-testid": "eb-brand-save", children: [
2668
- saving && /* @__PURE__ */ jsx9(Loader23, { className: "eb:animate-spin" }),
2510
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:justify-end eb:gap-2", children: [
2511
+ /* @__PURE__ */ jsx7(Button, { variant: "outline", size: "sm", onClick: () => close(false), children: t("Cancel") }),
2512
+ /* @__PURE__ */ jsxs7(Button, { size: "sm", onClick: save, disabled: saving || reading || uploading || logoInvalid, "data-testid": "eb-brand-save", children: [
2513
+ saving && /* @__PURE__ */ jsx7(Loader23, { className: "eb:animate-spin" }),
2669
2514
  t("Save")
2670
2515
  ] })
2671
2516
  ] })
@@ -2684,30 +2529,30 @@ function BrandPreview({ brand, fallbackName }) {
2684
2529
  const link2 = contrastRatio(primary, PALETTE.white) >= 3 ? primary : heading2;
2685
2530
  const font = brand.font || FONT_STACK;
2686
2531
  const name = brand.name || fallbackName;
2687
- return /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2688
- /* @__PURE__ */ jsx9("span", { className: "eb:text-[12px] eb:font-medium eb:text-foreground-muted", children: t("Preview") }),
2689
- /* @__PURE__ */ jsx9(
2532
+ return /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5", children: [
2533
+ /* @__PURE__ */ jsx7("span", { className: "eb:text-[12px] eb:font-medium eb:text-foreground-muted", children: t("Preview") }),
2534
+ /* @__PURE__ */ jsx7(
2690
2535
  "div",
2691
2536
  {
2692
2537
  className: "eb:overflow-hidden eb:rounded-lg2 eb:p-2.5 eb:ring-1 eb:ring-border",
2693
2538
  style: { backgroundColor: PALETTE.canvas, fontFamily: font },
2694
2539
  "data-testid": "eb-brand-preview",
2695
2540
  "aria-hidden": "true",
2696
- children: /* @__PURE__ */ jsxs9("div", { className: "eb:overflow-hidden eb:rounded-[3px]", style: { backgroundColor: PALETTE.white }, children: [
2697
- /* @__PURE__ */ jsx9("div", { className: "eb:px-3 eb:pt-3 eb:pb-2", children: brand.logoUrl ? /* @__PURE__ */ jsx9("img", { src: brand.logoUrl, alt: "", style: { width: Math.round((brand.logoWidth || 140) * 0.45), maxWidth: "100%" } }) : /* @__PURE__ */ jsx9("span", { className: "eb:text-[11px] eb:font-bold", style: { color: PALETTE.ink }, children: name }) }),
2698
- /* @__PURE__ */ jsxs9("div", { className: "eb:px-3 eb:py-4 eb:text-center", style: { backgroundColor: primary, color: onPrimary }, children: [
2699
- /* @__PURE__ */ jsx9("div", { className: "eb:text-[13px] eb:leading-tight eb:font-bold", children: t("Big news") }),
2700
- /* @__PURE__ */ jsx9("div", { className: "eb:mt-1 eb:text-[9px] eb:opacity-90", children: t("A short line under the title.") })
2541
+ children: /* @__PURE__ */ jsxs7("div", { className: "eb:overflow-hidden eb:rounded-[3px]", style: { backgroundColor: PALETTE.white }, children: [
2542
+ /* @__PURE__ */ jsx7("div", { className: "eb:px-3 eb:pt-3 eb:pb-2", children: brand.logoUrl ? /* @__PURE__ */ jsx7("img", { src: brand.logoUrl, alt: "", style: { width: Math.round((brand.logoWidth || 140) * 0.45), maxWidth: "100%" } }) : /* @__PURE__ */ jsx7("span", { className: "eb:text-[11px] eb:font-bold", style: { color: PALETTE.ink }, children: name }) }),
2543
+ /* @__PURE__ */ jsxs7("div", { className: "eb:px-3 eb:py-4 eb:text-center", style: { backgroundColor: primary, color: onPrimary }, children: [
2544
+ /* @__PURE__ */ jsx7("div", { className: "eb:text-[13px] eb:leading-tight eb:font-bold", children: t("Big news") }),
2545
+ /* @__PURE__ */ jsx7("div", { className: "eb:mt-1 eb:text-[9px] eb:opacity-90", children: t("A short line under the title.") })
2701
2546
  ] }),
2702
- /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:flex-col eb:gap-1.5 eb:px-3 eb:py-3", children: [
2703
- /* @__PURE__ */ jsx9("div", { className: "eb:text-[11px] eb:leading-tight eb:font-bold", style: { color: heading2 }, children: t("A headline") }),
2704
- /* @__PURE__ */ jsxs9("div", { className: "eb:text-[9px] eb:leading-snug", style: { color: PALETTE.ink }, children: [
2547
+ /* @__PURE__ */ jsxs7("div", { className: "eb:flex eb:flex-col eb:gap-1.5 eb:px-3 eb:py-3", children: [
2548
+ /* @__PURE__ */ jsx7("div", { className: "eb:text-[11px] eb:leading-tight eb:font-bold", style: { color: heading2 }, children: t("A headline") }),
2549
+ /* @__PURE__ */ jsxs7("div", { className: "eb:text-[9px] eb:leading-snug", style: { color: PALETTE.ink }, children: [
2705
2550
  t("Some text, with"),
2706
2551
  " ",
2707
- /* @__PURE__ */ jsx9("span", { className: "eb:underline", style: { color: link2 }, children: t("a link") }),
2552
+ /* @__PURE__ */ jsx7("span", { className: "eb:underline", style: { color: link2 }, children: t("a link") }),
2708
2553
  "."
2709
2554
  ] }),
2710
- /* @__PURE__ */ jsx9(
2555
+ /* @__PURE__ */ jsx7(
2711
2556
  "span",
2712
2557
  {
2713
2558
  className: cn("eb:mt-1 eb:self-start eb:rounded-[3px] eb:px-2.5 eb:py-1 eb:text-[9px] eb:font-bold"),
@@ -2716,7 +2561,7 @@ function BrandPreview({ brand, fallbackName }) {
2716
2561
  }
2717
2562
  )
2718
2563
  ] }),
2719
- /* @__PURE__ */ jsx9("div", { className: "eb:px-3 eb:pb-2.5 eb:text-center eb:text-[7px]", style: { color: "#6d7484" }, children: name })
2564
+ /* @__PURE__ */ jsx7("div", { className: "eb:px-3 eb:pb-2.5 eb:text-center eb:text-[7px]", style: { color: "#6d7484" }, children: name })
2720
2565
  ] })
2721
2566
  }
2722
2567
  )
@@ -4672,14 +4517,14 @@ function createDefaultEmailEditor(options = {}) {
4672
4517
  }
4673
4518
 
4674
4519
  // src/ui/EmailCanvas.jsx
4675
- import { useEffect as useEffect5, useRef as useRef3 } from "react";
4676
- import { jsx as jsx10 } from "react/jsx-runtime";
4520
+ import { useEffect as useEffect4, useRef as useRef2 } from "react";
4521
+ import { jsx as jsx8 } from "react/jsx-runtime";
4677
4522
  function EmailCanvas({ editor, document = null, onReady, onError, className }) {
4678
- const ref = useRef3(null);
4679
- const documentRef = useRef3(document);
4680
- const callbacks = useRef3({ onReady, onError });
4523
+ const ref = useRef2(null);
4524
+ const documentRef = useRef2(document);
4525
+ const callbacks = useRef2({ onReady, onError });
4681
4526
  callbacks.current = { onReady, onError };
4682
- useEffect5(() => {
4527
+ useEffect4(() => {
4683
4528
  if (!editor || !ref.current) return void 0;
4684
4529
  let alive = true;
4685
4530
  editor.initialize({ container: ref.current, document: documentRef.current }).then(() => {
@@ -4692,15 +4537,15 @@ function EmailCanvas({ editor, document = null, onReady, onError, className }) {
4692
4537
  editor.destroy();
4693
4538
  };
4694
4539
  }, [editor]);
4695
- return /* @__PURE__ */ jsx10("div", { ref, className: cn("eb-canvas eb:h-full eb:w-full", className), "data-testid": "eb-canvas" });
4540
+ return /* @__PURE__ */ jsx8("div", { ref, className: cn("eb-canvas eb:h-full eb:w-full", className), "data-testid": "eb-canvas" });
4696
4541
  }
4697
4542
 
4698
4543
  // src/ui/EmailBuilder.jsx
4699
- import { useCallback as useCallback3, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef8, useState as useState14 } from "react";
4700
- import { AlertTriangle, Loader2 as Loader25, Plus as Plus2, Save, SlidersHorizontal } from "lucide-react";
4544
+ import { useCallback as useCallback3, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef8, useState as useState13 } from "react";
4545
+ import { AlertTriangle, Loader2 as Loader25, Plus as Plus3, Save, SlidersHorizontal } from "lucide-react";
4701
4546
 
4702
4547
  // src/features/brand/useBrand.js
4703
- import { useCallback, useEffect as useEffect6, useState as useState10 } from "react";
4548
+ import { useCallback, useEffect as useEffect5, useState as useState8 } from "react";
4704
4549
  var entries = /* @__PURE__ */ new WeakMap();
4705
4550
  function brandOf(storage) {
4706
4551
  let entry = entries.get(storage);
@@ -4721,8 +4566,8 @@ function brandOf(storage) {
4721
4566
  return created;
4722
4567
  }
4723
4568
  function useBrand(storage) {
4724
- const [brand, setState] = useState10(() => brandOf(storage).value);
4725
- useEffect6(() => {
4569
+ const [brand, setState] = useState8(() => brandOf(storage).value);
4570
+ useEffect5(() => {
4726
4571
  const entry = brandOf(storage);
4727
4572
  setState(entry.value);
4728
4573
  entry.listeners.add(setState);
@@ -4849,8 +4694,8 @@ import {
4849
4694
  Square,
4850
4695
  Type
4851
4696
  } from "lucide-react";
4852
- import { useRef as useRef4 } from "react";
4853
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
4697
+ import { useRef as useRef3 } from "react";
4698
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4854
4699
  var DRAG_THRESHOLD = 5;
4855
4700
  var ICONS2 = {
4856
4701
  Heading,
@@ -4875,8 +4720,8 @@ var GROUPS2 = [
4875
4720
  function BlockTile({ block, disabled, onAdd, onDragStart }) {
4876
4721
  const t = useT();
4877
4722
  const Icon = ICONS2[block.icon] || Square;
4878
- const press = useRef4(null);
4879
- return /* @__PURE__ */ jsx11(TooltipWrap, { label: block.description ? t(block.description) : block.description, children: /* @__PURE__ */ jsxs10(
4723
+ const press = useRef3(null);
4724
+ return /* @__PURE__ */ jsx9(TooltipWrap, { label: block.description ? t(block.description) : block.description, children: /* @__PURE__ */ jsxs8(
4880
4725
  "button",
4881
4726
  {
4882
4727
  type: "button",
@@ -4916,8 +4761,8 @@ function BlockTile({ block, disabled, onAdd, onDragStart }) {
4916
4761
  disabled && "eb:cursor-not-allowed eb:opacity-50"
4917
4762
  ),
4918
4763
  children: [
4919
- /* @__PURE__ */ jsx11(Icon, { className: "eb:h-5 eb:w-5 eb:text-foreground-lighter", "aria-hidden": "true" }),
4920
- /* @__PURE__ */ jsx11("span", { className: "eb:text-[12px] eb:text-foreground", children: t(block.label) })
4764
+ /* @__PURE__ */ jsx9(Icon, { className: "eb:h-5 eb:w-5 eb:text-foreground-lighter", "aria-hidden": "true" }),
4765
+ /* @__PURE__ */ jsx9("span", { className: "eb:text-[12px] eb:text-foreground", children: t(block.label) })
4921
4766
  ]
4922
4767
  }
4923
4768
  ) });
@@ -4925,12 +4770,12 @@ function BlockTile({ block, disabled, onAdd, onDragStart }) {
4925
4770
  function BlockSidebar({ editor, disabled = false, onAdded }) {
4926
4771
  const t = useT();
4927
4772
  const blocks = editor.listBlocks();
4928
- return /* @__PURE__ */ jsx11("aside", { "aria-label": t("Blocks"), className: "eb:min-h-0 eb:space-y-5 eb:overflow-y-auto eb:border-r eb:border-border eb:p-3", children: GROUPS2.map((group) => {
4773
+ return /* @__PURE__ */ jsx9("aside", { "aria-label": t("Blocks"), className: "eb:min-h-0 eb:space-y-5 eb:overflow-y-auto eb:border-r eb:border-border eb:p-3", children: GROUPS2.map((group) => {
4929
4774
  const items = blocks.filter((b) => b.kind === group.kind && b.mjml);
4930
4775
  if (!items.length) return null;
4931
- return /* @__PURE__ */ jsxs10("section", { className: "eb:space-y-2", children: [
4932
- /* @__PURE__ */ jsx11(SectionLabel, { children: t(group.title) }),
4933
- /* @__PURE__ */ jsx11("div", { className: "eb:grid eb:grid-cols-2 eb:gap-2", children: items.map((block) => /* @__PURE__ */ jsx11(
4776
+ return /* @__PURE__ */ jsxs8("section", { className: "eb:space-y-2", children: [
4777
+ /* @__PURE__ */ jsx9(SectionLabel, { children: t(group.title) }),
4778
+ /* @__PURE__ */ jsx9("div", { className: "eb:grid eb:grid-cols-2 eb:gap-2", children: items.map((block) => /* @__PURE__ */ jsx9(
4934
4779
  BlockTile,
4935
4780
  {
4936
4781
  block,
@@ -4948,15 +4793,15 @@ function BlockSidebar({ editor, disabled = false, onAdded }) {
4948
4793
 
4949
4794
  // src/ui/ElementActions.jsx
4950
4795
  import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Copy, Trash2 as Trash23 } from "lucide-react";
4951
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4796
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
4952
4797
  function ElementActions({ editor, selection }) {
4953
4798
  const t = useT();
4954
4799
  if (!selection || !selection.canRemove && !selection.canDuplicate) return null;
4955
4800
  const horizontal = selection.tagName === "mj-column";
4956
4801
  const [Prev, Next] = horizontal ? [ArrowLeft, ArrowRight] : [ArrowUp, ArrowDown];
4957
4802
  const [prevLabel, nextLabel] = horizontal ? [t("Move left"), t("Move right")] : [t("Move up"), t("Move down")];
4958
- return /* @__PURE__ */ jsxs11("div", { className: "eb:flex eb:items-center eb:gap-0.5 eb:border-b eb:border-border eb:px-3 eb:py-1.5", role: "toolbar", "aria-label": t("Element actions"), children: [
4959
- /* @__PURE__ */ jsx12(TooltipWrap, { label: prevLabel, children: /* @__PURE__ */ jsx12(
4803
+ return /* @__PURE__ */ jsxs9("div", { className: "eb:flex eb:items-center eb:gap-0.5 eb:border-b eb:border-border eb:px-3 eb:py-1.5", role: "toolbar", "aria-label": t("Element actions"), children: [
4804
+ /* @__PURE__ */ jsx10(TooltipWrap, { label: prevLabel, children: /* @__PURE__ */ jsx10(
4960
4805
  Button,
4961
4806
  {
4962
4807
  variant: "ghost",
@@ -4964,10 +4809,10 @@ function ElementActions({ editor, selection }) {
4964
4809
  "aria-label": prevLabel,
4965
4810
  disabled: !selection.canMoveUp,
4966
4811
  onClick: () => editor.move(-1, selection.id),
4967
- children: /* @__PURE__ */ jsx12(Prev, {})
4812
+ children: /* @__PURE__ */ jsx10(Prev, {})
4968
4813
  }
4969
4814
  ) }),
4970
- /* @__PURE__ */ jsx12(TooltipWrap, { label: nextLabel, children: /* @__PURE__ */ jsx12(
4815
+ /* @__PURE__ */ jsx10(TooltipWrap, { label: nextLabel, children: /* @__PURE__ */ jsx10(
4971
4816
  Button,
4972
4817
  {
4973
4818
  variant: "ghost",
@@ -4975,10 +4820,10 @@ function ElementActions({ editor, selection }) {
4975
4820
  "aria-label": nextLabel,
4976
4821
  disabled: !selection.canMoveDown,
4977
4822
  onClick: () => editor.move(1, selection.id),
4978
- children: /* @__PURE__ */ jsx12(Next, {})
4823
+ children: /* @__PURE__ */ jsx10(Next, {})
4979
4824
  }
4980
4825
  ) }),
4981
- /* @__PURE__ */ jsx12(TooltipWrap, { label: t("Duplicate"), children: /* @__PURE__ */ jsx12(
4826
+ /* @__PURE__ */ jsx10(TooltipWrap, { label: t("Duplicate"), children: /* @__PURE__ */ jsx10(
4982
4827
  Button,
4983
4828
  {
4984
4829
  variant: "ghost",
@@ -4986,10 +4831,10 @@ function ElementActions({ editor, selection }) {
4986
4831
  "aria-label": t("Duplicate"),
4987
4832
  disabled: !selection.canDuplicate,
4988
4833
  onClick: () => editor.duplicate(selection.id),
4989
- children: /* @__PURE__ */ jsx12(Copy, {})
4834
+ children: /* @__PURE__ */ jsx10(Copy, {})
4990
4835
  }
4991
4836
  ) }),
4992
- /* @__PURE__ */ jsx12(TooltipWrap, { label: t("Delete (Del)"), children: /* @__PURE__ */ jsx12(
4837
+ /* @__PURE__ */ jsx10(TooltipWrap, { label: t("Delete (Del)"), children: /* @__PURE__ */ jsx10(
4993
4838
  Button,
4994
4839
  {
4995
4840
  variant: "ghost",
@@ -4998,7 +4843,7 @@ function ElementActions({ editor, selection }) {
4998
4843
  disabled: !selection.canRemove,
4999
4844
  onClick: () => editor.remove(selection.id),
5000
4845
  className: "eb:ml-auto eb:text-foreground-muted eb:hover:bg-destructive/10 eb:hover:text-destructive",
5001
- children: /* @__PURE__ */ jsx12(Trash23, {})
4846
+ children: /* @__PURE__ */ jsx10(Trash23, {})
5002
4847
  }
5003
4848
  ) })
5004
4849
  ] });
@@ -5009,9 +4854,9 @@ import { useMemo as useMemo4, useRef as useRef6 } from "react";
5009
4854
  import { X as X2 } from "lucide-react";
5010
4855
 
5011
4856
  // src/ui/fields.jsx
5012
- import { useEffect as useEffect7, useRef as useRef5, useState as useState11 } from "react";
4857
+ import { useEffect as useEffect6, useRef as useRef4, useState as useState9 } from "react";
5013
4858
  import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Loader2 as Loader24, Upload as Upload2 } from "lucide-react";
5014
- import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
4859
+ import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
5015
4860
  var COLOR_DEBOUNCE_MS = 250;
5016
4861
  function emailColor(value) {
5017
4862
  const v = String(value || "").trim();
@@ -5020,11 +4865,11 @@ function emailColor(value) {
5020
4865
  return null;
5021
4866
  }
5022
4867
  function useDraft(value, toDraft) {
5023
- const [draft, setDraft] = useState11(() => toDraft(value));
5024
- const ref = useRef5(null);
5025
- const convert = useRef5(toDraft);
4868
+ const [draft, setDraft] = useState9(() => toDraft(value));
4869
+ const ref = useRef4(null);
4870
+ const convert = useRef4(toDraft);
5026
4871
  convert.current = toDraft;
5027
- useEffect7(() => {
4872
+ useEffect6(() => {
5028
4873
  const el = ref.current;
5029
4874
  const focused = el && el.ownerDocument?.activeElement && el.contains(el.ownerDocument.activeElement);
5030
4875
  if (!focused) setDraft(convert.current(value));
@@ -5033,10 +4878,10 @@ function useDraft(value, toDraft) {
5033
4878
  }
5034
4879
  var asText = (v) => v || "";
5035
4880
  function FieldLabel({ id, children }) {
5036
- return /* @__PURE__ */ jsx13(Label, { htmlFor: id, className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children });
4881
+ return /* @__PURE__ */ jsx11(Label, { htmlFor: id, className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children });
5037
4882
  }
5038
4883
  function FieldError({ children }) {
5039
- return children ? /* @__PURE__ */ jsx13("p", { className: "eb:text-[12px] eb:text-destructive", children }) : null;
4884
+ return children ? /* @__PURE__ */ jsx11("p", { className: "eb:text-[12px] eb:text-destructive", children }) : null;
5040
4885
  }
5041
4886
  function TextField({ id, property, value, fallback = "", onCommit, addon = null, error = null }) {
5042
4887
  const t = useT();
@@ -5067,23 +4912,23 @@ function TextField({ id, property, value, fallback = "", onCommit, addon = null,
5067
4912
  onKeyDown: keyDown,
5068
4913
  "aria-invalid": invalid || void 0
5069
4914
  };
5070
- return /* @__PURE__ */ jsxs12("div", { ref, className: "eb:space-y-1.5", children: [
5071
- /* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
5072
- property.type === "textarea" ? /* @__PURE__ */ jsx13(Textarea, { rows: 3, ...shared }) : addon ? /* @__PURE__ */ jsxs12("div", { className: "eb:flex eb:gap-2", children: [
5073
- /* @__PURE__ */ jsx13(Input, { ...shared, className: "eb:min-w-0 eb:flex-1" }),
4915
+ return /* @__PURE__ */ jsxs10("div", { ref, className: "eb:space-y-1.5", children: [
4916
+ /* @__PURE__ */ jsx11(FieldLabel, { id, children: t(property.label) }),
4917
+ property.type === "textarea" ? /* @__PURE__ */ jsx11(Textarea, { rows: 3, ...shared }) : addon ? /* @__PURE__ */ jsxs10("div", { className: "eb:flex eb:gap-2", children: [
4918
+ /* @__PURE__ */ jsx11(Input, { ...shared, className: "eb:min-w-0 eb:flex-1" }),
5074
4919
  addon
5075
- ] }) : /* @__PURE__ */ jsx13(Input, { ...shared }),
5076
- /* @__PURE__ */ jsx13(FieldError, { children: invalid ? kind === "image" ? t("An https:// address is required") : t("Address not allowed") : error })
4920
+ ] }) : /* @__PURE__ */ jsx11(Input, { ...shared }),
4921
+ /* @__PURE__ */ jsx11(FieldError, { children: invalid ? kind === "image" ? t("An https:// address is required") : t("Address not allowed") : error })
5077
4922
  ] });
5078
4923
  }
5079
4924
  function ImageField({ id, property, value, onCommit, services }) {
5080
4925
  const t = useT();
5081
- const inputRef = useRef5(
4926
+ const inputRef = useRef4(
5082
4927
  /** @type {HTMLInputElement|null} */
5083
4928
  null
5084
4929
  );
5085
- const [busy, setBusy] = useState11(false);
5086
- const [error, setError] = useState11(
4930
+ const [busy, setBusy] = useState9(false);
4931
+ const [error, setError] = useState9(
5087
4932
  /** @type {string|null} */
5088
4933
  null
5089
4934
  );
@@ -5105,8 +4950,8 @@ function ImageField({ id, property, value, onCommit, services }) {
5105
4950
  setBusy(false);
5106
4951
  }
5107
4952
  };
5108
- const addon = upload ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
5109
- /* @__PURE__ */ jsx13(
4953
+ const addon = upload ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
4954
+ /* @__PURE__ */ jsx11(
5110
4955
  "input",
5111
4956
  {
5112
4957
  ref: inputRef,
@@ -5119,7 +4964,7 @@ function ImageField({ id, property, value, onCommit, services }) {
5119
4964
  onChange: pick
5120
4965
  }
5121
4966
  ),
5122
- /* @__PURE__ */ jsxs12(
4967
+ /* @__PURE__ */ jsxs10(
5123
4968
  Button,
5124
4969
  {
5125
4970
  type: "button",
@@ -5128,13 +4973,13 @@ function ImageField({ id, property, value, onCommit, services }) {
5128
4973
  disabled: busy,
5129
4974
  onClick: () => inputRef.current?.click(),
5130
4975
  children: [
5131
- busy ? /* @__PURE__ */ jsx13(Loader24, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx13(Upload2, {}),
4976
+ busy ? /* @__PURE__ */ jsx11(Loader24, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx11(Upload2, {}),
5132
4977
  t("Upload")
5133
4978
  ]
5134
4979
  }
5135
4980
  )
5136
4981
  ] }) : null;
5137
- return /* @__PURE__ */ jsx13(TextField, { id, property, value, onCommit, addon, error });
4982
+ return /* @__PURE__ */ jsx11(TextField, { id, property, value, onCommit, addon, error });
5138
4983
  }
5139
4984
  var asNumber = (v) => {
5140
4985
  const n = Number.parseFloat(String(v || ""));
@@ -5156,10 +5001,10 @@ function SizeField({ id, property, value, fallback = "", onCommit }) {
5156
5001
  const next = `${n}${property.unit || "px"}`;
5157
5002
  if (next !== value) onCommit(next);
5158
5003
  };
5159
- return /* @__PURE__ */ jsxs12("div", { ref, className: "eb:space-y-1.5", children: [
5160
- /* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
5161
- /* @__PURE__ */ jsxs12("div", { className: "eb:relative", children: [
5162
- /* @__PURE__ */ jsx13(
5004
+ return /* @__PURE__ */ jsxs10("div", { ref, className: "eb:space-y-1.5", children: [
5005
+ /* @__PURE__ */ jsx11(FieldLabel, { id, children: t(property.label) }),
5006
+ /* @__PURE__ */ jsxs10("div", { className: "eb:relative", children: [
5007
+ /* @__PURE__ */ jsx11(
5163
5008
  Input,
5164
5009
  {
5165
5010
  id,
@@ -5178,17 +5023,17 @@ function SizeField({ id, property, value, fallback = "", onCommit }) {
5178
5023
  className: "eb:pr-9 eb:tabular-nums"
5179
5024
  }
5180
5025
  ),
5181
- /* @__PURE__ */ jsx13("span", { className: "eb:pointer-events-none eb:absolute eb:right-3 eb:top-1/2 eb:-translate-y-1/2 eb:text-[12px] eb:text-foreground-muted", children: property.unit || "px" })
5026
+ /* @__PURE__ */ jsx11("span", { className: "eb:pointer-events-none eb:absolute eb:right-3 eb:top-1/2 eb:-translate-y-1/2 eb:text-[12px] eb:text-foreground-muted", children: property.unit || "px" })
5182
5027
  ] })
5183
5028
  ] });
5184
5029
  }
5185
5030
  function ColorField({ id, property, value, fallback = "", onCommit }) {
5186
5031
  const t = useT();
5187
5032
  const [draft, setDraft, ref] = useDraft(value, asText);
5188
- const timer = useRef5(null);
5189
- const latest = useRef5({ value, onCommit });
5033
+ const timer = useRef4(null);
5034
+ const latest = useRef4({ value, onCommit });
5190
5035
  latest.current = { value, onCommit };
5191
- useEffect7(() => () => clearTimeout(timer.current), []);
5036
+ useEffect6(() => () => clearTimeout(timer.current), []);
5192
5037
  const change = (next) => {
5193
5038
  setDraft(next);
5194
5039
  clearTimeout(timer.current);
@@ -5201,9 +5046,9 @@ function ColorField({ id, property, value, fallback = "", onCommit }) {
5201
5046
  }
5202
5047
  }, COLOR_DEBOUNCE_MS);
5203
5048
  };
5204
- return /* @__PURE__ */ jsxs12("div", { ref, className: "eb:space-y-1.5", children: [
5205
- /* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
5206
- /* @__PURE__ */ jsx13(ColorPicker, { id, value: draft, placeholder: emailColor(fallback) || "", onChange: change })
5049
+ return /* @__PURE__ */ jsxs10("div", { ref, className: "eb:space-y-1.5", children: [
5050
+ /* @__PURE__ */ jsx11(FieldLabel, { id, children: t(property.label) }),
5051
+ /* @__PURE__ */ jsx11(ColorPicker, { id, value: draft, placeholder: emailColor(fallback) || "", onChange: change })
5207
5052
  ] });
5208
5053
  }
5209
5054
  var DEFAULT_OPTION = "__default__";
@@ -5213,9 +5058,9 @@ function SelectField({ id, property, value, fallback = "", onCommit }) {
5213
5058
  const words = (v) => String(v || "").trim().split(/\s+/).sort().join(" ");
5214
5059
  const fallbackOption = (property.options || []).find((o) => o.value && words(o.value) === words(fallback));
5215
5060
  const defaultLabel = fallbackOption ? t("Default ({value})", { value: t(fallbackOption.label) }) : t("Default");
5216
- return /* @__PURE__ */ jsxs12("div", { className: "eb:space-y-1.5", children: [
5217
- /* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
5218
- /* @__PURE__ */ jsxs12(
5061
+ return /* @__PURE__ */ jsxs10("div", { className: "eb:space-y-1.5", children: [
5062
+ /* @__PURE__ */ jsx11(FieldLabel, { id, children: t(property.label) }),
5063
+ /* @__PURE__ */ jsxs10(
5219
5064
  Select,
5220
5065
  {
5221
5066
  value: current,
@@ -5224,10 +5069,10 @@ function SelectField({ id, property, value, fallback = "", onCommit }) {
5224
5069
  if (v !== (value || "")) onCommit(v || null);
5225
5070
  },
5226
5071
  children: [
5227
- /* @__PURE__ */ jsx13(SelectTrigger, { id, className: "eb:w-full", children: /* @__PURE__ */ jsx13(SelectValue, { placeholder: defaultLabel }) }),
5228
- /* @__PURE__ */ jsxs12(SelectContent, { children: [
5229
- !(property.options || []).some((o) => !o.value) && /* @__PURE__ */ jsx13(SelectItem, { value: DEFAULT_OPTION, children: defaultLabel }),
5230
- (property.options || []).map((o) => /* @__PURE__ */ jsx13(SelectItem, { value: o.value || DEFAULT_OPTION, children: t(o.label) }, o.value || DEFAULT_OPTION))
5072
+ /* @__PURE__ */ jsx11(SelectTrigger, { id, className: "eb:w-full", children: /* @__PURE__ */ jsx11(SelectValue, { placeholder: defaultLabel }) }),
5073
+ /* @__PURE__ */ jsxs10(SelectContent, { children: [
5074
+ !(property.options || []).some((o) => !o.value) && /* @__PURE__ */ jsx11(SelectItem, { value: DEFAULT_OPTION, children: defaultLabel }),
5075
+ (property.options || []).map((o) => /* @__PURE__ */ jsx11(SelectItem, { value: o.value || DEFAULT_OPTION, children: t(o.label) }, o.value || DEFAULT_OPTION))
5231
5076
  ] })
5232
5077
  ]
5233
5078
  }
@@ -5237,9 +5082,9 @@ function SelectField({ id, property, value, fallback = "", onCommit }) {
5237
5082
  var ALIGN_ICONS = { left: AlignLeft, center: AlignCenter, right: AlignRight, justify: AlignJustify };
5238
5083
  function AlignField({ id, property, value, fallback = "", onCommit }) {
5239
5084
  const t = useT();
5240
- return /* @__PURE__ */ jsxs12("div", { className: "eb:space-y-1.5", children: [
5241
- /* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
5242
- /* @__PURE__ */ jsx13(
5085
+ return /* @__PURE__ */ jsxs10("div", { className: "eb:space-y-1.5", children: [
5086
+ /* @__PURE__ */ jsx11(FieldLabel, { id, children: t(property.label) }),
5087
+ /* @__PURE__ */ jsx11(
5243
5088
  "div",
5244
5089
  {
5245
5090
  id,
@@ -5249,7 +5094,7 @@ function AlignField({ id, property, value, fallback = "", onCommit }) {
5249
5094
  children: (property.options || []).map((option) => {
5250
5095
  const Icon = ALIGN_ICONS[option.value] || AlignLeft;
5251
5096
  const active = (value || fallback) === option.value;
5252
- return /* @__PURE__ */ jsx13(TooltipWrap, { label: t(option.label), children: /* @__PURE__ */ jsx13(
5097
+ return /* @__PURE__ */ jsx11(TooltipWrap, { label: t(option.label), children: /* @__PURE__ */ jsx11(
5253
5098
  "button",
5254
5099
  {
5255
5100
  type: "button",
@@ -5261,7 +5106,7 @@ function AlignField({ id, property, value, fallback = "", onCommit }) {
5261
5106
  "eb:inline-flex eb:h-7 eb:w-7 eb:items-center eb:justify-center eb:rounded-lg2 eb:transition-colors",
5262
5107
  active ? "eb:bg-primary eb:text-primary-foreground" : "eb:text-foreground-lighter eb:hover:bg-surface-200 eb:hover:text-foreground"
5263
5108
  ),
5264
- children: /* @__PURE__ */ jsx13(Icon, { className: "eb:h-3.5 eb:w-3.5" })
5109
+ children: /* @__PURE__ */ jsx11(Icon, { className: "eb:h-3.5 eb:w-3.5" })
5265
5110
  }
5266
5111
  ) }, option.value);
5267
5112
  })
@@ -5290,10 +5135,10 @@ function SpacingField({ id, property, value, fallback = "", onCommit }) {
5290
5135
  );
5291
5136
  if (next !== (value || "")) onCommit(next);
5292
5137
  };
5293
- return /* @__PURE__ */ jsxs12("fieldset", { ref, className: "eb:space-y-1.5", children: [
5294
- /* @__PURE__ */ jsx13("legend", { className: "eb:mb-1.5 eb:text-[12px] eb:text-foreground-lighter", children: t(property.label) }),
5295
- /* @__PURE__ */ jsx13("div", { className: "eb:grid eb:grid-cols-4 eb:gap-1.5", children: SIDE_LABELS.map(([side, label], i) => /* @__PURE__ */ jsxs12("div", { className: "eb:space-y-1", children: [
5296
- /* @__PURE__ */ jsx13(
5138
+ return /* @__PURE__ */ jsxs10("fieldset", { ref, className: "eb:space-y-1.5", children: [
5139
+ /* @__PURE__ */ jsx11("legend", { className: "eb:mb-1.5 eb:text-[12px] eb:text-foreground-lighter", children: t(property.label) }),
5140
+ /* @__PURE__ */ jsx11("div", { className: "eb:grid eb:grid-cols-4 eb:gap-1.5", children: SIDE_LABELS.map(([side, label], i) => /* @__PURE__ */ jsxs10("div", { className: "eb:space-y-1", children: [
5141
+ /* @__PURE__ */ jsx11(
5297
5142
  Input,
5298
5143
  {
5299
5144
  id: `${id}-${side}`,
@@ -5312,7 +5157,7 @@ function SpacingField({ id, property, value, fallback = "", onCommit }) {
5312
5157
  className: "eb:px-2 eb:text-center eb:tabular-nums"
5313
5158
  }
5314
5159
  ),
5315
- /* @__PURE__ */ jsx13("span", { className: "eb:block eb:text-center eb:text-[10.5px] eb:text-foreground-muted", children: t(label) })
5160
+ /* @__PURE__ */ jsx11("span", { className: "eb:block eb:text-center eb:text-[10.5px] eb:text-foreground-muted", children: t(label) })
5316
5161
  ] }, side)) })
5317
5162
  ] });
5318
5163
  }
@@ -5330,15 +5175,154 @@ var FIELDS = {
5330
5175
  function PropertyField({ property, value, fallback = "", onCommit, idPrefix = "eb", services = null }) {
5331
5176
  const Field = FIELDS[property.type] || TextField;
5332
5177
  const id = `${idPrefix}-${property.key}`;
5333
- return /* @__PURE__ */ jsx13(Field, { id, property, value, fallback, onCommit, services });
5178
+ return /* @__PURE__ */ jsx11(Field, { id, property, value, fallback, onCommit, services });
5179
+ }
5180
+
5181
+ // src/features/variables/VariableInsertButton.jsx
5182
+ import { useState as useState11 } from "react";
5183
+ import { Braces as Braces3 } from "lucide-react";
5184
+
5185
+ // src/features/variables/VariablePicker.jsx
5186
+ import { useEffect as useEffect7, useMemo as useMemo3, useRef as useRef5, useState as useState10 } from "react";
5187
+ import { Pencil as Pencil2, Plus as Plus2, Search as Search2 } from "lucide-react";
5188
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
5189
+ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, filter }) {
5190
+ const t = useT();
5191
+ const [query, setQuery] = useState10("");
5192
+ const [active, setActive] = useState10(0);
5193
+ const listRef = useRef5(null);
5194
+ const searchRef = useRef5(
5195
+ /** @type {HTMLInputElement|null} */
5196
+ null
5197
+ );
5198
+ useSearchShortcut(searchRef);
5199
+ const matches = useMemo3(() => {
5200
+ const q = query.trim().toLowerCase();
5201
+ return variables.filter((v) => filter ? filter(v) : true).filter(
5202
+ (v) => !q || t(v.label).toLowerCase().includes(q) || v.key.toLowerCase().includes(q) || t(v.group).toLowerCase().includes(q)
5203
+ );
5204
+ }, [variables, query, filter, t]);
5205
+ const groups = useMemo3(() => [...new Set(matches.map((v) => v.group))], [matches]);
5206
+ const ordered = useMemo3(() => groups.flatMap((g) => matches.filter((v) => v.group === g)), [groups, matches]);
5207
+ useEffect7(() => setActive(0), [query]);
5208
+ useEffect7(() => {
5209
+ listRef.current?.querySelector('[data-active="true"]')?.scrollIntoView({ block: "nearest" });
5210
+ }, [active]);
5211
+ const onKeyDown = (e) => {
5212
+ if (e.key === "ArrowDown") {
5213
+ e.preventDefault();
5214
+ setActive((i) => Math.min(i + 1, ordered.length - 1));
5215
+ } else if (e.key === "ArrowUp") {
5216
+ e.preventDefault();
5217
+ setActive((i) => Math.max(i - 1, 0));
5218
+ } else if (e.key === "Enter") {
5219
+ e.preventDefault();
5220
+ if (ordered[active]) onPick(ordered[active]);
5221
+ else if (onCreate && query.trim()) onCreate(query.trim());
5222
+ }
5223
+ };
5224
+ return /* @__PURE__ */ jsxs11("div", { className: "eb:flex eb:max-h-[min(440px,70vh)] eb:flex-col", "data-testid": "variable-picker", children: [
5225
+ /* @__PURE__ */ jsxs11("div", { className: "eb:relative eb:border-b eb:border-border eb:p-2", children: [
5226
+ /* @__PURE__ */ jsx12(Search2, { className: "eb:pointer-events-none eb:absolute eb:top-1/2 eb:left-4 eb:size-3.5 eb:-translate-y-1/2 eb:text-foreground-muted" }),
5227
+ /* @__PURE__ */ jsx12(
5228
+ "input",
5229
+ {
5230
+ ref: searchRef,
5231
+ autoFocus: true,
5232
+ value: query,
5233
+ onChange: (e) => setQuery(e.target.value),
5234
+ onKeyDown,
5235
+ placeholder: t("Search variables\u2026"),
5236
+ "aria-label": t("Search variables\u2026"),
5237
+ "aria-keyshortcuts": SEARCH_KEYS,
5238
+ className: "eb:h-8 eb:w-full eb:rounded-md eb:bg-surface-75 eb:pr-14 eb:pl-7 eb:text-[13px] eb:text-foreground eb:outline-none eb:placeholder:text-foreground-muted eb:focus-visible:ring-2 eb:focus-visible:ring-ring/40"
5239
+ }
5240
+ ),
5241
+ /* @__PURE__ */ jsx12(SearchKeyHint, { className: "eb:absolute eb:top-1/2 eb:right-4 eb:-translate-y-1/2" })
5242
+ ] }),
5243
+ /* @__PURE__ */ jsxs11("div", { ref: listRef, role: "listbox", "aria-label": t("Variables"), className: "eb:min-h-0 eb:flex-1 eb:overflow-y-auto eb:p-1", children: [
5244
+ ordered.length === 0 && /* @__PURE__ */ jsxs11("div", { className: "eb:px-2 eb:py-3 eb:text-center eb:text-[12px] eb:text-foreground-muted", children: [
5245
+ /* @__PURE__ */ jsx12("p", { children: t("No variable found.") }),
5246
+ onCreate && query.trim() && /* @__PURE__ */ jsxs11(
5247
+ "button",
5248
+ {
5249
+ type: "button",
5250
+ onClick: () => onCreate(query.trim()),
5251
+ className: "eb:mt-2 eb:inline-flex eb:items-center eb:gap-1 eb:rounded-md eb:px-2 eb:py-1 eb:text-[12px] eb:font-medium eb:text-primary eb:hover:bg-accent",
5252
+ children: [
5253
+ /* @__PURE__ */ jsx12(Plus2, { className: "eb:size-3.5" }),
5254
+ t("Create \u201C{name}\u201D", { name: query.trim() })
5255
+ ]
5256
+ }
5257
+ )
5258
+ ] }),
5259
+ groups.map((group) => /* @__PURE__ */ jsxs11("div", { role: "group", "aria-label": t(group), children: [
5260
+ /* @__PURE__ */ jsx12("p", { className: "eb:px-2 eb:pt-2 eb:pb-1 eb:text-[11px] eb:text-foreground-muted", children: t(group) }),
5261
+ ordered.filter((v) => v.group === group).map((variable) => {
5262
+ const index = ordered.indexOf(variable);
5263
+ return /* @__PURE__ */ jsxs11(
5264
+ "div",
5265
+ {
5266
+ "data-active": index === active,
5267
+ className: cn(
5268
+ "eb:group/var eb:flex eb:items-center eb:gap-1 eb:rounded-md",
5269
+ index === active ? "eb:bg-accent eb:text-accent-foreground" : "eb:hover:bg-accent/60"
5270
+ ),
5271
+ onMouseEnter: () => setActive(index),
5272
+ children: [
5273
+ /* @__PURE__ */ jsxs11(
5274
+ "button",
5275
+ {
5276
+ type: "button",
5277
+ role: "option",
5278
+ "aria-selected": index === active,
5279
+ "data-variable": variable.key,
5280
+ onClick: () => onPick(variable),
5281
+ className: "eb:flex eb:min-w-0 eb:flex-1 eb:items-center eb:gap-2 eb:px-2 eb:py-1.5 eb:text-left eb:text-[13px]",
5282
+ title: variable.description || void 0,
5283
+ children: [
5284
+ /* @__PURE__ */ jsx12("span", { className: "eb:min-w-0 eb:flex-1 eb:truncate", children: variable.custom ? variable.label : t(variable.label) }),
5285
+ /* @__PURE__ */ jsx12("code", { className: "eb:shrink-0 eb:font-mono eb:text-[10.5px] eb:text-foreground-muted", children: tokenOf(variable) })
5286
+ ]
5287
+ }
5288
+ ),
5289
+ onEdit && variable.custom && /* @__PURE__ */ jsx12(
5290
+ "button",
5291
+ {
5292
+ type: "button",
5293
+ "aria-label": t("Edit \u201C{name}\u201D", { name: variable.label }),
5294
+ title: t("Edit"),
5295
+ onClick: () => onEdit(variable),
5296
+ className: "eb:mr-1 eb:flex eb:size-6 eb:shrink-0 eb:items-center eb:justify-center eb:rounded-md eb:text-foreground-muted eb:opacity-0 eb:group-hover/var:opacity-100 eb:hover:bg-background eb:hover:text-foreground eb:focus-visible:opacity-100",
5297
+ children: /* @__PURE__ */ jsx12(Pencil2, { className: "eb:size-3" })
5298
+ }
5299
+ )
5300
+ ]
5301
+ },
5302
+ variable.key
5303
+ );
5304
+ })
5305
+ ] }, group))
5306
+ ] }),
5307
+ onCreate && /* @__PURE__ */ jsx12("div", { className: "eb:border-t eb:border-border eb:p-1", children: /* @__PURE__ */ jsxs11(
5308
+ "button",
5309
+ {
5310
+ type: "button",
5311
+ onClick: () => onCreate(query.trim()),
5312
+ className: "eb:flex eb:w-full eb:items-center eb:gap-2 eb:rounded-md eb:px-2 eb:py-1.5 eb:text-left eb:text-[13px] eb:font-medium eb:text-primary eb:hover:bg-accent",
5313
+ children: [
5314
+ /* @__PURE__ */ jsx12(Plus2, { className: "eb:size-4" }),
5315
+ t("New variable")
5316
+ ]
5317
+ }
5318
+ ) })
5319
+ ] });
5334
5320
  }
5335
5321
 
5336
5322
  // src/features/variables/VariableInsertButton.jsx
5337
- import { useState as useState12 } from "react";
5338
- import { Braces as Braces4 } from "lucide-react";
5339
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
5323
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
5340
5324
  function VariableInsertButton({ variables, inputRef, value, onChange, label }) {
5341
- const [open, setOpen] = useState12(false);
5325
+ const [open, setOpen] = useState11(false);
5342
5326
  const insert = (variable) => {
5343
5327
  const input = inputRef.current;
5344
5328
  const text = String(value || "");
@@ -5354,14 +5338,14 @@ function VariableInsertButton({ variables, inputRef, value, onChange, label }) {
5354
5338
  input.setSelectionRange(start + token.length, start + token.length);
5355
5339
  });
5356
5340
  };
5357
- return /* @__PURE__ */ jsxs13(Popover, { open, onOpenChange: setOpen, children: [
5358
- /* @__PURE__ */ jsx14(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx14(Button, { variant: "ghost", size: "icon-xs", "aria-label": label, title: label, children: /* @__PURE__ */ jsx14(Braces4, {}) }) }),
5359
- /* @__PURE__ */ jsx14(PopoverContent, { align: "end", className: "eb:w-72 eb:p-0", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx14(VariablePicker, { variables, onPick: insert, filter: (v) => v.kind !== "link" }) })
5341
+ return /* @__PURE__ */ jsxs12(Popover, { open, onOpenChange: setOpen, children: [
5342
+ /* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx13(Button, { variant: "ghost", size: "icon-xs", "aria-label": label, title: label, children: /* @__PURE__ */ jsx13(Braces3, {}) }) }),
5343
+ /* @__PURE__ */ jsx13(PopoverContent, { align: "end", className: "eb:w-72 eb:p-0", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx13(VariablePicker, { variables, onPick: insert, filter: (v) => v.kind !== "link" }) })
5360
5344
  ] });
5361
5345
  }
5362
5346
 
5363
5347
  // src/ui/PropertiesPanel.jsx
5364
- import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
5348
+ import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
5365
5349
  var GROUP_ORDER = Object.values(GROUPS);
5366
5350
  function grouped(properties) {
5367
5351
  const map = /* @__PURE__ */ new Map();
@@ -5375,9 +5359,9 @@ function grouped(properties) {
5375
5359
  }
5376
5360
  function PropertyGroups({ editor, element, block, idPrefix, services = null }) {
5377
5361
  const t = useT();
5378
- return grouped(block?.properties || []).map(([group, properties]) => /* @__PURE__ */ jsxs14("section", { className: "eb:space-y-3", children: [
5379
- /* @__PURE__ */ jsx15(SectionLabel, { children: t(group) }),
5380
- properties.map((property) => /* @__PURE__ */ jsx15(
5362
+ return grouped(block?.properties || []).map(([group, properties]) => /* @__PURE__ */ jsxs13("section", { className: "eb:space-y-3", children: [
5363
+ /* @__PURE__ */ jsx14(SectionLabel, { children: t(group) }),
5364
+ properties.map((property) => /* @__PURE__ */ jsx14(
5381
5365
  PropertyField,
5382
5366
  {
5383
5367
  idPrefix,
@@ -5395,9 +5379,9 @@ var LABEL_PROPERTY = { key: "content", label: "Label", type: "text", group: GROU
5395
5379
  var REWRITABLE_TAGS = /* @__PURE__ */ new Set(["mj-text", "mj-button"]);
5396
5380
  function PanelHeader({ title, onClose, closeLabel = "Deselect" }) {
5397
5381
  const t = useT();
5398
- return /* @__PURE__ */ jsxs14("header", { className: "eb:sticky eb:top-0 eb:z-10 eb:flex eb:h-11 eb:shrink-0 eb:items-center eb:gap-2 eb:border-b eb:border-border eb:bg-background eb:px-4", children: [
5399
- /* @__PURE__ */ jsx15("h3", { className: "eb:min-w-0 eb:flex-1 eb:text-[13px] eb:font-medium eb:text-foreground", children: /* @__PURE__ */ jsx15(TruncatedText, { children: title }) }),
5400
- onClose && /* @__PURE__ */ jsx15(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onClose, "aria-label": t(closeLabel), children: /* @__PURE__ */ jsx15(X2, {}) })
5382
+ return /* @__PURE__ */ jsxs13("header", { className: "eb:sticky eb:top-0 eb:z-10 eb:flex eb:h-11 eb:shrink-0 eb:items-center eb:gap-2 eb:border-b eb:border-border eb:bg-background eb:px-4", children: [
5383
+ /* @__PURE__ */ jsx14("h3", { className: "eb:min-w-0 eb:flex-1 eb:text-[13px] eb:font-medium eb:text-foreground", children: /* @__PURE__ */ jsx14(TruncatedText, { children: title }) }),
5384
+ onClose && /* @__PURE__ */ jsx14(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onClose, "aria-label": t(closeLabel), children: /* @__PURE__ */ jsx14(X2, {}) })
5401
5385
  ] });
5402
5386
  }
5403
5387
  function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, variables = null, ai = null, onDismiss = null }) {
@@ -5408,18 +5392,18 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
5408
5392
  const root = useMemo4(() => rootId ? editor.getElement(rootId) : null, [editor, rootId, changes]);
5409
5393
  const bodyBlock2 = root?.blockId ? editor.getBlock(root.blockId) : null;
5410
5394
  const field = (key) => (e) => onMetaChange({ ...meta, [key]: e.target.value });
5411
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
5412
- /* @__PURE__ */ jsx15(PanelHeader, { title: t("Email"), onClose: onDismiss, closeLabel: "Close" }),
5413
- /* @__PURE__ */ jsxs14("div", { className: "eb:space-y-5 eb:p-4", children: [
5414
- /* @__PURE__ */ jsxs14("section", { className: "eb:space-y-3", children: [
5415
- /* @__PURE__ */ jsx15(SectionLabel, { children: t("Template") }),
5416
- /* @__PURE__ */ jsxs14("div", { className: "eb:space-y-1.5", children: [
5417
- /* @__PURE__ */ jsxs14(Label, { htmlFor: "eb-meta-name", className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children: [
5395
+ return /* @__PURE__ */ jsxs13(Fragment6, { children: [
5396
+ /* @__PURE__ */ jsx14(PanelHeader, { title: t("Email"), onClose: onDismiss, closeLabel: "Close" }),
5397
+ /* @__PURE__ */ jsxs13("div", { className: "eb:space-y-5 eb:p-4", children: [
5398
+ /* @__PURE__ */ jsxs13("section", { className: "eb:space-y-3", children: [
5399
+ /* @__PURE__ */ jsx14(SectionLabel, { children: t("Template") }),
5400
+ /* @__PURE__ */ jsxs13("div", { className: "eb:space-y-1.5", children: [
5401
+ /* @__PURE__ */ jsxs13(Label, { htmlFor: "eb-meta-name", className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children: [
5418
5402
  t("Name"),
5419
5403
  " ",
5420
- /* @__PURE__ */ jsx15("span", { className: "eb:text-destructive", children: "*" })
5404
+ /* @__PURE__ */ jsx14("span", { className: "eb:text-destructive", children: "*" })
5421
5405
  ] }),
5422
- /* @__PURE__ */ jsx15(
5406
+ /* @__PURE__ */ jsx14(
5423
5407
  Input,
5424
5408
  {
5425
5409
  id: "eb-meta-name",
@@ -5429,12 +5413,12 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
5429
5413
  "aria-invalid": showErrors && !meta.name.trim() || void 0
5430
5414
  }
5431
5415
  ),
5432
- showErrors && !meta.name.trim() && /* @__PURE__ */ jsx15("p", { className: "eb:text-[12px] eb:text-destructive", children: t("Name is required") })
5416
+ showErrors && !meta.name.trim() && /* @__PURE__ */ jsx14("p", { className: "eb:text-[12px] eb:text-destructive", children: t("Name is required") })
5433
5417
  ] }),
5434
- /* @__PURE__ */ jsxs14("div", { className: "eb:space-y-1.5", children: [
5435
- /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:h-6 eb:items-center eb:justify-between", children: [
5436
- /* @__PURE__ */ jsx15(Label, { htmlFor: "eb-meta-subject", className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children: t("Subject") }),
5437
- variables && /* @__PURE__ */ jsx15(
5418
+ /* @__PURE__ */ jsxs13("div", { className: "eb:space-y-1.5", children: [
5419
+ /* @__PURE__ */ jsxs13("div", { className: "eb:flex eb:h-6 eb:items-center eb:justify-between", children: [
5420
+ /* @__PURE__ */ jsx14(Label, { htmlFor: "eb-meta-subject", className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children: t("Subject") }),
5421
+ variables && /* @__PURE__ */ jsx14(
5438
5422
  VariableInsertButton,
5439
5423
  {
5440
5424
  variables,
@@ -5445,8 +5429,8 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
5445
5429
  }
5446
5430
  )
5447
5431
  ] }),
5448
- /* @__PURE__ */ jsx15(Input, { ref: subjectRef, id: "eb-meta-subject", maxLength: 250, value: meta.subject, onChange: field("subject") }),
5449
- ai?.suggestSubjects && /* @__PURE__ */ jsx15(
5432
+ /* @__PURE__ */ jsx14(Input, { ref: subjectRef, id: "eb-meta-subject", maxLength: 250, value: meta.subject, onChange: field("subject") }),
5433
+ ai?.suggestSubjects && /* @__PURE__ */ jsx14(
5450
5434
  ai.components.Subjects,
5451
5435
  {
5452
5436
  editor,
@@ -5457,10 +5441,10 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
5457
5441
  }
5458
5442
  )
5459
5443
  ] }),
5460
- /* @__PURE__ */ jsxs14("div", { className: "eb:space-y-1.5", children: [
5461
- /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:h-6 eb:items-center eb:justify-between", children: [
5462
- /* @__PURE__ */ jsx15(Label, { htmlFor: "eb-meta-preheader", className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children: t("Preview text") }),
5463
- variables && /* @__PURE__ */ jsx15(
5444
+ /* @__PURE__ */ jsxs13("div", { className: "eb:space-y-1.5", children: [
5445
+ /* @__PURE__ */ jsxs13("div", { className: "eb:flex eb:h-6 eb:items-center eb:justify-between", children: [
5446
+ /* @__PURE__ */ jsx14(Label, { htmlFor: "eb-meta-preheader", className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children: t("Preview text") }),
5447
+ variables && /* @__PURE__ */ jsx14(
5464
5448
  VariableInsertButton,
5465
5449
  {
5466
5450
  variables,
@@ -5471,7 +5455,7 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
5471
5455
  }
5472
5456
  )
5473
5457
  ] }),
5474
- /* @__PURE__ */ jsx15(
5458
+ /* @__PURE__ */ jsx14(
5475
5459
  Textarea,
5476
5460
  {
5477
5461
  ref: preheaderRef,
@@ -5485,7 +5469,7 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
5485
5469
  )
5486
5470
  ] })
5487
5471
  ] }),
5488
- root && bodyBlock2 && /* @__PURE__ */ jsx15(PropertyGroups, { editor, element: root, block: bodyBlock2, idPrefix: "eb-page" })
5472
+ root && bodyBlock2 && /* @__PURE__ */ jsx14(PropertyGroups, { editor, element: root, block: bodyBlock2, idPrefix: "eb-page" })
5489
5473
  ] })
5490
5474
  ] });
5491
5475
  }
@@ -5504,7 +5488,7 @@ function PropertiesPanel({
5504
5488
  }) {
5505
5489
  const t = useT();
5506
5490
  const block = selection?.blockId ? editor.getBlock(selection.blockId) : null;
5507
- return /* @__PURE__ */ jsx15("aside", { "aria-label": t("Properties"), className: "eb:min-h-0 eb:overflow-y-auto eb:border-l eb:border-border", "data-testid": "eb-properties", children: !selection ? /* @__PURE__ */ jsx15(
5491
+ return /* @__PURE__ */ jsx14("aside", { "aria-label": t("Properties"), className: "eb:min-h-0 eb:overflow-y-auto eb:border-l eb:border-border", "data-testid": "eb-properties", children: !selection ? /* @__PURE__ */ jsx14(
5508
5492
  TemplateSettings,
5509
5493
  {
5510
5494
  editor,
@@ -5516,8 +5500,8 @@ function PropertiesPanel({
5516
5500
  ai,
5517
5501
  onDismiss
5518
5502
  }
5519
- ) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
5520
- /* @__PURE__ */ jsx15(
5503
+ ) : /* @__PURE__ */ jsxs13(Fragment6, { children: [
5504
+ /* @__PURE__ */ jsx14(
5521
5505
  PanelHeader,
5522
5506
  {
5523
5507
  title: t(selection.label),
@@ -5526,12 +5510,12 @@ function PropertiesPanel({
5526
5510
  }
5527
5511
  ),
5528
5512
  actions,
5529
- selection.multiple ? /* @__PURE__ */ jsx15("p", { className: "eb:p-4 eb:text-[13px] eb:leading-relaxed eb:text-foreground-lighter", "data-testid": "eb-select-all", children: t("{count} sections selected. Press Delete to remove them (Ctrl+Z brings them back).", {
5513
+ selection.multiple ? /* @__PURE__ */ jsx14("p", { className: "eb:p-4 eb:text-[13px] eb:leading-relaxed eb:text-foreground-lighter", "data-testid": "eb-select-all", children: t("{count} sections selected. Press Delete to remove them (Ctrl+Z brings them back).", {
5530
5514
  count: selection.multiple
5531
- }) }) : /* @__PURE__ */ jsxs14("div", { className: "eb:space-y-5 eb:p-4", children: [
5532
- selection.content !== null && selection.content !== void 0 && /* @__PURE__ */ jsxs14("section", { className: "eb:space-y-3", children: [
5533
- /* @__PURE__ */ jsx15(SectionLabel, { children: t(GROUPS.content) }),
5534
- /* @__PURE__ */ jsx15(
5515
+ }) }) : /* @__PURE__ */ jsxs13("div", { className: "eb:space-y-5 eb:p-4", children: [
5516
+ selection.content !== null && selection.content !== void 0 && /* @__PURE__ */ jsxs13("section", { className: "eb:space-y-3", children: [
5517
+ /* @__PURE__ */ jsx14(SectionLabel, { children: t(GROUPS.content) }),
5518
+ /* @__PURE__ */ jsx14(
5535
5519
  PropertyField,
5536
5520
  {
5537
5521
  idPrefix: "eb-prop",
@@ -5542,16 +5526,16 @@ function PropertiesPanel({
5542
5526
  `${selection.id}:content`
5543
5527
  )
5544
5528
  ] }),
5545
- selection.tagName === "mj-text" && /* @__PURE__ */ jsx15("p", { className: "eb:text-[12px] eb:text-foreground-muted", children: t("Double-click the text to edit it.") }),
5546
- ai?.rewrite && REWRITABLE_TAGS.has(selection.tagName) && /* @__PURE__ */ jsx15(ai.components.Rewrite, { editor, selection, rewrite: ai.rewrite }, selection.id),
5547
- /* @__PURE__ */ jsx15(PropertyGroups, { editor, element: selection, block, idPrefix: "eb-prop", services })
5529
+ selection.tagName === "mj-text" && /* @__PURE__ */ jsx14("p", { className: "eb:text-[12px] eb:text-foreground-muted", children: t("Double-click the text to edit it.") }),
5530
+ ai?.rewrite && REWRITABLE_TAGS.has(selection.tagName) && /* @__PURE__ */ jsx14(ai.components.Rewrite, { editor, selection, rewrite: ai.rewrite }, selection.id),
5531
+ /* @__PURE__ */ jsx14(PropertyGroups, { editor, element: selection, block, idPrefix: "eb-prop", services })
5548
5532
  ] })
5549
5533
  ] }) });
5550
5534
  }
5551
5535
 
5552
5536
  // src/ui/Toolbar.jsx
5553
5537
  import { ArrowLeft as ArrowLeft2, Monitor, Redo2, Smartphone, Undo2 } from "lucide-react";
5554
- import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
5538
+ import { Fragment as Fragment7, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
5555
5539
  function Toolbar({
5556
5540
  title,
5557
5541
  status,
@@ -5568,8 +5552,8 @@ function Toolbar({
5568
5552
  compact = false
5569
5553
  }) {
5570
5554
  const t = useT();
5571
- const identity2 = /* @__PURE__ */ jsxs15(Fragment7, { children: [
5572
- /* @__PURE__ */ jsxs15(
5555
+ const identity2 = /* @__PURE__ */ jsxs14(Fragment7, { children: [
5556
+ /* @__PURE__ */ jsxs14(
5573
5557
  Button,
5574
5558
  {
5575
5559
  variant: "ghost",
@@ -5577,50 +5561,50 @@ function Toolbar({
5577
5561
  onClick: onBack,
5578
5562
  "aria-label": compact ? t("Back") : void 0,
5579
5563
  children: [
5580
- /* @__PURE__ */ jsx16(ArrowLeft2, {}),
5564
+ /* @__PURE__ */ jsx15(ArrowLeft2, {}),
5581
5565
  !compact && t("Back")
5582
5566
  ]
5583
5567
  }
5584
5568
  ),
5585
- /* @__PURE__ */ jsx16(Separator, { orientation: "vertical", className: "eb:h-5" }),
5586
- /* @__PURE__ */ jsxs15("div", { className: cn("eb:min-w-0 eb:flex-1", !compact && "eb:max-w-[320px]"), children: [
5587
- /* @__PURE__ */ jsx16("p", { className: "eb:text-[13px] eb:font-medium eb:text-foreground", children: /* @__PURE__ */ jsx16(TruncatedText, { children: title || t("New template") }) }),
5588
- /* @__PURE__ */ jsx16("p", { className: "eb:text-[11px] eb:text-foreground-muted", role: "status", "aria-live": "polite", children: status })
5569
+ /* @__PURE__ */ jsx15(Separator, { orientation: "vertical", className: "eb:h-5" }),
5570
+ /* @__PURE__ */ jsxs14("div", { className: cn("eb:min-w-0 eb:flex-1", !compact && "eb:max-w-[320px]"), children: [
5571
+ /* @__PURE__ */ jsx15("p", { className: "eb:text-[13px] eb:font-medium eb:text-foreground", children: /* @__PURE__ */ jsx15(TruncatedText, { children: title || t("New template") }) }),
5572
+ /* @__PURE__ */ jsx15("p", { className: "eb:text-[11px] eb:text-foreground-muted", role: "status", "aria-live": "polite", children: status })
5589
5573
  ] })
5590
5574
  ] });
5591
- const editing = /* @__PURE__ */ jsxs15("div", { className: "eb:flex eb:shrink-0 eb:items-center eb:gap-2", children: [
5592
- /* @__PURE__ */ jsxs15("div", { className: "eb:flex eb:items-center eb:gap-0.5", children: [
5593
- /* @__PURE__ */ jsx16(TooltipWrap, { label: t("Undo (Ctrl+Z)"), children: /* @__PURE__ */ jsx16(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onUndo, disabled: !ready || !canUndo, "aria-label": t("Undo"), children: /* @__PURE__ */ jsx16(Undo2, {}) }) }),
5594
- /* @__PURE__ */ jsx16(TooltipWrap, { label: t("Redo (Ctrl+Y)"), children: /* @__PURE__ */ jsx16(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onRedo, disabled: !ready || !canRedo, "aria-label": t("Redo"), children: /* @__PURE__ */ jsx16(Redo2, {}) }) })
5575
+ const editing = /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:shrink-0 eb:items-center eb:gap-2", children: [
5576
+ /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:items-center eb:gap-0.5", children: [
5577
+ /* @__PURE__ */ jsx15(TooltipWrap, { label: t("Undo (Ctrl+Z)"), children: /* @__PURE__ */ jsx15(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onUndo, disabled: !ready || !canUndo, "aria-label": t("Undo"), children: /* @__PURE__ */ jsx15(Undo2, {}) }) }),
5578
+ /* @__PURE__ */ jsx15(TooltipWrap, { label: t("Redo (Ctrl+Y)"), children: /* @__PURE__ */ jsx15(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onRedo, disabled: !ready || !canRedo, "aria-label": t("Redo"), children: /* @__PURE__ */ jsx15(Redo2, {}) }) })
5595
5579
  ] }),
5596
- /* @__PURE__ */ jsx16(Tabs, { value: device, onValueChange: onDeviceChange, children: /* @__PURE__ */ jsxs15(TabsList, { "aria-label": t("Device"), children: [
5597
- /* @__PURE__ */ jsxs15(TabsTrigger, { value: "desktop", disabled: !ready, "aria-label": compact ? t("Desktop") : void 0, children: [
5598
- /* @__PURE__ */ jsx16(Monitor, {}),
5580
+ /* @__PURE__ */ jsx15(Tabs, { value: device, onValueChange: onDeviceChange, children: /* @__PURE__ */ jsxs14(TabsList, { "aria-label": t("Device"), children: [
5581
+ /* @__PURE__ */ jsxs14(TabsTrigger, { value: "desktop", disabled: !ready, "aria-label": compact ? t("Desktop") : void 0, children: [
5582
+ /* @__PURE__ */ jsx15(Monitor, {}),
5599
5583
  !compact && t("Desktop")
5600
5584
  ] }),
5601
- /* @__PURE__ */ jsxs15(TabsTrigger, { value: "mobile", disabled: !ready, "aria-label": compact ? t("Mobile") : void 0, children: [
5602
- /* @__PURE__ */ jsx16(Smartphone, {}),
5585
+ /* @__PURE__ */ jsxs14(TabsTrigger, { value: "mobile", disabled: !ready, "aria-label": compact ? t("Mobile") : void 0, children: [
5586
+ /* @__PURE__ */ jsx15(Smartphone, {}),
5603
5587
  !compact && t("Mobile")
5604
5588
  ] })
5605
5589
  ] }) })
5606
5590
  ] });
5607
5591
  if (compact) {
5608
- return /* @__PURE__ */ jsxs15("div", { className: "eb:shrink-0 eb:border-b eb:border-border", "data-layout": "compact", children: [
5609
- /* @__PURE__ */ jsxs15("div", { className: "eb:flex eb:h-12 eb:items-center eb:gap-2 eb:px-2", children: [
5592
+ return /* @__PURE__ */ jsxs14("div", { className: "eb:shrink-0 eb:border-b eb:border-border", "data-layout": "compact", children: [
5593
+ /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:h-12 eb:items-center eb:gap-2 eb:px-2", children: [
5610
5594
  identity2,
5611
5595
  primary
5612
5596
  ] }),
5613
- /* @__PURE__ */ jsxs15("div", { className: "eb:flex eb:items-center eb:gap-2 eb:overflow-x-auto eb:px-2 eb:pb-2", "data-testid": "eb-toolbar-actions", children: [
5597
+ /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:items-center eb:gap-2 eb:overflow-x-auto eb:px-2 eb:pb-2", "data-testid": "eb-toolbar-actions", children: [
5614
5598
  editing,
5615
- /* @__PURE__ */ jsx16(Separator, { orientation: "vertical", className: "eb:h-5 eb:shrink-0" }),
5616
- /* @__PURE__ */ jsx16("div", { className: "eb:flex eb:shrink-0 eb:items-center eb:gap-2", children: actions })
5599
+ /* @__PURE__ */ jsx15(Separator, { orientation: "vertical", className: "eb:h-5 eb:shrink-0" }),
5600
+ /* @__PURE__ */ jsx15("div", { className: "eb:flex eb:shrink-0 eb:items-center eb:gap-2", children: actions })
5617
5601
  ] })
5618
5602
  ] });
5619
5603
  }
5620
- return /* @__PURE__ */ jsxs15("div", { className: "eb:flex eb:h-12 eb:shrink-0 eb:items-center eb:gap-3 eb:border-b eb:border-border eb:px-3", children: [
5604
+ return /* @__PURE__ */ jsxs14("div", { className: "eb:flex eb:h-12 eb:shrink-0 eb:items-center eb:gap-3 eb:border-b eb:border-border eb:px-3", children: [
5621
5605
  identity2,
5622
5606
  editing,
5623
- /* @__PURE__ */ jsxs15("div", { className: "eb:ml-auto eb:flex eb:items-center eb:gap-2", "data-testid": "eb-toolbar-actions", children: [
5607
+ /* @__PURE__ */ jsxs14("div", { className: "eb:ml-auto eb:flex eb:items-center eb:gap-2", "data-testid": "eb-toolbar-actions", children: [
5624
5608
  actions,
5625
5609
  primary
5626
5610
  ] })
@@ -5630,7 +5614,7 @@ function Toolbar({
5630
5614
  // src/ui/Drawer.jsx
5631
5615
  import { useEffect as useEffect8 } from "react";
5632
5616
  import { X as X3 } from "lucide-react";
5633
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
5617
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
5634
5618
  function Drawer({ open, side = "left", title, onClose, children, testId, header: header2 = true }) {
5635
5619
  const t = useT();
5636
5620
  useEffect8(() => {
@@ -5641,9 +5625,9 @@ function Drawer({ open, side = "left", title, onClose, children, testId, header:
5641
5625
  window.addEventListener("keydown", onKey);
5642
5626
  return () => window.removeEventListener("keydown", onKey);
5643
5627
  }, [open, onClose]);
5644
- return /* @__PURE__ */ jsxs16("div", { className: cn("eb:absolute eb:inset-0 eb:z-20", !open && "eb:hidden"), "data-testid": testId, "data-open": open ? "true" : "false", children: [
5645
- /* @__PURE__ */ jsx17("div", { className: "eb:absolute eb:inset-0 eb:bg-black/30", onClick: onClose, "aria-hidden": "true" }),
5646
- /* @__PURE__ */ jsxs16(
5628
+ return /* @__PURE__ */ jsxs15("div", { className: cn("eb:absolute eb:inset-0 eb:z-20", !open && "eb:hidden"), "data-testid": testId, "data-open": open ? "true" : "false", children: [
5629
+ /* @__PURE__ */ jsx16("div", { className: "eb:absolute eb:inset-0 eb:bg-black/30", onClick: onClose, "aria-hidden": "true" }),
5630
+ /* @__PURE__ */ jsxs15(
5647
5631
  "section",
5648
5632
  {
5649
5633
  role: "dialog",
@@ -5653,11 +5637,11 @@ function Drawer({ open, side = "left", title, onClose, children, testId, header:
5653
5637
  side === "left" ? "eb:left-0 eb:border-r eb:border-border" : "eb:right-0 eb:border-l eb:border-border"
5654
5638
  ),
5655
5639
  children: [
5656
- header2 && /* @__PURE__ */ jsxs16("header", { className: "eb:flex eb:h-10 eb:shrink-0 eb:items-center eb:justify-between eb:border-b eb:border-border eb:px-3", children: [
5657
- /* @__PURE__ */ jsx17("h3", { className: "eb:text-[13px] eb:font-medium eb:text-foreground", children: title }),
5658
- /* @__PURE__ */ jsx17(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onClose, "aria-label": t("Close"), children: /* @__PURE__ */ jsx17(X3, {}) })
5640
+ header2 && /* @__PURE__ */ jsxs15("header", { className: "eb:flex eb:h-10 eb:shrink-0 eb:items-center eb:justify-between eb:border-b eb:border-border eb:px-3", children: [
5641
+ /* @__PURE__ */ jsx16("h3", { className: "eb:text-[13px] eb:font-medium eb:text-foreground", children: title }),
5642
+ /* @__PURE__ */ jsx16(Button, { variant: "ghost", size: "icon-sm-compact", onClick: onClose, "aria-label": t("Close"), children: /* @__PURE__ */ jsx16(X3, {}) })
5659
5643
  ] }),
5660
- /* @__PURE__ */ jsx17("div", { className: "eb:grid eb:min-h-0 eb:flex-1", children })
5644
+ /* @__PURE__ */ jsx16("div", { className: "eb:grid eb:min-h-0 eb:flex-1", children })
5661
5645
  ]
5662
5646
  }
5663
5647
  )
@@ -5665,10 +5649,10 @@ function Drawer({ open, side = "left", title, onClose, children, testId, header:
5665
5649
  }
5666
5650
 
5667
5651
  // src/ui/useEmailEditorState.js
5668
- import { useCallback as useCallback2, useEffect as useEffect9, useRef as useRef7, useState as useState13 } from "react";
5652
+ import { useCallback as useCallback2, useEffect as useEffect9, useRef as useRef7, useState as useState12 } from "react";
5669
5653
  var DIRTY_CHECK_MS = 150;
5670
5654
  function useEmailEditorState(editor) {
5671
- const [state, setState] = useState13(() => ({
5655
+ const [state, setState] = useState12(() => ({
5672
5656
  status: editor?.status || "idle",
5673
5657
  selection: null,
5674
5658
  canUndo: false,
@@ -5749,7 +5733,7 @@ function useEmailEditorState(editor) {
5749
5733
  }
5750
5734
 
5751
5735
  // src/ui/EmailBuilder.jsx
5752
- import { Fragment as Fragment8, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
5736
+ import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
5753
5737
  var EMPTY_META = { name: "", subject: "", preheader: "", description: "" };
5754
5738
  function metaOf(template) {
5755
5739
  return {
@@ -5787,7 +5771,7 @@ function Builder({
5787
5771
  );
5788
5772
  const storage = useMemo5(() => injectedStorage || createHttpStorage(), [injectedStorage]);
5789
5773
  const systemVariables = useMemo5(() => defineVariables(variablesProp || DEFAULT_VARIABLES), [variablesProp]);
5790
- const [customVariables, setCustomVariables] = useState14([]);
5774
+ const [customVariables, setCustomVariables] = useState13([]);
5791
5775
  const variables = useMemo5(() => mergeVariables(systemVariables, customVariables), [systemVariables, customVariables]);
5792
5776
  const canManageVariables = typeof storage.saveVariable === "function" && typeof storage.listVariables === "function";
5793
5777
  const reloadVariables = useCallback3(async () => {
@@ -5821,20 +5805,20 @@ function Builder({
5821
5805
  const state = useEmailEditorState(editor);
5822
5806
  const autosaveOn = isFeatureEnabled("autosave");
5823
5807
  const autosaveOptions = emailBuilderFeatures.get("autosave")?.options || {};
5824
- const [template, setTemplate] = useState14({ id: initialTemplateId, revision: null, savedAt: null, auto: false });
5825
- const [boot, setBoot] = useState14({ status: "loading", document: null, mjml: null, draft: false, message: null });
5826
- const [meta, setMeta] = useState14(EMPTY_META);
5827
- const [savedMeta, setSavedMeta] = useState14(EMPTY_META);
5828
- const [saving, setSaving] = useState14(null);
5829
- const [showErrors, setShowErrors] = useState14(false);
5830
- const [autosaveBlocked, setAutosaveBlocked] = useState14(null);
5831
- const [engineError, setEngineError] = useState14(null);
5832
- const [attempt, setAttempt] = useState14(0);
5808
+ const [template, setTemplate] = useState13({ id: initialTemplateId, revision: null, savedAt: null, auto: false });
5809
+ const [boot, setBoot] = useState13({ status: "loading", document: null, mjml: null, draft: false, message: null });
5810
+ const [meta, setMeta] = useState13(EMPTY_META);
5811
+ const [savedMeta, setSavedMeta] = useState13(EMPTY_META);
5812
+ const [saving, setSaving] = useState13(null);
5813
+ const [showErrors, setShowErrors] = useState13(false);
5814
+ const [autosaveBlocked, setAutosaveBlocked] = useState13(null);
5815
+ const [engineError, setEngineError] = useState13(null);
5816
+ const [attempt, setAttempt] = useState13(0);
5833
5817
  const rootRef = useRef8(null);
5834
5818
  const layout2 = useLayoutWidth(rootRef);
5835
5819
  const compact = layout2 !== "wide";
5836
5820
  const blocksInDrawer = layout2 === "narrow";
5837
- const [drawer, setDrawer] = useState14(null);
5821
+ const [drawer, setDrawer] = useState13(null);
5838
5822
  const closeDrawer = useCallback3(() => setDrawer(null), []);
5839
5823
  useEffect10(() => {
5840
5824
  if (!compact) setDrawer(null);
@@ -6103,7 +6087,7 @@ function Builder({
6103
6087
  const featuresWith = (slot) => emailBuilderFeatures.list((f) => f.enabled !== false && Boolean(f[slot]) && (f.isAvailable ? f.isAvailable(featureContext) : true));
6104
6088
  const toolbarFeatures = featuresWith("toolbar");
6105
6089
  const canvasBars = featuresWith("canvasBar");
6106
- const properties = /* @__PURE__ */ jsx18(
6090
+ const properties = /* @__PURE__ */ jsx17(
6107
6091
  PropertiesPanel,
6108
6092
  {
6109
6093
  onDismiss: compact ? closeDrawer : null,
@@ -6113,13 +6097,13 @@ function Builder({
6113
6097
  onMetaChange: setMeta,
6114
6098
  changes: state.changes,
6115
6099
  showErrors,
6116
- actions: /* @__PURE__ */ jsx18(ElementActions, { editor, selection: state.selection }),
6100
+ actions: /* @__PURE__ */ jsx17(ElementActions, { editor, selection: state.selection }),
6117
6101
  services,
6118
6102
  ai,
6119
6103
  variables
6120
6104
  }
6121
6105
  );
6122
- return /* @__PURE__ */ jsxs17(
6106
+ return /* @__PURE__ */ jsxs16(
6123
6107
  "div",
6124
6108
  {
6125
6109
  ref: rootRef,
@@ -6129,7 +6113,7 @@ function Builder({
6129
6113
  "data-layout": layout2,
6130
6114
  "data-template-id": template.id || "",
6131
6115
  children: [
6132
- /* @__PURE__ */ jsx18(
6116
+ /* @__PURE__ */ jsx17(
6133
6117
  Toolbar,
6134
6118
  {
6135
6119
  title: meta.name,
@@ -6145,19 +6129,19 @@ function Builder({
6145
6129
  compact,
6146
6130
  actions: [
6147
6131
  // The AI module's button first, when the host gave the module.
6148
- ai?.proofread && /* @__PURE__ */ jsx18(ai.components.Proofread, { context: featureContext, proofread: ai.proofread }, "ai-proofread"),
6132
+ ai?.proofread && /* @__PURE__ */ jsx17(ai.components.Proofread, { context: featureContext, proofread: ai.proofread }, "ai-proofread"),
6149
6133
  ...toolbarFeatures.map((feature) => {
6150
6134
  const Action = feature.toolbar;
6151
- return /* @__PURE__ */ jsx18(Action, { context: featureContext }, feature.id);
6135
+ return /* @__PURE__ */ jsx17(Action, { context: featureContext }, feature.id);
6152
6136
  })
6153
6137
  ].filter(Boolean),
6154
- primary: /* @__PURE__ */ jsxs17(Button, { size: "sm-compact", onClick: () => save(), disabled: !ready || saving !== null, children: [
6155
- saving === "manual" ? /* @__PURE__ */ jsx18(Loader25, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx18(Save, {}),
6138
+ primary: /* @__PURE__ */ jsxs16(Button, { size: "sm-compact", onClick: () => save(), disabled: !ready || saving !== null, children: [
6139
+ saving === "manual" ? /* @__PURE__ */ jsx17(Loader25, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx17(Save, {}),
6156
6140
  t("Save")
6157
6141
  ] })
6158
6142
  }
6159
6143
  ),
6160
- /* @__PURE__ */ jsxs17(
6144
+ /* @__PURE__ */ jsxs16(
6161
6145
  "div",
6162
6146
  {
6163
6147
  className: cn(
@@ -6167,12 +6151,12 @@ function Builder({
6167
6151
  layout2 === "narrow" && "eb:grid-cols-1"
6168
6152
  ),
6169
6153
  children: [
6170
- !blocksInDrawer && /* @__PURE__ */ jsx18(BlockSidebar, { editor, disabled: !ready, onAdded: compact ? () => setDrawer("properties") : void 0 }),
6171
- /* @__PURE__ */ jsx18("div", { className: "eb:relative eb:flex eb:min-w-0 eb:flex-col eb:bg-surface-75", "aria-busy": !ready, children: boot.status === "error" || engineError ? /* @__PURE__ */ jsxs17("div", { role: "alert", className: "eb:flex eb:h-full eb:flex-col eb:items-center eb:justify-center eb:gap-2 eb:p-6 eb:text-center", children: [
6172
- /* @__PURE__ */ jsx18(AlertTriangle, { className: "eb:size-6 eb:text-destructive", "aria-hidden": "true" }),
6173
- /* @__PURE__ */ jsx18("p", { className: "eb:text-[13px] eb:text-foreground", children: boot.status === "error" ? t("The template could not be loaded.") : t("The builder could not start.") }),
6174
- /* @__PURE__ */ jsx18("p", { className: "eb:max-w-sm eb:text-[12px] eb:text-foreground-muted", children: boot.message || engineError }),
6175
- engineError && /* @__PURE__ */ jsx18(
6154
+ !blocksInDrawer && /* @__PURE__ */ jsx17(BlockSidebar, { editor, disabled: !ready, onAdded: compact ? () => setDrawer("properties") : void 0 }),
6155
+ /* @__PURE__ */ jsx17("div", { className: "eb:relative eb:flex eb:min-w-0 eb:flex-col eb:bg-surface-75", "aria-busy": !ready, children: boot.status === "error" || engineError ? /* @__PURE__ */ jsxs16("div", { role: "alert", className: "eb:flex eb:h-full eb:flex-col eb:items-center eb:justify-center eb:gap-2 eb:p-6 eb:text-center", children: [
6156
+ /* @__PURE__ */ jsx17(AlertTriangle, { className: "eb:size-6 eb:text-destructive", "aria-hidden": "true" }),
6157
+ /* @__PURE__ */ jsx17("p", { className: "eb:text-[13px] eb:text-foreground", children: boot.status === "error" ? t("The template could not be loaded.") : t("The builder could not start.") }),
6158
+ /* @__PURE__ */ jsx17("p", { className: "eb:max-w-sm eb:text-[12px] eb:text-foreground-muted", children: boot.message || engineError }),
6159
+ engineError && /* @__PURE__ */ jsx17(
6176
6160
  Button,
6177
6161
  {
6178
6162
  variant: "outline",
@@ -6184,12 +6168,12 @@ function Builder({
6184
6168
  children: t("Retry")
6185
6169
  }
6186
6170
  )
6187
- ] }) : /* @__PURE__ */ jsxs17(Fragment8, { children: [
6171
+ ] }) : /* @__PURE__ */ jsxs16(Fragment8, { children: [
6188
6172
  canvasBars.map((feature) => {
6189
6173
  const Bar = feature.canvasBar;
6190
- return /* @__PURE__ */ jsx18(Bar, { context: featureContext }, feature.id);
6174
+ return /* @__PURE__ */ jsx17(Bar, { context: featureContext }, feature.id);
6191
6175
  }),
6192
- /* @__PURE__ */ jsx18("div", { className: "eb:relative eb:min-h-0 eb:flex-1", children: boot.status === "ready" && /* @__PURE__ */ jsx18(
6176
+ /* @__PURE__ */ jsx17("div", { className: "eb:relative eb:min-h-0 eb:flex-1", children: boot.status === "ready" && /* @__PURE__ */ jsx17(
6193
6177
  EmailCanvas,
6194
6178
  {
6195
6179
  editor,
@@ -6199,14 +6183,14 @@ function Builder({
6199
6183
  },
6200
6184
  attempt
6201
6185
  ) }),
6202
- !ready && /* @__PURE__ */ jsxs17("div", { className: "eb:absolute eb:inset-0 eb:flex eb:items-center eb:justify-center eb:bg-surface-75", role: "status", "aria-live": "polite", children: [
6203
- /* @__PURE__ */ jsx18(Loader25, { className: "eb:size-6 eb:animate-spin eb:text-foreground-muted", "aria-hidden": "true" }),
6204
- /* @__PURE__ */ jsx18("span", { className: "eb:sr-only", children: t("Loading the builder") })
6186
+ !ready && /* @__PURE__ */ jsxs16("div", { className: "eb:absolute eb:inset-0 eb:flex eb:items-center eb:justify-center eb:bg-surface-75", role: "status", "aria-live": "polite", children: [
6187
+ /* @__PURE__ */ jsx17(Loader25, { className: "eb:size-6 eb:animate-spin eb:text-foreground-muted", "aria-hidden": "true" }),
6188
+ /* @__PURE__ */ jsx17("span", { className: "eb:sr-only", children: t("Loading the builder") })
6205
6189
  ] })
6206
6190
  ] }) }),
6207
6191
  !compact && properties,
6208
- blocksInDrawer && /* @__PURE__ */ jsx18(Drawer, { open: drawer === "blocks", side: "left", title: t("Add a block"), onClose: closeDrawer, testId: "eb-blocks-drawer", children: /* @__PURE__ */ jsx18(BlockSidebar, { editor, disabled: !ready, onAdded: () => setDrawer("properties") }) }),
6209
- compact && /* @__PURE__ */ jsx18(
6192
+ blocksInDrawer && /* @__PURE__ */ jsx17(Drawer, { open: drawer === "blocks", side: "left", title: t("Add a block"), onClose: closeDrawer, testId: "eb-blocks-drawer", children: /* @__PURE__ */ jsx17(BlockSidebar, { editor, disabled: !ready, onAdded: () => setDrawer("properties") }) }),
6193
+ compact && /* @__PURE__ */ jsx17(
6210
6194
  Drawer,
6211
6195
  {
6212
6196
  open: drawer === "properties",
@@ -6221,12 +6205,12 @@ function Builder({
6221
6205
  ]
6222
6206
  }
6223
6207
  ),
6224
- compact && /* @__PURE__ */ jsxs17("div", { className: "eb:flex eb:shrink-0 eb:items-center eb:gap-2 eb:border-t eb:border-border eb:px-2 eb:py-2", "data-testid": "eb-compact-bar", children: [
6225
- blocksInDrawer && /* @__PURE__ */ jsxs17(Button, { variant: "outline", size: "sm-compact", disabled: !ready, onClick: () => setDrawer("blocks"), children: [
6226
- /* @__PURE__ */ jsx18(Plus2, {}),
6208
+ compact && /* @__PURE__ */ jsxs16("div", { className: "eb:flex eb:shrink-0 eb:items-center eb:gap-2 eb:border-t eb:border-border eb:px-2 eb:py-2", "data-testid": "eb-compact-bar", children: [
6209
+ blocksInDrawer && /* @__PURE__ */ jsxs16(Button, { variant: "outline", size: "sm-compact", disabled: !ready, onClick: () => setDrawer("blocks"), children: [
6210
+ /* @__PURE__ */ jsx17(Plus3, {}),
6227
6211
  t("Add a block")
6228
6212
  ] }),
6229
- /* @__PURE__ */ jsxs17(
6213
+ /* @__PURE__ */ jsxs16(
6230
6214
  Button,
6231
6215
  {
6232
6216
  variant: state.selection ? "default" : "outline",
@@ -6235,14 +6219,14 @@ function Builder({
6235
6219
  disabled: !ready,
6236
6220
  onClick: () => setDrawer("properties"),
6237
6221
  children: [
6238
- /* @__PURE__ */ jsx18(SlidersHorizontal, {}),
6239
- /* @__PURE__ */ jsx18("span", { className: "eb:truncate", children: ready && state.selection ? t("Edit: {element}", { element: t(state.selection.label) }) : t("Email settings") })
6222
+ /* @__PURE__ */ jsx17(SlidersHorizontal, {}),
6223
+ /* @__PURE__ */ jsx17("span", { className: "eb:truncate", children: ready && state.selection ? t("Edit: {element}", { element: t(state.selection.label) }) : t("Email settings") })
6240
6224
  ]
6241
6225
  }
6242
6226
  )
6243
6227
  ] }),
6244
- /* @__PURE__ */ jsx18(NoticeArea, {}),
6245
- ai?.key && ai.components.Connect && /* @__PURE__ */ jsx18(ai.components.Connect, { aiKey: ai.key })
6228
+ /* @__PURE__ */ jsx17(NoticeArea, {}),
6229
+ ai?.key && ai.components.Connect && /* @__PURE__ */ jsx17(ai.components.Connect, { aiKey: ai.key })
6246
6230
  ]
6247
6231
  }
6248
6232
  );
@@ -6253,7 +6237,7 @@ function EmailBuilder({ locale = "en", messages, onNotify, ai: aiProp = null, ..
6253
6237
  () => ai ? { ...messagesOf(ai.messages, locale), ...messages } : messages,
6254
6238
  [ai, locale, messages]
6255
6239
  );
6256
- return /* @__PURE__ */ jsx18(UiProvider, { locale, messages: allMessages, onNotify, children: /* @__PURE__ */ jsx18(Builder, { ...props, ai, templateId: props.templateId ?? null }) });
6240
+ return /* @__PURE__ */ jsx17(UiProvider, { locale, messages: allMessages, onNotify, children: /* @__PURE__ */ jsx17(Builder, { ...props, ai, templateId: props.templateId ?? null }) });
6257
6241
  }
6258
6242
  function useAiModule(value) {
6259
6243
  const valid = Boolean(value && typeof value === "object" && /** @type {any} */
@@ -6272,7 +6256,7 @@ function useAiModule(value) {
6272
6256
  // src/ui/EmailBuilderBoundary.jsx
6273
6257
  import { Component } from "react";
6274
6258
  import { AlertTriangle as AlertTriangle2, ArrowLeft as ArrowLeft3, RefreshCw } from "lucide-react";
6275
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
6259
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
6276
6260
  var isChunkError = (error) => error?.name === "ChunkLoadError" || /Loading (CSS )?chunk .* failed/i.test(String(error?.message || ""));
6277
6261
  var english = (text) => text;
6278
6262
  var EmailBuilderBoundary = class extends Component {
@@ -6297,23 +6281,23 @@ var EmailBuilderBoundary = class extends Component {
6297
6281
  const { error, attempt } = this.state;
6298
6282
  const t = this.props.t || english;
6299
6283
  if (!error) {
6300
- return /* @__PURE__ */ jsx19("div", { style: { height: "100%" }, children: this.props.children }, attempt);
6284
+ return /* @__PURE__ */ jsx18("div", { style: { height: "100%" }, children: this.props.children }, attempt);
6301
6285
  }
6302
- return /* @__PURE__ */ jsxs18(
6286
+ return /* @__PURE__ */ jsxs17(
6303
6287
  "div",
6304
6288
  {
6305
6289
  role: "alert",
6306
6290
  className: "eb-root eb:flex eb:h-full eb:flex-col eb:items-center eb:justify-center eb:gap-3 eb:p-6 eb:text-center",
6307
6291
  children: [
6308
- /* @__PURE__ */ jsx19(AlertTriangle2, { className: "eb:size-6 eb:text-destructive", "aria-hidden": "true" }),
6309
- /* @__PURE__ */ jsx19("p", { className: "eb:text-[13px] eb:text-foreground", children: t("The builder could not load.") }),
6310
- /* @__PURE__ */ jsxs18("div", { className: "eb:flex eb:gap-2", children: [
6311
- this.props.onClose && /* @__PURE__ */ jsxs18(Button, { variant: "outline", size: "sm", onClick: this.props.onClose, children: [
6312
- /* @__PURE__ */ jsx19(ArrowLeft3, {}),
6292
+ /* @__PURE__ */ jsx18(AlertTriangle2, { className: "eb:size-6 eb:text-destructive", "aria-hidden": "true" }),
6293
+ /* @__PURE__ */ jsx18("p", { className: "eb:text-[13px] eb:text-foreground", children: t("The builder could not load.") }),
6294
+ /* @__PURE__ */ jsxs17("div", { className: "eb:flex eb:gap-2", children: [
6295
+ this.props.onClose && /* @__PURE__ */ jsxs17(Button, { variant: "outline", size: "sm", onClick: this.props.onClose, children: [
6296
+ /* @__PURE__ */ jsx18(ArrowLeft3, {}),
6313
6297
  t("Back")
6314
6298
  ] }),
6315
- /* @__PURE__ */ jsxs18(Button, { size: "sm", onClick: this.retry, children: [
6316
- /* @__PURE__ */ jsx19(RefreshCw, {}),
6299
+ /* @__PURE__ */ jsxs17(Button, { size: "sm", onClick: this.retry, children: [
6300
+ /* @__PURE__ */ jsx18(RefreshCw, {}),
6317
6301
  t("Retry")
6318
6302
  ] })
6319
6303
  ] })
@@ -6341,4 +6325,4 @@ export {
6341
6325
  EmailBuilder,
6342
6326
  EmailBuilderBoundary
6343
6327
  };
6344
- //# sourceMappingURL=chunk-G7G3TRWG.js.map
6328
+ //# sourceMappingURL=chunk-2ZRGQFX6.js.map