best-email-builder 0.3.0 → 0.4.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 +133 -0
- package/README.md +214 -19
- package/dist/builder.js +4 -4
- package/dist/{chunk-ZSUHOCCE.js → chunk-AT73Y7JA.js} +159 -83
- package/dist/chunk-AT73Y7JA.js.map +1 -0
- package/dist/chunk-HHLOE6OZ.js +1682 -0
- package/dist/chunk-HHLOE6OZ.js.map +1 -0
- package/dist/chunk-JNHFZXDL.js +1776 -0
- package/dist/chunk-JNHFZXDL.js.map +1 -0
- package/dist/chunk-MY6WPDT4.js +6110 -0
- package/dist/chunk-MY6WPDT4.js.map +1 -0
- package/dist/{chunk-JOC752I3.js → chunk-NAEGU6PR.js} +13 -4
- package/dist/{chunk-JOC752I3.js.map → chunk-NAEGU6PR.js.map} +1 -1
- package/dist/{chunk-BVOVAEEJ.js → chunk-TGDZ4NFI.js} +44 -3
- package/dist/chunk-TGDZ4NFI.js.map +1 -0
- package/dist/index.js +45 -8
- package/dist/index.js.map +1 -1
- package/dist/library.js +3 -3
- package/dist/server.js +544 -204
- package/dist/server.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/blocks/shared.d.ts +20 -0
- package/dist/types/core/EmailEditor.d.ts +72 -19
- package/dist/types/core/constants.d.ts +1 -1
- package/dist/types/core/mjmlDefaults.d.ts +13 -0
- package/dist/types/core/scrollbars.d.ts +1 -1
- package/dist/types/defaultEditor.d.ts +4 -1
- package/dist/types/engine/NativeAdapter.d.ts +28 -0
- package/dist/types/engine/canvas/CanvasView.d.ts +88 -0
- package/dist/types/engine/canvas/canvasStyles.d.ts +3 -0
- package/dist/types/engine/canvas/icons.d.ts +14 -0
- package/dist/types/engine/canvas/morph.d.ts +21 -0
- package/dist/types/engine/canvasMjml.d.ts +30 -0
- package/dist/types/engine/mjml.d.ts +31 -0
- package/dist/types/engine/model.d.ts +130 -0
- package/dist/types/engine/placement.d.ts +69 -0
- package/dist/types/engine/richText.d.ts +15 -0
- package/dist/types/engine/unwrapModule.d.ts +29 -0
- package/dist/types/features/brand/BrandButton.d.ts +4 -0
- package/dist/types/features/brand/brand.d.ts +108 -0
- package/dist/types/features/brand/extract.d.ts +61 -0
- package/dist/types/features/brand/index.d.ts +2 -0
- package/dist/types/features/brand/messages.d.ts +13 -0
- package/dist/types/features/brand/useBrand.d.ts +22 -0
- package/dist/types/features/generate/GenerateButton.d.ts +3 -0
- package/dist/types/features/generate/RewriteText.d.ts +5 -0
- package/dist/types/features/generate/SubjectIdeas.d.ts +16 -0
- package/dist/types/features/generate/chip.d.ts +1 -0
- package/dist/types/features/generate/claude.d.ts +21 -0
- package/dist/types/features/generate/draft.d.ts +122 -0
- package/dist/types/features/generate/generator.d.ts +118 -0
- package/dist/types/features/generate/index.d.ts +2 -0
- package/dist/types/features/generate/prompt.d.ts +76 -0
- package/dist/types/features/generate/purposes.d.ts +48 -0
- package/dist/types/features/generate/rewrite.d.ts +83 -0
- package/dist/types/features/generate/subjects.d.ts +83 -0
- package/dist/types/features/preview/PreviewButton.d.ts +1 -1
- package/dist/types/features/preview/darkMode.d.ts +48 -0
- package/dist/types/index.d.ts +10 -1
- package/dist/types/server/brand.d.ts +32 -0
- package/dist/types/server/brandImport.d.ts +93 -0
- package/dist/types/server/compileMjml.d.ts +2 -0
- package/dist/types/server/handler.d.ts +25 -0
- package/dist/types/server/index.d.ts +11 -0
- package/dist/types/storage/client.d.ts +75 -3
- package/dist/types/ui/fields.d.ts +2 -1
- package/dist/types/ui/primitives/button.d.ts +1 -1
- package/dist/types/ui/primitives/color-picker.d.ts +2 -1
- package/dist/types/ui/useLayoutWidth.d.ts +1 -1
- package/package.json +13 -7
- package/dist/chunk-3M36VVXS.js +0 -665
- package/dist/chunk-3M36VVXS.js.map +0 -1
- package/dist/chunk-57CTQNTK.js +0 -56
- package/dist/chunk-57CTQNTK.js.map +0 -1
- package/dist/chunk-BVOVAEEJ.js.map +0 -1
- package/dist/chunk-ILRAQTHS.js +0 -3677
- package/dist/chunk-ILRAQTHS.js.map +0 -1
- package/dist/chunk-ZSUHOCCE.js.map +0 -1
- package/dist/types/adapters/grapesjs/GrapesJsAdapter.d.ts +0 -33
- package/dist/types/adapters/grapesjs/engineConfig.d.ts +0 -148
- package/dist/types/adapters/grapesjs/unwrapModule.d.ts +0 -18
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DARK_PAGE,
|
|
2
3
|
DEFAULT_ASSETS_PATH,
|
|
4
|
+
DEFAULT_BUTTON_URL,
|
|
3
5
|
DEFAULT_VARIABLES,
|
|
4
6
|
EMAIL_MOBILE_WIDTH,
|
|
7
|
+
FONT_STACK,
|
|
8
|
+
GROUPS,
|
|
5
9
|
IMAGE_TYPES,
|
|
10
|
+
PALETTE,
|
|
11
|
+
cleanBrand,
|
|
6
12
|
identity,
|
|
7
13
|
imageUploadError,
|
|
14
|
+
inWhiteSection,
|
|
15
|
+
prop,
|
|
8
16
|
readDocument,
|
|
17
|
+
simulateDarkMode,
|
|
9
18
|
translatorFor,
|
|
10
19
|
validateCustomVariable
|
|
11
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-HHLOE6OZ.js";
|
|
12
21
|
|
|
13
22
|
// src/ui/context.jsx
|
|
14
23
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -117,6 +126,40 @@ function PopoverContent({ className, align = "center", sideOffset = 4, ...props
|
|
|
117
126
|
}
|
|
118
127
|
) });
|
|
119
128
|
}
|
|
129
|
+
function DropdownMenu(props) {
|
|
130
|
+
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
131
|
+
}
|
|
132
|
+
function DropdownMenuTrigger(props) {
|
|
133
|
+
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
134
|
+
}
|
|
135
|
+
function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
|
|
136
|
+
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
137
|
+
DropdownMenuPrimitive.Content,
|
|
138
|
+
{
|
|
139
|
+
"data-slot": "dropdown-menu-content",
|
|
140
|
+
sideOffset,
|
|
141
|
+
className: cn(
|
|
142
|
+
"eb-scope eb:z-50 eb:max-h-(--radix-dropdown-menu-content-available-height) eb:min-w-[8rem] eb:origin-(--radix-dropdown-menu-content-transform-origin) eb:overflow-x-hidden eb:overflow-y-auto eb:rounded-lg2 eb:border eb:border-border eb:bg-popover eb:p-1 eb:text-popover-foreground eb:shadow-md",
|
|
143
|
+
FADE_ZOOM,
|
|
144
|
+
className
|
|
145
|
+
),
|
|
146
|
+
...props
|
|
147
|
+
}
|
|
148
|
+
) });
|
|
149
|
+
}
|
|
150
|
+
function DropdownMenuItem({ className, ...props }) {
|
|
151
|
+
return /* @__PURE__ */ jsx(
|
|
152
|
+
DropdownMenuPrimitive.Item,
|
|
153
|
+
{
|
|
154
|
+
"data-slot": "dropdown-menu-item",
|
|
155
|
+
className: cn(
|
|
156
|
+
"eb:relative eb:flex eb:cursor-default eb:items-center eb:gap-2 eb:rounded-sm eb:px-2 eb:py-1.5 eb:text-[13px] eb:outline-hidden eb:select-none eb:focus:bg-accent eb:focus:text-accent-foreground eb:data-[disabled]:pointer-events-none eb:data-[disabled]:opacity-50 eb:[&_svg]:pointer-events-none eb:[&_svg]:shrink-0 eb:[&_svg:not([class*='size-'])]:size-4",
|
|
157
|
+
className
|
|
158
|
+
),
|
|
159
|
+
...props
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
}
|
|
120
163
|
function Select(props) {
|
|
121
164
|
return /* @__PURE__ */ jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
|
|
122
165
|
}
|
|
@@ -409,7 +452,14 @@ function UiProvider({ locale = "en", messages, onNotify, children }) {
|
|
|
409
452
|
return;
|
|
410
453
|
}
|
|
411
454
|
const id = nextId.current += 1;
|
|
412
|
-
setNotices((list) =>
|
|
455
|
+
setNotices((list) => {
|
|
456
|
+
const same = list.filter((n) => n.level === level && n.message === message);
|
|
457
|
+
for (const notice of same) {
|
|
458
|
+
clearTimeout(timers.current.get(notice.id));
|
|
459
|
+
timers.current.delete(notice.id);
|
|
460
|
+
}
|
|
461
|
+
return [...list.filter((n) => !same.includes(n)).slice(-3), { id, level, message }];
|
|
462
|
+
});
|
|
413
463
|
timers.current.set(
|
|
414
464
|
id,
|
|
415
465
|
setTimeout(() => dismiss(id), NOTICE_TTL[level] || 4e3)
|
|
@@ -470,65 +520,6 @@ function UiProvider({ locale = "en", messages, onNotify, children }) {
|
|
|
470
520
|
] }) });
|
|
471
521
|
}
|
|
472
522
|
|
|
473
|
-
// src/blocks/shared.js
|
|
474
|
-
var PALETTE = {
|
|
475
|
-
ink: "#2b3038",
|
|
476
|
-
inkSoft: "#41506b",
|
|
477
|
-
navy: "#212e5a",
|
|
478
|
-
brand: "#2977bc",
|
|
479
|
-
border: "#dfe6f0",
|
|
480
|
-
canvas: "#eceff4",
|
|
481
|
-
surface: "#ffffff",
|
|
482
|
-
white: "#ffffff"
|
|
483
|
-
};
|
|
484
|
-
var DEFAULT_BUTTON_URL = "https://example.com";
|
|
485
|
-
var FONT_STACK = "Arial, Helvetica, sans-serif";
|
|
486
|
-
var FONT_OPTIONS = [
|
|
487
|
-
{ value: "Arial, Helvetica, sans-serif", label: "Arial" },
|
|
488
|
-
{ value: "Verdana, Geneva, sans-serif", label: "Verdana" },
|
|
489
|
-
{ value: "Tahoma, Geneva, sans-serif", label: "Tahoma" },
|
|
490
|
-
{ value: "'Trebuchet MS', Helvetica, sans-serif", label: "Trebuchet" },
|
|
491
|
-
{ value: "Georgia, Times, serif", label: "Georgia" },
|
|
492
|
-
{ value: "'Times New Roman', Times, serif", label: "Times" },
|
|
493
|
-
{ value: "'Courier New', Courier, monospace", label: "Courier" }
|
|
494
|
-
];
|
|
495
|
-
var ALIGN_OPTIONS = [
|
|
496
|
-
{ value: "left", label: "Left" },
|
|
497
|
-
{ value: "center", label: "Center" },
|
|
498
|
-
{ value: "right", label: "Right" }
|
|
499
|
-
];
|
|
500
|
-
var GROUPS = {
|
|
501
|
-
content: "Content",
|
|
502
|
-
link: "Link",
|
|
503
|
-
typography: "Typography",
|
|
504
|
-
colors: "Colors",
|
|
505
|
-
layout: "Layout",
|
|
506
|
-
spacing: "Spacing"
|
|
507
|
-
};
|
|
508
|
-
var prop = {
|
|
509
|
-
/** @returns {BlockProperty} */
|
|
510
|
-
fontFamily: () => ({ key: "font-family", label: "Font", type: "select", group: GROUPS.typography, options: FONT_OPTIONS }),
|
|
511
|
-
/** @returns {BlockProperty} */
|
|
512
|
-
fontSize: (min = 10, max = 48) => ({ key: "font-size", label: "Size", type: "size", group: GROUPS.typography, min, max, unit: "px" }),
|
|
513
|
-
/** @returns {BlockProperty} */
|
|
514
|
-
lineHeight: () => ({ key: "line-height", label: "Line height", type: "size", group: GROUPS.typography, min: 10, max: 80, unit: "px" }),
|
|
515
|
-
/** @returns {BlockProperty} */
|
|
516
|
-
color: (label = "Text") => ({ key: "color", label, type: "color", group: GROUPS.colors }),
|
|
517
|
-
/** @returns {BlockProperty} */
|
|
518
|
-
background: (key = "background-color", label = "Background") => ({ key, label, type: "color", group: GROUPS.colors }),
|
|
519
|
-
/** @returns {BlockProperty} */
|
|
520
|
-
align: (options = ALIGN_OPTIONS) => ({ key: "align", label: "Alignment", type: "align", group: GROUPS.layout, options }),
|
|
521
|
-
/** @returns {BlockProperty} */
|
|
522
|
-
padding: (key = "padding", label = "Padding") => ({ key, label, type: "spacing", group: GROUPS.spacing }),
|
|
523
|
-
/** @returns {BlockProperty} */
|
|
524
|
-
href: (label = "Link URL") => ({ key: "href", label, type: "url", group: GROUPS.link, placeholder: "https://" }),
|
|
525
|
-
/** @returns {BlockProperty} */
|
|
526
|
-
radius: (max = 40) => ({ key: "border-radius", label: "Corner radius", type: "size", group: GROUPS.layout, min: 0, max, unit: "px" })
|
|
527
|
-
};
|
|
528
|
-
function inWhiteSection(inner) {
|
|
529
|
-
return `<mj-section background-color="${PALETTE.surface}" padding-top="0px" padding-bottom="0px"><mj-column>${inner}</mj-column></mj-section>`;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
523
|
// src/features/templates/starter.js
|
|
533
524
|
function escapeXml(text) {
|
|
534
525
|
return String(text ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -834,7 +825,7 @@ function withDocument(template) {
|
|
|
834
825
|
if (!template || !template.document) return template;
|
|
835
826
|
return { ...template, document: readDocument(template.document) };
|
|
836
827
|
}
|
|
837
|
-
function createHttpStorage({ baseUrl = "/api/email-builder", headers = {}, fetch: fetchImpl } = {}) {
|
|
828
|
+
function createHttpStorage({ baseUrl = "/api/email-builder", headers = {}, fetch: fetchImpl, generate = false, brand = false } = {}) {
|
|
838
829
|
const root = baseUrl.replace(/\/+$/, "");
|
|
839
830
|
const doFetch = fetchImpl || ((input, init) => fetch(input, init));
|
|
840
831
|
const extraHeaders = () => typeof headers === "function" ? headers() : headers;
|
|
@@ -873,6 +864,18 @@ function createHttpStorage({ baseUrl = "/api/email-builder", headers = {}, fetch
|
|
|
873
864
|
deleteVariable: async (key) => {
|
|
874
865
|
await call(`/variables/${encodeURIComponent(key)}`, { method: "DELETE" });
|
|
875
866
|
},
|
|
867
|
+
...generate ? {
|
|
868
|
+
generate: async (input, { signal } = {}) => call("/generate", { method: "POST", body: JSON.stringify(input), signal }),
|
|
869
|
+
rewrite: async (input, { signal } = {}) => call("/rewrite", { method: "POST", body: JSON.stringify(input), signal }),
|
|
870
|
+
suggestSubjects: async (input, { signal } = {}) => call("/subjects", { method: "POST", body: JSON.stringify(input), signal })
|
|
871
|
+
} : {},
|
|
872
|
+
...brand ? {
|
|
873
|
+
loadBrand: async () => call("/brand"),
|
|
874
|
+
saveBrand: async (value) => call("/brand", { method: "PUT", body: JSON.stringify(value) }),
|
|
875
|
+
...brand === true || brand.import !== false ? {
|
|
876
|
+
importBrand: async (url, { signal } = {}) => call("/brand/import", { method: "POST", body: JSON.stringify({ url }), signal })
|
|
877
|
+
} : {}
|
|
878
|
+
} : {},
|
|
876
879
|
async uploadImage(file) {
|
|
877
880
|
assertUploadable(file);
|
|
878
881
|
const form = new FormData();
|
|
@@ -883,11 +886,22 @@ function createHttpStorage({ baseUrl = "/api/email-builder", headers = {}, fetch
|
|
|
883
886
|
}
|
|
884
887
|
};
|
|
885
888
|
}
|
|
886
|
-
function createMemoryStorage({
|
|
889
|
+
function createMemoryStorage({
|
|
890
|
+
render,
|
|
891
|
+
sendTest,
|
|
892
|
+
generate,
|
|
893
|
+
rewrite,
|
|
894
|
+
suggestSubjects,
|
|
895
|
+
importBrand,
|
|
896
|
+
brand = null,
|
|
897
|
+
assetsPath = DEFAULT_ASSETS_PATH,
|
|
898
|
+
systemVariables = DEFAULT_VARIABLES
|
|
899
|
+
} = {}) {
|
|
887
900
|
const rows = /* @__PURE__ */ new Map();
|
|
888
901
|
const versions = /* @__PURE__ */ new Map();
|
|
889
902
|
const images = /* @__PURE__ */ new Map();
|
|
890
903
|
const customVariables = /* @__PURE__ */ new Map();
|
|
904
|
+
let savedBrand = cleanBrand(brand);
|
|
891
905
|
let nextId = 1;
|
|
892
906
|
let tick = Date.parse("2026-01-01T00:00:00.000Z");
|
|
893
907
|
const now = () => new Date(tick += 1e3).toISOString();
|
|
@@ -1025,13 +1039,25 @@ function createMemoryStorage({ render, sendTest, assetsPath = DEFAULT_ASSETS_PAT
|
|
|
1025
1039
|
async deleteVariable(key) {
|
|
1026
1040
|
if (!customVariables.delete(String(key))) throw new StorageError("Variable not found", 404, "NOT_FOUND");
|
|
1027
1041
|
},
|
|
1042
|
+
async loadBrand() {
|
|
1043
|
+
return { ...savedBrand };
|
|
1044
|
+
},
|
|
1045
|
+
async saveBrand(value) {
|
|
1046
|
+
savedBrand = cleanBrand(value);
|
|
1047
|
+
return { ...savedBrand };
|
|
1048
|
+
},
|
|
1049
|
+
...importBrand ? { importBrand } : {},
|
|
1028
1050
|
...render ? { render } : {},
|
|
1029
1051
|
...sendTest ? { sendTest } : {},
|
|
1052
|
+
...generate ? { generate } : {},
|
|
1053
|
+
...rewrite ? { rewrite } : {},
|
|
1054
|
+
...suggestSubjects ? { suggestSubjects } : {},
|
|
1030
1055
|
dump: () => ({
|
|
1031
1056
|
rows: [...rows.values()],
|
|
1032
1057
|
versions: Object.fromEntries(versions),
|
|
1033
1058
|
images: [...images.keys()],
|
|
1034
|
-
variables: [...customVariables.values()]
|
|
1059
|
+
variables: [...customVariables.values()],
|
|
1060
|
+
brand: savedBrand
|
|
1035
1061
|
})
|
|
1036
1062
|
};
|
|
1037
1063
|
return storage;
|
|
@@ -1088,7 +1114,7 @@ function Label({ className, ...props }) {
|
|
|
1088
1114
|
|
|
1089
1115
|
// src/features/preview/PreviewButton.jsx
|
|
1090
1116
|
import { useMemo as useMemo2, useState as useState2 } from "react";
|
|
1091
|
-
import { AlertTriangle, CheckCircle2 as CheckCircle22, Eye, Info as Info2, Loader2, Monitor, RefreshCw, Smartphone } from "lucide-react";
|
|
1117
|
+
import { AlertTriangle, CheckCircle2 as CheckCircle22, Eye, Info as Info2, Loader2, Monitor, Moon, RefreshCw, Smartphone, Sun } from "lucide-react";
|
|
1092
1118
|
|
|
1093
1119
|
// src/core/scrollbars.js
|
|
1094
1120
|
var FRAME_SCROLLBAR_CSS = `
|
|
@@ -1145,9 +1171,11 @@ var withPreviewScrollbars = (html) => !html ? "" : /<\/head>/i.test(html) ? html
|
|
|
1145
1171
|
function EmailPreview({ html, loading = false, error = null, device = "desktop", onDeviceChange, onRefresh, hint = true }) {
|
|
1146
1172
|
const { t } = useUi();
|
|
1147
1173
|
const isMobile = device === "mobile";
|
|
1148
|
-
const
|
|
1174
|
+
const [scheme, setScheme] = useState2("light");
|
|
1175
|
+
const dark = scheme === "dark";
|
|
1176
|
+
const srcDoc = useMemo2(() => withPreviewScrollbars(dark ? simulateDarkMode(html) : html), [html, dark]);
|
|
1149
1177
|
return /* @__PURE__ */ jsxs4("div", { className: "eb:flex eb:h-full eb:min-h-0 eb:flex-col", children: [
|
|
1150
|
-
/* @__PURE__ */ jsxs4("div", { className: "eb:mb-2 eb:flex eb:shrink-0 eb:
|
|
1178
|
+
/* @__PURE__ */ jsxs4("div", { className: "eb:mb-2 eb:flex eb:shrink-0 eb:flex-wrap eb:items-center eb:gap-2", children: [
|
|
1151
1179
|
/* @__PURE__ */ jsx6(Tabs, { value: device, onValueChange: (value) => onDeviceChange?.(value), children: /* @__PURE__ */ jsxs4(TabsList, { "aria-label": t("Device"), children: [
|
|
1152
1180
|
/* @__PURE__ */ jsxs4(TabsTrigger, { value: "desktop", children: [
|
|
1153
1181
|
/* @__PURE__ */ jsx6(Monitor, {}),
|
|
@@ -1158,36 +1186,42 @@ function EmailPreview({ html, loading = false, error = null, device = "desktop",
|
|
|
1158
1186
|
t("Mobile")
|
|
1159
1187
|
] })
|
|
1160
1188
|
] }) }),
|
|
1189
|
+
/* @__PURE__ */ jsx6(Tabs, { value: scheme, onValueChange: setScheme, children: /* @__PURE__ */ jsxs4(TabsList, { "aria-label": t("Color scheme"), children: [
|
|
1190
|
+
/* @__PURE__ */ jsx6(TabsTrigger, { value: "light", "aria-label": t("Light mode"), title: t("Light mode"), children: /* @__PURE__ */ jsx6(Sun, {}) }),
|
|
1191
|
+
/* @__PURE__ */ jsx6(TabsTrigger, { value: "dark", "aria-label": t("Dark mode"), title: t("Dark mode"), children: /* @__PURE__ */ jsx6(Moon, {}) })
|
|
1192
|
+
] }) }),
|
|
1193
|
+
/* @__PURE__ */ jsx6("span", { className: "eb:flex-1" }),
|
|
1161
1194
|
onRefresh && /* @__PURE__ */ jsxs4(Button, { variant: "outline", size: "sm-compact", onClick: onRefresh, disabled: loading, children: [
|
|
1162
1195
|
loading ? /* @__PURE__ */ jsx6(Loader2, { className: "eb:animate-spin" }) : /* @__PURE__ */ jsx6(RefreshCw, {}),
|
|
1163
1196
|
t("Refresh")
|
|
1164
1197
|
] })
|
|
1165
1198
|
] }),
|
|
1166
1199
|
/* @__PURE__ */ jsx6("div", { className: "eb:min-h-0 eb:flex-1 eb:overflow-auto eb:rounded-lg2 eb:border eb:border-border eb:bg-surface-75 eb:p-3", children: error ? /* @__PURE__ */ jsx6("div", { className: "eb:flex eb:h-full eb:items-center eb:justify-center eb:p-6 eb:text-center eb:text-[13px] eb:text-destructive", children: error }) : !srcDoc ? /* @__PURE__ */ jsx6("div", { className: "eb:flex eb:h-full eb:items-center eb:justify-center eb:p-6 eb:text-center eb:text-[13px] eb:text-foreground-lighter", children: loading ? t("Rendering\u2026") : t("Nothing to show yet.") }) : (
|
|
1167
|
-
// Narrows and widens like the editor's canvas (
|
|
1200
|
+
// Narrows and widens like the editor's canvas (width .35s ease).
|
|
1168
1201
|
/* @__PURE__ */ jsx6(
|
|
1169
1202
|
"div",
|
|
1170
1203
|
{
|
|
1171
1204
|
className: cn(
|
|
1172
|
-
"eb:mx-auto eb:max-w-full eb:
|
|
1205
|
+
"eb:mx-auto eb:max-w-full eb:transition-[width,box-shadow] eb:duration-[350ms] eb:ease-in-out eb:motion-reduce:transition-none",
|
|
1173
1206
|
isMobile && "eb:shadow-sm"
|
|
1174
1207
|
),
|
|
1175
|
-
style: { width: isMobile ? EMAIL_MOBILE_WIDTH : "100%" },
|
|
1208
|
+
style: { width: isMobile ? EMAIL_MOBILE_WIDTH : "100%", background: dark ? DARK_PAGE : "#ffffff" },
|
|
1176
1209
|
"data-device": device,
|
|
1210
|
+
"data-scheme": scheme,
|
|
1177
1211
|
children: /* @__PURE__ */ jsx6(
|
|
1178
1212
|
"iframe",
|
|
1179
1213
|
{
|
|
1180
1214
|
sandbox: "",
|
|
1181
1215
|
srcDoc,
|
|
1182
1216
|
title: t("Email preview"),
|
|
1183
|
-
className: "eb:block eb:w-full eb:border-0 eb:
|
|
1184
|
-
style: { height: isMobile ? 760 : 900 }
|
|
1217
|
+
className: "eb:block eb:w-full eb:border-0 eb:transition-[height] eb:duration-[350ms] eb:ease-in-out eb:motion-reduce:transition-none",
|
|
1218
|
+
style: { height: isMobile ? 760 : 900, background: dark ? DARK_PAGE : "#ffffff" }
|
|
1185
1219
|
}
|
|
1186
1220
|
)
|
|
1187
1221
|
}
|
|
1188
1222
|
)
|
|
1189
1223
|
) }),
|
|
1190
|
-
hint && /* @__PURE__ */ jsx6("p", { className: "eb:mt-2 eb:shrink-0 eb:text-[11px] eb:leading-relaxed eb:text-foreground-lighter", children: t("Indicative preview \u2014 check it with \u201CSend test\u201D.") })
|
|
1224
|
+
dark ? /* @__PURE__ */ jsx6("p", { className: "eb:mt-2 eb:shrink-0 eb:text-[11px] eb:leading-relaxed eb:text-foreground-lighter", "data-testid": "eb-dark-hint", children: t("Dark mode as Gmail and Outlook apps show it: light backgrounds turn dark, dark text turns light, images stay as they are.") }) : hint && /* @__PURE__ */ jsx6("p", { className: "eb:mt-2 eb:shrink-0 eb:text-[11px] eb:leading-relaxed eb:text-foreground-lighter", children: t("Indicative preview \u2014 check it with \u201CSend test\u201D.") })
|
|
1191
1225
|
] });
|
|
1192
1226
|
}
|
|
1193
1227
|
function PreviewButton({ context }) {
|
|
@@ -1270,8 +1304,50 @@ function PreviewButton({ context }) {
|
|
|
1270
1304
|
] });
|
|
1271
1305
|
}
|
|
1272
1306
|
|
|
1307
|
+
// src/features/brand/useBrand.js
|
|
1308
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState3 } from "react";
|
|
1309
|
+
var entries = /* @__PURE__ */ new WeakMap();
|
|
1310
|
+
function brandOf(storage) {
|
|
1311
|
+
let entry = entries.get(storage);
|
|
1312
|
+
if (entry) return entry;
|
|
1313
|
+
const created = { value: {}, loaded: Promise.resolve({}), listeners: /* @__PURE__ */ new Set() };
|
|
1314
|
+
created.loaded = typeof storage?.loadBrand === "function" ? Promise.resolve().then(() => storage.loadBrand()).then(
|
|
1315
|
+
(brand) => cleanBrand(brand),
|
|
1316
|
+
() => (
|
|
1317
|
+
/** @type {Brand} */
|
|
1318
|
+
{}
|
|
1319
|
+
)
|
|
1320
|
+
).then((brand) => {
|
|
1321
|
+
created.value = brand;
|
|
1322
|
+
created.listeners.forEach((listener) => listener(brand));
|
|
1323
|
+
return brand;
|
|
1324
|
+
}) : created.loaded;
|
|
1325
|
+
if (storage && typeof storage === "object") entries.set(storage, created);
|
|
1326
|
+
return created;
|
|
1327
|
+
}
|
|
1328
|
+
function useBrand(storage) {
|
|
1329
|
+
const [brand, setState] = useState3(() => brandOf(storage).value);
|
|
1330
|
+
useEffect2(() => {
|
|
1331
|
+
const entry = brandOf(storage);
|
|
1332
|
+
setState(entry.value);
|
|
1333
|
+
entry.listeners.add(setState);
|
|
1334
|
+
return () => {
|
|
1335
|
+
entry.listeners.delete(setState);
|
|
1336
|
+
};
|
|
1337
|
+
}, [storage]);
|
|
1338
|
+
const setBrand = useCallback2(
|
|
1339
|
+
(value) => {
|
|
1340
|
+
const entry = brandOf(storage);
|
|
1341
|
+
entry.value = cleanBrand(value);
|
|
1342
|
+
entry.listeners.forEach((listener) => listener(entry.value));
|
|
1343
|
+
},
|
|
1344
|
+
[storage]
|
|
1345
|
+
);
|
|
1346
|
+
return { brand, setBrand };
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1273
1349
|
// src/ui/useLayoutWidth.js
|
|
1274
|
-
import { useEffect as
|
|
1350
|
+
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
1275
1351
|
var LAYOUT_BREAKPOINTS = { wide: 1180, medium: 760 };
|
|
1276
1352
|
function layoutFor(width) {
|
|
1277
1353
|
if (width >= LAYOUT_BREAKPOINTS.wide) return "wide";
|
|
@@ -1279,11 +1355,11 @@ function layoutFor(width) {
|
|
|
1279
1355
|
return "narrow";
|
|
1280
1356
|
}
|
|
1281
1357
|
function useLayoutWidth(ref) {
|
|
1282
|
-
const [layout, setLayout] =
|
|
1358
|
+
const [layout, setLayout] = useState4(
|
|
1283
1359
|
/** @type {'wide'|'medium'|'narrow'} */
|
|
1284
1360
|
"wide"
|
|
1285
1361
|
);
|
|
1286
|
-
|
|
1362
|
+
useEffect3(() => {
|
|
1287
1363
|
const el = ref.current;
|
|
1288
1364
|
if (!el || typeof ResizeObserver === "undefined") return void 0;
|
|
1289
1365
|
const measure = () => setLayout(layoutFor(el.getBoundingClientRect().width));
|
|
@@ -1296,12 +1372,6 @@ function useLayoutWidth(ref) {
|
|
|
1296
1372
|
}
|
|
1297
1373
|
|
|
1298
1374
|
export {
|
|
1299
|
-
PALETTE,
|
|
1300
|
-
DEFAULT_BUTTON_URL,
|
|
1301
|
-
FONT_STACK,
|
|
1302
|
-
GROUPS,
|
|
1303
|
-
prop,
|
|
1304
|
-
inWhiteSection,
|
|
1305
1375
|
socialBlock,
|
|
1306
1376
|
socialElementBlock,
|
|
1307
1377
|
cn,
|
|
@@ -1326,6 +1396,10 @@ export {
|
|
|
1326
1396
|
Popover,
|
|
1327
1397
|
PopoverTrigger,
|
|
1328
1398
|
PopoverContent,
|
|
1399
|
+
DropdownMenu,
|
|
1400
|
+
DropdownMenuTrigger,
|
|
1401
|
+
DropdownMenuContent,
|
|
1402
|
+
DropdownMenuItem,
|
|
1329
1403
|
Select,
|
|
1330
1404
|
SelectValue,
|
|
1331
1405
|
SelectTrigger,
|
|
@@ -1343,9 +1417,11 @@ export {
|
|
|
1343
1417
|
buildGallery,
|
|
1344
1418
|
withThumbnailImages,
|
|
1345
1419
|
withPlaceholderImages,
|
|
1420
|
+
brandOf,
|
|
1421
|
+
useBrand,
|
|
1346
1422
|
StorageError,
|
|
1347
1423
|
createHttpStorage,
|
|
1348
1424
|
createMemoryStorage,
|
|
1349
1425
|
useLayoutWidth
|
|
1350
1426
|
};
|
|
1351
|
-
//# sourceMappingURL=chunk-
|
|
1427
|
+
//# sourceMappingURL=chunk-AT73Y7JA.js.map
|