react-email-studio 3.2.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +214 -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 +212 -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 DROP_HERE_HEIGHT_PX = 45;
|
|
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 : DROP_HERE_HEIGHT_PX,
|
|
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,44 @@ function Cell({
|
|
|
2816
2834
|
onDragLeave: handleDragLeave,
|
|
2817
2835
|
onDrop: handleDrop,
|
|
2818
2836
|
style: {
|
|
2819
|
-
|
|
2820
|
-
|
|
2837
|
+
display: "flex",
|
|
2838
|
+
flexDirection: "column",
|
|
2839
|
+
minHeight: preview ? void 0 : cellEmpty ? DROP_HERE_HEIGHT_PX : 44,
|
|
2821
2840
|
borderRadius: 4,
|
|
2822
|
-
...preview ? {} : insertAt !== null ? { border: `1px dotted ${C.accent}`, background: `${C.accent}0a` } :
|
|
2823
|
-
background: insertAt !== null ? `${C.accent}0a` : "transparent",
|
|
2841
|
+
...preview ? {} : insertAt !== null && !cellEmpty ? { border: `1px dotted ${C.accent}`, background: `${C.accent}0a` } : {},
|
|
2842
|
+
background: insertAt !== null && !cellEmpty ? `${C.accent}0a` : "transparent",
|
|
2824
2843
|
transition: "border-color .15s,background .15s",
|
|
2825
2844
|
padding: preview ? 0 : 0,
|
|
2826
2845
|
position: "relative"
|
|
2827
2846
|
},
|
|
2828
2847
|
children: [
|
|
2829
|
-
|
|
2848
|
+
cellEmpty && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2849
|
+
"div",
|
|
2850
|
+
{
|
|
2851
|
+
style: {
|
|
2852
|
+
height: DROP_HERE_HEIGHT_PX,
|
|
2853
|
+
minHeight: DROP_HERE_HEIGHT_PX,
|
|
2854
|
+
maxHeight: DROP_HERE_HEIGHT_PX,
|
|
2855
|
+
display: "flex",
|
|
2856
|
+
alignItems: "center",
|
|
2857
|
+
justifyContent: "center",
|
|
2858
|
+
margin: 0,
|
|
2859
|
+
borderRadius: 6,
|
|
2860
|
+
boxSizing: "border-box",
|
|
2861
|
+
textAlign: "center",
|
|
2862
|
+
userSelect: "none",
|
|
2863
|
+
transition: "color .15s, border-color .15s, background .15s, box-shadow .15s",
|
|
2864
|
+
border: insertAt !== null ? `2px dashed ${C.accent}` : `2px dashed ${C.border}`,
|
|
2865
|
+
background: insertAt !== null ? `${C.accent}14` : `${C.canvas}`,
|
|
2866
|
+
boxShadow: insertAt !== null ? `inset 0 0 0 1px ${C.accent}22` : `inset 0 0 0 1px ${C.border}99`,
|
|
2867
|
+
color: insertAt !== null ? C.accent2 : C.muted,
|
|
2868
|
+
fontSize: 10,
|
|
2869
|
+
fontWeight: insertAt !== null ? 700 : 500,
|
|
2870
|
+
letterSpacing: "0.02em"
|
|
2871
|
+
},
|
|
2872
|
+
children: insertAt !== null ? "Release to drop" : "Drop here"
|
|
2873
|
+
}
|
|
2874
|
+
),
|
|
2830
2875
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Line, { idx: 0 }),
|
|
2831
2876
|
blocks.map((cb, ci) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2832
2877
|
BlockItem,
|
|
@@ -2877,7 +2922,6 @@ function LayoutRow({
|
|
|
2877
2922
|
transition: "outline .12s",
|
|
2878
2923
|
padding: row.padding,
|
|
2879
2924
|
position: "relative",
|
|
2880
|
-
...editChromeBorder(C, preview),
|
|
2881
2925
|
...backgroundLayerStyle({
|
|
2882
2926
|
bgColor: row.bgColor,
|
|
2883
2927
|
bgImage: row.bgImage,
|
|
@@ -2916,8 +2960,9 @@ function LayoutRow({
|
|
|
2916
2960
|
id: editorId ? `${editorId}-col-${row.id}-${ci}` : void 0,
|
|
2917
2961
|
style: {
|
|
2918
2962
|
flex: row.ratios[ci] ?? 1,
|
|
2919
|
-
minHeight: 50,
|
|
2920
|
-
|
|
2963
|
+
minHeight: preview ? 50 : DROP_HERE_HEIGHT_PX,
|
|
2964
|
+
display: "flex",
|
|
2965
|
+
flexDirection: "column",
|
|
2921
2966
|
...backgroundLayerStyle(cS),
|
|
2922
2967
|
padding: paddingCssLayout(cS.padding),
|
|
2923
2968
|
borderRadius: radiusCssLayout(cS.borderRadius),
|
|
@@ -3091,13 +3136,13 @@ var FONTS = [
|
|
|
3091
3136
|
"Trebuchet MS,sans-serif",
|
|
3092
3137
|
"Impact,sans-serif"
|
|
3093
3138
|
];
|
|
3094
|
-
function paddingToCss(
|
|
3095
|
-
if (typeof
|
|
3096
|
-
if (
|
|
3097
|
-
const t = typeof
|
|
3098
|
-
const r = typeof
|
|
3099
|
-
const b = typeof
|
|
3100
|
-
const l = typeof
|
|
3139
|
+
function paddingToCss(pad3, fallback) {
|
|
3140
|
+
if (typeof pad3 === "number" && Number.isFinite(pad3)) return `${Math.max(0, pad3)}px`;
|
|
3141
|
+
if (pad3 && typeof pad3 === "object" && !Array.isArray(pad3)) {
|
|
3142
|
+
const t = typeof pad3.top === "number" && Number.isFinite(pad3.top) ? pad3.top : fallback;
|
|
3143
|
+
const r = typeof pad3.right === "number" && Number.isFinite(pad3.right) ? pad3.right : t;
|
|
3144
|
+
const b = typeof pad3.bottom === "number" && Number.isFinite(pad3.bottom) ? pad3.bottom : t;
|
|
3145
|
+
const l = typeof pad3.left === "number" && Number.isFinite(pad3.left) ? pad3.left : r;
|
|
3101
3146
|
return `${t}px ${r}px ${b}px ${l}px`;
|
|
3102
3147
|
}
|
|
3103
3148
|
return `${fallback}px`;
|
|
@@ -4893,7 +4938,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4893
4938
|
/* @__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
4939
|
/* @__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
4940
|
/* @__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: (
|
|
4941
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4897
4942
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4898
4943
|
] });
|
|
4899
4944
|
case "text":
|
|
@@ -4919,7 +4964,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4919
4964
|
/* @__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
4965
|
/* @__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
4966
|
/* @__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: (
|
|
4967
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4923
4968
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4924
4969
|
] });
|
|
4925
4970
|
case "html":
|
|
@@ -4944,7 +4989,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4944
4989
|
}
|
|
4945
4990
|
) }, block.id),
|
|
4946
4991
|
/* @__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: (
|
|
4992
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4948
4993
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4949
4994
|
] });
|
|
4950
4995
|
case "image":
|
|
@@ -4967,7 +5012,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4967
5012
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right"], C }),
|
|
4968
5013
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BorderRadiusEditor, { value: p.borderRadius, onChange: (br) => set("borderRadius", br), C }),
|
|
4969
5014
|
/* @__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: (
|
|
5015
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4971
5016
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4972
5017
|
] });
|
|
4973
5018
|
case "button":
|
|
@@ -4987,7 +5032,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
4987
5032
|
Sel("fontWeight", "Weight", ["400", "500", "600", "700", "800"]),
|
|
4988
5033
|
Tog("fullWidth", "Full Width"),
|
|
4989
5034
|
/* @__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: (
|
|
5035
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4991
5036
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4992
5037
|
] });
|
|
4993
5038
|
case "link":
|
|
@@ -5002,7 +5047,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5002
5047
|
Sel("fontFamily", "Font", FONTS2),
|
|
5003
5048
|
Tog("underline", "Underline"),
|
|
5004
5049
|
/* @__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: (
|
|
5050
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5006
5051
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5007
5052
|
] });
|
|
5008
5053
|
case "divider":
|
|
@@ -5011,14 +5056,14 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5011
5056
|
/* @__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
5057
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DividerStyleButtons, { value: p.style, onChange: (s) => set("style", s), C }),
|
|
5013
5058
|
/* @__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: (
|
|
5059
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5015
5060
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5016
5061
|
] });
|
|
5017
5062
|
case "spacer":
|
|
5018
5063
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5019
5064
|
/* @__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
5065
|
/* @__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: (
|
|
5066
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5022
5067
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5023
5068
|
] });
|
|
5024
5069
|
case "social":
|
|
@@ -5067,7 +5112,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5067
5112
|
Sel("shape", "Shape", ["circle", "square"]),
|
|
5068
5113
|
/* @__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
5114
|
/* @__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: (
|
|
5115
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5071
5116
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5072
5117
|
] });
|
|
5073
5118
|
case "video":
|
|
@@ -5127,7 +5172,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5127
5172
|
] }),
|
|
5128
5173
|
/* @__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
5174
|
/* @__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: (
|
|
5175
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5131
5176
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5132
5177
|
] });
|
|
5133
5178
|
case "menu":
|
|
@@ -5153,7 +5198,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5153
5198
|
/* @__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
5199
|
/* @__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
5200
|
/* @__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: (
|
|
5201
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5157
5202
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5158
5203
|
] });
|
|
5159
5204
|
case "timer": {
|
|
@@ -5193,7 +5238,7 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5193
5238
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right"], C }),
|
|
5194
5239
|
Tog("showLabels", "Show Labels"),
|
|
5195
5240
|
/* @__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: (
|
|
5241
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5197
5242
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5198
5243
|
] });
|
|
5199
5244
|
}
|
|
@@ -5290,8 +5335,8 @@ function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
|
5290
5335
|
Tog("striped", "Striped rows"),
|
|
5291
5336
|
/* @__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
5337
|
/* @__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: (
|
|
5338
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5339
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Cell padding", value: p.cellPadding, onChange: (pad3) => set("cellPadding", pad3), C }),
|
|
5295
5340
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5296
5341
|
] });
|
|
5297
5342
|
case "layout":
|
|
@@ -5684,7 +5729,7 @@ function LayoutRowEditor({
|
|
|
5684
5729
|
}
|
|
5685
5730
|
) })
|
|
5686
5731
|
] }) : null,
|
|
5687
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Column padding", value: (row.columnStyles || {})[selCol]?.padding, onChange: (
|
|
5732
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaddingEditor, { label: "Column padding", value: (row.columnStyles || {})[selCol]?.padding, onChange: (pad3) => updCol(selCol, { padding: pad3 }), C }),
|
|
5688
5733
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BorderRadiusEditor, { label: "Column radius", value: (row.columnStyles || {})[selCol]?.borderRadius, onChange: (br) => updCol(selCol, { borderRadius: br }), C })
|
|
5689
5734
|
] })
|
|
5690
5735
|
] })
|
|
@@ -5961,8 +6006,8 @@ function MobilePhoneScaleSlot({ variantKey, children }) {
|
|
|
5961
6006
|
const pw = phone.offsetWidth;
|
|
5962
6007
|
const ph = phone.offsetHeight;
|
|
5963
6008
|
if (cw < 12 || ch < 12 || pw < 12 || ph < 12) return;
|
|
5964
|
-
const
|
|
5965
|
-
const raw = Math.min(1, (cw -
|
|
6009
|
+
const pad3 = 20;
|
|
6010
|
+
const raw = Math.min(1, (cw - pad3) / pw, (ch - pad3) / ph);
|
|
5966
6011
|
const s = Number.isFinite(raw) ? Math.max(0.2, raw) : 1;
|
|
5967
6012
|
setFit({ s, w: pw * s, h: ph * s });
|
|
5968
6013
|
};
|
|
@@ -6832,6 +6877,43 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
6832
6877
|
}
|
|
6833
6878
|
}
|
|
6834
6879
|
};
|
|
6880
|
+
const insertBlockFromLibrary = (contentType) => {
|
|
6881
|
+
if (!rows.length) return;
|
|
6882
|
+
if (selContentMeta?.inner) {
|
|
6883
|
+
const { rowId, cellIdx, contentIdx, inner } = selContentMeta;
|
|
6884
|
+
dropContent(rowId, cellIdx, {
|
|
6885
|
+
kind: "new",
|
|
6886
|
+
contentType,
|
|
6887
|
+
insertAt: null,
|
|
6888
|
+
nested: { parentBlockIdx: contentIdx, innerCellIdx: inner.cellIdx }
|
|
6889
|
+
});
|
|
6890
|
+
return;
|
|
6891
|
+
}
|
|
6892
|
+
if (selContentMeta?.rowId && typeof selContentMeta.cellIdx === "number" && selContentMeta.cellIdx >= 0) {
|
|
6893
|
+
const r = rows.find((x) => x.id === selContentMeta.rowId);
|
|
6894
|
+
if (r && selContentMeta.cellIdx < r.cells.length) {
|
|
6895
|
+
dropContent(selContentMeta.rowId, selContentMeta.cellIdx, {
|
|
6896
|
+
kind: "new",
|
|
6897
|
+
contentType,
|
|
6898
|
+
insertAt: null
|
|
6899
|
+
});
|
|
6900
|
+
return;
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6903
|
+
if (selectedRowId) {
|
|
6904
|
+
const targetRow = rows.find((r) => r.id === selectedRowId);
|
|
6905
|
+
if (targetRow) {
|
|
6906
|
+
dropContent(targetRow.id, 0, {
|
|
6907
|
+
kind: "new",
|
|
6908
|
+
contentType,
|
|
6909
|
+
insertAt: null
|
|
6910
|
+
});
|
|
6911
|
+
return;
|
|
6912
|
+
}
|
|
6913
|
+
}
|
|
6914
|
+
const main = rows[0];
|
|
6915
|
+
dropContent(main.id, 0, { kind: "new", contentType, insertAt: null });
|
|
6916
|
+
};
|
|
6835
6917
|
const deleteContent = (rowId, cellIdx, ci, inner = null) => {
|
|
6836
6918
|
if (!inner) {
|
|
6837
6919
|
mutate((prev) => prev.map((r) => {
|
|
@@ -7428,6 +7510,8 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
7428
7510
|
if (data.layoutPresetKey) {
|
|
7429
7511
|
const preset = LAYOUT_PRESETS.find((p) => p.key === data.layoutPresetKey);
|
|
7430
7512
|
if (preset) mutate((prev) => [...prev, makeLayoutRow(preset)]);
|
|
7513
|
+
} else if (data.contentType && typeof data.contentType === "string") {
|
|
7514
|
+
insertBlockFromLibrary(data.contentType);
|
|
7431
7515
|
}
|
|
7432
7516
|
} catch {
|
|
7433
7517
|
}
|
|
@@ -7468,6 +7552,21 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
7468
7552
|
}
|
|
7469
7553
|
return base;
|
|
7470
7554
|
})(),
|
|
7555
|
+
onDragOver: (e) => {
|
|
7556
|
+
e.preventDefault();
|
|
7557
|
+
e.stopPropagation();
|
|
7558
|
+
},
|
|
7559
|
+
onDrop: (e) => {
|
|
7560
|
+
e.preventDefault();
|
|
7561
|
+
e.stopPropagation();
|
|
7562
|
+
try {
|
|
7563
|
+
const data = JSON.parse(e.dataTransfer.getData("application/json") || "{}");
|
|
7564
|
+
if (data.contentType && typeof data.contentType === "string") {
|
|
7565
|
+
insertBlockFromLibrary(data.contentType);
|
|
7566
|
+
}
|
|
7567
|
+
} catch {
|
|
7568
|
+
}
|
|
7569
|
+
},
|
|
7471
7570
|
children: [
|
|
7472
7571
|
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
7572
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 30, marginBottom: 10 }, children: "\u2709" }),
|
|
@@ -7679,43 +7778,7 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
7679
7778
|
onDragStart: (e) => {
|
|
7680
7779
|
e.dataTransfer.setData("application/json", JSON.stringify({ contentType: bt.type }));
|
|
7681
7780
|
},
|
|
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
|
-
},
|
|
7781
|
+
onClick: () => insertBlockFromLibrary(bt.type),
|
|
7719
7782
|
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
7783
|
style: {
|
|
7721
7784
|
display: "flex",
|
|
@@ -8086,12 +8149,80 @@ var ReactEmailEditor = (0, import_react8.forwardRef)(
|
|
|
8086
8149
|
);
|
|
8087
8150
|
}
|
|
8088
8151
|
);
|
|
8152
|
+
|
|
8153
|
+
// src/lib/htmlToEmailDesign.ts
|
|
8154
|
+
var pad = (n) => ({ top: n, right: n, bottom: n, left: n });
|
|
8155
|
+
function extractHtmlForDesign(html) {
|
|
8156
|
+
const t = String(html ?? "").trim();
|
|
8157
|
+
if (!t) return "";
|
|
8158
|
+
const head = t.slice(0, 800).toLowerCase();
|
|
8159
|
+
if (!head.includes("<html") && !head.includes("<!doctype")) {
|
|
8160
|
+
return normalizeRichHtmlForStorage(t);
|
|
8161
|
+
}
|
|
8162
|
+
try {
|
|
8163
|
+
const doc = new DOMParser().parseFromString(t, "text/html");
|
|
8164
|
+
const body = doc.body;
|
|
8165
|
+
if (!body) return normalizeRichHtmlForStorage(t);
|
|
8166
|
+
return normalizeRichHtmlForStorage(body.innerHTML);
|
|
8167
|
+
} catch {
|
|
8168
|
+
return normalizeRichHtmlForStorage(t);
|
|
8169
|
+
}
|
|
8170
|
+
}
|
|
8171
|
+
function htmlToEmailDesignTemplate(html) {
|
|
8172
|
+
const inner = extractHtmlForDesign(html);
|
|
8173
|
+
if (!inner) return null;
|
|
8174
|
+
const doc = {
|
|
8175
|
+
type: "email_document",
|
|
8176
|
+
settings: {
|
|
8177
|
+
width: 600,
|
|
8178
|
+
backgroundColor: "#f1f5f9",
|
|
8179
|
+
contentBackgroundColor: "#ffffff",
|
|
8180
|
+
fontFamily: "Arial, Helvetica, sans-serif",
|
|
8181
|
+
lineHeightBase: 1.6,
|
|
8182
|
+
color: "#111827",
|
|
8183
|
+
responsive: true,
|
|
8184
|
+
rtl: false
|
|
8185
|
+
},
|
|
8186
|
+
rows: [
|
|
8187
|
+
{
|
|
8188
|
+
id: "row_html_import",
|
|
8189
|
+
type: "row",
|
|
8190
|
+
layout: { columns: 1, gap: 0, stackOnMobile: true, align: "center" },
|
|
8191
|
+
styles: {
|
|
8192
|
+
backgroundColor: "#ffffff",
|
|
8193
|
+
backgroundRepeat: "no-repeat",
|
|
8194
|
+
backgroundSize: "cover",
|
|
8195
|
+
padding: pad(24),
|
|
8196
|
+
textAlign: "left"
|
|
8197
|
+
},
|
|
8198
|
+
columns: [
|
|
8199
|
+
{
|
|
8200
|
+
id: "col_html_import",
|
|
8201
|
+
layout: { width: "100%", verticalAlign: "top", mobileWidth: "100%" },
|
|
8202
|
+
styles: { padding: pad(0), backgroundColor: "" },
|
|
8203
|
+
blocks: [
|
|
8204
|
+
{
|
|
8205
|
+
id: "block_html_import",
|
|
8206
|
+
type: "html",
|
|
8207
|
+
content: { html: inner },
|
|
8208
|
+
styles: {}
|
|
8209
|
+
}
|
|
8210
|
+
]
|
|
8211
|
+
}
|
|
8212
|
+
]
|
|
8213
|
+
}
|
|
8214
|
+
]
|
|
8215
|
+
};
|
|
8216
|
+
return doc;
|
|
8217
|
+
}
|
|
8089
8218
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8090
8219
|
0 && (module.exports = {
|
|
8091
8220
|
EmailPreviewModal,
|
|
8092
8221
|
ReactEmailEditor,
|
|
8093
8222
|
base64ToUtf8,
|
|
8094
8223
|
emailPreviewDevices,
|
|
8224
|
+
extractHtmlForDesign,
|
|
8225
|
+
htmlToEmailDesignTemplate,
|
|
8095
8226
|
jsonToHtml,
|
|
8096
8227
|
utf8ToBase64
|
|
8097
8228
|
});
|