best-email-builder 0.12.0 → 0.13.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.
- package/CHANGELOG.md +15 -0
- package/dist/ai-server.js +3 -3
- package/dist/ai.js +6 -6
- package/dist/builder.js +8 -8
- package/dist/{chunk-FYIIO7LD.js → chunk-2KOI5SWV.js} +2 -2
- package/dist/{chunk-LAUNZIFX.js → chunk-6QTSXJG4.js} +5 -5
- package/dist/chunk-6QTSXJG4.js.map +1 -0
- package/dist/{chunk-46ZVS2VX.js → chunk-A4KF7NMP.js} +2 -2
- package/dist/{chunk-OACK2DIW.js → chunk-G7G3TRWG.js} +662 -441
- package/dist/chunk-G7G3TRWG.js.map +1 -0
- package/dist/{chunk-6CTFMKAQ.js → chunk-JJ56652Y.js} +4 -4
- package/dist/{chunk-UUS325J7.js → chunk-LSOR4OII.js} +3 -3
- package/dist/{chunk-MOWQZKIQ.js → chunk-Q2ZUJFOY.js} +2 -2
- package/dist/{chunk-LZYDCWVH.js → chunk-Q5UPFM7J.js} +3 -3
- package/dist/{chunk-LZYDCWVH.js.map → chunk-Q5UPFM7J.js.map} +1 -1
- package/dist/{chunk-RONYPWDK.js → chunk-UGF3YJ64.js} +2 -2
- package/dist/{chunk-RSTERB7K.js → chunk-XF25DLD4.js} +3 -3
- package/dist/{chunk-JFIXYIZ3.js → chunk-ZTUW25BG.js} +7 -1
- package/dist/chunk-ZTUW25BG.js.map +1 -0
- package/dist/index.js +10 -10
- package/dist/library.js +5 -5
- package/dist/server.js +5 -5
- package/dist/styles.css +1 -1
- package/dist/types/core/EmailEditor.d.ts +16 -4
- package/dist/types/core/constants.d.ts +1 -1
- package/dist/types/engine/NativeAdapter.d.ts +1 -1
- package/dist/types/engine/canvas/CanvasView.d.ts +3 -0
- package/dist/types/engine/canvas/canvasStyles.d.ts +1 -1
- package/dist/types/features/variables/VariablesBar.d.ts +16 -0
- package/dist/types/ui/primitives/misc.d.ts +6 -2
- package/package.json +1 -1
- package/dist/chunk-JFIXYIZ3.js.map +0 -1
- package/dist/chunk-LAUNZIFX.js.map +0 -1
- package/dist/chunk-OACK2DIW.js.map +0 -1
- /package/dist/{chunk-FYIIO7LD.js.map → chunk-2KOI5SWV.js.map} +0 -0
- /package/dist/{chunk-46ZVS2VX.js.map → chunk-A4KF7NMP.js.map} +0 -0
- /package/dist/{chunk-6CTFMKAQ.js.map → chunk-JJ56652Y.js.map} +0 -0
- /package/dist/{chunk-UUS325J7.js.map → chunk-LSOR4OII.js.map} +0 -0
- /package/dist/{chunk-MOWQZKIQ.js.map → chunk-Q2ZUJFOY.js.map} +0 -0
- /package/dist/{chunk-RONYPWDK.js.map → chunk-UGF3YJ64.js.map} +0 -0
- /package/dist/{chunk-RSTERB7K.js.map → chunk-XF25DLD4.js.map} +0 -0
|
@@ -6,17 +6,17 @@ import {
|
|
|
6
6
|
useLayoutWidth,
|
|
7
7
|
useSearchShortcut,
|
|
8
8
|
withThumbnailImages
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LSOR4OII.js";
|
|
10
10
|
import {
|
|
11
11
|
BRAND_NOTES,
|
|
12
12
|
countImagesWithoutPicture,
|
|
13
13
|
logoWidthFor
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Q2ZUJFOY.js";
|
|
15
15
|
import {
|
|
16
16
|
cleanRichText,
|
|
17
17
|
escapeText,
|
|
18
18
|
textOfHtml
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-UGF3YJ64.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-
|
|
54
|
+
} from "./chunk-6QTSXJG4.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-
|
|
97
|
+
} from "./chunk-Q5UPFM7J.js";
|
|
98
98
|
import {
|
|
99
99
|
isSafeUrl
|
|
100
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-A4KF7NMP.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-
|
|
113
|
+
} from "./chunk-ZTUW25BG.js";
|
|
114
114
|
|
|
115
115
|
// src/core/events.js
|
|
116
116
|
function createEmitter({ onError } = {}) {
|
|
@@ -450,6 +450,19 @@ function createEmailEditor({ adapter, blocks, features = null, t = identity }) {
|
|
|
450
450
|
requireReady("insertLink");
|
|
451
451
|
return adapter.insertLink(String(href || ""), String(label || href || ""));
|
|
452
452
|
},
|
|
453
|
+
/**
|
|
454
|
+
* Shows a text where `insertText` would put it, without inserting it (a
|
|
455
|
+
* variable under the pointer). False if nothing would take it, or if the
|
|
456
|
+
* engine cannot preview. Not ready yet: nothing to show, no error.
|
|
457
|
+
*/
|
|
458
|
+
previewText(text) {
|
|
459
|
+
if (status !== "ready" || !adapter.previewText) return false;
|
|
460
|
+
return adapter.previewText(String(text ?? ""));
|
|
461
|
+
},
|
|
462
|
+
/** Takes the previewed text away. */
|
|
463
|
+
clearPreview() {
|
|
464
|
+
if (status === "ready") adapter.clearPreview?.();
|
|
465
|
+
},
|
|
453
466
|
undo() {
|
|
454
467
|
requireReady("undo");
|
|
455
468
|
adapter.undo();
|
|
@@ -1424,21 +1437,113 @@ var versionsFeature = {
|
|
|
1424
1437
|
toolbar: VersionsMenu
|
|
1425
1438
|
};
|
|
1426
1439
|
|
|
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
|
+
|
|
1427
1532
|
// src/features/variables/VariablesMenu.jsx
|
|
1428
|
-
import { useState as
|
|
1429
|
-
import { Braces as
|
|
1533
|
+
import { useState as useState5 } from "react";
|
|
1534
|
+
import { Braces as Braces3 } from "lucide-react";
|
|
1430
1535
|
|
|
1431
1536
|
// src/features/variables/VariableDialog.jsx
|
|
1432
|
-
import { useEffect, useMemo, useState as
|
|
1433
|
-
import { Braces, Loader2, Trash2 } from "lucide-react";
|
|
1434
|
-
import { jsx as
|
|
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";
|
|
1435
1540
|
function VariableDialog({ open, onOpenChange, variable = null, initialLabel = "", variables, storage, onSaved, onDeleted }) {
|
|
1436
1541
|
const { t, notify, confirm } = useUi();
|
|
1437
1542
|
const editing = Boolean(variable);
|
|
1438
|
-
const [form, setForm] =
|
|
1439
|
-
const [keyTouched, setKeyTouched] =
|
|
1440
|
-
const [errors, setErrors] =
|
|
1441
|
-
const [busy, setBusy] =
|
|
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);
|
|
1442
1547
|
useEffect(() => {
|
|
1443
1548
|
if (!open) return;
|
|
1444
1549
|
setForm(
|
|
@@ -1505,9 +1610,9 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
|
|
|
1505
1610
|
setBusy(false);
|
|
1506
1611
|
}
|
|
1507
1612
|
};
|
|
1508
|
-
const field = (name, label, props = {}, hint = null) => /* @__PURE__ */
|
|
1509
|
-
/* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
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(
|
|
1511
1616
|
Input,
|
|
1512
1617
|
{
|
|
1513
1618
|
id: `eb-var-${name}`,
|
|
@@ -1518,23 +1623,23 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
|
|
|
1518
1623
|
...props
|
|
1519
1624
|
}
|
|
1520
1625
|
),
|
|
1521
|
-
(errors[name] || hint) && /* @__PURE__ */
|
|
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 })
|
|
1522
1627
|
] });
|
|
1523
|
-
return /* @__PURE__ */
|
|
1628
|
+
return /* @__PURE__ */ jsx3(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs3(
|
|
1524
1629
|
DialogContent,
|
|
1525
1630
|
{
|
|
1526
1631
|
className: "eb:sm:max-w-[440px]",
|
|
1527
1632
|
onMouseDown: (e) => e.stopPropagation(),
|
|
1528
1633
|
onCloseAutoFocus: (e) => e.preventDefault(),
|
|
1529
1634
|
children: [
|
|
1530
|
-
/* @__PURE__ */
|
|
1531
|
-
/* @__PURE__ */
|
|
1532
|
-
/* @__PURE__ */
|
|
1533
|
-
/* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
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.") })
|
|
1535
1640
|
] })
|
|
1536
1641
|
] }) }),
|
|
1537
|
-
/* @__PURE__ */
|
|
1642
|
+
/* @__PURE__ */ jsxs3("form", { onSubmit: submit, className: "eb:space-y-3", noValidate: true, children: [
|
|
1538
1643
|
field("label", t("Name"), { autoFocus: true, maxLength: VARIABLE_LIMITS.label, placeholder: t("Order number") }),
|
|
1539
1644
|
field(
|
|
1540
1645
|
"key",
|
|
@@ -1542,9 +1647,9 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
|
|
|
1542
1647
|
{ disabled: editing, maxLength: VARIABLE_LIMITS.key, className: "eb:font-mono eb:text-[12px]" },
|
|
1543
1648
|
form.key ? `{{${form.key}}}` : null
|
|
1544
1649
|
),
|
|
1545
|
-
/* @__PURE__ */
|
|
1546
|
-
/* @__PURE__ */
|
|
1547
|
-
/* @__PURE__ */
|
|
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(
|
|
1548
1653
|
Input,
|
|
1549
1654
|
{
|
|
1550
1655
|
id: "eb-var-group",
|
|
@@ -1555,21 +1660,21 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
|
|
|
1555
1660
|
placeholder: t(CUSTOM_GROUP)
|
|
1556
1661
|
}
|
|
1557
1662
|
),
|
|
1558
|
-
/* @__PURE__ */
|
|
1663
|
+
/* @__PURE__ */ jsx3("datalist", { id: "eb-var-groups", children: groups.map((g) => /* @__PURE__ */ jsx3("option", { value: g }, g)) })
|
|
1559
1664
|
] }),
|
|
1560
|
-
/* @__PURE__ */
|
|
1665
|
+
/* @__PURE__ */ jsxs3("div", { className: "eb:grid eb:grid-cols-2 eb:gap-3", children: [
|
|
1561
1666
|
field("sample", t("Sample value"), { maxLength: VARIABLE_LIMITS.sample, placeholder: "CMD-1042" }, t("Preview and tests")),
|
|
1562
1667
|
field("fallback", t("Value if empty"), { maxLength: VARIABLE_LIMITS.fallback }, t("When a recipient has none"))
|
|
1563
1668
|
] }),
|
|
1564
|
-
/* @__PURE__ */
|
|
1565
|
-
editing && /* @__PURE__ */
|
|
1566
|
-
/* @__PURE__ */
|
|
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, {}),
|
|
1567
1672
|
t("Delete")
|
|
1568
1673
|
] }),
|
|
1569
|
-
/* @__PURE__ */
|
|
1570
|
-
/* @__PURE__ */
|
|
1571
|
-
/* @__PURE__ */
|
|
1572
|
-
busy && /* @__PURE__ */
|
|
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" }),
|
|
1573
1678
|
editing ? t("Save") : t("Create")
|
|
1574
1679
|
] })
|
|
1575
1680
|
] })
|
|
@@ -1581,13 +1686,13 @@ function VariableDialog({ open, onOpenChange, variable = null, initialLabel = ""
|
|
|
1581
1686
|
}
|
|
1582
1687
|
|
|
1583
1688
|
// src/features/variables/VariablePicker.jsx
|
|
1584
|
-
import { useEffect as useEffect2, useMemo as useMemo2, useRef, useState as
|
|
1689
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState4 } from "react";
|
|
1585
1690
|
import { Pencil, Plus, Search } from "lucide-react";
|
|
1586
|
-
import { jsx as
|
|
1691
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1587
1692
|
function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, filter }) {
|
|
1588
1693
|
const t = useT();
|
|
1589
|
-
const [query, setQuery] =
|
|
1590
|
-
const [active, setActive] =
|
|
1694
|
+
const [query, setQuery] = useState4("");
|
|
1695
|
+
const [active, setActive] = useState4(0);
|
|
1591
1696
|
const listRef = useRef(null);
|
|
1592
1697
|
const searchRef = useRef(
|
|
1593
1698
|
/** @type {HTMLInputElement|null} */
|
|
@@ -1619,10 +1724,10 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1619
1724
|
else if (onCreate && query.trim()) onCreate(query.trim());
|
|
1620
1725
|
}
|
|
1621
1726
|
};
|
|
1622
|
-
return /* @__PURE__ */
|
|
1623
|
-
/* @__PURE__ */
|
|
1624
|
-
/* @__PURE__ */
|
|
1625
|
-
/* @__PURE__ */
|
|
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(
|
|
1626
1731
|
"input",
|
|
1627
1732
|
{
|
|
1628
1733
|
ref: searchRef,
|
|
@@ -1636,29 +1741,29 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1636
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"
|
|
1637
1742
|
}
|
|
1638
1743
|
),
|
|
1639
|
-
/* @__PURE__ */
|
|
1744
|
+
/* @__PURE__ */ jsx4(SearchKeyHint, { className: "eb:absolute eb:top-1/2 eb:right-4 eb:-translate-y-1/2" })
|
|
1640
1745
|
] }),
|
|
1641
|
-
/* @__PURE__ */
|
|
1642
|
-
ordered.length === 0 && /* @__PURE__ */
|
|
1643
|
-
/* @__PURE__ */
|
|
1644
|
-
onCreate && query.trim() && /* @__PURE__ */
|
|
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(
|
|
1645
1750
|
"button",
|
|
1646
1751
|
{
|
|
1647
1752
|
type: "button",
|
|
1648
1753
|
onClick: () => onCreate(query.trim()),
|
|
1649
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",
|
|
1650
1755
|
children: [
|
|
1651
|
-
/* @__PURE__ */
|
|
1756
|
+
/* @__PURE__ */ jsx4(Plus, { className: "eb:size-3.5" }),
|
|
1652
1757
|
t("Create \u201C{name}\u201D", { name: query.trim() })
|
|
1653
1758
|
]
|
|
1654
1759
|
}
|
|
1655
1760
|
)
|
|
1656
1761
|
] }),
|
|
1657
|
-
groups.map((group) => /* @__PURE__ */
|
|
1658
|
-
/* @__PURE__ */
|
|
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) }),
|
|
1659
1764
|
ordered.filter((v) => v.group === group).map((variable) => {
|
|
1660
1765
|
const index = ordered.indexOf(variable);
|
|
1661
|
-
return /* @__PURE__ */
|
|
1766
|
+
return /* @__PURE__ */ jsxs4(
|
|
1662
1767
|
"div",
|
|
1663
1768
|
{
|
|
1664
1769
|
"data-active": index === active,
|
|
@@ -1668,7 +1773,7 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1668
1773
|
),
|
|
1669
1774
|
onMouseEnter: () => setActive(index),
|
|
1670
1775
|
children: [
|
|
1671
|
-
/* @__PURE__ */
|
|
1776
|
+
/* @__PURE__ */ jsxs4(
|
|
1672
1777
|
"button",
|
|
1673
1778
|
{
|
|
1674
1779
|
type: "button",
|
|
@@ -1679,12 +1784,12 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1679
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]",
|
|
1680
1785
|
title: variable.description || void 0,
|
|
1681
1786
|
children: [
|
|
1682
|
-
/* @__PURE__ */
|
|
1683
|
-
/* @__PURE__ */
|
|
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) })
|
|
1684
1789
|
]
|
|
1685
1790
|
}
|
|
1686
1791
|
),
|
|
1687
|
-
onEdit && variable.custom && /* @__PURE__ */
|
|
1792
|
+
onEdit && variable.custom && /* @__PURE__ */ jsx4(
|
|
1688
1793
|
"button",
|
|
1689
1794
|
{
|
|
1690
1795
|
type: "button",
|
|
@@ -1692,7 +1797,7 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1692
1797
|
title: t("Edit"),
|
|
1693
1798
|
onClick: () => onEdit(variable),
|
|
1694
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",
|
|
1695
|
-
children: /* @__PURE__ */
|
|
1800
|
+
children: /* @__PURE__ */ jsx4(Pencil, { className: "eb:size-3" })
|
|
1696
1801
|
}
|
|
1697
1802
|
)
|
|
1698
1803
|
]
|
|
@@ -1702,14 +1807,14 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1702
1807
|
})
|
|
1703
1808
|
] }, group))
|
|
1704
1809
|
] }),
|
|
1705
|
-
onCreate && /* @__PURE__ */
|
|
1810
|
+
onCreate && /* @__PURE__ */ jsx4("div", { className: "eb:border-t eb:border-border eb:p-1", children: /* @__PURE__ */ jsxs4(
|
|
1706
1811
|
"button",
|
|
1707
1812
|
{
|
|
1708
1813
|
type: "button",
|
|
1709
1814
|
onClick: () => onCreate(query.trim()),
|
|
1710
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",
|
|
1711
1816
|
children: [
|
|
1712
|
-
/* @__PURE__ */
|
|
1817
|
+
/* @__PURE__ */ jsx4(Plus, { className: "eb:size-4" }),
|
|
1713
1818
|
t("New variable")
|
|
1714
1819
|
]
|
|
1715
1820
|
}
|
|
@@ -1718,12 +1823,12 @@ function VariablePicker({ variables, onPick, onCreate = null, onEdit = null, fil
|
|
|
1718
1823
|
}
|
|
1719
1824
|
|
|
1720
1825
|
// src/features/variables/VariablesMenu.jsx
|
|
1721
|
-
import { Fragment, jsx as
|
|
1826
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1722
1827
|
function VariablesMenu({ context }) {
|
|
1723
1828
|
const { editor, ready, variables, storage, canManageVariables, reloadVariables } = context;
|
|
1724
1829
|
const { t, notify } = useUi();
|
|
1725
|
-
const [open, setOpen] =
|
|
1726
|
-
const [dialog, setDialog] =
|
|
1830
|
+
const [open, setOpen] = useState5(false);
|
|
1831
|
+
const [dialog, setDialog] = useState5(null);
|
|
1727
1832
|
const insert = (variable) => {
|
|
1728
1833
|
setOpen(false);
|
|
1729
1834
|
const done = variable.kind === "link" ? editor.insertLink(tokenOf(variable), t("Unsubscribe")) : editor.insertText(tokenOf(variable));
|
|
@@ -1740,9 +1845,9 @@ function VariablesMenu({ context }) {
|
|
|
1740
1845
|
setDialog({ variable, label: "" });
|
|
1741
1846
|
}
|
|
1742
1847
|
} : {};
|
|
1743
|
-
return /* @__PURE__ */
|
|
1744
|
-
/* @__PURE__ */
|
|
1745
|
-
/* @__PURE__ */
|
|
1848
|
+
return /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1849
|
+
/* @__PURE__ */ jsxs5(Popover, { open, onOpenChange: setOpen, children: [
|
|
1850
|
+
/* @__PURE__ */ jsx5(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
|
|
1746
1851
|
Button,
|
|
1747
1852
|
{
|
|
1748
1853
|
variant: "outline",
|
|
@@ -1750,23 +1855,23 @@ function VariablesMenu({ context }) {
|
|
|
1750
1855
|
disabled: !ready,
|
|
1751
1856
|
onPointerDown: (e) => e.pointerType === "mouse" && e.preventDefault(),
|
|
1752
1857
|
children: [
|
|
1753
|
-
/* @__PURE__ */
|
|
1858
|
+
/* @__PURE__ */ jsx5(Braces3, {}),
|
|
1754
1859
|
t("Variables")
|
|
1755
1860
|
]
|
|
1756
1861
|
}
|
|
1757
1862
|
) }),
|
|
1758
|
-
/* @__PURE__ */
|
|
1863
|
+
/* @__PURE__ */ jsx5(
|
|
1759
1864
|
PopoverContent,
|
|
1760
1865
|
{
|
|
1761
1866
|
align: "end",
|
|
1762
1867
|
className: "eb:w-80 eb:p-0",
|
|
1763
1868
|
onCloseAutoFocus: (e) => e.preventDefault(),
|
|
1764
1869
|
onMouseDown: (e) => e.stopPropagation(),
|
|
1765
|
-
children: /* @__PURE__ */
|
|
1870
|
+
children: /* @__PURE__ */ jsx5(VariablePicker, { variables, onPick: insert, ...manage })
|
|
1766
1871
|
}
|
|
1767
1872
|
)
|
|
1768
1873
|
] }),
|
|
1769
|
-
canManageVariables && /* @__PURE__ */
|
|
1874
|
+
canManageVariables && /* @__PURE__ */ jsx5(
|
|
1770
1875
|
VariableDialog,
|
|
1771
1876
|
{
|
|
1772
1877
|
open: Boolean(dialog),
|
|
@@ -1801,7 +1906,8 @@ var variablesFeature = {
|
|
|
1801
1906
|
id: "variables",
|
|
1802
1907
|
label: "Variables",
|
|
1803
1908
|
order: 10,
|
|
1804
|
-
toolbar: VariablesMenu
|
|
1909
|
+
toolbar: VariablesMenu,
|
|
1910
|
+
canvasBar: VariablesBar
|
|
1805
1911
|
};
|
|
1806
1912
|
|
|
1807
1913
|
// src/features/preview/index.js
|
|
@@ -1814,9 +1920,9 @@ var previewFeature = {
|
|
|
1814
1920
|
};
|
|
1815
1921
|
|
|
1816
1922
|
// src/features/test-email/TestEmailButton.jsx
|
|
1817
|
-
import { useState as
|
|
1923
|
+
import { useState as useState6 } from "react";
|
|
1818
1924
|
import { CheckCircle2, Loader2 as Loader22, Send, XCircle } from "lucide-react";
|
|
1819
|
-
import { Fragment as Fragment2, jsx as
|
|
1925
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1820
1926
|
var KEY = "best-email-builder:test-addresses";
|
|
1821
1927
|
function readAddresses(fallback) {
|
|
1822
1928
|
try {
|
|
@@ -1834,10 +1940,10 @@ function rememberAddresses(value) {
|
|
|
1834
1940
|
function TestEmailButton({ context }) {
|
|
1835
1941
|
const { editor, ready, meta, storage, testRecipients = [] } = context;
|
|
1836
1942
|
const { t, notify } = useUi();
|
|
1837
|
-
const [open, setOpen] =
|
|
1838
|
-
const [addresses, setAddresses] =
|
|
1839
|
-
const [sending, setSending] =
|
|
1840
|
-
const [report, setReport] =
|
|
1943
|
+
const [open, setOpen] = useState6(false);
|
|
1944
|
+
const [addresses, setAddresses] = useState6("");
|
|
1945
|
+
const [sending, setSending] = useState6(false);
|
|
1946
|
+
const [report, setReport] = useState6(null);
|
|
1841
1947
|
const emails = addresses.split(/[,;\s]+/).map((a) => a.trim()).filter(Boolean);
|
|
1842
1948
|
const send = async () => {
|
|
1843
1949
|
if (!emails.length) return;
|
|
@@ -1860,8 +1966,8 @@ function TestEmailButton({ context }) {
|
|
|
1860
1966
|
setSending(false);
|
|
1861
1967
|
}
|
|
1862
1968
|
};
|
|
1863
|
-
return /* @__PURE__ */
|
|
1864
|
-
/* @__PURE__ */
|
|
1969
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1970
|
+
/* @__PURE__ */ jsxs6(
|
|
1865
1971
|
Button,
|
|
1866
1972
|
{
|
|
1867
1973
|
variant: "outline",
|
|
@@ -1873,22 +1979,22 @@ function TestEmailButton({ context }) {
|
|
|
1873
1979
|
setOpen(true);
|
|
1874
1980
|
},
|
|
1875
1981
|
children: [
|
|
1876
|
-
/* @__PURE__ */
|
|
1982
|
+
/* @__PURE__ */ jsx6(Send, {}),
|
|
1877
1983
|
t("Test")
|
|
1878
1984
|
]
|
|
1879
1985
|
}
|
|
1880
1986
|
),
|
|
1881
|
-
/* @__PURE__ */
|
|
1882
|
-
/* @__PURE__ */
|
|
1883
|
-
/* @__PURE__ */
|
|
1884
|
-
/* @__PURE__ */
|
|
1885
|
-
/* @__PURE__ */
|
|
1886
|
-
/* @__PURE__ */
|
|
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.") })
|
|
1887
1993
|
] })
|
|
1888
1994
|
] }) }),
|
|
1889
|
-
/* @__PURE__ */
|
|
1890
|
-
/* @__PURE__ */
|
|
1891
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsxs6("div", { className: "eb:space-y-2", children: [
|
|
1996
|
+
/* @__PURE__ */ jsx6(Label, { htmlFor: "eb-test-addresses", children: t("Addresses") }),
|
|
1997
|
+
/* @__PURE__ */ jsx6(
|
|
1892
1998
|
Textarea,
|
|
1893
1999
|
{
|
|
1894
2000
|
id: "eb-test-addresses",
|
|
@@ -1899,20 +2005,20 @@ function TestEmailButton({ context }) {
|
|
|
1899
2005
|
}
|
|
1900
2006
|
)
|
|
1901
2007
|
] }),
|
|
1902
|
-
report && /* @__PURE__ */
|
|
1903
|
-
report.results.map((r) => /* @__PURE__ */
|
|
1904
|
-
r.ok ? /* @__PURE__ */
|
|
1905
|
-
/* @__PURE__ */
|
|
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: [
|
|
1906
2012
|
r.email,
|
|
1907
2013
|
r.error ? ` \u2014 ${r.error}` : ""
|
|
1908
2014
|
] })
|
|
1909
2015
|
] }, r.email)),
|
|
1910
|
-
report.invalid.map((email2) => /* @__PURE__ */
|
|
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}`))
|
|
1911
2017
|
] }),
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */
|
|
1914
|
-
/* @__PURE__ */
|
|
1915
|
-
sending ? /* @__PURE__ */
|
|
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, {}),
|
|
1916
2022
|
t("Send")
|
|
1917
2023
|
] })
|
|
1918
2024
|
] })
|
|
@@ -1930,9 +2036,9 @@ var testEmailFeature = {
|
|
|
1930
2036
|
};
|
|
1931
2037
|
|
|
1932
2038
|
// src/features/templates/TemplateGallery.jsx
|
|
1933
|
-
import { useEffect as useEffect3, useMemo as useMemo3, useState as
|
|
2039
|
+
import { useEffect as useEffect3, useMemo as useMemo3, useState as useState7 } from "react";
|
|
1934
2040
|
import { LayoutTemplate, Search as Search2, X } from "lucide-react";
|
|
1935
|
-
import { Fragment as Fragment3, jsx as
|
|
2041
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1936
2042
|
var THUMBNAIL_SCALE = 0.38;
|
|
1937
2043
|
var EMAIL_WIDTH = 600;
|
|
1938
2044
|
var FADE_LINE = "eb:block eb:overflow-hidden eb:whitespace-nowrap eb:[mask-image:linear-gradient(to_right,#000_calc(100%-2.5rem),transparent)]";
|
|
@@ -1940,12 +2046,12 @@ var NO_SCROLLBAR = "<style>html,body{overflow:hidden!important;scrollbar-width:n
|
|
|
1940
2046
|
var withoutScrollbar = (html) => !html ? html : /<\/head>/i.test(html) ? html.replace(/<\/head>/i, `${NO_SCROLLBAR}</head>`) : NO_SCROLLBAR + html;
|
|
1941
2047
|
var fold = (text) => String(text || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
|
|
1942
2048
|
function Thumbnail({ html, title }) {
|
|
1943
|
-
return /* @__PURE__ */
|
|
2049
|
+
return /* @__PURE__ */ jsx7(
|
|
1944
2050
|
"div",
|
|
1945
2051
|
{
|
|
1946
2052
|
className: "eb:relative eb:h-[220px] eb:shrink-0 eb:overflow-hidden eb:rounded-md eb:border eb:border-border eb:bg-surface-75",
|
|
1947
2053
|
"aria-hidden": "true",
|
|
1948
|
-
children: /* @__PURE__ */
|
|
2054
|
+
children: /* @__PURE__ */ jsx7(
|
|
1949
2055
|
"iframe",
|
|
1950
2056
|
{
|
|
1951
2057
|
title,
|
|
@@ -1967,10 +2073,10 @@ function Thumbnail({ html, title }) {
|
|
|
1967
2073
|
function TemplateGalleryButton({ context }) {
|
|
1968
2074
|
const { editor, ready, templates, isDirty, markDirty, template, setMeta } = context;
|
|
1969
2075
|
const { t, confirm, notify } = useUi();
|
|
1970
|
-
const [open, setOpen] =
|
|
1971
|
-
const [query, setQuery] =
|
|
1972
|
-
const [chosen, setChosen] =
|
|
1973
|
-
const [rendered, setRendered] =
|
|
2076
|
+
const [open, setOpen] = useState7(false);
|
|
2077
|
+
const [query, setQuery] = useState7("");
|
|
2078
|
+
const [chosen, setChosen] = useState7(() => /* @__PURE__ */ new Set());
|
|
2079
|
+
const [rendered, setRendered] = useState7({});
|
|
1974
2080
|
useEffect3(() => {
|
|
1975
2081
|
if (!open || !ready) return void 0;
|
|
1976
2082
|
let alive = true;
|
|
@@ -2027,8 +2133,8 @@ function TemplateGalleryButton({ context }) {
|
|
|
2027
2133
|
setOpen(false);
|
|
2028
2134
|
notify("success", t("\u201C{name}\u201D template applied.", { name: entry.name }));
|
|
2029
2135
|
};
|
|
2030
|
-
return /* @__PURE__ */
|
|
2031
|
-
/* @__PURE__ */
|
|
2136
|
+
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
2137
|
+
/* @__PURE__ */ jsxs7(
|
|
2032
2138
|
Button,
|
|
2033
2139
|
{
|
|
2034
2140
|
variant: "outline",
|
|
@@ -2040,12 +2146,12 @@ function TemplateGalleryButton({ context }) {
|
|
|
2040
2146
|
setOpen(true);
|
|
2041
2147
|
},
|
|
2042
2148
|
children: [
|
|
2043
|
-
/* @__PURE__ */
|
|
2149
|
+
/* @__PURE__ */ jsx7(LayoutTemplate, {}),
|
|
2044
2150
|
t("Templates")
|
|
2045
2151
|
]
|
|
2046
2152
|
}
|
|
2047
2153
|
),
|
|
2048
|
-
/* @__PURE__ */
|
|
2154
|
+
/* @__PURE__ */ jsx7(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs7(
|
|
2049
2155
|
DialogContent,
|
|
2050
2156
|
{
|
|
2051
2157
|
className: "eb:flex eb:h-[min(48rem,calc(100dvh-2rem))] eb:flex-col eb:sm:max-w-4xl",
|
|
@@ -2057,14 +2163,14 @@ function TemplateGalleryButton({ context }) {
|
|
|
2057
2163
|
}
|
|
2058
2164
|
},
|
|
2059
2165
|
children: [
|
|
2060
|
-
/* @__PURE__ */
|
|
2061
|
-
/* @__PURE__ */
|
|
2062
|
-
/* @__PURE__ */
|
|
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.") })
|
|
2063
2169
|
] }),
|
|
2064
|
-
/* @__PURE__ */
|
|
2065
|
-
/* @__PURE__ */
|
|
2066
|
-
/* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
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(
|
|
2068
2174
|
Input,
|
|
2069
2175
|
{
|
|
2070
2176
|
type: "search",
|
|
@@ -2075,20 +2181,20 @@ function TemplateGalleryButton({ context }) {
|
|
|
2075
2181
|
className: "eb:pr-8 eb:pl-8 eb:[&::-webkit-search-cancel-button]:hidden"
|
|
2076
2182
|
}
|
|
2077
2183
|
),
|
|
2078
|
-
query && /* @__PURE__ */
|
|
2184
|
+
query && /* @__PURE__ */ jsx7(
|
|
2079
2185
|
"button",
|
|
2080
2186
|
{
|
|
2081
2187
|
type: "button",
|
|
2082
2188
|
onClick: () => setQuery(""),
|
|
2083
2189
|
"aria-label": t("Clear the search"),
|
|
2084
2190
|
className: "eb:absolute eb:top-1/2 eb:right-2.5 eb:-translate-y-1/2 eb:cursor-pointer",
|
|
2085
|
-
children: /* @__PURE__ */
|
|
2191
|
+
children: /* @__PURE__ */ jsx7(X, { className: "eb:size-3.5 eb:text-foreground-muted eb:hover:text-foreground" })
|
|
2086
2192
|
}
|
|
2087
2193
|
)
|
|
2088
2194
|
] }),
|
|
2089
|
-
tags.length > 0 && /* @__PURE__ */
|
|
2090
|
-
/* @__PURE__ */
|
|
2091
|
-
/* @__PURE__ */
|
|
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(
|
|
2092
2198
|
FilterReset,
|
|
2093
2199
|
{
|
|
2094
2200
|
label: t("Clear the tag filters"),
|
|
@@ -2099,7 +2205,7 @@ function TemplateGalleryButton({ context }) {
|
|
|
2099
2205
|
)
|
|
2100
2206
|
] })
|
|
2101
2207
|
] }),
|
|
2102
|
-
/* @__PURE__ */
|
|
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(
|
|
2103
2209
|
"button",
|
|
2104
2210
|
{
|
|
2105
2211
|
type: "button",
|
|
@@ -2108,10 +2214,10 @@ function TemplateGalleryButton({ context }) {
|
|
|
2108
2214
|
title: card.description,
|
|
2109
2215
|
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",
|
|
2110
2216
|
children: [
|
|
2111
|
-
/* @__PURE__ */
|
|
2112
|
-
/* @__PURE__ */
|
|
2113
|
-
/* @__PURE__ */
|
|
2114
|
-
/* @__PURE__ */
|
|
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 })
|
|
2115
2221
|
] })
|
|
2116
2222
|
]
|
|
2117
2223
|
}
|
|
@@ -2132,14 +2238,14 @@ var templatesFeature = {
|
|
|
2132
2238
|
};
|
|
2133
2239
|
|
|
2134
2240
|
// src/features/brand/BrandButton.jsx
|
|
2135
|
-
import { useEffect as useEffect4, useRef as useRef2, useState as
|
|
2241
|
+
import { useEffect as useEffect4, useRef as useRef2, useState as useState9 } from "react";
|
|
2136
2242
|
import { Globe, ImageOff, Loader2 as Loader23, Palette, Trash2 as Trash22, TriangleAlert, Upload, WandSparkles } from "lucide-react";
|
|
2137
2243
|
|
|
2138
2244
|
// src/ui/primitives/color-picker.jsx
|
|
2139
|
-
import { useState as
|
|
2245
|
+
import { useState as useState8 } from "react";
|
|
2140
2246
|
import { HexAlphaColorPicker } from "react-colorful";
|
|
2141
2247
|
import { Check } from "lucide-react";
|
|
2142
|
-
import { jsx as
|
|
2248
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2143
2249
|
var PRESET_COLORS = [
|
|
2144
2250
|
"#8B5CF6",
|
|
2145
2251
|
"#A78BFA",
|
|
@@ -2170,20 +2276,20 @@ function normalizeHex(v) {
|
|
|
2170
2276
|
}
|
|
2171
2277
|
function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
|
|
2172
2278
|
const t = useT();
|
|
2173
|
-
const [open, setOpen] =
|
|
2279
|
+
const [open, setOpen] = useState8(false);
|
|
2174
2280
|
const valid = isValidHex(value);
|
|
2175
2281
|
const normalized = valid ? normalizeHex(value) : "";
|
|
2176
2282
|
const emit = (hex) => onChange(normalizeHex(hex));
|
|
2177
|
-
return /* @__PURE__ */
|
|
2178
|
-
/* @__PURE__ */
|
|
2179
|
-
/* @__PURE__ */
|
|
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(
|
|
2180
2286
|
"button",
|
|
2181
2287
|
{
|
|
2182
2288
|
type: "button",
|
|
2183
2289
|
"aria-label": t("Pick a colour"),
|
|
2184
2290
|
title: t("Pick a colour"),
|
|
2185
2291
|
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]",
|
|
2186
|
-
children: /* @__PURE__ */
|
|
2292
|
+
children: /* @__PURE__ */ jsx8(
|
|
2187
2293
|
"span",
|
|
2188
2294
|
{
|
|
2189
2295
|
className: "eb:absolute eb:inset-0",
|
|
@@ -2193,18 +2299,18 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
|
|
|
2193
2299
|
)
|
|
2194
2300
|
}
|
|
2195
2301
|
) }),
|
|
2196
|
-
/* @__PURE__ */
|
|
2197
|
-
/* @__PURE__ */
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
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(
|
|
2200
2306
|
"span",
|
|
2201
2307
|
{
|
|
2202
2308
|
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",
|
|
2203
2309
|
"aria-hidden": true,
|
|
2204
|
-
children: /* @__PURE__ */
|
|
2310
|
+
children: /* @__PURE__ */ jsx8("span", { className: "eb:absolute eb:inset-0", style: { backgroundColor: valid ? value : "transparent" } })
|
|
2205
2311
|
}
|
|
2206
2312
|
),
|
|
2207
|
-
/* @__PURE__ */
|
|
2313
|
+
/* @__PURE__ */ jsx8(
|
|
2208
2314
|
Input,
|
|
2209
2315
|
{
|
|
2210
2316
|
value: value || "",
|
|
@@ -2216,7 +2322,7 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
|
|
|
2216
2322
|
}
|
|
2217
2323
|
)
|
|
2218
2324
|
] }),
|
|
2219
|
-
/* @__PURE__ */
|
|
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(
|
|
2220
2326
|
"button",
|
|
2221
2327
|
{
|
|
2222
2328
|
type: "button",
|
|
@@ -2225,13 +2331,13 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
|
|
|
2225
2331
|
"aria-label": c,
|
|
2226
2332
|
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",
|
|
2227
2333
|
style: { backgroundColor: c },
|
|
2228
|
-
children: normalized === c && /* @__PURE__ */
|
|
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)]" })
|
|
2229
2335
|
},
|
|
2230
2336
|
c
|
|
2231
2337
|
)) })
|
|
2232
2338
|
] })
|
|
2233
2339
|
] }),
|
|
2234
|
-
/* @__PURE__ */
|
|
2340
|
+
/* @__PURE__ */ jsx8(
|
|
2235
2341
|
Input,
|
|
2236
2342
|
{
|
|
2237
2343
|
id,
|
|
@@ -2246,7 +2352,7 @@ function ColorPicker({ value, onChange, id, className, placeholder = "" }) {
|
|
|
2246
2352
|
}
|
|
2247
2353
|
|
|
2248
2354
|
// src/features/brand/BrandButton.jsx
|
|
2249
|
-
import { Fragment as Fragment4, jsx as
|
|
2355
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2250
2356
|
var toForm = (brand) => ({
|
|
2251
2357
|
name: brand.name || "",
|
|
2252
2358
|
logoUrl: brand.logoUrl || "",
|
|
@@ -2260,18 +2366,18 @@ var isLogoUrl = (url) => !url || url.startsWith("/") || /^https:\/\//i.test(url)
|
|
|
2260
2366
|
function BrandButton({ context }) {
|
|
2261
2367
|
const { editor, ready, storage, brand, setBrand, hostSender } = context;
|
|
2262
2368
|
const { t, notify } = useUi();
|
|
2263
|
-
const [open, setOpen] =
|
|
2264
|
-
const [form, setForm] =
|
|
2265
|
-
const [applyNow, setApplyNow] =
|
|
2266
|
-
const [reading, setReading] =
|
|
2267
|
-
const [readError, setReadError] =
|
|
2268
|
-
const [notes, setNotes] =
|
|
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(
|
|
2269
2375
|
/** @type {string[]} */
|
|
2270
2376
|
[]
|
|
2271
2377
|
);
|
|
2272
|
-
const [uploading, setUploading] =
|
|
2273
|
-
const [saving, setSaving] =
|
|
2274
|
-
const [error, setError] =
|
|
2378
|
+
const [uploading, setUploading] = useState9(false);
|
|
2379
|
+
const [saving, setSaving] = useState9(false);
|
|
2380
|
+
const [error, setError] = useState9("");
|
|
2275
2381
|
const abortRef = useRef2(
|
|
2276
2382
|
/** @type {AbortController|null} */
|
|
2277
2383
|
null
|
|
@@ -2393,11 +2499,11 @@ function BrandButton({ context }) {
|
|
|
2393
2499
|
}
|
|
2394
2500
|
};
|
|
2395
2501
|
const swatch = brand?.primary;
|
|
2396
|
-
return /* @__PURE__ */
|
|
2397
|
-
/* @__PURE__ */
|
|
2398
|
-
/* @__PURE__ */
|
|
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, {}),
|
|
2399
2505
|
t("Brand"),
|
|
2400
|
-
swatch && /* @__PURE__ */
|
|
2506
|
+
swatch && /* @__PURE__ */ jsx9(
|
|
2401
2507
|
"span",
|
|
2402
2508
|
{
|
|
2403
2509
|
"aria-hidden": "true",
|
|
@@ -2406,18 +2512,18 @@ function BrandButton({ context }) {
|
|
|
2406
2512
|
}
|
|
2407
2513
|
)
|
|
2408
2514
|
] }),
|
|
2409
|
-
/* @__PURE__ */
|
|
2515
|
+
/* @__PURE__ */ jsx9(Dialog, { open, onOpenChange: close, children: /* @__PURE__ */ jsxs9(
|
|
2410
2516
|
DialogContent,
|
|
2411
2517
|
{
|
|
2412
2518
|
className: "eb:flex eb:max-h-[calc(100dvh-2rem)] eb:flex-col eb:gap-0 eb:p-0 eb:sm:max-w-2xl",
|
|
2413
2519
|
"data-testid": "eb-brand",
|
|
2414
2520
|
children: [
|
|
2415
|
-
/* @__PURE__ */
|
|
2416
|
-
/* @__PURE__ */
|
|
2417
|
-
/* @__PURE__ */
|
|
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.") })
|
|
2418
2524
|
] }),
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
canRead && /* @__PURE__ */
|
|
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(
|
|
2421
2527
|
"form",
|
|
2422
2528
|
{
|
|
2423
2529
|
className: "eb:mb-5 eb:flex eb:flex-col eb:gap-1.5",
|
|
@@ -2426,11 +2532,11 @@ function BrandButton({ context }) {
|
|
|
2426
2532
|
readWebsite();
|
|
2427
2533
|
},
|
|
2428
2534
|
children: [
|
|
2429
|
-
/* @__PURE__ */
|
|
2430
|
-
/* @__PURE__ */
|
|
2431
|
-
/* @__PURE__ */
|
|
2432
|
-
/* @__PURE__ */
|
|
2433
|
-
/* @__PURE__ */
|
|
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(
|
|
2434
2540
|
Input,
|
|
2435
2541
|
{
|
|
2436
2542
|
id: "eb-brand-website",
|
|
@@ -2444,28 +2550,28 @@ function BrandButton({ context }) {
|
|
|
2444
2550
|
}
|
|
2445
2551
|
)
|
|
2446
2552
|
] }),
|
|
2447
|
-
/* @__PURE__ */
|
|
2448
|
-
reading ? /* @__PURE__ */
|
|
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, {}),
|
|
2449
2555
|
t("Get my brand")
|
|
2450
2556
|
] })
|
|
2451
2557
|
] }),
|
|
2452
|
-
reading ? /* @__PURE__ */
|
|
2453
|
-
/* @__PURE__ */
|
|
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" }),
|
|
2454
2560
|
readError
|
|
2455
|
-
] }) : notes.length ? /* @__PURE__ */
|
|
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.") })
|
|
2456
2562
|
]
|
|
2457
2563
|
}
|
|
2458
2564
|
),
|
|
2459
|
-
/* @__PURE__ */
|
|
2460
|
-
/* @__PURE__ */
|
|
2461
|
-
/* @__PURE__ */
|
|
2462
|
-
/* @__PURE__ */
|
|
2463
|
-
/* @__PURE__ */
|
|
2464
|
-
/* @__PURE__ */
|
|
2465
|
-
/* @__PURE__ */
|
|
2466
|
-
/* @__PURE__ */
|
|
2467
|
-
canUpload && /* @__PURE__ */
|
|
2468
|
-
/* @__PURE__ */
|
|
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(
|
|
2469
2575
|
"input",
|
|
2470
2576
|
{
|
|
2471
2577
|
ref: fileRef,
|
|
@@ -2478,18 +2584,18 @@ function BrandButton({ context }) {
|
|
|
2478
2584
|
onChange: pickLogo
|
|
2479
2585
|
}
|
|
2480
2586
|
),
|
|
2481
|
-
/* @__PURE__ */
|
|
2482
|
-
uploading ? /* @__PURE__ */
|
|
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, {}),
|
|
2483
2589
|
t("Upload")
|
|
2484
2590
|
] })
|
|
2485
2591
|
] }),
|
|
2486
|
-
form.logoUrl && /* @__PURE__ */
|
|
2487
|
-
/* @__PURE__ */
|
|
2592
|
+
form.logoUrl && /* @__PURE__ */ jsxs9(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => set({ logoUrl: "", logoWidth: 0 }), children: [
|
|
2593
|
+
/* @__PURE__ */ jsx9(Trash22, {}),
|
|
2488
2594
|
t("Remove")
|
|
2489
2595
|
] })
|
|
2490
2596
|
] })
|
|
2491
2597
|
] }),
|
|
2492
|
-
/* @__PURE__ */
|
|
2598
|
+
/* @__PURE__ */ jsx9(
|
|
2493
2599
|
Input,
|
|
2494
2600
|
{
|
|
2495
2601
|
id: "eb-brand-logo",
|
|
@@ -2500,11 +2606,11 @@ function BrandButton({ context }) {
|
|
|
2500
2606
|
className: "eb:text-[12px]"
|
|
2501
2607
|
}
|
|
2502
2608
|
),
|
|
2503
|
-
logoInvalid && /* @__PURE__ */
|
|
2609
|
+
logoInvalid && /* @__PURE__ */ jsx9("p", { className: "eb:text-[12px] eb:text-destructive", children: t("An https:// address is required") })
|
|
2504
2610
|
] }),
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
/* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
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(
|
|
2508
2614
|
Input,
|
|
2509
2615
|
{
|
|
2510
2616
|
id: "eb-brand-name",
|
|
@@ -2515,36 +2621,36 @@ function BrandButton({ context }) {
|
|
|
2515
2621
|
}
|
|
2516
2622
|
)
|
|
2517
2623
|
] }),
|
|
2518
|
-
/* @__PURE__ */
|
|
2519
|
-
/* @__PURE__ */
|
|
2520
|
-
/* @__PURE__ */
|
|
2521
|
-
/* @__PURE__ */
|
|
2522
|
-
/* @__PURE__ */
|
|
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") })
|
|
2523
2629
|
] }),
|
|
2524
|
-
/* @__PURE__ */
|
|
2525
|
-
/* @__PURE__ */
|
|
2526
|
-
/* @__PURE__ */
|
|
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 })
|
|
2527
2633
|
] })
|
|
2528
2634
|
] }),
|
|
2529
|
-
/* @__PURE__ */
|
|
2530
|
-
/* @__PURE__ */
|
|
2531
|
-
/* @__PURE__ */
|
|
2532
|
-
/* @__PURE__ */
|
|
2533
|
-
/* @__PURE__ */
|
|
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)) })
|
|
2534
2640
|
] })
|
|
2535
2641
|
] })
|
|
2536
2642
|
] }),
|
|
2537
|
-
/* @__PURE__ */
|
|
2643
|
+
/* @__PURE__ */ jsx9(BrandPreview, { brand: draft, fallbackName: hostSender?.name || t("Your company") })
|
|
2538
2644
|
] })
|
|
2539
2645
|
] }),
|
|
2540
|
-
/* @__PURE__ */
|
|
2541
|
-
error && /* @__PURE__ */
|
|
2542
|
-
/* @__PURE__ */
|
|
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" }),
|
|
2543
2649
|
error
|
|
2544
2650
|
] }),
|
|
2545
|
-
/* @__PURE__ */
|
|
2546
|
-
/* @__PURE__ */
|
|
2547
|
-
/* @__PURE__ */
|
|
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(
|
|
2548
2654
|
"input",
|
|
2549
2655
|
{
|
|
2550
2656
|
type: "checkbox",
|
|
@@ -2556,10 +2662,10 @@ function BrandButton({ context }) {
|
|
|
2556
2662
|
),
|
|
2557
2663
|
t("Also apply to this email")
|
|
2558
2664
|
] }),
|
|
2559
|
-
/* @__PURE__ */
|
|
2560
|
-
/* @__PURE__ */
|
|
2561
|
-
/* @__PURE__ */
|
|
2562
|
-
saving && /* @__PURE__ */
|
|
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" }),
|
|
2563
2669
|
t("Save")
|
|
2564
2670
|
] })
|
|
2565
2671
|
] })
|
|
@@ -2578,30 +2684,30 @@ function BrandPreview({ brand, fallbackName }) {
|
|
|
2578
2684
|
const link2 = contrastRatio(primary, PALETTE.white) >= 3 ? primary : heading2;
|
|
2579
2685
|
const font = brand.font || FONT_STACK;
|
|
2580
2686
|
const name = brand.name || fallbackName;
|
|
2581
|
-
return /* @__PURE__ */
|
|
2582
|
-
/* @__PURE__ */
|
|
2583
|
-
/* @__PURE__ */
|
|
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(
|
|
2584
2690
|
"div",
|
|
2585
2691
|
{
|
|
2586
2692
|
className: "eb:overflow-hidden eb:rounded-lg2 eb:p-2.5 eb:ring-1 eb:ring-border",
|
|
2587
2693
|
style: { backgroundColor: PALETTE.canvas, fontFamily: font },
|
|
2588
2694
|
"data-testid": "eb-brand-preview",
|
|
2589
2695
|
"aria-hidden": "true",
|
|
2590
|
-
children: /* @__PURE__ */
|
|
2591
|
-
/* @__PURE__ */
|
|
2592
|
-
/* @__PURE__ */
|
|
2593
|
-
/* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
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.") })
|
|
2595
2701
|
] }),
|
|
2596
|
-
/* @__PURE__ */
|
|
2597
|
-
/* @__PURE__ */
|
|
2598
|
-
/* @__PURE__ */
|
|
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: [
|
|
2599
2705
|
t("Some text, with"),
|
|
2600
2706
|
" ",
|
|
2601
|
-
/* @__PURE__ */
|
|
2707
|
+
/* @__PURE__ */ jsx9("span", { className: "eb:underline", style: { color: link2 }, children: t("a link") }),
|
|
2602
2708
|
"."
|
|
2603
2709
|
] }),
|
|
2604
|
-
/* @__PURE__ */
|
|
2710
|
+
/* @__PURE__ */ jsx9(
|
|
2605
2711
|
"span",
|
|
2606
2712
|
{
|
|
2607
2713
|
className: cn("eb:mt-1 eb:self-start eb:rounded-[3px] eb:px-2.5 eb:py-1 eb:text-[9px] eb:font-bold"),
|
|
@@ -2610,7 +2716,7 @@ function BrandPreview({ brand, fallbackName }) {
|
|
|
2610
2716
|
}
|
|
2611
2717
|
)
|
|
2612
2718
|
] }),
|
|
2613
|
-
/* @__PURE__ */
|
|
2719
|
+
/* @__PURE__ */ jsx9("div", { className: "eb:px-3 eb:pb-2.5 eb:text-center eb:text-[7px]", style: { color: "#6d7484" }, children: name })
|
|
2614
2720
|
] })
|
|
2615
2721
|
}
|
|
2616
2722
|
)
|
|
@@ -2921,6 +3027,9 @@ body { margin: 0; }
|
|
|
2921
3027
|
.eb-node a { cursor: pointer; }
|
|
2922
3028
|
[contenteditable="true"] { outline: none; cursor: text; caret-color: ${PRIMARY}; }
|
|
2923
3029
|
td.eb-placeholder { outline: 1.5px dashed #c3cad6; outline-offset: -8px; }
|
|
3030
|
+
.eb-preview-text[data-typing]::after { content: ''; display: inline-block; width: 1.5px; height: 1em; margin-left: 1px;
|
|
3031
|
+
vertical-align: -0.12em; background: currentColor; animation: eb-preview-caret 0.7s steps(1) infinite; }
|
|
3032
|
+
@keyframes eb-preview-caret { 50% { opacity: 0; } }
|
|
2924
3033
|
.eb-placeholder { user-select: none; }
|
|
2925
3034
|
|
|
2926
3035
|
#eb-ui { position: absolute; top: 0; left: 0; width: 0; height: 0; z-index: 2147483000;
|
|
@@ -3205,6 +3314,7 @@ function createCanvasView(options) {
|
|
|
3205
3314
|
}
|
|
3206
3315
|
syncAttributes(doc.body, parsed.body);
|
|
3207
3316
|
morphChildren(doc.body, parsed.body, (element) => element === editingEl);
|
|
3317
|
+
if (preview && !preview.el.isConnected) dropPreview();
|
|
3208
3318
|
if (editingId && editingEl && !editingEl.isConnected) {
|
|
3209
3319
|
const again = editableOf(editingId);
|
|
3210
3320
|
if (again) {
|
|
@@ -3364,6 +3474,7 @@ function createCanvasView(options) {
|
|
|
3364
3474
|
function startEditing(id, at = null) {
|
|
3365
3475
|
if (editingId === id) return;
|
|
3366
3476
|
finishEditing();
|
|
3477
|
+
dropPreview();
|
|
3367
3478
|
const el = editableOf(id);
|
|
3368
3479
|
if (!el) return;
|
|
3369
3480
|
editingId = id;
|
|
@@ -3380,10 +3491,18 @@ function createCanvasView(options) {
|
|
|
3380
3491
|
refreshOverlays();
|
|
3381
3492
|
}
|
|
3382
3493
|
function contentOfEditing() {
|
|
3383
|
-
|
|
3494
|
+
if (!editingEl) return "";
|
|
3495
|
+
let source = editingEl;
|
|
3496
|
+
if (preview && editingEl.contains(preview.el)) {
|
|
3497
|
+
source = /** @type {HTMLElement} */
|
|
3498
|
+
editingEl.cloneNode(true);
|
|
3499
|
+
source.querySelectorAll(`.${PREVIEW_CLASS}`).forEach((el) => el.remove());
|
|
3500
|
+
}
|
|
3501
|
+
return cleanRichText(source.innerHTML, doc);
|
|
3384
3502
|
}
|
|
3385
3503
|
function finishEditing() {
|
|
3386
3504
|
if (!editingId || !editingEl) return;
|
|
3505
|
+
dropPreview();
|
|
3387
3506
|
const id = editingId;
|
|
3388
3507
|
const html = contentOfEditing();
|
|
3389
3508
|
editingEl.removeAttribute("contenteditable");
|
|
@@ -3439,6 +3558,90 @@ function createCanvasView(options) {
|
|
|
3439
3558
|
} else placeCaret(null);
|
|
3440
3559
|
return true;
|
|
3441
3560
|
}
|
|
3561
|
+
let preview = null;
|
|
3562
|
+
const PREVIEW_CLASS = "eb-preview-text";
|
|
3563
|
+
function previewSpot() {
|
|
3564
|
+
if (editingEl) {
|
|
3565
|
+
const range = savedRange && editingEl.contains(savedRange.commonAncestorContainer) ? savedRange.cloneRange() : null;
|
|
3566
|
+
if (range) {
|
|
3567
|
+
range.collapse(false);
|
|
3568
|
+
return { range, prefix: "" };
|
|
3569
|
+
}
|
|
3570
|
+
return { parent: editingEl, prefix: "" };
|
|
3571
|
+
}
|
|
3572
|
+
const tag = selectedId ? info(selectedId)?.tag : null;
|
|
3573
|
+
if (!selectedId || tag !== "mj-text" && tag !== "mj-button") return null;
|
|
3574
|
+
const parent = tag === "mj-text" ? editableOf(selectedId) : elementOf(selectedId)?.querySelector("a, p");
|
|
3575
|
+
return parent ? { parent, prefix: " " } : null;
|
|
3576
|
+
}
|
|
3577
|
+
function stepPreview() {
|
|
3578
|
+
if (!preview) return;
|
|
3579
|
+
const current = preview;
|
|
3580
|
+
const { shown, target } = current;
|
|
3581
|
+
const next = !target.startsWith(shown) ? shown.slice(0, -1) : shown.length < target.length ? target.slice(0, shown.length + 1) : null;
|
|
3582
|
+
if (next === null) {
|
|
3583
|
+
current.timer = 0;
|
|
3584
|
+
current.el.removeAttribute("data-typing");
|
|
3585
|
+
if (!target) dropPreview();
|
|
3586
|
+
return;
|
|
3587
|
+
}
|
|
3588
|
+
current.shown = next;
|
|
3589
|
+
current.el.textContent = next;
|
|
3590
|
+
current.el.setAttribute("data-typing", "");
|
|
3591
|
+
current.timer = win.setTimeout(stepPreview, next.length < shown.length ? 12 : 22);
|
|
3592
|
+
scheduleOverlays();
|
|
3593
|
+
}
|
|
3594
|
+
function animatePreview() {
|
|
3595
|
+
if (!preview || preview.timer) return;
|
|
3596
|
+
if (win.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
|
|
3597
|
+
preview.shown = preview.target;
|
|
3598
|
+
preview.el.textContent = preview.target;
|
|
3599
|
+
if (!preview.target) dropPreview();
|
|
3600
|
+
scheduleOverlays();
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
stepPreview();
|
|
3604
|
+
}
|
|
3605
|
+
function previewText(text) {
|
|
3606
|
+
if (!text) {
|
|
3607
|
+
hidePreview();
|
|
3608
|
+
return false;
|
|
3609
|
+
}
|
|
3610
|
+
if (preview && !preview.el.isConnected) dropPreview();
|
|
3611
|
+
if (!preview) {
|
|
3612
|
+
const spot = previewSpot();
|
|
3613
|
+
if (!spot) return false;
|
|
3614
|
+
const el = doc.createElement("span");
|
|
3615
|
+
el.className = PREVIEW_CLASS;
|
|
3616
|
+
el.setAttribute("contenteditable", "false");
|
|
3617
|
+
el.setAttribute("data-testid", "eb-canvas-preview");
|
|
3618
|
+
if (spot.range) spot.range.insertNode(el);
|
|
3619
|
+
else spot.parent?.appendChild(el);
|
|
3620
|
+
preview = { el, prefix: spot.prefix, shown: "", target: "", timer: 0 };
|
|
3621
|
+
}
|
|
3622
|
+
preview.target = preview.prefix + text;
|
|
3623
|
+
animatePreview();
|
|
3624
|
+
return true;
|
|
3625
|
+
}
|
|
3626
|
+
function hidePreview() {
|
|
3627
|
+
if (!preview) return;
|
|
3628
|
+
preview.target = "";
|
|
3629
|
+
animatePreview();
|
|
3630
|
+
}
|
|
3631
|
+
function dropPreview() {
|
|
3632
|
+
if (!preview) return;
|
|
3633
|
+
win.clearTimeout(preview.timer);
|
|
3634
|
+
preview.el.remove();
|
|
3635
|
+
preview = null;
|
|
3636
|
+
scheduleOverlays();
|
|
3637
|
+
}
|
|
3638
|
+
function settlePreview() {
|
|
3639
|
+
if (!preview) return;
|
|
3640
|
+
win.clearTimeout(preview.timer);
|
|
3641
|
+
preview.el.textContent = preview.target;
|
|
3642
|
+
preview.el.removeAttribute("data-typing");
|
|
3643
|
+
preview = null;
|
|
3644
|
+
}
|
|
3442
3645
|
const TEXT_BUTTONS = [
|
|
3443
3646
|
["bold", t("Bold (Ctrl+B)")],
|
|
3444
3647
|
["italic", t("Italic (Ctrl+I)")],
|
|
@@ -3760,6 +3963,7 @@ function createCanvasView(options) {
|
|
|
3760
3963
|
/** @param {string|null} id */
|
|
3761
3964
|
setSelection(id) {
|
|
3762
3965
|
if (editingId && editingId !== id) finishEditing();
|
|
3966
|
+
if (id !== selectedId) dropPreview();
|
|
3763
3967
|
selectedId = id;
|
|
3764
3968
|
refreshOverlays();
|
|
3765
3969
|
if (id) {
|
|
@@ -3792,6 +3996,7 @@ function createCanvasView(options) {
|
|
|
3792
3996
|
editingId: () => editingId,
|
|
3793
3997
|
/** @param {string} text */
|
|
3794
3998
|
insertText(text) {
|
|
3999
|
+
dropPreview();
|
|
3795
4000
|
if (!restoreCaret()) return false;
|
|
3796
4001
|
doc.execCommand("insertText", false, text);
|
|
3797
4002
|
options.onEditInput(
|
|
@@ -3803,6 +4008,7 @@ function createCanvasView(options) {
|
|
|
3803
4008
|
},
|
|
3804
4009
|
/** @param {string} html */
|
|
3805
4010
|
insertHtml(html) {
|
|
4011
|
+
dropPreview();
|
|
3806
4012
|
if (!restoreCaret()) return false;
|
|
3807
4013
|
doc.execCommand("insertHTML", false, html);
|
|
3808
4014
|
options.onEditInput(
|
|
@@ -3812,8 +4018,12 @@ function createCanvasView(options) {
|
|
|
3812
4018
|
);
|
|
3813
4019
|
return true;
|
|
3814
4020
|
},
|
|
4021
|
+
previewText,
|
|
4022
|
+
hidePreview,
|
|
4023
|
+
settlePreview,
|
|
3815
4024
|
destroy() {
|
|
3816
4025
|
destroyed = true;
|
|
4026
|
+
dropPreview();
|
|
3817
4027
|
cancelDrag();
|
|
3818
4028
|
resizeObserver.disconnect();
|
|
3819
4029
|
if (overlayFrame) win.cancelAnimationFrame(overlayFrame);
|
|
@@ -4358,9 +4568,16 @@ function createNativeAdapter({ loadCompiler = defaultLoadCompiler } = {}) {
|
|
|
4358
4568
|
if (view.editingId()) return view.insertText(text);
|
|
4359
4569
|
const node = selectedId ? findNode(root, selectedId) : null;
|
|
4360
4570
|
if (!node || !TEXT_TAGS.has(node.tag)) return false;
|
|
4571
|
+
view.settlePreview();
|
|
4361
4572
|
commit(setContent(root, node.id, `${node.content || ""} ${escapeText(text)}`));
|
|
4362
4573
|
return true;
|
|
4363
4574
|
},
|
|
4575
|
+
previewText(text) {
|
|
4576
|
+
return view ? view.previewText(text) : false;
|
|
4577
|
+
},
|
|
4578
|
+
clearPreview() {
|
|
4579
|
+
view?.hidePreview();
|
|
4580
|
+
},
|
|
4364
4581
|
insertLink(href, label) {
|
|
4365
4582
|
if (!view || !root) return false;
|
|
4366
4583
|
const safeHref = escapeText(href).replace(/"/g, """);
|
|
@@ -4456,7 +4673,7 @@ function createDefaultEmailEditor(options = {}) {
|
|
|
4456
4673
|
|
|
4457
4674
|
// src/ui/EmailCanvas.jsx
|
|
4458
4675
|
import { useEffect as useEffect5, useRef as useRef3 } from "react";
|
|
4459
|
-
import { jsx as
|
|
4676
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
4460
4677
|
function EmailCanvas({ editor, document = null, onReady, onError, className }) {
|
|
4461
4678
|
const ref = useRef3(null);
|
|
4462
4679
|
const documentRef = useRef3(document);
|
|
@@ -4475,15 +4692,15 @@ function EmailCanvas({ editor, document = null, onReady, onError, className }) {
|
|
|
4475
4692
|
editor.destroy();
|
|
4476
4693
|
};
|
|
4477
4694
|
}, [editor]);
|
|
4478
|
-
return /* @__PURE__ */
|
|
4695
|
+
return /* @__PURE__ */ jsx10("div", { ref, className: cn("eb-canvas eb:h-full eb:w-full", className), "data-testid": "eb-canvas" });
|
|
4479
4696
|
}
|
|
4480
4697
|
|
|
4481
4698
|
// src/ui/EmailBuilder.jsx
|
|
4482
|
-
import { useCallback as useCallback3, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef8, useState as
|
|
4699
|
+
import { useCallback as useCallback3, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef8, useState as useState14 } from "react";
|
|
4483
4700
|
import { AlertTriangle, Loader2 as Loader25, Plus as Plus2, Save, SlidersHorizontal } from "lucide-react";
|
|
4484
4701
|
|
|
4485
4702
|
// src/features/brand/useBrand.js
|
|
4486
|
-
import { useCallback, useEffect as useEffect6, useState as
|
|
4703
|
+
import { useCallback, useEffect as useEffect6, useState as useState10 } from "react";
|
|
4487
4704
|
var entries = /* @__PURE__ */ new WeakMap();
|
|
4488
4705
|
function brandOf(storage) {
|
|
4489
4706
|
let entry = entries.get(storage);
|
|
@@ -4504,7 +4721,7 @@ function brandOf(storage) {
|
|
|
4504
4721
|
return created;
|
|
4505
4722
|
}
|
|
4506
4723
|
function useBrand(storage) {
|
|
4507
|
-
const [brand, setState] =
|
|
4724
|
+
const [brand, setState] = useState10(() => brandOf(storage).value);
|
|
4508
4725
|
useEffect6(() => {
|
|
4509
4726
|
const entry = brandOf(storage);
|
|
4510
4727
|
setState(entry.value);
|
|
@@ -4633,7 +4850,7 @@ import {
|
|
|
4633
4850
|
Type
|
|
4634
4851
|
} from "lucide-react";
|
|
4635
4852
|
import { useRef as useRef4 } from "react";
|
|
4636
|
-
import { jsx as
|
|
4853
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4637
4854
|
var DRAG_THRESHOLD = 5;
|
|
4638
4855
|
var ICONS2 = {
|
|
4639
4856
|
Heading,
|
|
@@ -4659,7 +4876,7 @@ function BlockTile({ block, disabled, onAdd, onDragStart }) {
|
|
|
4659
4876
|
const t = useT();
|
|
4660
4877
|
const Icon = ICONS2[block.icon] || Square;
|
|
4661
4878
|
const press = useRef4(null);
|
|
4662
|
-
return /* @__PURE__ */
|
|
4879
|
+
return /* @__PURE__ */ jsx11(TooltipWrap, { label: block.description ? t(block.description) : block.description, children: /* @__PURE__ */ jsxs10(
|
|
4663
4880
|
"button",
|
|
4664
4881
|
{
|
|
4665
4882
|
type: "button",
|
|
@@ -4699,8 +4916,8 @@ function BlockTile({ block, disabled, onAdd, onDragStart }) {
|
|
|
4699
4916
|
disabled && "eb:cursor-not-allowed eb:opacity-50"
|
|
4700
4917
|
),
|
|
4701
4918
|
children: [
|
|
4702
|
-
/* @__PURE__ */
|
|
4703
|
-
/* @__PURE__ */
|
|
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) })
|
|
4704
4921
|
]
|
|
4705
4922
|
}
|
|
4706
4923
|
) });
|
|
@@ -4708,12 +4925,12 @@ function BlockTile({ block, disabled, onAdd, onDragStart }) {
|
|
|
4708
4925
|
function BlockSidebar({ editor, disabled = false, onAdded }) {
|
|
4709
4926
|
const t = useT();
|
|
4710
4927
|
const blocks = editor.listBlocks();
|
|
4711
|
-
return /* @__PURE__ */
|
|
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) => {
|
|
4712
4929
|
const items = blocks.filter((b) => b.kind === group.kind && b.mjml);
|
|
4713
4930
|
if (!items.length) return null;
|
|
4714
|
-
return /* @__PURE__ */
|
|
4715
|
-
/* @__PURE__ */
|
|
4716
|
-
/* @__PURE__ */
|
|
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(
|
|
4717
4934
|
BlockTile,
|
|
4718
4935
|
{
|
|
4719
4936
|
block,
|
|
@@ -4731,15 +4948,15 @@ function BlockSidebar({ editor, disabled = false, onAdded }) {
|
|
|
4731
4948
|
|
|
4732
4949
|
// src/ui/ElementActions.jsx
|
|
4733
4950
|
import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Copy, Trash2 as Trash23 } from "lucide-react";
|
|
4734
|
-
import { jsx as
|
|
4951
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4735
4952
|
function ElementActions({ editor, selection }) {
|
|
4736
4953
|
const t = useT();
|
|
4737
4954
|
if (!selection || !selection.canRemove && !selection.canDuplicate) return null;
|
|
4738
4955
|
const horizontal = selection.tagName === "mj-column";
|
|
4739
4956
|
const [Prev, Next] = horizontal ? [ArrowLeft, ArrowRight] : [ArrowUp, ArrowDown];
|
|
4740
4957
|
const [prevLabel, nextLabel] = horizontal ? [t("Move left"), t("Move right")] : [t("Move up"), t("Move down")];
|
|
4741
|
-
return /* @__PURE__ */
|
|
4742
|
-
/* @__PURE__ */
|
|
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(
|
|
4743
4960
|
Button,
|
|
4744
4961
|
{
|
|
4745
4962
|
variant: "ghost",
|
|
@@ -4747,10 +4964,10 @@ function ElementActions({ editor, selection }) {
|
|
|
4747
4964
|
"aria-label": prevLabel,
|
|
4748
4965
|
disabled: !selection.canMoveUp,
|
|
4749
4966
|
onClick: () => editor.move(-1, selection.id),
|
|
4750
|
-
children: /* @__PURE__ */
|
|
4967
|
+
children: /* @__PURE__ */ jsx12(Prev, {})
|
|
4751
4968
|
}
|
|
4752
4969
|
) }),
|
|
4753
|
-
/* @__PURE__ */
|
|
4970
|
+
/* @__PURE__ */ jsx12(TooltipWrap, { label: nextLabel, children: /* @__PURE__ */ jsx12(
|
|
4754
4971
|
Button,
|
|
4755
4972
|
{
|
|
4756
4973
|
variant: "ghost",
|
|
@@ -4758,10 +4975,10 @@ function ElementActions({ editor, selection }) {
|
|
|
4758
4975
|
"aria-label": nextLabel,
|
|
4759
4976
|
disabled: !selection.canMoveDown,
|
|
4760
4977
|
onClick: () => editor.move(1, selection.id),
|
|
4761
|
-
children: /* @__PURE__ */
|
|
4978
|
+
children: /* @__PURE__ */ jsx12(Next, {})
|
|
4762
4979
|
}
|
|
4763
4980
|
) }),
|
|
4764
|
-
/* @__PURE__ */
|
|
4981
|
+
/* @__PURE__ */ jsx12(TooltipWrap, { label: t("Duplicate"), children: /* @__PURE__ */ jsx12(
|
|
4765
4982
|
Button,
|
|
4766
4983
|
{
|
|
4767
4984
|
variant: "ghost",
|
|
@@ -4769,10 +4986,10 @@ function ElementActions({ editor, selection }) {
|
|
|
4769
4986
|
"aria-label": t("Duplicate"),
|
|
4770
4987
|
disabled: !selection.canDuplicate,
|
|
4771
4988
|
onClick: () => editor.duplicate(selection.id),
|
|
4772
|
-
children: /* @__PURE__ */
|
|
4989
|
+
children: /* @__PURE__ */ jsx12(Copy, {})
|
|
4773
4990
|
}
|
|
4774
4991
|
) }),
|
|
4775
|
-
/* @__PURE__ */
|
|
4992
|
+
/* @__PURE__ */ jsx12(TooltipWrap, { label: t("Delete (Del)"), children: /* @__PURE__ */ jsx12(
|
|
4776
4993
|
Button,
|
|
4777
4994
|
{
|
|
4778
4995
|
variant: "ghost",
|
|
@@ -4781,7 +4998,7 @@ function ElementActions({ editor, selection }) {
|
|
|
4781
4998
|
disabled: !selection.canRemove,
|
|
4782
4999
|
onClick: () => editor.remove(selection.id),
|
|
4783
5000
|
className: "eb:ml-auto eb:text-foreground-muted eb:hover:bg-destructive/10 eb:hover:text-destructive",
|
|
4784
|
-
children: /* @__PURE__ */
|
|
5001
|
+
children: /* @__PURE__ */ jsx12(Trash23, {})
|
|
4785
5002
|
}
|
|
4786
5003
|
) })
|
|
4787
5004
|
] });
|
|
@@ -4792,9 +5009,9 @@ import { useMemo as useMemo4, useRef as useRef6 } from "react";
|
|
|
4792
5009
|
import { X as X2 } from "lucide-react";
|
|
4793
5010
|
|
|
4794
5011
|
// src/ui/fields.jsx
|
|
4795
|
-
import { useEffect as useEffect7, useRef as useRef5, useState as
|
|
5012
|
+
import { useEffect as useEffect7, useRef as useRef5, useState as useState11 } from "react";
|
|
4796
5013
|
import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Loader2 as Loader24, Upload as Upload2 } from "lucide-react";
|
|
4797
|
-
import { Fragment as Fragment5, jsx as
|
|
5014
|
+
import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4798
5015
|
var COLOR_DEBOUNCE_MS = 250;
|
|
4799
5016
|
function emailColor(value) {
|
|
4800
5017
|
const v = String(value || "").trim();
|
|
@@ -4803,7 +5020,7 @@ function emailColor(value) {
|
|
|
4803
5020
|
return null;
|
|
4804
5021
|
}
|
|
4805
5022
|
function useDraft(value, toDraft) {
|
|
4806
|
-
const [draft, setDraft] =
|
|
5023
|
+
const [draft, setDraft] = useState11(() => toDraft(value));
|
|
4807
5024
|
const ref = useRef5(null);
|
|
4808
5025
|
const convert = useRef5(toDraft);
|
|
4809
5026
|
convert.current = toDraft;
|
|
@@ -4816,10 +5033,10 @@ function useDraft(value, toDraft) {
|
|
|
4816
5033
|
}
|
|
4817
5034
|
var asText = (v) => v || "";
|
|
4818
5035
|
function FieldLabel({ id, children }) {
|
|
4819
|
-
return /* @__PURE__ */
|
|
5036
|
+
return /* @__PURE__ */ jsx13(Label, { htmlFor: id, className: "eb:text-[12px] eb:font-normal eb:text-foreground-lighter", children });
|
|
4820
5037
|
}
|
|
4821
5038
|
function FieldError({ children }) {
|
|
4822
|
-
return children ? /* @__PURE__ */
|
|
5039
|
+
return children ? /* @__PURE__ */ jsx13("p", { className: "eb:text-[12px] eb:text-destructive", children }) : null;
|
|
4823
5040
|
}
|
|
4824
5041
|
function TextField({ id, property, value, fallback = "", onCommit, addon = null, error = null }) {
|
|
4825
5042
|
const t = useT();
|
|
@@ -4850,13 +5067,13 @@ function TextField({ id, property, value, fallback = "", onCommit, addon = null,
|
|
|
4850
5067
|
onKeyDown: keyDown,
|
|
4851
5068
|
"aria-invalid": invalid || void 0
|
|
4852
5069
|
};
|
|
4853
|
-
return /* @__PURE__ */
|
|
4854
|
-
/* @__PURE__ */
|
|
4855
|
-
property.type === "textarea" ? /* @__PURE__ */
|
|
4856
|
-
/* @__PURE__ */
|
|
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" }),
|
|
4857
5074
|
addon
|
|
4858
|
-
] }) : /* @__PURE__ */
|
|
4859
|
-
/* @__PURE__ */
|
|
5075
|
+
] }) : /* @__PURE__ */ jsx13(Input, { ...shared }),
|
|
5076
|
+
/* @__PURE__ */ jsx13(FieldError, { children: invalid ? kind === "image" ? t("An https:// address is required") : t("Address not allowed") : error })
|
|
4860
5077
|
] });
|
|
4861
5078
|
}
|
|
4862
5079
|
function ImageField({ id, property, value, onCommit, services }) {
|
|
@@ -4865,8 +5082,8 @@ function ImageField({ id, property, value, onCommit, services }) {
|
|
|
4865
5082
|
/** @type {HTMLInputElement|null} */
|
|
4866
5083
|
null
|
|
4867
5084
|
);
|
|
4868
|
-
const [busy, setBusy] =
|
|
4869
|
-
const [error, setError] =
|
|
5085
|
+
const [busy, setBusy] = useState11(false);
|
|
5086
|
+
const [error, setError] = useState11(
|
|
4870
5087
|
/** @type {string|null} */
|
|
4871
5088
|
null
|
|
4872
5089
|
);
|
|
@@ -4888,8 +5105,8 @@ function ImageField({ id, property, value, onCommit, services }) {
|
|
|
4888
5105
|
setBusy(false);
|
|
4889
5106
|
}
|
|
4890
5107
|
};
|
|
4891
|
-
const addon = upload ? /* @__PURE__ */
|
|
4892
|
-
/* @__PURE__ */
|
|
5108
|
+
const addon = upload ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
5109
|
+
/* @__PURE__ */ jsx13(
|
|
4893
5110
|
"input",
|
|
4894
5111
|
{
|
|
4895
5112
|
ref: inputRef,
|
|
@@ -4902,7 +5119,7 @@ function ImageField({ id, property, value, onCommit, services }) {
|
|
|
4902
5119
|
onChange: pick
|
|
4903
5120
|
}
|
|
4904
5121
|
),
|
|
4905
|
-
/* @__PURE__ */
|
|
5122
|
+
/* @__PURE__ */ jsxs12(
|
|
4906
5123
|
Button,
|
|
4907
5124
|
{
|
|
4908
5125
|
type: "button",
|
|
@@ -4911,13 +5128,13 @@ function ImageField({ id, property, value, onCommit, services }) {
|
|
|
4911
5128
|
disabled: busy,
|
|
4912
5129
|
onClick: () => inputRef.current?.click(),
|
|
4913
5130
|
children: [
|
|
4914
|
-
busy ? /* @__PURE__ */
|
|
5131
|
+
busy ? /* @__PURE__ */ jsx13(Loader24, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx13(Upload2, {}),
|
|
4915
5132
|
t("Upload")
|
|
4916
5133
|
]
|
|
4917
5134
|
}
|
|
4918
5135
|
)
|
|
4919
5136
|
] }) : null;
|
|
4920
|
-
return /* @__PURE__ */
|
|
5137
|
+
return /* @__PURE__ */ jsx13(TextField, { id, property, value, onCommit, addon, error });
|
|
4921
5138
|
}
|
|
4922
5139
|
var asNumber = (v) => {
|
|
4923
5140
|
const n = Number.parseFloat(String(v || ""));
|
|
@@ -4939,10 +5156,10 @@ function SizeField({ id, property, value, fallback = "", onCommit }) {
|
|
|
4939
5156
|
const next = `${n}${property.unit || "px"}`;
|
|
4940
5157
|
if (next !== value) onCommit(next);
|
|
4941
5158
|
};
|
|
4942
|
-
return /* @__PURE__ */
|
|
4943
|
-
/* @__PURE__ */
|
|
4944
|
-
/* @__PURE__ */
|
|
4945
|
-
/* @__PURE__ */
|
|
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(
|
|
4946
5163
|
Input,
|
|
4947
5164
|
{
|
|
4948
5165
|
id,
|
|
@@ -4961,7 +5178,7 @@ function SizeField({ id, property, value, fallback = "", onCommit }) {
|
|
|
4961
5178
|
className: "eb:pr-9 eb:tabular-nums"
|
|
4962
5179
|
}
|
|
4963
5180
|
),
|
|
4964
|
-
/* @__PURE__ */
|
|
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" })
|
|
4965
5182
|
] })
|
|
4966
5183
|
] });
|
|
4967
5184
|
}
|
|
@@ -4984,9 +5201,9 @@ function ColorField({ id, property, value, fallback = "", onCommit }) {
|
|
|
4984
5201
|
}
|
|
4985
5202
|
}, COLOR_DEBOUNCE_MS);
|
|
4986
5203
|
};
|
|
4987
|
-
return /* @__PURE__ */
|
|
4988
|
-
/* @__PURE__ */
|
|
4989
|
-
/* @__PURE__ */
|
|
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 })
|
|
4990
5207
|
] });
|
|
4991
5208
|
}
|
|
4992
5209
|
var DEFAULT_OPTION = "__default__";
|
|
@@ -4996,9 +5213,9 @@ function SelectField({ id, property, value, fallback = "", onCommit }) {
|
|
|
4996
5213
|
const words = (v) => String(v || "").trim().split(/\s+/).sort().join(" ");
|
|
4997
5214
|
const fallbackOption = (property.options || []).find((o) => o.value && words(o.value) === words(fallback));
|
|
4998
5215
|
const defaultLabel = fallbackOption ? t("Default ({value})", { value: t(fallbackOption.label) }) : t("Default");
|
|
4999
|
-
return /* @__PURE__ */
|
|
5000
|
-
/* @__PURE__ */
|
|
5001
|
-
/* @__PURE__ */
|
|
5216
|
+
return /* @__PURE__ */ jsxs12("div", { className: "eb:space-y-1.5", children: [
|
|
5217
|
+
/* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
|
|
5218
|
+
/* @__PURE__ */ jsxs12(
|
|
5002
5219
|
Select,
|
|
5003
5220
|
{
|
|
5004
5221
|
value: current,
|
|
@@ -5007,10 +5224,10 @@ function SelectField({ id, property, value, fallback = "", onCommit }) {
|
|
|
5007
5224
|
if (v !== (value || "")) onCommit(v || null);
|
|
5008
5225
|
},
|
|
5009
5226
|
children: [
|
|
5010
|
-
/* @__PURE__ */
|
|
5011
|
-
/* @__PURE__ */
|
|
5012
|
-
!(property.options || []).some((o) => !o.value) && /* @__PURE__ */
|
|
5013
|
-
(property.options || []).map((o) => /* @__PURE__ */
|
|
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))
|
|
5014
5231
|
] })
|
|
5015
5232
|
]
|
|
5016
5233
|
}
|
|
@@ -5020,9 +5237,9 @@ function SelectField({ id, property, value, fallback = "", onCommit }) {
|
|
|
5020
5237
|
var ALIGN_ICONS = { left: AlignLeft, center: AlignCenter, right: AlignRight, justify: AlignJustify };
|
|
5021
5238
|
function AlignField({ id, property, value, fallback = "", onCommit }) {
|
|
5022
5239
|
const t = useT();
|
|
5023
|
-
return /* @__PURE__ */
|
|
5024
|
-
/* @__PURE__ */
|
|
5025
|
-
/* @__PURE__ */
|
|
5240
|
+
return /* @__PURE__ */ jsxs12("div", { className: "eb:space-y-1.5", children: [
|
|
5241
|
+
/* @__PURE__ */ jsx13(FieldLabel, { id, children: t(property.label) }),
|
|
5242
|
+
/* @__PURE__ */ jsx13(
|
|
5026
5243
|
"div",
|
|
5027
5244
|
{
|
|
5028
5245
|
id,
|
|
@@ -5032,7 +5249,7 @@ function AlignField({ id, property, value, fallback = "", onCommit }) {
|
|
|
5032
5249
|
children: (property.options || []).map((option) => {
|
|
5033
5250
|
const Icon = ALIGN_ICONS[option.value] || AlignLeft;
|
|
5034
5251
|
const active = (value || fallback) === option.value;
|
|
5035
|
-
return /* @__PURE__ */
|
|
5252
|
+
return /* @__PURE__ */ jsx13(TooltipWrap, { label: t(option.label), children: /* @__PURE__ */ jsx13(
|
|
5036
5253
|
"button",
|
|
5037
5254
|
{
|
|
5038
5255
|
type: "button",
|
|
@@ -5044,7 +5261,7 @@ function AlignField({ id, property, value, fallback = "", onCommit }) {
|
|
|
5044
5261
|
"eb:inline-flex eb:h-7 eb:w-7 eb:items-center eb:justify-center eb:rounded-lg2 eb:transition-colors",
|
|
5045
5262
|
active ? "eb:bg-primary eb:text-primary-foreground" : "eb:text-foreground-lighter eb:hover:bg-surface-200 eb:hover:text-foreground"
|
|
5046
5263
|
),
|
|
5047
|
-
children: /* @__PURE__ */
|
|
5264
|
+
children: /* @__PURE__ */ jsx13(Icon, { className: "eb:h-3.5 eb:w-3.5" })
|
|
5048
5265
|
}
|
|
5049
5266
|
) }, option.value);
|
|
5050
5267
|
})
|
|
@@ -5073,10 +5290,10 @@ function SpacingField({ id, property, value, fallback = "", onCommit }) {
|
|
|
5073
5290
|
);
|
|
5074
5291
|
if (next !== (value || "")) onCommit(next);
|
|
5075
5292
|
};
|
|
5076
|
-
return /* @__PURE__ */
|
|
5077
|
-
/* @__PURE__ */
|
|
5078
|
-
/* @__PURE__ */
|
|
5079
|
-
/* @__PURE__ */
|
|
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(
|
|
5080
5297
|
Input,
|
|
5081
5298
|
{
|
|
5082
5299
|
id: `${id}-${side}`,
|
|
@@ -5095,7 +5312,7 @@ function SpacingField({ id, property, value, fallback = "", onCommit }) {
|
|
|
5095
5312
|
className: "eb:px-2 eb:text-center eb:tabular-nums"
|
|
5096
5313
|
}
|
|
5097
5314
|
),
|
|
5098
|
-
/* @__PURE__ */
|
|
5315
|
+
/* @__PURE__ */ jsx13("span", { className: "eb:block eb:text-center eb:text-[10.5px] eb:text-foreground-muted", children: t(label) })
|
|
5099
5316
|
] }, side)) })
|
|
5100
5317
|
] });
|
|
5101
5318
|
}
|
|
@@ -5113,15 +5330,15 @@ var FIELDS = {
|
|
|
5113
5330
|
function PropertyField({ property, value, fallback = "", onCommit, idPrefix = "eb", services = null }) {
|
|
5114
5331
|
const Field = FIELDS[property.type] || TextField;
|
|
5115
5332
|
const id = `${idPrefix}-${property.key}`;
|
|
5116
|
-
return /* @__PURE__ */
|
|
5333
|
+
return /* @__PURE__ */ jsx13(Field, { id, property, value, fallback, onCommit, services });
|
|
5117
5334
|
}
|
|
5118
5335
|
|
|
5119
5336
|
// src/features/variables/VariableInsertButton.jsx
|
|
5120
|
-
import { useState as
|
|
5121
|
-
import { Braces as
|
|
5122
|
-
import { jsx as
|
|
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";
|
|
5123
5340
|
function VariableInsertButton({ variables, inputRef, value, onChange, label }) {
|
|
5124
|
-
const [open, setOpen] =
|
|
5341
|
+
const [open, setOpen] = useState12(false);
|
|
5125
5342
|
const insert = (variable) => {
|
|
5126
5343
|
const input = inputRef.current;
|
|
5127
5344
|
const text = String(value || "");
|
|
@@ -5137,14 +5354,14 @@ function VariableInsertButton({ variables, inputRef, value, onChange, label }) {
|
|
|
5137
5354
|
input.setSelectionRange(start + token.length, start + token.length);
|
|
5138
5355
|
});
|
|
5139
5356
|
};
|
|
5140
|
-
return /* @__PURE__ */
|
|
5141
|
-
/* @__PURE__ */
|
|
5142
|
-
/* @__PURE__ */
|
|
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" }) })
|
|
5143
5360
|
] });
|
|
5144
5361
|
}
|
|
5145
5362
|
|
|
5146
5363
|
// src/ui/PropertiesPanel.jsx
|
|
5147
|
-
import { Fragment as Fragment6, jsx as
|
|
5364
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5148
5365
|
var GROUP_ORDER = Object.values(GROUPS);
|
|
5149
5366
|
function grouped(properties) {
|
|
5150
5367
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -5158,9 +5375,9 @@ function grouped(properties) {
|
|
|
5158
5375
|
}
|
|
5159
5376
|
function PropertyGroups({ editor, element, block, idPrefix, services = null }) {
|
|
5160
5377
|
const t = useT();
|
|
5161
|
-
return grouped(block?.properties || []).map(([group, properties]) => /* @__PURE__ */
|
|
5162
|
-
/* @__PURE__ */
|
|
5163
|
-
properties.map((property) => /* @__PURE__ */
|
|
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(
|
|
5164
5381
|
PropertyField,
|
|
5165
5382
|
{
|
|
5166
5383
|
idPrefix,
|
|
@@ -5178,9 +5395,9 @@ var LABEL_PROPERTY = { key: "content", label: "Label", type: "text", group: GROU
|
|
|
5178
5395
|
var REWRITABLE_TAGS = /* @__PURE__ */ new Set(["mj-text", "mj-button"]);
|
|
5179
5396
|
function PanelHeader({ title, onClose, closeLabel = "Deselect" }) {
|
|
5180
5397
|
const t = useT();
|
|
5181
|
-
return /* @__PURE__ */
|
|
5182
|
-
/* @__PURE__ */
|
|
5183
|
-
onClose && /* @__PURE__ */
|
|
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, {}) })
|
|
5184
5401
|
] });
|
|
5185
5402
|
}
|
|
5186
5403
|
function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, variables = null, ai = null, onDismiss = null }) {
|
|
@@ -5191,18 +5408,18 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
|
|
|
5191
5408
|
const root = useMemo4(() => rootId ? editor.getElement(rootId) : null, [editor, rootId, changes]);
|
|
5192
5409
|
const bodyBlock2 = root?.blockId ? editor.getBlock(root.blockId) : null;
|
|
5193
5410
|
const field = (key) => (e) => onMetaChange({ ...meta, [key]: e.target.value });
|
|
5194
|
-
return /* @__PURE__ */
|
|
5195
|
-
/* @__PURE__ */
|
|
5196
|
-
/* @__PURE__ */
|
|
5197
|
-
/* @__PURE__ */
|
|
5198
|
-
/* @__PURE__ */
|
|
5199
|
-
/* @__PURE__ */
|
|
5200
|
-
/* @__PURE__ */
|
|
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: [
|
|
5201
5418
|
t("Name"),
|
|
5202
5419
|
" ",
|
|
5203
|
-
/* @__PURE__ */
|
|
5420
|
+
/* @__PURE__ */ jsx15("span", { className: "eb:text-destructive", children: "*" })
|
|
5204
5421
|
] }),
|
|
5205
|
-
/* @__PURE__ */
|
|
5422
|
+
/* @__PURE__ */ jsx15(
|
|
5206
5423
|
Input,
|
|
5207
5424
|
{
|
|
5208
5425
|
id: "eb-meta-name",
|
|
@@ -5212,12 +5429,12 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
|
|
|
5212
5429
|
"aria-invalid": showErrors && !meta.name.trim() || void 0
|
|
5213
5430
|
}
|
|
5214
5431
|
),
|
|
5215
|
-
showErrors && !meta.name.trim() && /* @__PURE__ */
|
|
5432
|
+
showErrors && !meta.name.trim() && /* @__PURE__ */ jsx15("p", { className: "eb:text-[12px] eb:text-destructive", children: t("Name is required") })
|
|
5216
5433
|
] }),
|
|
5217
|
-
/* @__PURE__ */
|
|
5218
|
-
/* @__PURE__ */
|
|
5219
|
-
/* @__PURE__ */
|
|
5220
|
-
variables && /* @__PURE__ */
|
|
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(
|
|
5221
5438
|
VariableInsertButton,
|
|
5222
5439
|
{
|
|
5223
5440
|
variables,
|
|
@@ -5228,8 +5445,8 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
|
|
|
5228
5445
|
}
|
|
5229
5446
|
)
|
|
5230
5447
|
] }),
|
|
5231
|
-
/* @__PURE__ */
|
|
5232
|
-
ai?.suggestSubjects && /* @__PURE__ */
|
|
5448
|
+
/* @__PURE__ */ jsx15(Input, { ref: subjectRef, id: "eb-meta-subject", maxLength: 250, value: meta.subject, onChange: field("subject") }),
|
|
5449
|
+
ai?.suggestSubjects && /* @__PURE__ */ jsx15(
|
|
5233
5450
|
ai.components.Subjects,
|
|
5234
5451
|
{
|
|
5235
5452
|
editor,
|
|
@@ -5240,10 +5457,10 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
|
|
|
5240
5457
|
}
|
|
5241
5458
|
)
|
|
5242
5459
|
] }),
|
|
5243
|
-
/* @__PURE__ */
|
|
5244
|
-
/* @__PURE__ */
|
|
5245
|
-
/* @__PURE__ */
|
|
5246
|
-
variables && /* @__PURE__ */
|
|
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(
|
|
5247
5464
|
VariableInsertButton,
|
|
5248
5465
|
{
|
|
5249
5466
|
variables,
|
|
@@ -5254,7 +5471,7 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
|
|
|
5254
5471
|
}
|
|
5255
5472
|
)
|
|
5256
5473
|
] }),
|
|
5257
|
-
/* @__PURE__ */
|
|
5474
|
+
/* @__PURE__ */ jsx15(
|
|
5258
5475
|
Textarea,
|
|
5259
5476
|
{
|
|
5260
5477
|
ref: preheaderRef,
|
|
@@ -5268,7 +5485,7 @@ function TemplateSettings({ editor, meta, onMetaChange, changes, showErrors, var
|
|
|
5268
5485
|
)
|
|
5269
5486
|
] })
|
|
5270
5487
|
] }),
|
|
5271
|
-
root && bodyBlock2 && /* @__PURE__ */
|
|
5488
|
+
root && bodyBlock2 && /* @__PURE__ */ jsx15(PropertyGroups, { editor, element: root, block: bodyBlock2, idPrefix: "eb-page" })
|
|
5272
5489
|
] })
|
|
5273
5490
|
] });
|
|
5274
5491
|
}
|
|
@@ -5287,7 +5504,7 @@ function PropertiesPanel({
|
|
|
5287
5504
|
}) {
|
|
5288
5505
|
const t = useT();
|
|
5289
5506
|
const block = selection?.blockId ? editor.getBlock(selection.blockId) : null;
|
|
5290
|
-
return /* @__PURE__ */
|
|
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(
|
|
5291
5508
|
TemplateSettings,
|
|
5292
5509
|
{
|
|
5293
5510
|
editor,
|
|
@@ -5299,8 +5516,8 @@ function PropertiesPanel({
|
|
|
5299
5516
|
ai,
|
|
5300
5517
|
onDismiss
|
|
5301
5518
|
}
|
|
5302
|
-
) : /* @__PURE__ */
|
|
5303
|
-
/* @__PURE__ */
|
|
5519
|
+
) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
5520
|
+
/* @__PURE__ */ jsx15(
|
|
5304
5521
|
PanelHeader,
|
|
5305
5522
|
{
|
|
5306
5523
|
title: t(selection.label),
|
|
@@ -5309,12 +5526,12 @@ function PropertiesPanel({
|
|
|
5309
5526
|
}
|
|
5310
5527
|
),
|
|
5311
5528
|
actions,
|
|
5312
|
-
selection.multiple ? /* @__PURE__ */
|
|
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).", {
|
|
5313
5530
|
count: selection.multiple
|
|
5314
|
-
}) }) : /* @__PURE__ */
|
|
5315
|
-
selection.content !== null && selection.content !== void 0 && /* @__PURE__ */
|
|
5316
|
-
/* @__PURE__ */
|
|
5317
|
-
/* @__PURE__ */
|
|
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(
|
|
5318
5535
|
PropertyField,
|
|
5319
5536
|
{
|
|
5320
5537
|
idPrefix: "eb-prop",
|
|
@@ -5325,16 +5542,16 @@ function PropertiesPanel({
|
|
|
5325
5542
|
`${selection.id}:content`
|
|
5326
5543
|
)
|
|
5327
5544
|
] }),
|
|
5328
|
-
selection.tagName === "mj-text" && /* @__PURE__ */
|
|
5329
|
-
ai?.rewrite && REWRITABLE_TAGS.has(selection.tagName) && /* @__PURE__ */
|
|
5330
|
-
/* @__PURE__ */
|
|
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 })
|
|
5331
5548
|
] })
|
|
5332
5549
|
] }) });
|
|
5333
5550
|
}
|
|
5334
5551
|
|
|
5335
5552
|
// src/ui/Toolbar.jsx
|
|
5336
5553
|
import { ArrowLeft as ArrowLeft2, Monitor, Redo2, Smartphone, Undo2 } from "lucide-react";
|
|
5337
|
-
import { Fragment as Fragment7, jsx as
|
|
5554
|
+
import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
5338
5555
|
function Toolbar({
|
|
5339
5556
|
title,
|
|
5340
5557
|
status,
|
|
@@ -5351,8 +5568,8 @@ function Toolbar({
|
|
|
5351
5568
|
compact = false
|
|
5352
5569
|
}) {
|
|
5353
5570
|
const t = useT();
|
|
5354
|
-
const identity2 = /* @__PURE__ */
|
|
5355
|
-
/* @__PURE__ */
|
|
5571
|
+
const identity2 = /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
5572
|
+
/* @__PURE__ */ jsxs15(
|
|
5356
5573
|
Button,
|
|
5357
5574
|
{
|
|
5358
5575
|
variant: "ghost",
|
|
@@ -5360,50 +5577,50 @@ function Toolbar({
|
|
|
5360
5577
|
onClick: onBack,
|
|
5361
5578
|
"aria-label": compact ? t("Back") : void 0,
|
|
5362
5579
|
children: [
|
|
5363
|
-
/* @__PURE__ */
|
|
5580
|
+
/* @__PURE__ */ jsx16(ArrowLeft2, {}),
|
|
5364
5581
|
!compact && t("Back")
|
|
5365
5582
|
]
|
|
5366
5583
|
}
|
|
5367
5584
|
),
|
|
5368
|
-
/* @__PURE__ */
|
|
5369
|
-
/* @__PURE__ */
|
|
5370
|
-
/* @__PURE__ */
|
|
5371
|
-
/* @__PURE__ */
|
|
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 })
|
|
5372
5589
|
] })
|
|
5373
5590
|
] });
|
|
5374
|
-
const editing = /* @__PURE__ */
|
|
5375
|
-
/* @__PURE__ */
|
|
5376
|
-
/* @__PURE__ */
|
|
5377
|
-
/* @__PURE__ */
|
|
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, {}) }) })
|
|
5378
5595
|
] }),
|
|
5379
|
-
/* @__PURE__ */
|
|
5380
|
-
/* @__PURE__ */
|
|
5381
|
-
/* @__PURE__ */
|
|
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, {}),
|
|
5382
5599
|
!compact && t("Desktop")
|
|
5383
5600
|
] }),
|
|
5384
|
-
/* @__PURE__ */
|
|
5385
|
-
/* @__PURE__ */
|
|
5601
|
+
/* @__PURE__ */ jsxs15(TabsTrigger, { value: "mobile", disabled: !ready, "aria-label": compact ? t("Mobile") : void 0, children: [
|
|
5602
|
+
/* @__PURE__ */ jsx16(Smartphone, {}),
|
|
5386
5603
|
!compact && t("Mobile")
|
|
5387
5604
|
] })
|
|
5388
5605
|
] }) })
|
|
5389
5606
|
] });
|
|
5390
5607
|
if (compact) {
|
|
5391
|
-
return /* @__PURE__ */
|
|
5392
|
-
/* @__PURE__ */
|
|
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: [
|
|
5393
5610
|
identity2,
|
|
5394
5611
|
primary
|
|
5395
5612
|
] }),
|
|
5396
|
-
/* @__PURE__ */
|
|
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: [
|
|
5397
5614
|
editing,
|
|
5398
|
-
/* @__PURE__ */
|
|
5399
|
-
/* @__PURE__ */
|
|
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 })
|
|
5400
5617
|
] })
|
|
5401
5618
|
] });
|
|
5402
5619
|
}
|
|
5403
|
-
return /* @__PURE__ */
|
|
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: [
|
|
5404
5621
|
identity2,
|
|
5405
5622
|
editing,
|
|
5406
|
-
/* @__PURE__ */
|
|
5623
|
+
/* @__PURE__ */ jsxs15("div", { className: "eb:ml-auto eb:flex eb:items-center eb:gap-2", "data-testid": "eb-toolbar-actions", children: [
|
|
5407
5624
|
actions,
|
|
5408
5625
|
primary
|
|
5409
5626
|
] })
|
|
@@ -5413,7 +5630,7 @@ function Toolbar({
|
|
|
5413
5630
|
// src/ui/Drawer.jsx
|
|
5414
5631
|
import { useEffect as useEffect8 } from "react";
|
|
5415
5632
|
import { X as X3 } from "lucide-react";
|
|
5416
|
-
import { jsx as
|
|
5633
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5417
5634
|
function Drawer({ open, side = "left", title, onClose, children, testId, header: header2 = true }) {
|
|
5418
5635
|
const t = useT();
|
|
5419
5636
|
useEffect8(() => {
|
|
@@ -5424,9 +5641,9 @@ function Drawer({ open, side = "left", title, onClose, children, testId, header:
|
|
|
5424
5641
|
window.addEventListener("keydown", onKey);
|
|
5425
5642
|
return () => window.removeEventListener("keydown", onKey);
|
|
5426
5643
|
}, [open, onClose]);
|
|
5427
|
-
return /* @__PURE__ */
|
|
5428
|
-
/* @__PURE__ */
|
|
5429
|
-
/* @__PURE__ */
|
|
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(
|
|
5430
5647
|
"section",
|
|
5431
5648
|
{
|
|
5432
5649
|
role: "dialog",
|
|
@@ -5436,11 +5653,11 @@ function Drawer({ open, side = "left", title, onClose, children, testId, header:
|
|
|
5436
5653
|
side === "left" ? "eb:left-0 eb:border-r eb:border-border" : "eb:right-0 eb:border-l eb:border-border"
|
|
5437
5654
|
),
|
|
5438
5655
|
children: [
|
|
5439
|
-
header2 && /* @__PURE__ */
|
|
5440
|
-
/* @__PURE__ */
|
|
5441
|
-
/* @__PURE__ */
|
|
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, {}) })
|
|
5442
5659
|
] }),
|
|
5443
|
-
/* @__PURE__ */
|
|
5660
|
+
/* @__PURE__ */ jsx17("div", { className: "eb:grid eb:min-h-0 eb:flex-1", children })
|
|
5444
5661
|
]
|
|
5445
5662
|
}
|
|
5446
5663
|
)
|
|
@@ -5448,10 +5665,10 @@ function Drawer({ open, side = "left", title, onClose, children, testId, header:
|
|
|
5448
5665
|
}
|
|
5449
5666
|
|
|
5450
5667
|
// src/ui/useEmailEditorState.js
|
|
5451
|
-
import { useCallback as useCallback2, useEffect as useEffect9, useRef as useRef7, useState as
|
|
5668
|
+
import { useCallback as useCallback2, useEffect as useEffect9, useRef as useRef7, useState as useState13 } from "react";
|
|
5452
5669
|
var DIRTY_CHECK_MS = 150;
|
|
5453
5670
|
function useEmailEditorState(editor) {
|
|
5454
|
-
const [state, setState] =
|
|
5671
|
+
const [state, setState] = useState13(() => ({
|
|
5455
5672
|
status: editor?.status || "idle",
|
|
5456
5673
|
selection: null,
|
|
5457
5674
|
canUndo: false,
|
|
@@ -5532,7 +5749,7 @@ function useEmailEditorState(editor) {
|
|
|
5532
5749
|
}
|
|
5533
5750
|
|
|
5534
5751
|
// src/ui/EmailBuilder.jsx
|
|
5535
|
-
import { Fragment as Fragment8, jsx as
|
|
5752
|
+
import { Fragment as Fragment8, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
5536
5753
|
var EMPTY_META = { name: "", subject: "", preheader: "", description: "" };
|
|
5537
5754
|
function metaOf(template) {
|
|
5538
5755
|
return {
|
|
@@ -5570,7 +5787,7 @@ function Builder({
|
|
|
5570
5787
|
);
|
|
5571
5788
|
const storage = useMemo5(() => injectedStorage || createHttpStorage(), [injectedStorage]);
|
|
5572
5789
|
const systemVariables = useMemo5(() => defineVariables(variablesProp || DEFAULT_VARIABLES), [variablesProp]);
|
|
5573
|
-
const [customVariables, setCustomVariables] =
|
|
5790
|
+
const [customVariables, setCustomVariables] = useState14([]);
|
|
5574
5791
|
const variables = useMemo5(() => mergeVariables(systemVariables, customVariables), [systemVariables, customVariables]);
|
|
5575
5792
|
const canManageVariables = typeof storage.saveVariable === "function" && typeof storage.listVariables === "function";
|
|
5576
5793
|
const reloadVariables = useCallback3(async () => {
|
|
@@ -5604,20 +5821,20 @@ function Builder({
|
|
|
5604
5821
|
const state = useEmailEditorState(editor);
|
|
5605
5822
|
const autosaveOn = isFeatureEnabled("autosave");
|
|
5606
5823
|
const autosaveOptions = emailBuilderFeatures.get("autosave")?.options || {};
|
|
5607
|
-
const [template, setTemplate] =
|
|
5608
|
-
const [boot, setBoot] =
|
|
5609
|
-
const [meta, setMeta] =
|
|
5610
|
-
const [savedMeta, setSavedMeta] =
|
|
5611
|
-
const [saving, setSaving] =
|
|
5612
|
-
const [showErrors, setShowErrors] =
|
|
5613
|
-
const [autosaveBlocked, setAutosaveBlocked] =
|
|
5614
|
-
const [engineError, setEngineError] =
|
|
5615
|
-
const [attempt, setAttempt] =
|
|
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);
|
|
5616
5833
|
const rootRef = useRef8(null);
|
|
5617
5834
|
const layout2 = useLayoutWidth(rootRef);
|
|
5618
5835
|
const compact = layout2 !== "wide";
|
|
5619
5836
|
const blocksInDrawer = layout2 === "narrow";
|
|
5620
|
-
const [drawer, setDrawer] =
|
|
5837
|
+
const [drawer, setDrawer] = useState14(null);
|
|
5621
5838
|
const closeDrawer = useCallback3(() => setDrawer(null), []);
|
|
5622
5839
|
useEffect10(() => {
|
|
5623
5840
|
if (!compact) setDrawer(null);
|
|
@@ -5883,10 +6100,10 @@ function Builder({
|
|
|
5883
6100
|
setBrand,
|
|
5884
6101
|
ai
|
|
5885
6102
|
};
|
|
5886
|
-
const
|
|
5887
|
-
|
|
5888
|
-
);
|
|
5889
|
-
const properties = /* @__PURE__ */
|
|
6103
|
+
const featuresWith = (slot) => emailBuilderFeatures.list((f) => f.enabled !== false && Boolean(f[slot]) && (f.isAvailable ? f.isAvailable(featureContext) : true));
|
|
6104
|
+
const toolbarFeatures = featuresWith("toolbar");
|
|
6105
|
+
const canvasBars = featuresWith("canvasBar");
|
|
6106
|
+
const properties = /* @__PURE__ */ jsx18(
|
|
5890
6107
|
PropertiesPanel,
|
|
5891
6108
|
{
|
|
5892
6109
|
onDismiss: compact ? closeDrawer : null,
|
|
@@ -5896,13 +6113,13 @@ function Builder({
|
|
|
5896
6113
|
onMetaChange: setMeta,
|
|
5897
6114
|
changes: state.changes,
|
|
5898
6115
|
showErrors,
|
|
5899
|
-
actions: /* @__PURE__ */
|
|
6116
|
+
actions: /* @__PURE__ */ jsx18(ElementActions, { editor, selection: state.selection }),
|
|
5900
6117
|
services,
|
|
5901
6118
|
ai,
|
|
5902
6119
|
variables
|
|
5903
6120
|
}
|
|
5904
6121
|
);
|
|
5905
|
-
return /* @__PURE__ */
|
|
6122
|
+
return /* @__PURE__ */ jsxs17(
|
|
5906
6123
|
"div",
|
|
5907
6124
|
{
|
|
5908
6125
|
ref: rootRef,
|
|
@@ -5912,7 +6129,7 @@ function Builder({
|
|
|
5912
6129
|
"data-layout": layout2,
|
|
5913
6130
|
"data-template-id": template.id || "",
|
|
5914
6131
|
children: [
|
|
5915
|
-
/* @__PURE__ */
|
|
6132
|
+
/* @__PURE__ */ jsx18(
|
|
5916
6133
|
Toolbar,
|
|
5917
6134
|
{
|
|
5918
6135
|
title: meta.name,
|
|
@@ -5928,19 +6145,19 @@ function Builder({
|
|
|
5928
6145
|
compact,
|
|
5929
6146
|
actions: [
|
|
5930
6147
|
// The AI module's button first, when the host gave the module.
|
|
5931
|
-
ai?.proofread && /* @__PURE__ */
|
|
6148
|
+
ai?.proofread && /* @__PURE__ */ jsx18(ai.components.Proofread, { context: featureContext, proofread: ai.proofread }, "ai-proofread"),
|
|
5932
6149
|
...toolbarFeatures.map((feature) => {
|
|
5933
6150
|
const Action = feature.toolbar;
|
|
5934
|
-
return /* @__PURE__ */
|
|
6151
|
+
return /* @__PURE__ */ jsx18(Action, { context: featureContext }, feature.id);
|
|
5935
6152
|
})
|
|
5936
6153
|
].filter(Boolean),
|
|
5937
|
-
primary: /* @__PURE__ */
|
|
5938
|
-
saving === "manual" ? /* @__PURE__ */
|
|
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, {}),
|
|
5939
6156
|
t("Save")
|
|
5940
6157
|
] })
|
|
5941
6158
|
}
|
|
5942
6159
|
),
|
|
5943
|
-
/* @__PURE__ */
|
|
6160
|
+
/* @__PURE__ */ jsxs17(
|
|
5944
6161
|
"div",
|
|
5945
6162
|
{
|
|
5946
6163
|
className: cn(
|
|
@@ -5950,12 +6167,12 @@ function Builder({
|
|
|
5950
6167
|
layout2 === "narrow" && "eb:grid-cols-1"
|
|
5951
6168
|
),
|
|
5952
6169
|
children: [
|
|
5953
|
-
!blocksInDrawer && /* @__PURE__ */
|
|
5954
|
-
/* @__PURE__ */
|
|
5955
|
-
/* @__PURE__ */
|
|
5956
|
-
/* @__PURE__ */
|
|
5957
|
-
/* @__PURE__ */
|
|
5958
|
-
engineError && /* @__PURE__ */
|
|
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(
|
|
5959
6176
|
Button,
|
|
5960
6177
|
{
|
|
5961
6178
|
variant: "outline",
|
|
@@ -5967,8 +6184,12 @@ function Builder({
|
|
|
5967
6184
|
children: t("Retry")
|
|
5968
6185
|
}
|
|
5969
6186
|
)
|
|
5970
|
-
] }) : /* @__PURE__ */
|
|
5971
|
-
|
|
6187
|
+
] }) : /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
6188
|
+
canvasBars.map((feature) => {
|
|
6189
|
+
const Bar = feature.canvasBar;
|
|
6190
|
+
return /* @__PURE__ */ jsx18(Bar, { context: featureContext }, feature.id);
|
|
6191
|
+
}),
|
|
6192
|
+
/* @__PURE__ */ jsx18("div", { className: "eb:relative eb:min-h-0 eb:flex-1", children: boot.status === "ready" && /* @__PURE__ */ jsx18(
|
|
5972
6193
|
EmailCanvas,
|
|
5973
6194
|
{
|
|
5974
6195
|
editor,
|
|
@@ -5977,15 +6198,15 @@ function Builder({
|
|
|
5977
6198
|
onError: (error) => setEngineError(error.message)
|
|
5978
6199
|
},
|
|
5979
6200
|
attempt
|
|
5980
|
-
),
|
|
5981
|
-
!ready && /* @__PURE__ */
|
|
5982
|
-
/* @__PURE__ */
|
|
5983
|
-
/* @__PURE__ */
|
|
6201
|
+
) }),
|
|
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") })
|
|
5984
6205
|
] })
|
|
5985
6206
|
] }) }),
|
|
5986
6207
|
!compact && properties,
|
|
5987
|
-
blocksInDrawer && /* @__PURE__ */
|
|
5988
|
-
compact && /* @__PURE__ */
|
|
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(
|
|
5989
6210
|
Drawer,
|
|
5990
6211
|
{
|
|
5991
6212
|
open: drawer === "properties",
|
|
@@ -6000,12 +6221,12 @@ function Builder({
|
|
|
6000
6221
|
]
|
|
6001
6222
|
}
|
|
6002
6223
|
),
|
|
6003
|
-
compact && /* @__PURE__ */
|
|
6004
|
-
blocksInDrawer && /* @__PURE__ */
|
|
6005
|
-
/* @__PURE__ */
|
|
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, {}),
|
|
6006
6227
|
t("Add a block")
|
|
6007
6228
|
] }),
|
|
6008
|
-
/* @__PURE__ */
|
|
6229
|
+
/* @__PURE__ */ jsxs17(
|
|
6009
6230
|
Button,
|
|
6010
6231
|
{
|
|
6011
6232
|
variant: state.selection ? "default" : "outline",
|
|
@@ -6014,14 +6235,14 @@ function Builder({
|
|
|
6014
6235
|
disabled: !ready,
|
|
6015
6236
|
onClick: () => setDrawer("properties"),
|
|
6016
6237
|
children: [
|
|
6017
|
-
/* @__PURE__ */
|
|
6018
|
-
/* @__PURE__ */
|
|
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") })
|
|
6019
6240
|
]
|
|
6020
6241
|
}
|
|
6021
6242
|
)
|
|
6022
6243
|
] }),
|
|
6023
|
-
/* @__PURE__ */
|
|
6024
|
-
ai?.key && ai.components.Connect && /* @__PURE__ */
|
|
6244
|
+
/* @__PURE__ */ jsx18(NoticeArea, {}),
|
|
6245
|
+
ai?.key && ai.components.Connect && /* @__PURE__ */ jsx18(ai.components.Connect, { aiKey: ai.key })
|
|
6025
6246
|
]
|
|
6026
6247
|
}
|
|
6027
6248
|
);
|
|
@@ -6032,7 +6253,7 @@ function EmailBuilder({ locale = "en", messages, onNotify, ai: aiProp = null, ..
|
|
|
6032
6253
|
() => ai ? { ...messagesOf(ai.messages, locale), ...messages } : messages,
|
|
6033
6254
|
[ai, locale, messages]
|
|
6034
6255
|
);
|
|
6035
|
-
return /* @__PURE__ */
|
|
6256
|
+
return /* @__PURE__ */ jsx18(UiProvider, { locale, messages: allMessages, onNotify, children: /* @__PURE__ */ jsx18(Builder, { ...props, ai, templateId: props.templateId ?? null }) });
|
|
6036
6257
|
}
|
|
6037
6258
|
function useAiModule(value) {
|
|
6038
6259
|
const valid = Boolean(value && typeof value === "object" && /** @type {any} */
|
|
@@ -6051,7 +6272,7 @@ function useAiModule(value) {
|
|
|
6051
6272
|
// src/ui/EmailBuilderBoundary.jsx
|
|
6052
6273
|
import { Component } from "react";
|
|
6053
6274
|
import { AlertTriangle as AlertTriangle2, ArrowLeft as ArrowLeft3, RefreshCw } from "lucide-react";
|
|
6054
|
-
import { jsx as
|
|
6275
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
6055
6276
|
var isChunkError = (error) => error?.name === "ChunkLoadError" || /Loading (CSS )?chunk .* failed/i.test(String(error?.message || ""));
|
|
6056
6277
|
var english = (text) => text;
|
|
6057
6278
|
var EmailBuilderBoundary = class extends Component {
|
|
@@ -6076,23 +6297,23 @@ var EmailBuilderBoundary = class extends Component {
|
|
|
6076
6297
|
const { error, attempt } = this.state;
|
|
6077
6298
|
const t = this.props.t || english;
|
|
6078
6299
|
if (!error) {
|
|
6079
|
-
return /* @__PURE__ */
|
|
6300
|
+
return /* @__PURE__ */ jsx19("div", { style: { height: "100%" }, children: this.props.children }, attempt);
|
|
6080
6301
|
}
|
|
6081
|
-
return /* @__PURE__ */
|
|
6302
|
+
return /* @__PURE__ */ jsxs18(
|
|
6082
6303
|
"div",
|
|
6083
6304
|
{
|
|
6084
6305
|
role: "alert",
|
|
6085
6306
|
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",
|
|
6086
6307
|
children: [
|
|
6087
|
-
/* @__PURE__ */
|
|
6088
|
-
/* @__PURE__ */
|
|
6089
|
-
/* @__PURE__ */
|
|
6090
|
-
this.props.onClose && /* @__PURE__ */
|
|
6091
|
-
/* @__PURE__ */
|
|
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, {}),
|
|
6092
6313
|
t("Back")
|
|
6093
6314
|
] }),
|
|
6094
|
-
/* @__PURE__ */
|
|
6095
|
-
/* @__PURE__ */
|
|
6315
|
+
/* @__PURE__ */ jsxs18(Button, { size: "sm", onClick: this.retry, children: [
|
|
6316
|
+
/* @__PURE__ */ jsx19(RefreshCw, {}),
|
|
6096
6317
|
t("Retry")
|
|
6097
6318
|
] })
|
|
6098
6319
|
] })
|
|
@@ -6120,4 +6341,4 @@ export {
|
|
|
6120
6341
|
EmailBuilder,
|
|
6121
6342
|
EmailBuilderBoundary
|
|
6122
6343
|
};
|
|
6123
|
-
//# sourceMappingURL=chunk-
|
|
6344
|
+
//# sourceMappingURL=chunk-G7G3TRWG.js.map
|