react-email-studio 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +213 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +211 -83
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,8 @@ __export(index_exports, {
|
|
|
34
34
|
ReactEmailEditor: () => ReactEmailEditor,
|
|
35
35
|
base64ToUtf8: () => base64ToUtf8,
|
|
36
36
|
emailPreviewDevices: () => DEVICES,
|
|
37
|
+
extractHtmlForDesign: () => extractHtmlForDesign,
|
|
38
|
+
htmlToEmailDesignTemplate: () => htmlToEmailDesignTemplate,
|
|
37
39
|
jsonToHtml: () => jsonToHtml,
|
|
38
40
|
utf8ToBase64: () => utf8ToBase64
|
|
39
41
|
});
|
|
@@ -168,7 +170,7 @@ var I18N = {
|
|
|
168
170
|
blockPaletteGroupActions: "Buttons & links",
|
|
169
171
|
blockPaletteGroupWidgets: "Widgets",
|
|
170
172
|
closePanel: "Close",
|
|
171
|
-
canvasEmptyHint: "Drag blocks from the library into
|
|
173
|
+
canvasEmptyHint: "Drag row layouts or blocks from the library. Drop blocks into a column or onto the mail preview area.",
|
|
172
174
|
emailContentSettings: "Email content",
|
|
173
175
|
loadingDesign: "Loading design\u2026"
|
|
174
176
|
},
|
|
@@ -1123,7 +1125,7 @@ function rowToHtml(row) {
|
|
|
1123
1125
|
const r = row.ratios[i] ?? 1;
|
|
1124
1126
|
const cs = row.columnStyles && row.columnStyles[i] ? row.columnStyles[i] : {};
|
|
1125
1127
|
const colShell = emailSurfaceBgCss(cs);
|
|
1126
|
-
const
|
|
1128
|
+
const pad3 = cs.padding && typeof cs.padding === "object" && !Array.isArray(cs.padding) ? `padding:${(() => {
|
|
1127
1129
|
const o = cs.padding;
|
|
1128
1130
|
const t = numOr2(o.top, 0);
|
|
1129
1131
|
const rgt = numOr2(o.right, t);
|
|
@@ -1139,7 +1141,7 @@ function rowToHtml(row) {
|
|
|
1139
1141
|
const bl = numOr2(x.bl, tr2);
|
|
1140
1142
|
return `border-radius:${tl}px ${tr2}px ${br}px ${bl}px;`;
|
|
1141
1143
|
})() : typeof cs.borderRadius === "number" && Number.isFinite(cs.borderRadius) ? `border-radius:${cs.borderRadius}px;` : "";
|
|
1142
|
-
return `<div style="flex:${r} 1 0;min-width:0;box-sizing:border-box;${
|
|
1144
|
+
return `<div style="flex:${r} 1 0;min-width:0;box-sizing:border-box;${pad3}${rad}${colShell}">${cell.map(blockToHtml).join("")}</div>`;
|
|
1143
1145
|
}).join("")}</div>`;
|
|
1144
1146
|
const innerTrim = inner.replace(/>\s+</g, "><").trim();
|
|
1145
1147
|
const body = innerTrim || " ";
|
|
@@ -1359,8 +1361,8 @@ function layoutColumnBorderRadiusForDoc(r) {
|
|
|
1359
1361
|
}
|
|
1360
1362
|
return 0;
|
|
1361
1363
|
}
|
|
1362
|
-
function columnPaddingNonZero(
|
|
1363
|
-
return
|
|
1364
|
+
function columnPaddingNonZero(pad3) {
|
|
1365
|
+
return pad3.top !== 0 || pad3.right !== 0 || pad3.bottom !== 0 || pad3.left !== 0;
|
|
1364
1366
|
}
|
|
1365
1367
|
function columnRadiusNonZero(r) {
|
|
1366
1368
|
if (typeof r === "number") return r !== 0;
|
|
@@ -1717,9 +1719,9 @@ function mapBlockToInternal(b, layoutDepth = 0) {
|
|
|
1717
1719
|
if (asNum(s.fontWeight) != null) block.props.fontWeight = s.fontWeight;
|
|
1718
1720
|
if (asNum(s.borderRadius) != null) block.props.borderRadius = s.borderRadius;
|
|
1719
1721
|
if (s.padding && typeof s.padding === "object") {
|
|
1720
|
-
const
|
|
1721
|
-
block.props.paddingV = asNum(
|
|
1722
|
-
block.props.paddingH = asNum(
|
|
1722
|
+
const pad3 = s.padding;
|
|
1723
|
+
block.props.paddingV = asNum(pad3.top) ?? block.props.paddingV;
|
|
1724
|
+
block.props.paddingH = asNum(pad3.right) ?? block.props.paddingH;
|
|
1723
1725
|
}
|
|
1724
1726
|
if (asStr(s.textAlign)) block.props.align = s.textAlign;
|
|
1725
1727
|
break;
|
|
@@ -2234,9 +2236,15 @@ function useLiveCountdown(endDate) {
|
|
|
2234
2236
|
const s = Math.floor(diff % 6e4 / 1e3);
|
|
2235
2237
|
return [d, h, m, s];
|
|
2236
2238
|
}
|
|
2237
|
-
function
|
|
2238
|
-
return {};
|
|
2239
|
+
function layoutSplitChromeBorder(_C, preview) {
|
|
2240
|
+
if (preview) return {};
|
|
2241
|
+
return {
|
|
2242
|
+
border: "1px dotted rgba(148, 163, 184, 0.5)",
|
|
2243
|
+
boxSizing: "border-box"
|
|
2244
|
+
};
|
|
2239
2245
|
}
|
|
2246
|
+
var CONTENT_BLOCK_HOVER_BORDER = "1px dotted rgba(148, 163, 184, 0.5)";
|
|
2247
|
+
var EMPTY_CELL_COLUMN_MIN_H = "min(320px, 42vh)";
|
|
2240
2248
|
function blockLinkCaptureHandler(preview, e) {
|
|
2241
2249
|
if (preview) return;
|
|
2242
2250
|
const t = e.target;
|
|
@@ -2268,6 +2276,7 @@ function radiusCssLayout(v) {
|
|
|
2268
2276
|
return "0px";
|
|
2269
2277
|
}
|
|
2270
2278
|
function ContentBlock({ block, selected, onClick, preview, C }) {
|
|
2279
|
+
const [hover, setHover] = (0, import_react.useState)(false);
|
|
2271
2280
|
const { type, props: p } = block;
|
|
2272
2281
|
const numOr2 = (v, fb) => typeof v === "number" && Number.isFinite(v) ? v : fb;
|
|
2273
2282
|
const boxPx = (v) => {
|
|
@@ -2311,14 +2320,19 @@ function ContentBlock({ block, selected, onClick, preview, C }) {
|
|
|
2311
2320
|
onClick: preview ? void 0 : onClick || void 0,
|
|
2312
2321
|
onClickCapture: (e) => blockLinkCaptureHandler(preview, e),
|
|
2313
2322
|
onAuxClickCapture: (e) => blockLinkCaptureHandler(preview, e),
|
|
2323
|
+
onMouseEnter: preview ? void 0 : () => setHover(true),
|
|
2324
|
+
onMouseLeave: preview ? void 0 : () => setHover(false),
|
|
2314
2325
|
style: {
|
|
2315
2326
|
cursor: preview ? "default" : onClick ? "pointer" : "default",
|
|
2316
2327
|
outline: selected && !preview ? `2px solid ${C.accent}` : "2px solid transparent",
|
|
2317
2328
|
outlineOffset: 1,
|
|
2318
2329
|
borderRadius: 3,
|
|
2319
|
-
transition: "outline .12s",
|
|
2330
|
+
transition: "outline .12s, border-color .12s",
|
|
2320
2331
|
position: "relative",
|
|
2321
|
-
...
|
|
2332
|
+
...preview ? {} : {
|
|
2333
|
+
border: hover ? CONTENT_BLOCK_HOVER_BORDER : "1px solid transparent",
|
|
2334
|
+
boxSizing: "border-box"
|
|
2335
|
+
},
|
|
2322
2336
|
...shellBg,
|
|
2323
2337
|
padding: paddingCss(p.padding),
|
|
2324
2338
|
margin: marginCss(p.margin)
|
|
@@ -2558,7 +2572,7 @@ function NestedRowBlock({
|
|
|
2558
2572
|
outline: rowSelected ? `2px solid ${C.accent}` : "2px solid transparent",
|
|
2559
2573
|
outlineOffset: 1,
|
|
2560
2574
|
transition: "outline .12s",
|
|
2561
|
-
...
|
|
2575
|
+
...layoutSplitChromeBorder(C, preview),
|
|
2562
2576
|
...backgroundLayerStyle({
|
|
2563
2577
|
bgColor: p.bgColor,
|
|
2564
2578
|
bgImage: p.bgImage,
|
|
@@ -2590,7 +2604,10 @@ function NestedRowBlock({
|
|
|
2590
2604
|
style: {
|
|
2591
2605
|
flex: p.ratios?.[ici] ?? 1,
|
|
2592
2606
|
minWidth: 0,
|
|
2593
|
-
|
|
2607
|
+
minHeight: preview ? void 0 : EMPTY_CELL_COLUMN_MIN_H,
|
|
2608
|
+
display: "flex",
|
|
2609
|
+
flexDirection: "column",
|
|
2610
|
+
...layoutSplitChromeBorder(C, preview),
|
|
2594
2611
|
...backgroundLayerStyle(cS),
|
|
2595
2612
|
padding: paddingCssLayout(cS.padding),
|
|
2596
2613
|
borderRadius: radiusCssLayout(cS.borderRadius),
|
|
@@ -2807,6 +2824,7 @@ function Cell({
|
|
|
2807
2824
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { position: "absolute", left: -4, top: "50%", transform: "translateY(-50%)", width: 8, height: 8, borderRadius: "50%", background: C.accent } }),
|
|
2808
2825
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { position: "absolute", right: -4, top: "50%", transform: "translateY(-50%)", width: 8, height: 8, borderRadius: "50%", background: C.accent } })
|
|
2809
2826
|
] }) : null;
|
|
2827
|
+
const cellEmpty = !preview && blocks.length === 0;
|
|
2810
2828
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2811
2829
|
"div",
|
|
2812
2830
|
{
|
|
@@ -2816,17 +2834,43 @@ function Cell({
|
|
|
2816
2834
|
onDragLeave: handleDragLeave,
|
|
2817
2835
|
onDrop: handleDrop,
|
|
2818
2836
|
style: {
|
|
2819
|
-
flex: 1,
|
|
2820
|
-
|
|
2837
|
+
flex: cellEmpty ? 1 : void 0,
|
|
2838
|
+
display: "flex",
|
|
2839
|
+
flexDirection: "column",
|
|
2840
|
+
minHeight: preview ? void 0 : cellEmpty ? 0 : 44,
|
|
2821
2841
|
borderRadius: 4,
|
|
2822
|
-
...preview ? {} : insertAt !== null ? { border: `1px dotted ${C.accent}`, background: `${C.accent}0a` } :
|
|
2823
|
-
background: insertAt !== null ? `${C.accent}0a` : "transparent",
|
|
2842
|
+
...preview ? {} : insertAt !== null && !cellEmpty ? { border: `1px dotted ${C.accent}`, background: `${C.accent}0a` } : {},
|
|
2843
|
+
background: insertAt !== null && !cellEmpty ? `${C.accent}0a` : "transparent",
|
|
2824
2844
|
transition: "border-color .15s,background .15s",
|
|
2825
2845
|
padding: preview ? 0 : 0,
|
|
2826
2846
|
position: "relative"
|
|
2827
2847
|
},
|
|
2828
2848
|
children: [
|
|
2829
|
-
|
|
2849
|
+
cellEmpty && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2850
|
+
"div",
|
|
2851
|
+
{
|
|
2852
|
+
style: {
|
|
2853
|
+
flex: 1,
|
|
2854
|
+
display: "flex",
|
|
2855
|
+
alignItems: "center",
|
|
2856
|
+
justifyContent: "center",
|
|
2857
|
+
margin: 4,
|
|
2858
|
+
borderRadius: 8,
|
|
2859
|
+
boxSizing: "border-box",
|
|
2860
|
+
textAlign: "center",
|
|
2861
|
+
userSelect: "none",
|
|
2862
|
+
transition: "color .15s, border-color .15s, background .15s, box-shadow .15s",
|
|
2863
|
+
border: insertAt !== null ? `2px dashed ${C.accent}` : `2px dashed ${C.border}`,
|
|
2864
|
+
background: insertAt !== null ? `${C.accent}14` : `${C.canvas}`,
|
|
2865
|
+
boxShadow: insertAt !== null ? `inset 0 0 0 1px ${C.accent}22` : `inset 0 0 0 1px ${C.border}99`,
|
|
2866
|
+
color: insertAt !== null ? C.accent2 : C.muted,
|
|
2867
|
+
fontSize: 11,
|
|
2868
|
+
fontWeight: insertAt !== null ? 700 : 500,
|
|
2869
|
+
letterSpacing: "0.02em"
|
|
2870
|
+
},
|
|
2871
|
+
children: insertAt !== null ? "Release to drop" : "Drop here"
|
|
2872
|
+
}
|
|
2873
|
+
),
|
|
2830
2874
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { idx: 0 }),
|
|
2831
2875
|
blocks.map((cb, ci) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2832
2876
|
BlockItem,
|
|
@@ -2877,7 +2921,6 @@ function LayoutRow({
|
|
|
2877
2921
|
transition: "outline .12s",
|
|
2878
2922
|
padding: row.padding,
|
|
2879
2923
|
position: "relative",
|
|
2880
|
-
...editChromeBorder(C, preview),
|
|
2881
2924
|
...backgroundLayerStyle({
|
|
2882
2925
|
bgColor: row.bgColor,
|
|
2883
2926
|
bgImage: row.bgImage,
|
|
@@ -2916,8 +2959,9 @@ function LayoutRow({
|
|
|
2916
2959
|
id: editorId ? `${editorId}-col-${row.id}-${ci}` : void 0,
|
|
2917
2960
|
style: {
|
|
2918
2961
|
flex: row.ratios[ci] ?? 1,
|
|
2919
|
-
minHeight: 50,
|
|
2920
|
-
|
|
2962
|
+
minHeight: preview ? 50 : EMPTY_CELL_COLUMN_MIN_H,
|
|
2963
|
+
display: "flex",
|
|
2964
|
+
flexDirection: "column",
|
|
2921
2965
|
...backgroundLayerStyle(cS),
|
|
2922
2966
|
padding: paddingCssLayout(cS.padding),
|
|
2923
2967
|
borderRadius: radiusCssLayout(cS.borderRadius),
|
|
@@ -3091,13 +3135,13 @@ var FONTS = [
|
|
|
3091
3135
|
"Trebuchet MS,sans-serif",
|
|
3092
3136
|
"Impact,sans-serif"
|
|
3093
3137
|
];
|
|
3094
|
-
function paddingToCss(
|
|
3095
|
-
if (typeof
|
|
3096
|
-
if (
|
|
3097
|
-
const t = typeof
|
|
3098
|
-
const r = typeof
|
|
3099
|
-
const b = typeof
|
|
3100
|
-
const l = typeof
|
|
3138
|
+
function paddingToCss(pad3, fallback) {
|
|
3139
|
+
if (typeof pad3 === "number" && Number.isFinite(pad3)) return `${Math.max(0, pad3)}px`;
|
|
3140
|
+
if (pad3 && typeof pad3 === "object" && !Array.isArray(pad3)) {
|
|
3141
|
+
const t = typeof pad3.top === "number" && Number.isFinite(pad3.top) ? pad3.top : fallback;
|
|
3142
|
+
const r = typeof pad3.right === "number" && Number.isFinite(pad3.right) ? pad3.right : t;
|
|
3143
|
+
const b = typeof pad3.bottom === "number" && Number.isFinite(pad3.bottom) ? pad3.bottom : t;
|
|
3144
|
+
const l = typeof pad3.left === "number" && Number.isFinite(pad3.left) ? pad3.left : r;
|
|
3101
3145
|
return `${t}px ${r}px ${b}px ${l}px`;
|
|
3102
3146
|
}
|
|
3103
3147
|
return `${fallback}px`;
|
|
@@ -4893,7 +4937,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4893
4937
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Letter spacing", value: p.letterSpacing ?? 0, onChange: (n) => set("letterSpacing", n), min: 0, max: 30, step: 0.5, C }),
|
|
4894
4938
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PR, { label: "Line height", C, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "number", style: useIS(C).IS, min: 0.8, max: 4, step: 0.05, value: p.lineHeight ?? 1.2, onChange: (e) => set("lineHeight", +e.target.value) }) }),
|
|
4895
4939
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4896
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
4940
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4897
4941
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4898
4942
|
] });
|
|
4899
4943
|
case "text":
|
|
@@ -4919,7 +4963,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4919
4963
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PR, { label: "Line height", C, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "number", style: useIS(C).IS, min: 1, max: 4, step: 0.05, value: p.lineHeight ?? 1.65, onChange: (e) => set("lineHeight", +e.target.value) }) }),
|
|
4920
4964
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Letter spacing", value: p.letterSpacing ?? 0, onChange: (n) => set("letterSpacing", n), min: 0, max: 30, step: 0.5, C }),
|
|
4921
4965
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4922
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
4966
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4923
4967
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4924
4968
|
] });
|
|
4925
4969
|
case "html":
|
|
@@ -4944,7 +4988,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4944
4988
|
}
|
|
4945
4989
|
) }, block.id),
|
|
4946
4990
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4947
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
4991
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4948
4992
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4949
4993
|
] });
|
|
4950
4994
|
case "image":
|
|
@@ -4967,7 +5011,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4967
5011
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right"], C }),
|
|
4968
5012
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BorderRadiusEditor, { value: p.borderRadius, onChange: (br) => set("borderRadius", br), C }),
|
|
4969
5013
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4970
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5014
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4971
5015
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4972
5016
|
] });
|
|
4973
5017
|
case "button":
|
|
@@ -4987,7 +5031,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4987
5031
|
Sel("fontWeight", "Weight", ["400", "500", "600", "700", "800"]),
|
|
4988
5032
|
Tog("fullWidth", "Full Width"),
|
|
4989
5033
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "backdrop", p, set, C, onUpload, syncKey: block.id }),
|
|
4990
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5034
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4991
5035
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4992
5036
|
] });
|
|
4993
5037
|
case "link":
|
|
@@ -5002,7 +5046,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5002
5046
|
Sel("fontFamily", "Font", FONTS2),
|
|
5003
5047
|
Tog("underline", "Underline"),
|
|
5004
5048
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5005
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5049
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5006
5050
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5007
5051
|
] });
|
|
5008
5052
|
case "divider":
|
|
@@ -5011,14 +5055,14 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5011
5055
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Thickness", value: p.thickness ?? 1, onChange: (n) => set("thickness", n), min: 1, max: 20, step: 1, C }),
|
|
5012
5056
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DividerStyleButtons, { value: p.style, onChange: (s) => set("style", s), C }),
|
|
5013
5057
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5014
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5058
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5015
5059
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5016
5060
|
] });
|
|
5017
5061
|
case "spacer":
|
|
5018
5062
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5019
5063
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Height", value: p.height ?? 24, onChange: (n) => set("height", n), min: 4, max: 300, step: 1, C }),
|
|
5020
5064
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5021
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5065
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5022
5066
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5023
5067
|
] });
|
|
5024
5068
|
case "social":
|
|
@@ -5067,7 +5111,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5067
5111
|
Sel("shape", "Shape", ["circle", "square"]),
|
|
5068
5112
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Gap", value: p.gap ?? 6, onChange: (n) => set("gap", n), min: 0, max: 40, step: 1, C }),
|
|
5069
5113
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5070
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5114
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5071
5115
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5072
5116
|
] });
|
|
5073
5117
|
case "video":
|
|
@@ -5127,7 +5171,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5127
5171
|
] }),
|
|
5128
5172
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Height", value: p.height ?? 280, onChange: (n) => set("height", n), min: 80, max: 720, step: 1, C }),
|
|
5129
5173
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5130
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5174
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5131
5175
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5132
5176
|
] });
|
|
5133
5177
|
case "menu":
|
|
@@ -5153,7 +5197,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5153
5197
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Font size", value: p.fontSize ?? 14, onChange: (n) => set("fontSize", n), min: 8, max: 48, step: 1, C }),
|
|
5154
5198
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Item gap", value: p.gap ?? 20, onChange: (n) => set("gap", n), min: 0, max: 80, step: 1, C }),
|
|
5155
5199
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5156
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5200
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5157
5201
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5158
5202
|
] });
|
|
5159
5203
|
case "timer": {
|
|
@@ -5193,7 +5237,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5193
5237
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right"], C }),
|
|
5194
5238
|
Tog("showLabels", "Show Labels"),
|
|
5195
5239
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "backdrop", p, set, C, onUpload, syncKey: block.id }),
|
|
5196
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5240
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5197
5241
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5198
5242
|
] });
|
|
5199
5243
|
}
|
|
@@ -5290,8 +5334,8 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5290
5334
|
Tog("striped", "Striped rows"),
|
|
5291
5335
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NumRangePx, { label: "Font size", value: p.fontSize ?? 13, onChange: (n) => set("fontSize", n), min: 10, max: 24, step: 1, C }),
|
|
5292
5336
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5293
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (
|
|
5294
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Cell padding", value: p.cellPadding, onChange: (
|
|
5337
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5338
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Cell padding", value: p.cellPadding, onChange: (pad3) => set("cellPadding", pad3), C }),
|
|
5295
5339
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5296
5340
|
] });
|
|
5297
5341
|
case "layout":
|
|
@@ -5684,7 +5728,7 @@ function LayoutRowEditor({
|
|
|
5684
5728
|
}
|
|
5685
5729
|
) })
|
|
5686
5730
|
] }) : null,
|
|
5687
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Column padding", value: (row.columnStyles || {})[selCol]?.padding, onChange: (
|
|
5731
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Column padding", value: (row.columnStyles || {})[selCol]?.padding, onChange: (pad3) => updCol(selCol, { padding: pad3 }), C }),
|
|
5688
5732
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BorderRadiusEditor, { label: "Column radius", value: (row.columnStyles || {})[selCol]?.borderRadius, onChange: (br) => updCol(selCol, { borderRadius: br }), C })
|
|
5689
5733
|
] })
|
|
5690
5734
|
] })
|
|
@@ -5961,8 +6005,8 @@ function MobilePhoneScaleSlot({ variantKey, children }) {
|
|
|
5961
6005
|
const pw = phone.offsetWidth;
|
|
5962
6006
|
const ph = phone.offsetHeight;
|
|
5963
6007
|
if (cw < 12 || ch < 12 || pw < 12 || ph < 12) return;
|
|
5964
|
-
const
|
|
5965
|
-
const raw = Math.min(1, (cw -
|
|
6008
|
+
const pad3 = 20;
|
|
6009
|
+
const raw = Math.min(1, (cw - pad3) / pw, (ch - pad3) / ph);
|
|
5966
6010
|
const s = Number.isFinite(raw) ? Math.max(0.2, raw) : 1;
|
|
5967
6011
|
setFit({ s, w: pw * s, h: ph * s });
|
|
5968
6012
|
};
|
|
@@ -6832,6 +6876,43 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
6832
6876
|
}
|
|
6833
6877
|
}
|
|
6834
6878
|
};
|
|
6879
|
+
const insertBlockFromLibrary = (contentType) => {
|
|
6880
|
+
if (!rows.length) return;
|
|
6881
|
+
if (selContentMeta?.inner) {
|
|
6882
|
+
const { rowId, cellIdx, contentIdx, inner } = selContentMeta;
|
|
6883
|
+
dropContent(rowId, cellIdx, {
|
|
6884
|
+
kind: "new",
|
|
6885
|
+
contentType,
|
|
6886
|
+
insertAt: null,
|
|
6887
|
+
nested: { parentBlockIdx: contentIdx, innerCellIdx: inner.cellIdx }
|
|
6888
|
+
});
|
|
6889
|
+
return;
|
|
6890
|
+
}
|
|
6891
|
+
if (selContentMeta?.rowId && typeof selContentMeta.cellIdx === "number" && selContentMeta.cellIdx >= 0) {
|
|
6892
|
+
const r = rows.find((x) => x.id === selContentMeta.rowId);
|
|
6893
|
+
if (r && selContentMeta.cellIdx < r.cells.length) {
|
|
6894
|
+
dropContent(selContentMeta.rowId, selContentMeta.cellIdx, {
|
|
6895
|
+
kind: "new",
|
|
6896
|
+
contentType,
|
|
6897
|
+
insertAt: null
|
|
6898
|
+
});
|
|
6899
|
+
return;
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
if (selectedRowId) {
|
|
6903
|
+
const targetRow = rows.find((r) => r.id === selectedRowId);
|
|
6904
|
+
if (targetRow) {
|
|
6905
|
+
dropContent(targetRow.id, 0, {
|
|
6906
|
+
kind: "new",
|
|
6907
|
+
contentType,
|
|
6908
|
+
insertAt: null
|
|
6909
|
+
});
|
|
6910
|
+
return;
|
|
6911
|
+
}
|
|
6912
|
+
}
|
|
6913
|
+
const main = rows[0];
|
|
6914
|
+
dropContent(main.id, 0, { kind: "new", contentType, insertAt: null });
|
|
6915
|
+
};
|
|
6835
6916
|
const deleteContent = (rowId, cellIdx, ci, inner = null) => {
|
|
6836
6917
|
if (!inner) {
|
|
6837
6918
|
mutate((prev) => prev.map((r) => {
|
|
@@ -7428,6 +7509,8 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
7428
7509
|
if (data.layoutPresetKey) {
|
|
7429
7510
|
const preset = LAYOUT_PRESETS.find((p) => p.key === data.layoutPresetKey);
|
|
7430
7511
|
if (preset) mutate((prev) => [...prev, makeLayoutRow(preset)]);
|
|
7512
|
+
} else if (data.contentType && typeof data.contentType === "string") {
|
|
7513
|
+
insertBlockFromLibrary(data.contentType);
|
|
7431
7514
|
}
|
|
7432
7515
|
} catch {
|
|
7433
7516
|
}
|
|
@@ -7468,6 +7551,21 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
7468
7551
|
}
|
|
7469
7552
|
return base;
|
|
7470
7553
|
})(),
|
|
7554
|
+
onDragOver: (e) => {
|
|
7555
|
+
e.preventDefault();
|
|
7556
|
+
e.stopPropagation();
|
|
7557
|
+
},
|
|
7558
|
+
onDrop: (e) => {
|
|
7559
|
+
e.preventDefault();
|
|
7560
|
+
e.stopPropagation();
|
|
7561
|
+
try {
|
|
7562
|
+
const data = JSON.parse(e.dataTransfer.getData("application/json") || "{}");
|
|
7563
|
+
if (data.contentType && typeof data.contentType === "string") {
|
|
7564
|
+
insertBlockFromLibrary(data.contentType);
|
|
7565
|
+
}
|
|
7566
|
+
} catch {
|
|
7567
|
+
}
|
|
7568
|
+
},
|
|
7471
7569
|
children: [
|
|
7472
7570
|
rows.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { id: eid("canvas-empty"), style: { padding: "56px 20px", textAlign: "center", color: C.muted, border: `2px dashed ${C.border}`, borderRadius: 7 }, children: [
|
|
7473
7571
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 30, marginBottom: 10 }, children: "\u2709" }),
|
|
@@ -7679,43 +7777,7 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
7679
7777
|
onDragStart: (e) => {
|
|
7680
7778
|
e.dataTransfer.setData("application/json", JSON.stringify({ contentType: bt.type }));
|
|
7681
7779
|
},
|
|
7682
|
-
onClick: () =>
|
|
7683
|
-
if (!rows.length) return;
|
|
7684
|
-
if (selContentMeta?.inner) {
|
|
7685
|
-
const { rowId, cellIdx, contentIdx, inner } = selContentMeta;
|
|
7686
|
-
dropContent(rowId, cellIdx, {
|
|
7687
|
-
kind: "new",
|
|
7688
|
-
contentType: bt.type,
|
|
7689
|
-
insertAt: null,
|
|
7690
|
-
nested: { parentBlockIdx: contentIdx, innerCellIdx: inner.cellIdx }
|
|
7691
|
-
});
|
|
7692
|
-
return;
|
|
7693
|
-
}
|
|
7694
|
-
if (selContentMeta?.rowId && typeof selContentMeta.cellIdx === "number" && selContentMeta.cellIdx >= 0) {
|
|
7695
|
-
const r = rows.find((x) => x.id === selContentMeta.rowId);
|
|
7696
|
-
if (r && selContentMeta.cellIdx < r.cells.length) {
|
|
7697
|
-
dropContent(selContentMeta.rowId, selContentMeta.cellIdx, {
|
|
7698
|
-
kind: "new",
|
|
7699
|
-
contentType: bt.type,
|
|
7700
|
-
insertAt: null
|
|
7701
|
-
});
|
|
7702
|
-
return;
|
|
7703
|
-
}
|
|
7704
|
-
}
|
|
7705
|
-
if (selectedRowId) {
|
|
7706
|
-
const targetRow = rows.find((r) => r.id === selectedRowId);
|
|
7707
|
-
if (targetRow) {
|
|
7708
|
-
dropContent(targetRow.id, 0, {
|
|
7709
|
-
kind: "new",
|
|
7710
|
-
contentType: bt.type,
|
|
7711
|
-
insertAt: null
|
|
7712
|
-
});
|
|
7713
|
-
return;
|
|
7714
|
-
}
|
|
7715
|
-
}
|
|
7716
|
-
const main = rows[0];
|
|
7717
|
-
dropContent(main.id, 0, { kind: "new", contentType: bt.type, insertAt: null });
|
|
7718
|
-
},
|
|
7780
|
+
onClick: () => insertBlockFromLibrary(bt.type),
|
|
7719
7781
|
title: selContentMeta?.inner ? "Click to add inside the selected nested column" : selContentMeta?.rowId ? "Click to add in the selected column" : selectedRowId ? "Click to add to column 1 of the selected row" : "Click to add to the first row, first column",
|
|
7720
7782
|
style: {
|
|
7721
7783
|
display: "flex",
|
|
@@ -8086,12 +8148,80 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
8086
8148
|
);
|
|
8087
8149
|
}
|
|
8088
8150
|
);
|
|
8151
|
+
|
|
8152
|
+
// src/lib/htmlToEmailDesign.ts
|
|
8153
|
+
var pad = (n) => ({ top: n, right: n, bottom: n, left: n });
|
|
8154
|
+
function extractHtmlForDesign(html) {
|
|
8155
|
+
const t = String(html ?? "").trim();
|
|
8156
|
+
if (!t) return "";
|
|
8157
|
+
const head = t.slice(0, 800).toLowerCase();
|
|
8158
|
+
if (!head.includes("<html") && !head.includes("<!doctype")) {
|
|
8159
|
+
return normalizeRichHtmlForStorage(t);
|
|
8160
|
+
}
|
|
8161
|
+
try {
|
|
8162
|
+
const doc = new DOMParser().parseFromString(t, "text/html");
|
|
8163
|
+
const body = doc.body;
|
|
8164
|
+
if (!body) return normalizeRichHtmlForStorage(t);
|
|
8165
|
+
return normalizeRichHtmlForStorage(body.innerHTML);
|
|
8166
|
+
} catch {
|
|
8167
|
+
return normalizeRichHtmlForStorage(t);
|
|
8168
|
+
}
|
|
8169
|
+
}
|
|
8170
|
+
function htmlToEmailDesignTemplate(html) {
|
|
8171
|
+
const inner = extractHtmlForDesign(html);
|
|
8172
|
+
if (!inner) return null;
|
|
8173
|
+
const doc = {
|
|
8174
|
+
type: "email_document",
|
|
8175
|
+
settings: {
|
|
8176
|
+
width: 600,
|
|
8177
|
+
backgroundColor: "#f1f5f9",
|
|
8178
|
+
contentBackgroundColor: "#ffffff",
|
|
8179
|
+
fontFamily: "Arial, Helvetica, sans-serif",
|
|
8180
|
+
lineHeightBase: 1.6,
|
|
8181
|
+
color: "#111827",
|
|
8182
|
+
responsive: true,
|
|
8183
|
+
rtl: false
|
|
8184
|
+
},
|
|
8185
|
+
rows: [
|
|
8186
|
+
{
|
|
8187
|
+
id: "row_html_import",
|
|
8188
|
+
type: "row",
|
|
8189
|
+
layout: { columns: 1, gap: 0, stackOnMobile: true, align: "center" },
|
|
8190
|
+
styles: {
|
|
8191
|
+
backgroundColor: "#ffffff",
|
|
8192
|
+
backgroundRepeat: "no-repeat",
|
|
8193
|
+
backgroundSize: "cover",
|
|
8194
|
+
padding: pad(24),
|
|
8195
|
+
textAlign: "left"
|
|
8196
|
+
},
|
|
8197
|
+
columns: [
|
|
8198
|
+
{
|
|
8199
|
+
id: "col_html_import",
|
|
8200
|
+
layout: { width: "100%", verticalAlign: "top", mobileWidth: "100%" },
|
|
8201
|
+
styles: { padding: pad(0), backgroundColor: "" },
|
|
8202
|
+
blocks: [
|
|
8203
|
+
{
|
|
8204
|
+
id: "block_html_import",
|
|
8205
|
+
type: "html",
|
|
8206
|
+
content: { html: inner },
|
|
8207
|
+
styles: {}
|
|
8208
|
+
}
|
|
8209
|
+
]
|
|
8210
|
+
}
|
|
8211
|
+
]
|
|
8212
|
+
}
|
|
8213
|
+
]
|
|
8214
|
+
};
|
|
8215
|
+
return doc;
|
|
8216
|
+
}
|
|
8089
8217
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8090
8218
|
0 && (module.exports = {
|
|
8091
8219
|
EmailPreviewModal,
|
|
8092
8220
|
ReactEmailEditor,
|
|
8093
8221
|
base64ToUtf8,
|
|
8094
8222
|
emailPreviewDevices,
|
|
8223
|
+
extractHtmlForDesign,
|
|
8224
|
+
htmlToEmailDesignTemplate,
|
|
8095
8225
|
jsonToHtml,
|
|
8096
8226
|
utf8ToBase64
|
|
8097
8227
|
});
|