react-email-studio 3.1.1 → 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/CHANGELOG.md +27 -0
- package/README.md +5 -1
- package/TUTORIAL.md +1 -2
- package/dist/index.cjs +278 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +282 -158
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
useRef as useRef6,
|
|
5
5
|
useEffect as useEffect6,
|
|
6
6
|
useCallback as useCallback2,
|
|
7
|
-
useMemo as
|
|
7
|
+
useMemo as useMemo3,
|
|
8
8
|
forwardRef,
|
|
9
9
|
useImperativeHandle,
|
|
10
10
|
Fragment as Fragment6
|
|
@@ -120,7 +120,6 @@ var I18N = {
|
|
|
120
120
|
delete: "Delete",
|
|
121
121
|
moveUp: "Move Up",
|
|
122
122
|
moveDown: "Move Down",
|
|
123
|
-
mergeTags: "Merge Tags",
|
|
124
123
|
autoSaved: "Auto-saved",
|
|
125
124
|
search: "Search blocks\u2026",
|
|
126
125
|
zoomIn: "Zoom In",
|
|
@@ -137,7 +136,7 @@ var I18N = {
|
|
|
137
136
|
blockPaletteGroupActions: "Buttons & links",
|
|
138
137
|
blockPaletteGroupWidgets: "Widgets",
|
|
139
138
|
closePanel: "Close",
|
|
140
|
-
canvasEmptyHint: "Drag blocks from the library into
|
|
139
|
+
canvasEmptyHint: "Drag row layouts or blocks from the library. Drop blocks into a column or onto the mail preview area.",
|
|
141
140
|
emailContentSettings: "Email content",
|
|
142
141
|
loadingDesign: "Loading design\u2026"
|
|
143
142
|
},
|
|
@@ -179,7 +178,6 @@ var I18N = {
|
|
|
179
178
|
delete: "Supprimer",
|
|
180
179
|
moveUp: "Monter",
|
|
181
180
|
moveDown: "Descendre",
|
|
182
|
-
mergeTags: "Balises fusion",
|
|
183
181
|
autoSaved: "Auto-sauvegard\xE9",
|
|
184
182
|
search: "Rechercher\u2026",
|
|
185
183
|
colorScheme: "Sch\xE9ma de couleurs",
|
|
@@ -239,7 +237,6 @@ var I18N = {
|
|
|
239
237
|
delete: "L\xF6schen",
|
|
240
238
|
moveUp: "Nach oben",
|
|
241
239
|
moveDown: "Nach unten",
|
|
242
|
-
mergeTags: "Merge-Tags",
|
|
243
240
|
autoSaved: "Auto-gespeichert",
|
|
244
241
|
search: "Bl\xF6cke suchen\u2026",
|
|
245
242
|
colorScheme: "Farbschema",
|
|
@@ -297,7 +294,6 @@ var I18N = {
|
|
|
297
294
|
delete: "Eliminar",
|
|
298
295
|
moveUp: "Subir",
|
|
299
296
|
moveDown: "Bajar",
|
|
300
|
-
mergeTags: "Etiquetas de fusi\xF3n",
|
|
301
297
|
autoSaved: "Auto-guardado",
|
|
302
298
|
search: "Buscar bloques\u2026",
|
|
303
299
|
zoomIn: "Zoom +",
|
|
@@ -1095,7 +1091,7 @@ function rowToHtml(row) {
|
|
|
1095
1091
|
const r = row.ratios[i] ?? 1;
|
|
1096
1092
|
const cs = row.columnStyles && row.columnStyles[i] ? row.columnStyles[i] : {};
|
|
1097
1093
|
const colShell = emailSurfaceBgCss(cs);
|
|
1098
|
-
const
|
|
1094
|
+
const pad3 = cs.padding && typeof cs.padding === "object" && !Array.isArray(cs.padding) ? `padding:${(() => {
|
|
1099
1095
|
const o = cs.padding;
|
|
1100
1096
|
const t = numOr2(o.top, 0);
|
|
1101
1097
|
const rgt = numOr2(o.right, t);
|
|
@@ -1111,7 +1107,7 @@ function rowToHtml(row) {
|
|
|
1111
1107
|
const bl = numOr2(x.bl, tr2);
|
|
1112
1108
|
return `border-radius:${tl}px ${tr2}px ${br}px ${bl}px;`;
|
|
1113
1109
|
})() : typeof cs.borderRadius === "number" && Number.isFinite(cs.borderRadius) ? `border-radius:${cs.borderRadius}px;` : "";
|
|
1114
|
-
return `<div style="flex:${r} 1 0;min-width:0;box-sizing:border-box;${
|
|
1110
|
+
return `<div style="flex:${r} 1 0;min-width:0;box-sizing:border-box;${pad3}${rad}${colShell}">${cell.map(blockToHtml).join("")}</div>`;
|
|
1115
1111
|
}).join("")}</div>`;
|
|
1116
1112
|
const innerTrim = inner.replace(/>\s+</g, "><").trim();
|
|
1117
1113
|
const body = innerTrim || " ";
|
|
@@ -1331,8 +1327,8 @@ function layoutColumnBorderRadiusForDoc(r) {
|
|
|
1331
1327
|
}
|
|
1332
1328
|
return 0;
|
|
1333
1329
|
}
|
|
1334
|
-
function columnPaddingNonZero(
|
|
1335
|
-
return
|
|
1330
|
+
function columnPaddingNonZero(pad3) {
|
|
1331
|
+
return pad3.top !== 0 || pad3.right !== 0 || pad3.bottom !== 0 || pad3.left !== 0;
|
|
1336
1332
|
}
|
|
1337
1333
|
function columnRadiusNonZero(r) {
|
|
1338
1334
|
if (typeof r === "number") return r !== 0;
|
|
@@ -1689,9 +1685,9 @@ function mapBlockToInternal(b, layoutDepth = 0) {
|
|
|
1689
1685
|
if (asNum(s.fontWeight) != null) block.props.fontWeight = s.fontWeight;
|
|
1690
1686
|
if (asNum(s.borderRadius) != null) block.props.borderRadius = s.borderRadius;
|
|
1691
1687
|
if (s.padding && typeof s.padding === "object") {
|
|
1692
|
-
const
|
|
1693
|
-
block.props.paddingV = asNum(
|
|
1694
|
-
block.props.paddingH = asNum(
|
|
1688
|
+
const pad3 = s.padding;
|
|
1689
|
+
block.props.paddingV = asNum(pad3.top) ?? block.props.paddingV;
|
|
1690
|
+
block.props.paddingH = asNum(pad3.right) ?? block.props.paddingH;
|
|
1695
1691
|
}
|
|
1696
1692
|
if (asStr(s.textAlign)) block.props.align = s.textAlign;
|
|
1697
1693
|
break;
|
|
@@ -2206,10 +2202,15 @@ function useLiveCountdown(endDate) {
|
|
|
2206
2202
|
const s = Math.floor(diff % 6e4 / 1e3);
|
|
2207
2203
|
return [d, h, m, s];
|
|
2208
2204
|
}
|
|
2209
|
-
function
|
|
2205
|
+
function layoutSplitChromeBorder(_C, preview) {
|
|
2210
2206
|
if (preview) return {};
|
|
2211
|
-
return {
|
|
2207
|
+
return {
|
|
2208
|
+
border: "1px dotted rgba(148, 163, 184, 0.5)",
|
|
2209
|
+
boxSizing: "border-box"
|
|
2210
|
+
};
|
|
2212
2211
|
}
|
|
2212
|
+
var CONTENT_BLOCK_HOVER_BORDER = "1px dotted rgba(148, 163, 184, 0.5)";
|
|
2213
|
+
var EMPTY_CELL_COLUMN_MIN_H = "min(320px, 42vh)";
|
|
2213
2214
|
function blockLinkCaptureHandler(preview, e) {
|
|
2214
2215
|
if (preview) return;
|
|
2215
2216
|
const t = e.target;
|
|
@@ -2241,6 +2242,7 @@ function radiusCssLayout(v) {
|
|
|
2241
2242
|
return "0px";
|
|
2242
2243
|
}
|
|
2243
2244
|
function ContentBlock({ block, selected, onClick, preview, C }) {
|
|
2245
|
+
const [hover, setHover] = useState(false);
|
|
2244
2246
|
const { type, props: p } = block;
|
|
2245
2247
|
const numOr2 = (v, fb) => typeof v === "number" && Number.isFinite(v) ? v : fb;
|
|
2246
2248
|
const boxPx = (v) => {
|
|
@@ -2284,14 +2286,19 @@ function ContentBlock({ block, selected, onClick, preview, C }) {
|
|
|
2284
2286
|
onClick: preview ? void 0 : onClick || void 0,
|
|
2285
2287
|
onClickCapture: (e) => blockLinkCaptureHandler(preview, e),
|
|
2286
2288
|
onAuxClickCapture: (e) => blockLinkCaptureHandler(preview, e),
|
|
2289
|
+
onMouseEnter: preview ? void 0 : () => setHover(true),
|
|
2290
|
+
onMouseLeave: preview ? void 0 : () => setHover(false),
|
|
2287
2291
|
style: {
|
|
2288
2292
|
cursor: preview ? "default" : onClick ? "pointer" : "default",
|
|
2289
2293
|
outline: selected && !preview ? `2px solid ${C.accent}` : "2px solid transparent",
|
|
2290
2294
|
outlineOffset: 1,
|
|
2291
2295
|
borderRadius: 3,
|
|
2292
|
-
transition: "outline .12s",
|
|
2296
|
+
transition: "outline .12s, border-color .12s",
|
|
2293
2297
|
position: "relative",
|
|
2294
|
-
...
|
|
2298
|
+
...preview ? {} : {
|
|
2299
|
+
border: hover ? CONTENT_BLOCK_HOVER_BORDER : "1px solid transparent",
|
|
2300
|
+
boxSizing: "border-box"
|
|
2301
|
+
},
|
|
2295
2302
|
...shellBg,
|
|
2296
2303
|
padding: paddingCss(p.padding),
|
|
2297
2304
|
margin: marginCss(p.margin)
|
|
@@ -2510,6 +2517,8 @@ function NestedRowBlock({
|
|
|
2510
2517
|
rowId,
|
|
2511
2518
|
cellIdx,
|
|
2512
2519
|
parentBlockIdx,
|
|
2520
|
+
/** When this layout sits inside another layout column, meta uses `contentIdx` + `inner` like other nested blocks. */
|
|
2521
|
+
selectionInner,
|
|
2513
2522
|
editorId,
|
|
2514
2523
|
selectedKey,
|
|
2515
2524
|
selContentMeta,
|
|
@@ -2521,7 +2530,7 @@ function NestedRowBlock({
|
|
|
2521
2530
|
C
|
|
2522
2531
|
}) {
|
|
2523
2532
|
const p = block.props;
|
|
2524
|
-
const rowSelected = !preview && selContentMeta && selContentMeta.rowId === rowId && selContentMeta.cellIdx === cellIdx && selContentMeta.contentIdx === parentBlockIdx && !selContentMeta.inner &&
|
|
2533
|
+
const rowSelected = !preview && selContentMeta && selContentMeta.rowId === rowId && selContentMeta.cellIdx === cellIdx && selectedKey === block.id && (selectionInner == null ? selContentMeta.contentIdx === parentBlockIdx && !selContentMeta.inner : selContentMeta.contentIdx === parentBlockIdx && selContentMeta.inner && selContentMeta.inner.cellIdx === selectionInner.cellIdx && selContentMeta.inner.contentIdx === selectionInner.contentIdx);
|
|
2525
2534
|
const rowStyle = {
|
|
2526
2535
|
padding: p.padding ?? 8,
|
|
2527
2536
|
position: "relative",
|
|
@@ -2529,7 +2538,7 @@ function NestedRowBlock({
|
|
|
2529
2538
|
outline: rowSelected ? `2px solid ${C.accent}` : "2px solid transparent",
|
|
2530
2539
|
outlineOffset: 1,
|
|
2531
2540
|
transition: "outline .12s",
|
|
2532
|
-
...
|
|
2541
|
+
...layoutSplitChromeBorder(C, preview),
|
|
2533
2542
|
...backgroundLayerStyle({
|
|
2534
2543
|
bgColor: p.bgColor,
|
|
2535
2544
|
bgImage: p.bgImage,
|
|
@@ -2545,7 +2554,13 @@ function NestedRowBlock({
|
|
|
2545
2554
|
style: rowStyle,
|
|
2546
2555
|
onClick: preview ? void 0 : (e) => {
|
|
2547
2556
|
e.stopPropagation();
|
|
2548
|
-
onSelectContent(
|
|
2557
|
+
onSelectContent(
|
|
2558
|
+
block.id,
|
|
2559
|
+
rowId,
|
|
2560
|
+
cellIdx,
|
|
2561
|
+
parentBlockIdx,
|
|
2562
|
+
selectionInner ?? null
|
|
2563
|
+
);
|
|
2549
2564
|
},
|
|
2550
2565
|
children: /* @__PURE__ */ jsx3("div", { style: { display: "flex", gap: p.gap ?? 12 }, children: (p.cells || []).map((innerBlocks, ici) => {
|
|
2551
2566
|
const cS = p.columnStyles && p.columnStyles[ici] || {};
|
|
@@ -2555,7 +2570,10 @@ function NestedRowBlock({
|
|
|
2555
2570
|
style: {
|
|
2556
2571
|
flex: p.ratios?.[ici] ?? 1,
|
|
2557
2572
|
minWidth: 0,
|
|
2558
|
-
|
|
2573
|
+
minHeight: preview ? void 0 : EMPTY_CELL_COLUMN_MIN_H,
|
|
2574
|
+
display: "flex",
|
|
2575
|
+
flexDirection: "column",
|
|
2576
|
+
...layoutSplitChromeBorder(C, preview),
|
|
2559
2577
|
...backgroundLayerStyle(cS),
|
|
2560
2578
|
padding: paddingCssLayout(cS.padding),
|
|
2561
2579
|
borderRadius: radiusCssLayout(cS.borderRadius),
|
|
@@ -2611,7 +2629,13 @@ function BlockItem({
|
|
|
2611
2629
|
if (!onSelectContent) return;
|
|
2612
2630
|
e.stopPropagation();
|
|
2613
2631
|
if (isSplitLayoutBlock(cb)) {
|
|
2614
|
-
onSelectContent(
|
|
2632
|
+
onSelectContent(
|
|
2633
|
+
cb.id,
|
|
2634
|
+
rowId,
|
|
2635
|
+
cellIdx,
|
|
2636
|
+
nest ? nest.parentBlockIdx : ci,
|
|
2637
|
+
nest ? { cellIdx: innerCellIdx, contentIdx: ci } : null
|
|
2638
|
+
);
|
|
2615
2639
|
} else {
|
|
2616
2640
|
onSelectContent(
|
|
2617
2641
|
cb.id,
|
|
@@ -2682,6 +2706,7 @@ function BlockItem({
|
|
|
2682
2706
|
rowId,
|
|
2683
2707
|
cellIdx,
|
|
2684
2708
|
parentBlockIdx: nest ? nest.parentBlockIdx : ci,
|
|
2709
|
+
selectionInner: nest ? { cellIdx: innerCellIdx, contentIdx: ci } : null,
|
|
2685
2710
|
editorId,
|
|
2686
2711
|
selectedKey,
|
|
2687
2712
|
selContentMeta,
|
|
@@ -2765,6 +2790,7 @@ function Cell({
|
|
|
2765
2790
|
/* @__PURE__ */ jsx3("div", { style: { position: "absolute", left: -4, top: "50%", transform: "translateY(-50%)", width: 8, height: 8, borderRadius: "50%", background: C.accent } }),
|
|
2766
2791
|
/* @__PURE__ */ jsx3("div", { style: { position: "absolute", right: -4, top: "50%", transform: "translateY(-50%)", width: 8, height: 8, borderRadius: "50%", background: C.accent } })
|
|
2767
2792
|
] }) : null;
|
|
2793
|
+
const cellEmpty = !preview && blocks.length === 0;
|
|
2768
2794
|
return /* @__PURE__ */ jsxs2(
|
|
2769
2795
|
"div",
|
|
2770
2796
|
{
|
|
@@ -2774,17 +2800,43 @@ function Cell({
|
|
|
2774
2800
|
onDragLeave: handleDragLeave,
|
|
2775
2801
|
onDrop: handleDrop,
|
|
2776
2802
|
style: {
|
|
2777
|
-
flex: 1,
|
|
2778
|
-
|
|
2803
|
+
flex: cellEmpty ? 1 : void 0,
|
|
2804
|
+
display: "flex",
|
|
2805
|
+
flexDirection: "column",
|
|
2806
|
+
minHeight: preview ? void 0 : cellEmpty ? 0 : 44,
|
|
2779
2807
|
borderRadius: 4,
|
|
2780
|
-
...preview ? {} : insertAt !== null ? { border: `1px dotted ${C.accent}`, background: `${C.accent}0a` } :
|
|
2781
|
-
background: insertAt !== null ? `${C.accent}0a` : "transparent",
|
|
2808
|
+
...preview ? {} : insertAt !== null && !cellEmpty ? { border: `1px dotted ${C.accent}`, background: `${C.accent}0a` } : {},
|
|
2809
|
+
background: insertAt !== null && !cellEmpty ? `${C.accent}0a` : "transparent",
|
|
2782
2810
|
transition: "border-color .15s,background .15s",
|
|
2783
2811
|
padding: preview ? 0 : 0,
|
|
2784
2812
|
position: "relative"
|
|
2785
2813
|
},
|
|
2786
2814
|
children: [
|
|
2787
|
-
|
|
2815
|
+
cellEmpty && /* @__PURE__ */ jsx3(
|
|
2816
|
+
"div",
|
|
2817
|
+
{
|
|
2818
|
+
style: {
|
|
2819
|
+
flex: 1,
|
|
2820
|
+
display: "flex",
|
|
2821
|
+
alignItems: "center",
|
|
2822
|
+
justifyContent: "center",
|
|
2823
|
+
margin: 4,
|
|
2824
|
+
borderRadius: 8,
|
|
2825
|
+
boxSizing: "border-box",
|
|
2826
|
+
textAlign: "center",
|
|
2827
|
+
userSelect: "none",
|
|
2828
|
+
transition: "color .15s, border-color .15s, background .15s, box-shadow .15s",
|
|
2829
|
+
border: insertAt !== null ? `2px dashed ${C.accent}` : `2px dashed ${C.border}`,
|
|
2830
|
+
background: insertAt !== null ? `${C.accent}14` : `${C.canvas}`,
|
|
2831
|
+
boxShadow: insertAt !== null ? `inset 0 0 0 1px ${C.accent}22` : `inset 0 0 0 1px ${C.border}99`,
|
|
2832
|
+
color: insertAt !== null ? C.accent2 : C.muted,
|
|
2833
|
+
fontSize: 11,
|
|
2834
|
+
fontWeight: insertAt !== null ? 700 : 500,
|
|
2835
|
+
letterSpacing: "0.02em"
|
|
2836
|
+
},
|
|
2837
|
+
children: insertAt !== null ? "Release to drop" : "Drop here"
|
|
2838
|
+
}
|
|
2839
|
+
),
|
|
2788
2840
|
/* @__PURE__ */ jsx3(Line, { idx: 0 }),
|
|
2789
2841
|
blocks.map((cb, ci) => /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsx3(
|
|
2790
2842
|
BlockItem,
|
|
@@ -2835,7 +2887,6 @@ function LayoutRow({
|
|
|
2835
2887
|
transition: "outline .12s",
|
|
2836
2888
|
padding: row.padding,
|
|
2837
2889
|
position: "relative",
|
|
2838
|
-
...editChromeBorder(C, preview),
|
|
2839
2890
|
...backgroundLayerStyle({
|
|
2840
2891
|
bgColor: row.bgColor,
|
|
2841
2892
|
bgImage: row.bgImage,
|
|
@@ -2874,8 +2925,9 @@ function LayoutRow({
|
|
|
2874
2925
|
id: editorId ? `${editorId}-col-${row.id}-${ci}` : void 0,
|
|
2875
2926
|
style: {
|
|
2876
2927
|
flex: row.ratios[ci] ?? 1,
|
|
2877
|
-
minHeight: 50,
|
|
2878
|
-
|
|
2928
|
+
minHeight: preview ? 50 : EMPTY_CELL_COLUMN_MIN_H,
|
|
2929
|
+
display: "flex",
|
|
2930
|
+
flexDirection: "column",
|
|
2879
2931
|
...backgroundLayerStyle(cS),
|
|
2880
2932
|
padding: paddingCssLayout(cS.padding),
|
|
2881
2933
|
borderRadius: radiusCssLayout(cS.borderRadius),
|
|
@@ -2989,7 +3041,7 @@ var CanvasRow = ({
|
|
|
2989
3041
|
import { Image as ImageIcon2, Repeat as RepeatIcon, Scaling as Scaling2, Crosshair as Crosshair2, Blend as GradientIcon2, Droplets as ColorIcon } from "lucide-react";
|
|
2990
3042
|
|
|
2991
3043
|
// src/editor/properties/PropertyEditors.tsx
|
|
2992
|
-
import { useRef as useRef2, useState as useState3, useEffect as useEffect3, Fragment as Fragment3 } from "react";
|
|
3044
|
+
import { useRef as useRef2, useState as useState3, useEffect as useEffect3, useMemo, Fragment as Fragment3 } from "react";
|
|
2993
3045
|
import {
|
|
2994
3046
|
AlignCenter as AlignCenter2,
|
|
2995
3047
|
AlignJustify as AlignJustify2,
|
|
@@ -3090,13 +3142,13 @@ var FONTS = [
|
|
|
3090
3142
|
"Trebuchet MS,sans-serif",
|
|
3091
3143
|
"Impact,sans-serif"
|
|
3092
3144
|
];
|
|
3093
|
-
function paddingToCss(
|
|
3094
|
-
if (typeof
|
|
3095
|
-
if (
|
|
3096
|
-
const t = typeof
|
|
3097
|
-
const r = typeof
|
|
3098
|
-
const b = typeof
|
|
3099
|
-
const l = typeof
|
|
3145
|
+
function paddingToCss(pad3, fallback) {
|
|
3146
|
+
if (typeof pad3 === "number" && Number.isFinite(pad3)) return `${Math.max(0, pad3)}px`;
|
|
3147
|
+
if (pad3 && typeof pad3 === "object" && !Array.isArray(pad3)) {
|
|
3148
|
+
const t = typeof pad3.top === "number" && Number.isFinite(pad3.top) ? pad3.top : fallback;
|
|
3149
|
+
const r = typeof pad3.right === "number" && Number.isFinite(pad3.right) ? pad3.right : t;
|
|
3150
|
+
const b = typeof pad3.bottom === "number" && Number.isFinite(pad3.bottom) ? pad3.bottom : t;
|
|
3151
|
+
const l = typeof pad3.left === "number" && Number.isFinite(pad3.left) ? pad3.left : r;
|
|
3100
3152
|
return `${t}px ${r}px ${b}px ${l}px`;
|
|
3101
3153
|
}
|
|
3102
3154
|
return `${fallback}px`;
|
|
@@ -3310,11 +3362,8 @@ function ToolbarTypographyControls({ editor, C }) {
|
|
|
3310
3362
|
}
|
|
3311
3363
|
function FormattingToolbar({
|
|
3312
3364
|
editor,
|
|
3313
|
-
C
|
|
3314
|
-
mergeTags,
|
|
3315
|
-
onMergeTagInsert
|
|
3365
|
+
C
|
|
3316
3366
|
}) {
|
|
3317
|
-
const [mergeSel, setMergeSel] = useState2("");
|
|
3318
3367
|
const [linkPanelOpen, setLinkPanelOpen] = useState2(false);
|
|
3319
3368
|
const [linkUrlValue, setLinkUrlValue] = useState2("");
|
|
3320
3369
|
const ibtn = (active) => toolbarIconBtn(C, active);
|
|
@@ -3634,8 +3683,6 @@ function TextRichEditor({
|
|
|
3634
3683
|
value,
|
|
3635
3684
|
onChange,
|
|
3636
3685
|
typography,
|
|
3637
|
-
mergeTags,
|
|
3638
|
-
onMergeTagInsert,
|
|
3639
3686
|
placeholder = "Write your message\u2026",
|
|
3640
3687
|
headerTitle = "Rich editor",
|
|
3641
3688
|
C
|
|
@@ -3779,15 +3826,7 @@ function TextRichEditor({
|
|
|
3779
3826
|
]
|
|
3780
3827
|
}
|
|
3781
3828
|
),
|
|
3782
|
-
/* @__PURE__ */ jsx4(
|
|
3783
|
-
FormattingToolbar,
|
|
3784
|
-
{
|
|
3785
|
-
editor,
|
|
3786
|
-
C,
|
|
3787
|
-
mergeTags,
|
|
3788
|
-
onMergeTagInsert
|
|
3789
|
-
}
|
|
3790
|
-
),
|
|
3829
|
+
/* @__PURE__ */ jsx4(FormattingToolbar, { editor, C }),
|
|
3791
3830
|
/* @__PURE__ */ jsx4("style", { children: proseStyle }),
|
|
3792
3831
|
/* @__PURE__ */ jsx4(
|
|
3793
3832
|
"div",
|
|
@@ -3838,15 +3877,7 @@ function TextRichEditor({
|
|
|
3838
3877
|
background: C.inputBg
|
|
3839
3878
|
},
|
|
3840
3879
|
children: [
|
|
3841
|
-
/* @__PURE__ */ jsx4(
|
|
3842
|
-
FormattingToolbar,
|
|
3843
|
-
{
|
|
3844
|
-
editor,
|
|
3845
|
-
C,
|
|
3846
|
-
mergeTags,
|
|
3847
|
-
onMergeTagInsert
|
|
3848
|
-
}
|
|
3849
|
-
),
|
|
3880
|
+
/* @__PURE__ */ jsx4(FormattingToolbar, { editor, C }),
|
|
3850
3881
|
/* @__PURE__ */ jsx4("style", { children: proseStyle }),
|
|
3851
3882
|
/* @__PURE__ */ jsx4(
|
|
3852
3883
|
"div",
|
|
@@ -4846,7 +4877,7 @@ function BlockSurfaceBgInspector({
|
|
|
4846
4877
|
] }) : null
|
|
4847
4878
|
] });
|
|
4848
4879
|
}
|
|
4849
|
-
function ContentBlockEditor({ block, onChange,
|
|
4880
|
+
function ContentBlockEditor({ block, onChange, onClose, onUpload, C }) {
|
|
4850
4881
|
const { IS, CI } = useIS(C);
|
|
4851
4882
|
const imageFileRef = useRef2(null);
|
|
4852
4883
|
const p = block.props;
|
|
@@ -4865,7 +4896,6 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
4865
4896
|
/* @__PURE__ */ jsx6("input", { type: "checkbox", checked: !!p[k], onChange: (e) => set(k, e.target.checked), style: { width: 15, height: 15, accentColor: C.accent } }),
|
|
4866
4897
|
/* @__PURE__ */ jsx6("span", { style: { color: C.muted, fontSize: 12 }, children: p[k] ? "On" : "Off" })
|
|
4867
4898
|
] }) });
|
|
4868
|
-
const TagPicker = (_field) => null;
|
|
4869
4899
|
const FONTS2 = ["Georgia,serif", "Arial,sans-serif", "Verdana,sans-serif", "'Courier New',monospace", "Trebuchet MS,sans-serif", "Impact,sans-serif"];
|
|
4870
4900
|
const ImgUpload = (key) => {
|
|
4871
4901
|
if (!onUpload) return null;
|
|
@@ -4914,12 +4944,12 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
4914
4944
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Letter spacing", value: p.letterSpacing ?? 0, onChange: (n) => set("letterSpacing", n), min: 0, max: 30, step: 0.5, C }),
|
|
4915
4945
|
/* @__PURE__ */ jsx6(PR, { label: "Line height", C, children: /* @__PURE__ */ jsx6("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) }) }),
|
|
4916
4946
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4917
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
4947
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4918
4948
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4919
4949
|
] });
|
|
4920
4950
|
case "text":
|
|
4921
4951
|
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
4922
|
-
/* @__PURE__ */ jsx6(PR, { label: "Content
|
|
4952
|
+
/* @__PURE__ */ jsx6(PR, { label: "Content", C, children: /* @__PURE__ */ jsx6(
|
|
4923
4953
|
"textarea",
|
|
4924
4954
|
{
|
|
4925
4955
|
style: { ...IS, minHeight: 200, resize: "vertical", fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace", fontSize: 12, lineHeight: 1.45 },
|
|
@@ -4930,24 +4960,6 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
4930
4960
|
},
|
|
4931
4961
|
block.id
|
|
4932
4962
|
) }),
|
|
4933
|
-
mergeTags && mergeTags.length > 0 ? /* @__PURE__ */ jsx6(PR, { label: "Insert merge tag", C, children: /* @__PURE__ */ jsxs4(
|
|
4934
|
-
"select",
|
|
4935
|
-
{
|
|
4936
|
-
style: IS,
|
|
4937
|
-
defaultValue: "",
|
|
4938
|
-
onChange: (e) => {
|
|
4939
|
-
const v = e.target.value;
|
|
4940
|
-
if (v) {
|
|
4941
|
-
set("content", normalizeRichHtmlForStorage((p.content || "") + " " + v));
|
|
4942
|
-
e.target.value = "";
|
|
4943
|
-
}
|
|
4944
|
-
},
|
|
4945
|
-
children: [
|
|
4946
|
-
/* @__PURE__ */ jsx6("option", { value: "", children: "Choose\u2026" }),
|
|
4947
|
-
mergeTags.map((t) => /* @__PURE__ */ jsx6("option", { value: t.value, children: t.name }, t.name))
|
|
4948
|
-
]
|
|
4949
|
-
}
|
|
4950
|
-
) }) : null,
|
|
4951
4963
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Font size", value: p.fontSize ?? 15, onChange: (n) => set("fontSize", n), min: 8, max: 96, step: 1, C }),
|
|
4952
4964
|
Col("color", "Color"),
|
|
4953
4965
|
/* @__PURE__ */ jsx6(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right", "justify"], C }),
|
|
@@ -4958,7 +4970,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
4958
4970
|
/* @__PURE__ */ jsx6(PR, { label: "Line height", C, children: /* @__PURE__ */ jsx6("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) }) }),
|
|
4959
4971
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Letter spacing", value: p.letterSpacing ?? 0, onChange: (n) => set("letterSpacing", n), min: 0, max: 30, step: 0.5, C }),
|
|
4960
4972
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4961
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
4973
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4962
4974
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4963
4975
|
] });
|
|
4964
4976
|
case "html":
|
|
@@ -4977,15 +4989,13 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
4977
4989
|
letterSpacing: p.letterSpacing,
|
|
4978
4990
|
padding: p.padding
|
|
4979
4991
|
},
|
|
4980
|
-
mergeTags,
|
|
4981
|
-
onMergeTagInsert: (tag) => set("content", (p.content || "") + " " + tag),
|
|
4982
4992
|
placeholder: "Write your rich content\u2026",
|
|
4983
4993
|
headerTitle: "Rich editor",
|
|
4984
4994
|
C
|
|
4985
4995
|
}
|
|
4986
4996
|
) }, block.id),
|
|
4987
4997
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
4988
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
4998
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
4989
4999
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
4990
5000
|
] });
|
|
4991
5001
|
case "image":
|
|
@@ -5008,7 +5018,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5008
5018
|
/* @__PURE__ */ jsx6(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right"], C }),
|
|
5009
5019
|
/* @__PURE__ */ jsx6(BorderRadiusEditor, { value: p.borderRadius, onChange: (br) => set("borderRadius", br), C }),
|
|
5010
5020
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5011
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5021
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5012
5022
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5013
5023
|
] });
|
|
5014
5024
|
case "button":
|
|
@@ -5028,7 +5038,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5028
5038
|
Sel("fontWeight", "Weight", ["400", "500", "600", "700", "800"]),
|
|
5029
5039
|
Tog("fullWidth", "Full Width"),
|
|
5030
5040
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "backdrop", p, set, C, onUpload, syncKey: block.id }),
|
|
5031
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5041
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5032
5042
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5033
5043
|
] });
|
|
5034
5044
|
case "link":
|
|
@@ -5043,7 +5053,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5043
5053
|
Sel("fontFamily", "Font", FONTS2),
|
|
5044
5054
|
Tog("underline", "Underline"),
|
|
5045
5055
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5046
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5056
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5047
5057
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5048
5058
|
] });
|
|
5049
5059
|
case "divider":
|
|
@@ -5052,14 +5062,14 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5052
5062
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Thickness", value: p.thickness ?? 1, onChange: (n) => set("thickness", n), min: 1, max: 20, step: 1, C }),
|
|
5053
5063
|
/* @__PURE__ */ jsx6(DividerStyleButtons, { value: p.style, onChange: (s) => set("style", s), C }),
|
|
5054
5064
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5055
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5065
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5056
5066
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5057
5067
|
] });
|
|
5058
5068
|
case "spacer":
|
|
5059
5069
|
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
5060
5070
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Height", value: p.height ?? 24, onChange: (n) => set("height", n), min: 4, max: 300, step: 1, C }),
|
|
5061
5071
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5062
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5072
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5063
5073
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5064
5074
|
] });
|
|
5065
5075
|
case "social":
|
|
@@ -5108,7 +5118,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5108
5118
|
Sel("shape", "Shape", ["circle", "square"]),
|
|
5109
5119
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Gap", value: p.gap ?? 6, onChange: (n) => set("gap", n), min: 0, max: 40, step: 1, C }),
|
|
5110
5120
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5111
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5121
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5112
5122
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5113
5123
|
] });
|
|
5114
5124
|
case "video":
|
|
@@ -5168,7 +5178,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5168
5178
|
] }),
|
|
5169
5179
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Height", value: p.height ?? 280, onChange: (n) => set("height", n), min: 80, max: 720, step: 1, C }),
|
|
5170
5180
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5171
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5181
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5172
5182
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5173
5183
|
] });
|
|
5174
5184
|
case "menu":
|
|
@@ -5194,7 +5204,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5194
5204
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Font size", value: p.fontSize ?? 14, onChange: (n) => set("fontSize", n), min: 8, max: 48, step: 1, C }),
|
|
5195
5205
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Item gap", value: p.gap ?? 20, onChange: (n) => set("gap", n), min: 0, max: 80, step: 1, C }),
|
|
5196
5206
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5197
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5207
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5198
5208
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5199
5209
|
] });
|
|
5200
5210
|
case "timer": {
|
|
@@ -5234,7 +5244,7 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5234
5244
|
/* @__PURE__ */ jsx6(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right"], C }),
|
|
5235
5245
|
Tog("showLabels", "Show Labels"),
|
|
5236
5246
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "backdrop", p, set, C, onUpload, syncKey: block.id }),
|
|
5237
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5247
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5238
5248
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5239
5249
|
] });
|
|
5240
5250
|
}
|
|
@@ -5331,8 +5341,8 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5331
5341
|
Tog("striped", "Striped rows"),
|
|
5332
5342
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Font size", value: p.fontSize ?? 13, onChange: (n) => set("fontSize", n), min: 10, max: 24, step: 1, C }),
|
|
5333
5343
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
5334
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (
|
|
5335
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { label: "Cell padding", value: p.cellPadding, onChange: (
|
|
5344
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { value: p.padding, onChange: (pad3) => set("padding", pad3), C }),
|
|
5345
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { label: "Cell padding", value: p.cellPadding, onChange: (pad3) => set("cellPadding", pad3), C }),
|
|
5336
5346
|
/* @__PURE__ */ jsx6(MarginEditor, { value: p.margin, onChange: (m) => set("margin", m), C })
|
|
5337
5347
|
] });
|
|
5338
5348
|
case "layout":
|
|
@@ -5385,6 +5395,19 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
5385
5395
|
return null;
|
|
5386
5396
|
}
|
|
5387
5397
|
}
|
|
5398
|
+
function inferLayoutRowBgStep(r) {
|
|
5399
|
+
if (r.bgGradient) return "gradient";
|
|
5400
|
+
if (String(r.bgImage || "").trim()) return "image";
|
|
5401
|
+
if (String(r.bgColor || "").trim()) return "solid";
|
|
5402
|
+
return null;
|
|
5403
|
+
}
|
|
5404
|
+
function inferColumnBgStep(columnStyles, selCol) {
|
|
5405
|
+
const cs = (columnStyles || {})[selCol] || {};
|
|
5406
|
+
if (cs.bgGradient) return "gradient";
|
|
5407
|
+
if (String(cs.bgImage || "").trim()) return "image";
|
|
5408
|
+
if (String(cs.bgColor || "").trim()) return "solid";
|
|
5409
|
+
return null;
|
|
5410
|
+
}
|
|
5388
5411
|
function LayoutRowEditor({
|
|
5389
5412
|
row,
|
|
5390
5413
|
onChange,
|
|
@@ -5396,49 +5419,37 @@ function LayoutRowEditor({
|
|
|
5396
5419
|
customizationHint
|
|
5397
5420
|
}) {
|
|
5398
5421
|
const { IS, CI } = useIS(C);
|
|
5399
|
-
const
|
|
5400
|
-
const
|
|
5401
|
-
const [
|
|
5422
|
+
const colCount = Math.max(1, row.ratios?.length || row.cells?.length || 1);
|
|
5423
|
+
const ratioList = row.ratios?.length ? row.ratios : [1];
|
|
5424
|
+
const [selCol, setSelCol] = useState3(0);
|
|
5425
|
+
const [rowBgPickerMode, setRowBgPickerMode] = useState3(null);
|
|
5426
|
+
const [colBgPickerMode, setColBgPickerMode] = useState3(null);
|
|
5427
|
+
const inferredRowBg = useMemo(() => inferLayoutRowBgStep(row), [row.bgGradient, row.bgImage, row.bgColor]);
|
|
5428
|
+
const inferredColBg = useMemo(
|
|
5429
|
+
() => inferColumnBgStep(row.columnStyles, selCol),
|
|
5430
|
+
[row.columnStyles, selCol]
|
|
5431
|
+
);
|
|
5432
|
+
const rowBgUiStep = inferredRowBg ?? rowBgPickerMode;
|
|
5433
|
+
const colBgUiStep = inferredColBg ?? colBgPickerMode;
|
|
5402
5434
|
useEffect3(() => {
|
|
5403
|
-
if (initialCol !== null && initialCol !== void 0) {
|
|
5404
|
-
setSelCol(initialCol);
|
|
5435
|
+
if (initialCol !== null && initialCol !== void 0 && initialCol >= 0) {
|
|
5436
|
+
setSelCol(Math.min(initialCol, colCount - 1));
|
|
5437
|
+
} else {
|
|
5438
|
+
setSelCol((c) => Math.min(Math.max(0, c), colCount - 1));
|
|
5405
5439
|
}
|
|
5406
|
-
}, [initialCol]);
|
|
5440
|
+
}, [initialCol, row.id, colCount]);
|
|
5407
5441
|
useEffect3(() => {
|
|
5408
|
-
|
|
5409
|
-
setRowBgUiStep("gradient");
|
|
5410
|
-
return;
|
|
5411
|
-
}
|
|
5412
|
-
if (String(row.bgImage || "").trim()) {
|
|
5413
|
-
setRowBgUiStep("image");
|
|
5414
|
-
return;
|
|
5415
|
-
}
|
|
5416
|
-
if (String(row.bgColor || "").trim()) {
|
|
5417
|
-
setRowBgUiStep("solid");
|
|
5418
|
-
return;
|
|
5419
|
-
}
|
|
5420
|
-
setRowBgUiStep(null);
|
|
5442
|
+
setRowBgPickerMode(null);
|
|
5421
5443
|
}, [row.id]);
|
|
5422
5444
|
useEffect3(() => {
|
|
5423
|
-
|
|
5424
|
-
setColBgUiStep(null);
|
|
5425
|
-
return;
|
|
5426
|
-
}
|
|
5427
|
-
const cs = (row.columnStyles || {})[selCol] || {};
|
|
5428
|
-
if (cs.bgGradient) {
|
|
5429
|
-
setColBgUiStep("gradient");
|
|
5430
|
-
return;
|
|
5431
|
-
}
|
|
5432
|
-
if (String(cs.bgImage || "").trim()) {
|
|
5433
|
-
setColBgUiStep("image");
|
|
5434
|
-
return;
|
|
5435
|
-
}
|
|
5436
|
-
if (String(cs.bgColor || "").trim()) {
|
|
5437
|
-
setColBgUiStep("solid");
|
|
5438
|
-
return;
|
|
5439
|
-
}
|
|
5440
|
-
setColBgUiStep(null);
|
|
5445
|
+
setColBgPickerMode(null);
|
|
5441
5446
|
}, [selCol, row.id]);
|
|
5447
|
+
useEffect3(() => {
|
|
5448
|
+
if (inferredRowBg) setRowBgPickerMode(null);
|
|
5449
|
+
}, [inferredRowBg]);
|
|
5450
|
+
useEffect3(() => {
|
|
5451
|
+
if (inferredColBg) setColBgPickerMode(null);
|
|
5452
|
+
}, [inferredColBg]);
|
|
5442
5453
|
const set = (k, v) => onChange({ ...row, [k]: v });
|
|
5443
5454
|
const applyColumnCount = (n) => {
|
|
5444
5455
|
const prevCells = [...row.cells || []];
|
|
@@ -5454,16 +5465,13 @@ function LayoutRowEditor({
|
|
|
5454
5465
|
}
|
|
5455
5466
|
onChange({ ...row, cols: n, preset: "custom", cells, ratios });
|
|
5456
5467
|
};
|
|
5457
|
-
const colCount = Math.max(1, row.ratios?.length || row.cells?.length || 1);
|
|
5458
|
-
const ratioList = row.ratios?.length ? row.ratios : [1];
|
|
5459
5468
|
const updCol = (i, upd) => {
|
|
5460
5469
|
const styles = { ...row.columnStyles || {} };
|
|
5461
5470
|
styles[i] = { ...styles[i] || {}, ...upd };
|
|
5462
5471
|
set("columnStyles", styles);
|
|
5463
5472
|
};
|
|
5464
5473
|
const setColBgMode = (mode) => {
|
|
5465
|
-
|
|
5466
|
-
setColBgUiStep(mode);
|
|
5474
|
+
setColBgPickerMode(mode);
|
|
5467
5475
|
const cs = (row.columnStyles || {})[selCol] || {};
|
|
5468
5476
|
if (mode === "solid") {
|
|
5469
5477
|
updCol(selCol, { bgGradient: null, bgImage: "" });
|
|
@@ -5481,7 +5489,7 @@ function LayoutRowEditor({
|
|
|
5481
5489
|
const total = ratioList.reduce((a, b) => a + b, 0) || 1;
|
|
5482
5490
|
const POS_OPTS = ["center", "top", "bottom", "left", "right", "top left", "top right", "bottom left", "bottom right"];
|
|
5483
5491
|
const setRowBgMode = (mode) => {
|
|
5484
|
-
|
|
5492
|
+
setRowBgPickerMode(mode);
|
|
5485
5493
|
if (mode === "solid") {
|
|
5486
5494
|
set("bgGradient", null);
|
|
5487
5495
|
set("bgImage", "");
|
|
@@ -5639,7 +5647,7 @@ function LayoutRowEditor({
|
|
|
5639
5647
|
},
|
|
5640
5648
|
i
|
|
5641
5649
|
)) }),
|
|
5642
|
-
|
|
5650
|
+
colCount > 0 && /* @__PURE__ */ jsxs4("div", { style: { background: C.surface, padding: 10, borderRadius: 8, border: `1px solid ${C.border}` }, children: [
|
|
5643
5651
|
/* @__PURE__ */ jsx6(BgModeButtons, { value: colBgUiStep, onChange: setColBgMode, C }),
|
|
5644
5652
|
colBgUiStep === null ? /* @__PURE__ */ jsx6("div", { style: { fontSize: 11, color: C.muted, marginBottom: 10, lineHeight: 1.45 }, children: "Choose Color, Gradient, or Image \u2014 then edit column background details." }) : null,
|
|
5645
5653
|
colBgUiStep === "solid" ? /* @__PURE__ */ jsx6(PR, { label: `col ${selCol + 1} bg`, C, children: /* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
@@ -5727,7 +5735,7 @@ function LayoutRowEditor({
|
|
|
5727
5735
|
}
|
|
5728
5736
|
) })
|
|
5729
5737
|
] }) : null,
|
|
5730
|
-
/* @__PURE__ */ jsx6(PaddingEditor, { label: "Column padding", value: (row.columnStyles || {})[selCol]?.padding, onChange: (
|
|
5738
|
+
/* @__PURE__ */ jsx6(PaddingEditor, { label: "Column padding", value: (row.columnStyles || {})[selCol]?.padding, onChange: (pad3) => updCol(selCol, { padding: pad3 }), C }),
|
|
5731
5739
|
/* @__PURE__ */ jsx6(BorderRadiusEditor, { label: "Column radius", value: (row.columnStyles || {})[selCol]?.borderRadius, onChange: (br) => updCol(selCol, { borderRadius: br }), C })
|
|
5732
5740
|
] })
|
|
5733
5741
|
] })
|
|
@@ -5738,7 +5746,7 @@ function LayoutRowEditor({
|
|
|
5738
5746
|
import {
|
|
5739
5747
|
useState as useState4,
|
|
5740
5748
|
useEffect as useEffect4,
|
|
5741
|
-
useMemo,
|
|
5749
|
+
useMemo as useMemo2,
|
|
5742
5750
|
useRef as useRef3,
|
|
5743
5751
|
useLayoutEffect
|
|
5744
5752
|
} from "react";
|
|
@@ -6010,8 +6018,8 @@ function MobilePhoneScaleSlot({ variantKey, children }) {
|
|
|
6010
6018
|
const pw = phone.offsetWidth;
|
|
6011
6019
|
const ph = phone.offsetHeight;
|
|
6012
6020
|
if (cw < 12 || ch < 12 || pw < 12 || ph < 12) return;
|
|
6013
|
-
const
|
|
6014
|
-
const raw = Math.min(1, (cw -
|
|
6021
|
+
const pad3 = 20;
|
|
6022
|
+
const raw = Math.min(1, (cw - pad3) / pw, (ch - pad3) / ph);
|
|
6015
6023
|
const s = Number.isFinite(raw) ? Math.max(0.2, raw) : 1;
|
|
6016
6024
|
setFit({ s, w: pw * s, h: ph * s });
|
|
6017
6025
|
};
|
|
@@ -6116,8 +6124,8 @@ function PreviewModal({
|
|
|
6116
6124
|
const iframeHDesktop = "min(720px, calc(100vh - 200px))";
|
|
6117
6125
|
const mobileIframeW = previewIframeWidthPx("mobile", mobileVariant);
|
|
6118
6126
|
const tabletIframeW = previewIframeWidthPx("tablet");
|
|
6119
|
-
const srcDocMobile =
|
|
6120
|
-
const srcDocTablet =
|
|
6127
|
+
const srcDocMobile = useMemo2(() => previewEmailSrcDoc(html, mobileIframeW), [html, mobileIframeW]);
|
|
6128
|
+
const srcDocTablet = useMemo2(() => previewEmailSrcDoc(html, tabletIframeW), [html, tabletIframeW]);
|
|
6121
6129
|
const IframeContent = ({
|
|
6122
6130
|
srcDoc,
|
|
6123
6131
|
title: iframeTitle,
|
|
@@ -6513,7 +6521,7 @@ var ReactEmailEditor = forwardRef(
|
|
|
6513
6521
|
style = {}
|
|
6514
6522
|
}, ref) {
|
|
6515
6523
|
const opt = options;
|
|
6516
|
-
const mergedThemes =
|
|
6524
|
+
const mergedThemes = useMemo3(
|
|
6517
6525
|
() => ({ ...THEMES, ...opt.appearance?.customThemes || {} }),
|
|
6518
6526
|
[opt.appearance?.customThemes]
|
|
6519
6527
|
);
|
|
@@ -6536,7 +6544,6 @@ var ReactEmailEditor = forwardRef(
|
|
|
6536
6544
|
const [locale, setLocale] = useState6(
|
|
6537
6545
|
typeof opt.locale === "string" ? opt.locale : "en"
|
|
6538
6546
|
);
|
|
6539
|
-
const [mergeTags, setMergeTagsState] = useState6(() => opt.mergeTags ?? []);
|
|
6540
6547
|
const [zoom, setZoom] = useState6(100);
|
|
6541
6548
|
const [rightRailWidth, setRightRailWidth] = useState6(RIGHT_RAIL_DEFAULT_W);
|
|
6542
6549
|
const [ctxMenu, setCtxMenu] = useState6(null);
|
|
@@ -6882,6 +6889,43 @@ var ReactEmailEditor = forwardRef(
|
|
|
6882
6889
|
}
|
|
6883
6890
|
}
|
|
6884
6891
|
};
|
|
6892
|
+
const insertBlockFromLibrary = (contentType) => {
|
|
6893
|
+
if (!rows.length) return;
|
|
6894
|
+
if (selContentMeta?.inner) {
|
|
6895
|
+
const { rowId, cellIdx, contentIdx, inner } = selContentMeta;
|
|
6896
|
+
dropContent(rowId, cellIdx, {
|
|
6897
|
+
kind: "new",
|
|
6898
|
+
contentType,
|
|
6899
|
+
insertAt: null,
|
|
6900
|
+
nested: { parentBlockIdx: contentIdx, innerCellIdx: inner.cellIdx }
|
|
6901
|
+
});
|
|
6902
|
+
return;
|
|
6903
|
+
}
|
|
6904
|
+
if (selContentMeta?.rowId && typeof selContentMeta.cellIdx === "number" && selContentMeta.cellIdx >= 0) {
|
|
6905
|
+
const r = rows.find((x) => x.id === selContentMeta.rowId);
|
|
6906
|
+
if (r && selContentMeta.cellIdx < r.cells.length) {
|
|
6907
|
+
dropContent(selContentMeta.rowId, selContentMeta.cellIdx, {
|
|
6908
|
+
kind: "new",
|
|
6909
|
+
contentType,
|
|
6910
|
+
insertAt: null
|
|
6911
|
+
});
|
|
6912
|
+
return;
|
|
6913
|
+
}
|
|
6914
|
+
}
|
|
6915
|
+
if (selectedRowId) {
|
|
6916
|
+
const targetRow = rows.find((r) => r.id === selectedRowId);
|
|
6917
|
+
if (targetRow) {
|
|
6918
|
+
dropContent(targetRow.id, 0, {
|
|
6919
|
+
kind: "new",
|
|
6920
|
+
contentType,
|
|
6921
|
+
insertAt: null
|
|
6922
|
+
});
|
|
6923
|
+
return;
|
|
6924
|
+
}
|
|
6925
|
+
}
|
|
6926
|
+
const main = rows[0];
|
|
6927
|
+
dropContent(main.id, 0, { kind: "new", contentType, insertAt: null });
|
|
6928
|
+
};
|
|
6885
6929
|
const deleteContent = (rowId, cellIdx, ci, inner = null) => {
|
|
6886
6930
|
if (!inner) {
|
|
6887
6931
|
mutate((prev) => prev.map((r) => {
|
|
@@ -6931,7 +6975,7 @@ var ReactEmailEditor = forwardRef(
|
|
|
6931
6975
|
}));
|
|
6932
6976
|
return;
|
|
6933
6977
|
}
|
|
6934
|
-
const loc = { type: "nested", rowId, outerCellIdx: cellIdx, blockIdx:
|
|
6978
|
+
const loc = { type: "nested", rowId, outerCellIdx: cellIdx, blockIdx: ci, innerCellIdx: inner.cellIdx };
|
|
6935
6979
|
mutate((prev) => updateColumnAt(prev, loc, (c) => c.map((b, j) => j === inner.contentIdx ? upd : b)));
|
|
6936
6980
|
};
|
|
6937
6981
|
const selectContent = (contentId, rowId, cellIdx, parentBlockIdx, inner = null) => {
|
|
@@ -7478,6 +7522,8 @@ var ReactEmailEditor = forwardRef(
|
|
|
7478
7522
|
if (data.layoutPresetKey) {
|
|
7479
7523
|
const preset = LAYOUT_PRESETS.find((p) => p.key === data.layoutPresetKey);
|
|
7480
7524
|
if (preset) mutate((prev) => [...prev, makeLayoutRow(preset)]);
|
|
7525
|
+
} else if (data.contentType && typeof data.contentType === "string") {
|
|
7526
|
+
insertBlockFromLibrary(data.contentType);
|
|
7481
7527
|
}
|
|
7482
7528
|
} catch {
|
|
7483
7529
|
}
|
|
@@ -7518,6 +7564,21 @@ var ReactEmailEditor = forwardRef(
|
|
|
7518
7564
|
}
|
|
7519
7565
|
return base;
|
|
7520
7566
|
})(),
|
|
7567
|
+
onDragOver: (e) => {
|
|
7568
|
+
e.preventDefault();
|
|
7569
|
+
e.stopPropagation();
|
|
7570
|
+
},
|
|
7571
|
+
onDrop: (e) => {
|
|
7572
|
+
e.preventDefault();
|
|
7573
|
+
e.stopPropagation();
|
|
7574
|
+
try {
|
|
7575
|
+
const data = JSON.parse(e.dataTransfer.getData("application/json") || "{}");
|
|
7576
|
+
if (data.contentType && typeof data.contentType === "string") {
|
|
7577
|
+
insertBlockFromLibrary(data.contentType);
|
|
7578
|
+
}
|
|
7579
|
+
} catch {
|
|
7580
|
+
}
|
|
7581
|
+
},
|
|
7521
7582
|
children: [
|
|
7522
7583
|
rows.length === 0 && /* @__PURE__ */ jsxs9("div", { id: eid("canvas-empty"), style: { padding: "56px 20px", textAlign: "center", color: C.muted, border: `2px dashed ${C.border}`, borderRadius: 7 }, children: [
|
|
7523
7584
|
/* @__PURE__ */ jsx11("div", { style: { fontSize: 30, marginBottom: 10 }, children: "\u2709" }),
|
|
@@ -7662,7 +7723,6 @@ var ReactEmailEditor = forwardRef(
|
|
|
7662
7723
|
setSelMeta(null);
|
|
7663
7724
|
setSelectedRowId(null);
|
|
7664
7725
|
},
|
|
7665
|
-
mergeTags,
|
|
7666
7726
|
onUpload,
|
|
7667
7727
|
C
|
|
7668
7728
|
}
|
|
@@ -7730,12 +7790,8 @@ var ReactEmailEditor = forwardRef(
|
|
|
7730
7790
|
onDragStart: (e) => {
|
|
7731
7791
|
e.dataTransfer.setData("application/json", JSON.stringify({ contentType: bt.type }));
|
|
7732
7792
|
},
|
|
7733
|
-
onClick: () =>
|
|
7734
|
-
|
|
7735
|
-
if (!targetRow) return;
|
|
7736
|
-
dropContent(targetRow.id, 0, { kind: "new", contentType: bt.type, insertAt: null });
|
|
7737
|
-
},
|
|
7738
|
-
title: `Drag into a cell or click to add to ${selectedRowId ? "selected row" : "last row"}`,
|
|
7793
|
+
onClick: () => insertBlockFromLibrary(bt.type),
|
|
7794
|
+
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",
|
|
7739
7795
|
style: {
|
|
7740
7796
|
display: "flex",
|
|
7741
7797
|
flexDirection: "row",
|
|
@@ -8105,11 +8161,79 @@ var ReactEmailEditor = forwardRef(
|
|
|
8105
8161
|
);
|
|
8106
8162
|
}
|
|
8107
8163
|
);
|
|
8164
|
+
|
|
8165
|
+
// src/lib/htmlToEmailDesign.ts
|
|
8166
|
+
var pad = (n) => ({ top: n, right: n, bottom: n, left: n });
|
|
8167
|
+
function extractHtmlForDesign(html) {
|
|
8168
|
+
const t = String(html ?? "").trim();
|
|
8169
|
+
if (!t) return "";
|
|
8170
|
+
const head = t.slice(0, 800).toLowerCase();
|
|
8171
|
+
if (!head.includes("<html") && !head.includes("<!doctype")) {
|
|
8172
|
+
return normalizeRichHtmlForStorage(t);
|
|
8173
|
+
}
|
|
8174
|
+
try {
|
|
8175
|
+
const doc = new DOMParser().parseFromString(t, "text/html");
|
|
8176
|
+
const body = doc.body;
|
|
8177
|
+
if (!body) return normalizeRichHtmlForStorage(t);
|
|
8178
|
+
return normalizeRichHtmlForStorage(body.innerHTML);
|
|
8179
|
+
} catch {
|
|
8180
|
+
return normalizeRichHtmlForStorage(t);
|
|
8181
|
+
}
|
|
8182
|
+
}
|
|
8183
|
+
function htmlToEmailDesignTemplate(html) {
|
|
8184
|
+
const inner = extractHtmlForDesign(html);
|
|
8185
|
+
if (!inner) return null;
|
|
8186
|
+
const doc = {
|
|
8187
|
+
type: "email_document",
|
|
8188
|
+
settings: {
|
|
8189
|
+
width: 600,
|
|
8190
|
+
backgroundColor: "#f1f5f9",
|
|
8191
|
+
contentBackgroundColor: "#ffffff",
|
|
8192
|
+
fontFamily: "Arial, Helvetica, sans-serif",
|
|
8193
|
+
lineHeightBase: 1.6,
|
|
8194
|
+
color: "#111827",
|
|
8195
|
+
responsive: true,
|
|
8196
|
+
rtl: false
|
|
8197
|
+
},
|
|
8198
|
+
rows: [
|
|
8199
|
+
{
|
|
8200
|
+
id: "row_html_import",
|
|
8201
|
+
type: "row",
|
|
8202
|
+
layout: { columns: 1, gap: 0, stackOnMobile: true, align: "center" },
|
|
8203
|
+
styles: {
|
|
8204
|
+
backgroundColor: "#ffffff",
|
|
8205
|
+
backgroundRepeat: "no-repeat",
|
|
8206
|
+
backgroundSize: "cover",
|
|
8207
|
+
padding: pad(24),
|
|
8208
|
+
textAlign: "left"
|
|
8209
|
+
},
|
|
8210
|
+
columns: [
|
|
8211
|
+
{
|
|
8212
|
+
id: "col_html_import",
|
|
8213
|
+
layout: { width: "100%", verticalAlign: "top", mobileWidth: "100%" },
|
|
8214
|
+
styles: { padding: pad(0), backgroundColor: "" },
|
|
8215
|
+
blocks: [
|
|
8216
|
+
{
|
|
8217
|
+
id: "block_html_import",
|
|
8218
|
+
type: "html",
|
|
8219
|
+
content: { html: inner },
|
|
8220
|
+
styles: {}
|
|
8221
|
+
}
|
|
8222
|
+
]
|
|
8223
|
+
}
|
|
8224
|
+
]
|
|
8225
|
+
}
|
|
8226
|
+
]
|
|
8227
|
+
};
|
|
8228
|
+
return doc;
|
|
8229
|
+
}
|
|
8108
8230
|
export {
|
|
8109
8231
|
PreviewModal as EmailPreviewModal,
|
|
8110
8232
|
ReactEmailEditor,
|
|
8111
8233
|
base64ToUtf8,
|
|
8112
8234
|
DEVICES as emailPreviewDevices,
|
|
8235
|
+
extractHtmlForDesign,
|
|
8236
|
+
htmlToEmailDesignTemplate,
|
|
8113
8237
|
jsonToHtml,
|
|
8114
8238
|
utf8ToBase64
|
|
8115
8239
|
};
|