react-email-studio 2.0.0 → 3.0.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/TUTORIAL.md +264 -264
- package/USER_README.md +28 -28
- package/dist/index.cjs +502 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +502 -50
- package/dist/index.js.map +1 -1
- package/package.json +62 -58
package/dist/index.js
CHANGED
|
@@ -660,6 +660,10 @@ function makeContentBlock(type) {
|
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
// src/lib/columnPath.ts
|
|
663
|
+
var MAX_NESTED_LAYOUT_DEPTH = 1;
|
|
664
|
+
function nestedLayoutDepth(nested) {
|
|
665
|
+
return nested != null && nested.parentBlockIdx != null && nested.innerCellIdx != null ? 1 : 0;
|
|
666
|
+
}
|
|
663
667
|
function isSplitLayoutBlock(b) {
|
|
664
668
|
return b && b.type === "layout" && b.props && Array.isArray(b.props.cells);
|
|
665
669
|
}
|
|
@@ -1251,8 +1255,18 @@ function normalizeEmailDocument(input) {
|
|
|
1251
1255
|
settings: doc.settings && typeof doc.settings === "object" && !Array.isArray(doc.settings) ? doc.settings : {},
|
|
1252
1256
|
rows: rows.map((r, ri) => {
|
|
1253
1257
|
const columns = Array.isArray(r.columns) ? r.columns : [];
|
|
1254
|
-
const
|
|
1255
|
-
const
|
|
1258
|
+
const layoutColCount = typeof r.layout?.columns === "number" && r.layout.columns > 0 ? Math.floor(r.layout.columns) : 0;
|
|
1259
|
+
const colCount = Math.max(1, columns.length, layoutColCount);
|
|
1260
|
+
const colsNormalized = (() => {
|
|
1261
|
+
if (columns.length >= colCount) return columns;
|
|
1262
|
+
if (columns.length > 0) {
|
|
1263
|
+
return [
|
|
1264
|
+
...columns,
|
|
1265
|
+
...Array.from({ length: colCount - columns.length }).map(() => ({}))
|
|
1266
|
+
];
|
|
1267
|
+
}
|
|
1268
|
+
return Array.from({ length: colCount }).map(() => ({}));
|
|
1269
|
+
})();
|
|
1256
1270
|
return {
|
|
1257
1271
|
id: ensureId(r.id, `row${ri + 1}`),
|
|
1258
1272
|
type: "row",
|
|
@@ -1263,6 +1277,7 @@ function normalizeEmailDocument(input) {
|
|
|
1263
1277
|
align: r.layout?.align || "center"
|
|
1264
1278
|
},
|
|
1265
1279
|
styles: r.styles && typeof r.styles === "object" && !Array.isArray(r.styles) ? r.styles : {},
|
|
1280
|
+
...typeof r._reactEmailStudio === "object" && r._reactEmailStudio !== null && !Array.isArray(r._reactEmailStudio) ? { _reactEmailStudio: r._reactEmailStudio } : {},
|
|
1266
1281
|
columns: colsNormalized.map((c, ci) => ({
|
|
1267
1282
|
id: ensureId(c.id, `col${ri + 1}_${ci + 1}`),
|
|
1268
1283
|
layout: c.layout && typeof c.layout === "object" && !Array.isArray(c.layout) ? c.layout : {},
|
|
@@ -1273,7 +1288,8 @@ function normalizeEmailDocument(input) {
|
|
|
1273
1288
|
content: b?.content && typeof b.content === "object" && !Array.isArray(b.content) ? b.content : {},
|
|
1274
1289
|
styles: b?.styles && typeof b.styles === "object" && !Array.isArray(b.styles) ? b.styles : {},
|
|
1275
1290
|
behavior: b?.behavior && typeof b.behavior === "object" && !Array.isArray(b.behavior) ? b.behavior : {},
|
|
1276
|
-
responsive: b?.responsive && typeof b.responsive === "object" && !Array.isArray(b.responsive) ? b.responsive : {}
|
|
1291
|
+
responsive: b?.responsive && typeof b.responsive === "object" && !Array.isArray(b.responsive) ? b.responsive : {},
|
|
1292
|
+
...b?.props && typeof b.props === "object" && !Array.isArray(b.props) ? { props: b.props } : {}
|
|
1277
1293
|
})) : []
|
|
1278
1294
|
}))
|
|
1279
1295
|
};
|
|
@@ -1284,6 +1300,14 @@ function normalizeEmailDocument(input) {
|
|
|
1284
1300
|
}
|
|
1285
1301
|
|
|
1286
1302
|
// src/lib/emailDesignJson.ts
|
|
1303
|
+
var MAX_LAYOUT_TREE_DEPTH = 32;
|
|
1304
|
+
function cloneJson(v) {
|
|
1305
|
+
try {
|
|
1306
|
+
return JSON.parse(JSON.stringify(v));
|
|
1307
|
+
} catch {
|
|
1308
|
+
return v;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1287
1311
|
function layoutColumnPaddingForDoc(p) {
|
|
1288
1312
|
if (typeof p === "number" && Number.isFinite(p)) {
|
|
1289
1313
|
const n = Math.max(0, p);
|
|
@@ -1370,7 +1394,242 @@ function normalizeBoxStyles(props, t) {
|
|
|
1370
1394
|
}
|
|
1371
1395
|
props.padding = boxPad(props.padding, uniformPadDefault(def?.padding));
|
|
1372
1396
|
}
|
|
1373
|
-
function
|
|
1397
|
+
function internalBlockToEmailDoc(b, depth = 0) {
|
|
1398
|
+
const p = b?.props && typeof b.props === "object" ? b.props : {};
|
|
1399
|
+
const id = typeof b?.id === "string" ? b.id : uid();
|
|
1400
|
+
const type = b?.type === "nestedRow" ? "layout" : b?.type;
|
|
1401
|
+
if (!isKnownBlockType(type)) {
|
|
1402
|
+
return { id, type: String(type || "text"), content: {}, styles: {} };
|
|
1403
|
+
}
|
|
1404
|
+
switch (type) {
|
|
1405
|
+
case "heading": {
|
|
1406
|
+
const fw = typeof p.fontWeight === "number" ? p.fontWeight : typeof p.fontWeight === "string" ? Number.parseInt(String(p.fontWeight), 10) || (p.bold ? 700 : 400) : p.bold ? 700 : 400;
|
|
1407
|
+
const padUniform = typeof p.padding === "number" && Number.isFinite(p.padding) ? p.padding : uniformPadDefault(p.padding);
|
|
1408
|
+
return {
|
|
1409
|
+
id,
|
|
1410
|
+
type,
|
|
1411
|
+
content: { text: typeof p.content === "string" ? p.content : "", tag: p.level || "h2" },
|
|
1412
|
+
styles: {
|
|
1413
|
+
fontSize: p.fontSize,
|
|
1414
|
+
fontWeight: fw,
|
|
1415
|
+
color: p.color,
|
|
1416
|
+
lineHeight: p.lineHeight,
|
|
1417
|
+
textAlign: p.align,
|
|
1418
|
+
letterSpacing: p.letterSpacing,
|
|
1419
|
+
marginBottom: padUniform
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
case "text":
|
|
1424
|
+
return {
|
|
1425
|
+
id,
|
|
1426
|
+
type,
|
|
1427
|
+
content: { html: typeof p.content === "string" ? p.content : "" },
|
|
1428
|
+
styles: {
|
|
1429
|
+
fontSize: p.fontSize,
|
|
1430
|
+
color: p.color,
|
|
1431
|
+
lineHeight: p.lineHeight,
|
|
1432
|
+
textAlign: p.align,
|
|
1433
|
+
...p.padding && typeof p.padding === "object" && !Array.isArray(p.padding) ? { padding: layoutColumnPaddingForDoc(p.padding) } : {}
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
case "html":
|
|
1437
|
+
return {
|
|
1438
|
+
id,
|
|
1439
|
+
type,
|
|
1440
|
+
content: { html: typeof p.content === "string" ? p.content : "" },
|
|
1441
|
+
styles: p.padding && typeof p.padding === "object" && !Array.isArray(p.padding) ? { padding: layoutColumnPaddingForDoc(p.padding) } : {}
|
|
1442
|
+
};
|
|
1443
|
+
case "image": {
|
|
1444
|
+
const br = p.borderRadius;
|
|
1445
|
+
const borderRadius = typeof br === "number" && Number.isFinite(br) ? br : br && typeof br === "object" && !Array.isArray(br) ? Math.round(
|
|
1446
|
+
(numOr(br.tl, 0) + numOr(br.tr, numOr(br.tl, 0)) + numOr(br.br, numOr(br.tl, 0)) + numOr(br.bl, numOr(br.tr, 0))) / 4
|
|
1447
|
+
) : 0;
|
|
1448
|
+
return {
|
|
1449
|
+
id,
|
|
1450
|
+
type,
|
|
1451
|
+
content: {
|
|
1452
|
+
src: p.src || "",
|
|
1453
|
+
alt: p.alt || "",
|
|
1454
|
+
link: p.link || ""
|
|
1455
|
+
},
|
|
1456
|
+
styles: {
|
|
1457
|
+
width: p.width,
|
|
1458
|
+
align: p.align,
|
|
1459
|
+
borderRadius
|
|
1460
|
+
},
|
|
1461
|
+
...p.linkTarget === "_blank" ? { behavior: { openInNewTab: true } } : {}
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
case "button": {
|
|
1465
|
+
let borderRadiusOut;
|
|
1466
|
+
if (typeof p.borderRadius === "number" && Number.isFinite(p.borderRadius)) {
|
|
1467
|
+
borderRadiusOut = p.borderRadius;
|
|
1468
|
+
} else if (p.borderRadius && typeof p.borderRadius === "object" && !Array.isArray(p.borderRadius)) {
|
|
1469
|
+
const br = p.borderRadius;
|
|
1470
|
+
const tl = numOr(br.tl, 0);
|
|
1471
|
+
const tr2 = numOr(br.tr, tl);
|
|
1472
|
+
const brc = numOr(br.br, tl);
|
|
1473
|
+
const bl = numOr(br.bl, tr2);
|
|
1474
|
+
borderRadiusOut = tl === tr2 && tr2 === brc && brc === bl ? tl : Math.round((tl + tr2 + brc + bl) / 4);
|
|
1475
|
+
}
|
|
1476
|
+
return {
|
|
1477
|
+
id,
|
|
1478
|
+
type,
|
|
1479
|
+
content: { text: p.label || "", href: p.href || "#" },
|
|
1480
|
+
styles: {
|
|
1481
|
+
backgroundColor: p.bgColor,
|
|
1482
|
+
color: p.textColor,
|
|
1483
|
+
fontSize: p.fontSize,
|
|
1484
|
+
fontWeight: p.fontWeight,
|
|
1485
|
+
...borderRadiusOut !== void 0 ? { borderRadius: borderRadiusOut } : {},
|
|
1486
|
+
textAlign: p.align,
|
|
1487
|
+
padding: {
|
|
1488
|
+
top: p.paddingV ?? 11,
|
|
1489
|
+
right: p.paddingH ?? 24,
|
|
1490
|
+
bottom: p.paddingV ?? 11,
|
|
1491
|
+
left: p.paddingH ?? 24
|
|
1492
|
+
}
|
|
1493
|
+
},
|
|
1494
|
+
...p.linkTarget === "_blank" ? { behavior: { openInNewTab: true } } : {}
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
case "divider": {
|
|
1498
|
+
const padY = typeof p.padding === "number" && Number.isFinite(p.padding) ? p.padding : p.padding && typeof p.padding === "object" && !Array.isArray(p.padding) ? numOr(p.padding.top, 12) : 12;
|
|
1499
|
+
return {
|
|
1500
|
+
id,
|
|
1501
|
+
type,
|
|
1502
|
+
content: {},
|
|
1503
|
+
styles: { color: p.color, thickness: p.thickness, paddingY: padY }
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
case "spacer":
|
|
1507
|
+
return { id, type, content: {}, styles: { height: p.height } };
|
|
1508
|
+
case "social": {
|
|
1509
|
+
const urls = p.socialUrls && typeof p.socialUrls === "object" && !Array.isArray(p.socialUrls) ? p.socialUrls : {};
|
|
1510
|
+
const networks = {};
|
|
1511
|
+
const ordered = Array.isArray(p.networks) ? p.networks.filter((n) => typeof n === "string" && !!n) : [];
|
|
1512
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1513
|
+
for (const n of ordered) {
|
|
1514
|
+
const u = urls[n];
|
|
1515
|
+
networks[n] = typeof u === "string" && u.trim() ? u : "";
|
|
1516
|
+
seen.add(n);
|
|
1517
|
+
}
|
|
1518
|
+
for (const key of Object.keys(urls)) {
|
|
1519
|
+
if (seen.has(key)) continue;
|
|
1520
|
+
const v = urls[key];
|
|
1521
|
+
if (typeof v === "string" && v.trim()) {
|
|
1522
|
+
networks[key] = v;
|
|
1523
|
+
seen.add(key);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
const padStyles = p.padding != null ? typeof p.padding === "number" && Number.isFinite(p.padding) ? { padding: layoutColumnPaddingForDoc(p.padding) } : p.padding && typeof p.padding === "object" && !Array.isArray(p.padding) ? { padding: layoutColumnPaddingForDoc(p.padding) } : {} : {};
|
|
1527
|
+
return {
|
|
1528
|
+
id,
|
|
1529
|
+
type,
|
|
1530
|
+
content: { networks },
|
|
1531
|
+
styles: {
|
|
1532
|
+
iconSize: p.iconSize,
|
|
1533
|
+
gap: p.gap,
|
|
1534
|
+
shape: p.shape,
|
|
1535
|
+
align: p.align,
|
|
1536
|
+
...padStyles
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
case "table":
|
|
1541
|
+
return {
|
|
1542
|
+
id,
|
|
1543
|
+
type,
|
|
1544
|
+
content: { data: Array.isArray(p.data) ? p.data : [] },
|
|
1545
|
+
styles: {
|
|
1546
|
+
borderColor: p.cellBorder,
|
|
1547
|
+
cellPadding: p.cellPadding,
|
|
1548
|
+
headerBg: p.headerBg,
|
|
1549
|
+
striped: p.striped
|
|
1550
|
+
}
|
|
1551
|
+
};
|
|
1552
|
+
case "video":
|
|
1553
|
+
return {
|
|
1554
|
+
id,
|
|
1555
|
+
type,
|
|
1556
|
+
content: { url: p.src || "" },
|
|
1557
|
+
styles: { height: p.height }
|
|
1558
|
+
};
|
|
1559
|
+
case "timer": {
|
|
1560
|
+
let timerBr;
|
|
1561
|
+
if (typeof p.borderRadius === "number" && Number.isFinite(p.borderRadius)) {
|
|
1562
|
+
timerBr = p.borderRadius;
|
|
1563
|
+
} else if (p.borderRadius && typeof p.borderRadius === "object" && !Array.isArray(p.borderRadius)) {
|
|
1564
|
+
const br = p.borderRadius;
|
|
1565
|
+
const tl = numOr(br.tl, 0);
|
|
1566
|
+
const tr2 = numOr(br.tr, tl);
|
|
1567
|
+
const brc = numOr(br.br, tl);
|
|
1568
|
+
const bl = numOr(br.bl, tr2);
|
|
1569
|
+
timerBr = tl === tr2 && tr2 === brc && brc === bl ? tl : Math.round((tl + tr2 + brc + bl) / 4);
|
|
1570
|
+
}
|
|
1571
|
+
return {
|
|
1572
|
+
id,
|
|
1573
|
+
type,
|
|
1574
|
+
content: { endDate: p.endDate || "" },
|
|
1575
|
+
styles: {
|
|
1576
|
+
backgroundColor: p.bgColor,
|
|
1577
|
+
color: p.textColor,
|
|
1578
|
+
padding: typeof p.padding === "number" ? p.padding : uniformPadDefault(p.padding),
|
|
1579
|
+
...timerBr !== void 0 ? { borderRadius: timerBr } : {},
|
|
1580
|
+
textAlign: p.align
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
case "menu":
|
|
1585
|
+
return {
|
|
1586
|
+
id,
|
|
1587
|
+
type,
|
|
1588
|
+
content: { items: Array.isArray(p.items) ? p.items : [] },
|
|
1589
|
+
styles: { fontSize: p.fontSize, color: p.color }
|
|
1590
|
+
};
|
|
1591
|
+
case "link":
|
|
1592
|
+
return {
|
|
1593
|
+
id,
|
|
1594
|
+
type,
|
|
1595
|
+
content: { text: p.label || "", href: p.href || "#" },
|
|
1596
|
+
styles: { color: p.color, fontSize: p.fontSize, textAlign: p.align },
|
|
1597
|
+
...p.linkTarget === "_blank" ? { behavior: { openInNewTab: true } } : {}
|
|
1598
|
+
};
|
|
1599
|
+
case "layout": {
|
|
1600
|
+
const ratios = Array.isArray(p.ratios) ? [...p.ratios] : [1];
|
|
1601
|
+
const emptyCells = ratios.map(() => []);
|
|
1602
|
+
const rawCells = Array.isArray(p.cells) ? p.cells : [];
|
|
1603
|
+
const cellsOut = depth >= MAX_LAYOUT_TREE_DEPTH ? emptyCells : ratios.map((_, i) => {
|
|
1604
|
+
const col = rawCells[i];
|
|
1605
|
+
return Array.isArray(col) ? col.map((child) => internalBlockToEmailDoc(child, depth + 1)) : [];
|
|
1606
|
+
});
|
|
1607
|
+
return {
|
|
1608
|
+
id,
|
|
1609
|
+
type,
|
|
1610
|
+
content: {
|
|
1611
|
+
preset: p.preset,
|
|
1612
|
+
cols: p.cols,
|
|
1613
|
+
ratios,
|
|
1614
|
+
gap: p.gap,
|
|
1615
|
+
padding: p.padding,
|
|
1616
|
+
bgColor: p.bgColor,
|
|
1617
|
+
bgImage: p.bgImage,
|
|
1618
|
+
bgSize: p.bgSize,
|
|
1619
|
+
bgRepeat: p.bgRepeat,
|
|
1620
|
+
bgPosition: p.bgPosition,
|
|
1621
|
+
bgGradient: p.bgGradient ?? null,
|
|
1622
|
+
columnStyles: p.columnStyles,
|
|
1623
|
+
cells: cellsOut
|
|
1624
|
+
},
|
|
1625
|
+
styles: {}
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
default:
|
|
1629
|
+
return { id, type, content: {}, styles: {} };
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
function mapBlockToInternal(b, layoutDepth = 0) {
|
|
1374
1633
|
const t = b.type;
|
|
1375
1634
|
if (!isKnownBlockType(t)) return null;
|
|
1376
1635
|
const block = makeContentBlock(t);
|
|
@@ -1441,8 +1700,28 @@ function mapBlockToInternal(b) {
|
|
|
1441
1700
|
if (asNum(s.height) != null) block.props.height = s.height;
|
|
1442
1701
|
break;
|
|
1443
1702
|
case "social": {
|
|
1444
|
-
const
|
|
1445
|
-
|
|
1703
|
+
const networksRaw = c.networks;
|
|
1704
|
+
let networksObj = {};
|
|
1705
|
+
if (Array.isArray(networksRaw)) {
|
|
1706
|
+
const urlMap = c.socialUrls && typeof c.socialUrls === "object" && !Array.isArray(c.socialUrls) ? c.socialUrls : {};
|
|
1707
|
+
for (const n of networksRaw) {
|
|
1708
|
+
if (typeof n !== "string" || !n) continue;
|
|
1709
|
+
const u = urlMap[n];
|
|
1710
|
+
networksObj[n] = typeof u === "string" ? u : "";
|
|
1711
|
+
}
|
|
1712
|
+
for (const key of Object.keys(urlMap)) {
|
|
1713
|
+
if (key in networksObj) continue;
|
|
1714
|
+
const u = urlMap[key];
|
|
1715
|
+
if (typeof u === "string" && u.trim()) networksObj[key] = u;
|
|
1716
|
+
}
|
|
1717
|
+
} else if (networksRaw && typeof networksRaw === "object" && !Array.isArray(networksRaw)) {
|
|
1718
|
+
networksObj = { ...networksRaw };
|
|
1719
|
+
for (const k of Object.keys(networksObj)) {
|
|
1720
|
+
const v = networksObj[k];
|
|
1721
|
+
networksObj[k] = typeof v === "string" ? v : "";
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
const keys = Object.keys(networksObj);
|
|
1446
1725
|
if (keys.length) {
|
|
1447
1726
|
block.props.networks = keys;
|
|
1448
1727
|
block.props.socialUrls = networksObj;
|
|
@@ -1451,6 +1730,13 @@ function mapBlockToInternal(b) {
|
|
|
1451
1730
|
if (asNum(s.gap) != null) block.props.gap = s.gap;
|
|
1452
1731
|
if (asStr(s.shape)) block.props.shape = s.shape;
|
|
1453
1732
|
if (asStr(s.align)) block.props.align = s.align;
|
|
1733
|
+
if (s.padding != null) {
|
|
1734
|
+
if (typeof s.padding === "number" && Number.isFinite(s.padding)) {
|
|
1735
|
+
block.props.padding = s.padding;
|
|
1736
|
+
} else if (s.padding && typeof s.padding === "object" && !Array.isArray(s.padding)) {
|
|
1737
|
+
block.props.padding = layoutColumnPaddingForDoc(s.padding);
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1454
1740
|
break;
|
|
1455
1741
|
}
|
|
1456
1742
|
case "table":
|
|
@@ -1491,15 +1777,81 @@ function mapBlockToInternal(b) {
|
|
|
1491
1777
|
if (asNum(s.fontSize) != null) block.props.fontSize = s.fontSize;
|
|
1492
1778
|
if (asStr(s.textAlign)) block.props.align = s.textAlign;
|
|
1493
1779
|
break;
|
|
1494
|
-
case "layout":
|
|
1780
|
+
case "layout": {
|
|
1781
|
+
if (Array.isArray(c.cells)) {
|
|
1782
|
+
const d = DEFAULT_BLOCK_PROPS.layout;
|
|
1783
|
+
block.props.preset = asStr(c.preset) ?? block.props.preset;
|
|
1784
|
+
if (typeof c.cols === "number") block.props.cols = c.cols;
|
|
1785
|
+
if (Array.isArray(c.ratios)) block.props.ratios = [...c.ratios];
|
|
1786
|
+
if (typeof c.gap === "number") block.props.gap = c.gap;
|
|
1787
|
+
if (c.padding !== void 0 && c.padding !== null) block.props.padding = c.padding;
|
|
1788
|
+
if (typeof c.bgColor === "string") block.props.bgColor = c.bgColor;
|
|
1789
|
+
if (typeof c.bgImage === "string") block.props.bgImage = c.bgImage;
|
|
1790
|
+
if (typeof c.bgSize === "string") block.props.bgSize = c.bgSize;
|
|
1791
|
+
if (typeof c.bgRepeat === "string") block.props.bgRepeat = c.bgRepeat;
|
|
1792
|
+
if (typeof c.bgPosition === "string") block.props.bgPosition = c.bgPosition;
|
|
1793
|
+
if (c.bgGradient !== void 0) block.props.bgGradient = c.bgGradient;
|
|
1794
|
+
if (c.columnStyles && typeof c.columnStyles === "object" && !Array.isArray(c.columnStyles)) {
|
|
1795
|
+
block.props.columnStyles = c.columnStyles;
|
|
1796
|
+
}
|
|
1797
|
+
block.props.cells = c.cells.map(
|
|
1798
|
+
(col) => Array.isArray(col) ? col.map((raw) => mapEmbeddedLayoutCellBlock(raw, layoutDepth + 1)).filter((x) => x != null) : []
|
|
1799
|
+
);
|
|
1800
|
+
} else {
|
|
1801
|
+
block.props.preset = asStr(c.preset) ?? block.props.preset;
|
|
1802
|
+
}
|
|
1495
1803
|
break;
|
|
1804
|
+
}
|
|
1496
1805
|
default:
|
|
1497
1806
|
break;
|
|
1498
1807
|
}
|
|
1808
|
+
const styleObj = s && typeof s === "object" && !Array.isArray(s) ? s : {};
|
|
1809
|
+
const hasDocStyles = Object.keys(styleObj).some((k) => {
|
|
1810
|
+
const v = styleObj[k];
|
|
1811
|
+
return v !== void 0 && v !== null && v !== "";
|
|
1812
|
+
});
|
|
1813
|
+
const skipContentMergeKeys = {
|
|
1814
|
+
heading: /* @__PURE__ */ new Set(["text", "tag"]),
|
|
1815
|
+
text: /* @__PURE__ */ new Set(["html", "text"]),
|
|
1816
|
+
html: /* @__PURE__ */ new Set(["html"]),
|
|
1817
|
+
image: /* @__PURE__ */ new Set(["src", "alt", "link"]),
|
|
1818
|
+
button: /* @__PURE__ */ new Set(["text", "href"]),
|
|
1819
|
+
link: /* @__PURE__ */ new Set(["text", "href"]),
|
|
1820
|
+
social: /* @__PURE__ */ new Set(["networks", "socialUrls"]),
|
|
1821
|
+
table: /* @__PURE__ */ new Set(["data"]),
|
|
1822
|
+
menu: /* @__PURE__ */ new Set(["items"]),
|
|
1823
|
+
video: /* @__PURE__ */ new Set(["url"]),
|
|
1824
|
+
timer: /* @__PURE__ */ new Set(["endDate"])
|
|
1825
|
+
};
|
|
1826
|
+
if (!hasDocStyles && c && typeof c === "object" && t !== "layout") {
|
|
1827
|
+
const known = DEFAULT_BLOCK_PROPS[t];
|
|
1828
|
+
const skip = skipContentMergeKeys[t];
|
|
1829
|
+
if (known && typeof known === "object" && !Array.isArray(known)) {
|
|
1830
|
+
for (const key of Object.keys(known)) {
|
|
1831
|
+
if (skip?.has(key)) continue;
|
|
1832
|
+
if (key in c && c[key] !== void 0) {
|
|
1833
|
+
block.props[key] = c[key];
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
applyImportedEditorPropsFromDoc(block, t, b, layoutDepth);
|
|
1499
1839
|
return block;
|
|
1500
1840
|
}
|
|
1501
1841
|
function rowToInternal(r) {
|
|
1502
|
-
const
|
|
1842
|
+
const columns = Array.isArray(r.columns) ? r.columns : [];
|
|
1843
|
+
const layoutColCount = typeof r.layout?.columns === "number" && r.layout.columns > 0 ? Math.floor(r.layout.columns) : 0;
|
|
1844
|
+
const cols = Math.max(1, columns.length, layoutColCount);
|
|
1845
|
+
const colList = (() => {
|
|
1846
|
+
if (columns.length >= cols) return columns;
|
|
1847
|
+
if (columns.length > 0) {
|
|
1848
|
+
return [
|
|
1849
|
+
...columns,
|
|
1850
|
+
...Array.from({ length: cols - columns.length }).map(() => ({}))
|
|
1851
|
+
];
|
|
1852
|
+
}
|
|
1853
|
+
return Array.from({ length: cols }).map(() => ({}));
|
|
1854
|
+
})();
|
|
1503
1855
|
const preset = pickPresetByColCount(cols) || LAYOUT_PRESETS[0];
|
|
1504
1856
|
const row = makeLayoutRow(preset);
|
|
1505
1857
|
row.id = typeof r.id === "string" ? r.id : uid();
|
|
@@ -1512,14 +1864,14 @@ function rowToInternal(r) {
|
|
|
1512
1864
|
row.bgSize = r.styles?.backgroundSize || row.bgSize;
|
|
1513
1865
|
row.bgPosition = r.styles?.backgroundPosition || row.bgPosition || "center";
|
|
1514
1866
|
row.bgGradient = r.styles?.backgroundGradient || row.bgGradient || null;
|
|
1515
|
-
|
|
1516
|
-
const colList = columns.length ? columns : Array.from({ length: cols }).map(() => ({}));
|
|
1517
|
-
row.cells = colList.slice(0, cols).map((c) => {
|
|
1867
|
+
row.cells = colList.map((c) => {
|
|
1518
1868
|
const blocks = Array.isArray(c.blocks) ? c.blocks : [];
|
|
1519
|
-
return blocks.map(mapBlockToInternal).filter((x) => x != null);
|
|
1869
|
+
return blocks.map((blk) => mapBlockToInternal(blk, 0)).filter((x) => x != null);
|
|
1520
1870
|
});
|
|
1521
|
-
const
|
|
1522
|
-
|
|
1871
|
+
const studio = r._reactEmailStudio;
|
|
1872
|
+
const snap = studio?.row;
|
|
1873
|
+
const columnStylesFromDoc = {};
|
|
1874
|
+
colList.forEach((c, i) => {
|
|
1523
1875
|
const bgColor = typeof c.styles?.backgroundColor === "string" ? c.styles.backgroundColor : "";
|
|
1524
1876
|
const padding = layoutColumnPaddingForDoc(c.styles?.padding);
|
|
1525
1877
|
const borderRadius = layoutColumnBorderRadiusForDoc(c.styles?.borderRadius);
|
|
@@ -1531,17 +1883,30 @@ function rowToInternal(r) {
|
|
|
1531
1883
|
const hasPad = columnPaddingNonZero(padding);
|
|
1532
1884
|
const hasBr = columnRadiusNonZero(borderRadius);
|
|
1533
1885
|
if (bgColor || hasPad || hasBr || bgImage || bgRepeat || bgSize || bgPosition || bgGradient) {
|
|
1534
|
-
|
|
1886
|
+
columnStylesFromDoc[i] = { bgColor, padding, borderRadius, bgImage, bgRepeat, bgSize, bgPosition, bgGradient };
|
|
1535
1887
|
}
|
|
1536
1888
|
});
|
|
1537
|
-
if (
|
|
1889
|
+
if (snap && typeof snap === "object" && !Array.isArray(snap)) {
|
|
1890
|
+
const { cells: _omitCells, columnStyles: snapCs, ...rest } = snap;
|
|
1891
|
+
Object.assign(row, rest);
|
|
1892
|
+
const snapColumn = snapCs && typeof snapCs === "object" && !Array.isArray(snapCs) ? snapCs : {};
|
|
1893
|
+
row.columnStyles = { ...snapColumn, ...columnStylesFromDoc };
|
|
1894
|
+
if (!Object.keys(row.columnStyles).length) delete row.columnStyles;
|
|
1895
|
+
} else if (Object.keys(columnStylesFromDoc).length) {
|
|
1896
|
+
row.columnStyles = columnStylesFromDoc;
|
|
1897
|
+
}
|
|
1538
1898
|
return row;
|
|
1539
1899
|
}
|
|
1540
1900
|
function normalizeEmailDesignInput(input) {
|
|
1541
1901
|
const doc = normalizeEmailDocument(input);
|
|
1542
1902
|
if (!doc) return null;
|
|
1543
1903
|
const s = doc.settings || {};
|
|
1544
|
-
const
|
|
1904
|
+
const studioSettings = s._reactEmailStudio;
|
|
1905
|
+
const settings = {};
|
|
1906
|
+
if (studioSettings?.editorSettings && typeof studioSettings.editorSettings === "object" && !Array.isArray(studioSettings.editorSettings)) {
|
|
1907
|
+
Object.assign(settings, cloneJson(studioSettings.editorSettings));
|
|
1908
|
+
}
|
|
1909
|
+
Object.assign(settings, {
|
|
1545
1910
|
bgColor: s.backgroundColor || "#f1f5f9",
|
|
1546
1911
|
bgImage: s.backgroundImage || "",
|
|
1547
1912
|
bgRepeat: s.backgroundRepeat || "no-repeat",
|
|
@@ -1555,15 +1920,15 @@ function normalizeEmailDesignInput(input) {
|
|
|
1555
1920
|
contentBgPosition: s.contentBackgroundPosition || "center",
|
|
1556
1921
|
contentBgGradient: s.contentBackgroundGradient || null,
|
|
1557
1922
|
contentWidth: typeof s.width === "number" ? s.width : 600,
|
|
1558
|
-
padding: 24,
|
|
1559
|
-
borderRadius: 8,
|
|
1923
|
+
padding: typeof studioSettings?.contentPadding === "number" ? studioSettings.contentPadding : typeof settings.padding === "number" ? settings.padding : 24,
|
|
1924
|
+
borderRadius: typeof studioSettings?.contentBorderRadius === "number" ? studioSettings.contentBorderRadius : typeof settings.borderRadius === "number" ? settings.borderRadius : 8,
|
|
1560
1925
|
pageFontFamily: s.fontFamily,
|
|
1561
1926
|
pageTextColor: s.color,
|
|
1562
1927
|
pageLineHeight: s.lineHeightBase != null ? String(s.lineHeightBase) : void 0,
|
|
1563
1928
|
pageResponsive: s.responsive,
|
|
1564
1929
|
pageRtl: s.rtl,
|
|
1565
1930
|
fontFamily: s.fontFamily
|
|
1566
|
-
};
|
|
1931
|
+
});
|
|
1567
1932
|
const rows = (doc.rows || []).map(rowToInternal);
|
|
1568
1933
|
return withHydratedRows({ rows, settings, __emailDocument: doc });
|
|
1569
1934
|
}
|
|
@@ -1587,14 +1952,29 @@ function designToEmailDocument(rows, settings) {
|
|
|
1587
1952
|
fontFamily: settings.fontFamily || settings.pageFontFamily || "Arial, Helvetica, sans-serif",
|
|
1588
1953
|
lineHeightBase: settings.pageLineHeight ? Number(settings.pageLineHeight) : 1.6,
|
|
1589
1954
|
color: settings.pageTextColor || "#111827",
|
|
1590
|
-
responsive: true,
|
|
1591
|
-
rtl:
|
|
1955
|
+
responsive: typeof settings.pageResponsive === "boolean" ? settings.pageResponsive : true,
|
|
1956
|
+
rtl: !!settings.pageRtl,
|
|
1957
|
+
_reactEmailStudio: {
|
|
1958
|
+
contentPadding: settings.padding ?? 24,
|
|
1959
|
+
contentBorderRadius: settings.borderRadius ?? 8,
|
|
1960
|
+
editorSettings: cloneJson(settings)
|
|
1961
|
+
}
|
|
1592
1962
|
},
|
|
1593
1963
|
rows: rows.map((r, ri) => {
|
|
1594
|
-
const
|
|
1964
|
+
const cellArrays = Array.isArray(r.cells) ? r.cells : [];
|
|
1965
|
+
const declaredCols = typeof r.cols === "number" && r.cols > 0 ? r.cols : 0;
|
|
1966
|
+
const cols = Math.max(1, cellArrays.length, declaredCols);
|
|
1967
|
+
const rowPad = r.padding && typeof r.padding === "object" && !Array.isArray(r.padding) ? layoutColumnPaddingForDoc(r.padding) : (() => {
|
|
1968
|
+
const n = typeof r.padding === "number" && Number.isFinite(r.padding) ? r.padding : 0;
|
|
1969
|
+
return { top: n, right: n, bottom: n, left: n };
|
|
1970
|
+
})();
|
|
1971
|
+
const { cells: _rowCells, ...rowEditorSnap } = r;
|
|
1595
1972
|
return {
|
|
1596
1973
|
id: r.id || `row_${ri + 1}`,
|
|
1597
1974
|
type: "row",
|
|
1975
|
+
_reactEmailStudio: {
|
|
1976
|
+
row: cloneJson(rowEditorSnap)
|
|
1977
|
+
},
|
|
1598
1978
|
layout: {
|
|
1599
1979
|
columns: cols,
|
|
1600
1980
|
gap: r.gap ?? 0,
|
|
@@ -1608,13 +1988,14 @@ function designToEmailDocument(rows, settings) {
|
|
|
1608
1988
|
backgroundSize: r.bgSize || "cover",
|
|
1609
1989
|
backgroundPosition: r.bgPosition || "center",
|
|
1610
1990
|
backgroundGradient: r.bgGradient || null,
|
|
1611
|
-
padding:
|
|
1991
|
+
padding: rowPad,
|
|
1612
1992
|
borderRadius: 0,
|
|
1613
1993
|
borderWidth: 0,
|
|
1614
1994
|
borderColor: "#e5e7eb",
|
|
1615
1995
|
textAlign: "left"
|
|
1616
1996
|
},
|
|
1617
|
-
columns: (
|
|
1997
|
+
columns: Array.from({ length: cols }, (_, ci) => {
|
|
1998
|
+
const cellBlocks = cellArrays[ci] ?? [];
|
|
1618
1999
|
const cs = r.columnStyles && r.columnStyles[ci] || {};
|
|
1619
2000
|
return {
|
|
1620
2001
|
id: `col_${ri + 1}_${ci + 1}`,
|
|
@@ -1629,12 +2010,7 @@ function designToEmailDocument(rows, settings) {
|
|
|
1629
2010
|
backgroundGradient: cs.bgGradient || null,
|
|
1630
2011
|
borderRadius: layoutColumnBorderRadiusForDoc(cs.borderRadius)
|
|
1631
2012
|
},
|
|
1632
|
-
blocks: (cellBlocks || []).map((b) => (
|
|
1633
|
-
id: b.id,
|
|
1634
|
-
type: b.type,
|
|
1635
|
-
content: b.props,
|
|
1636
|
-
styles: {}
|
|
1637
|
-
}))
|
|
2013
|
+
blocks: (cellBlocks || []).map((b) => exportEmailDocBlock(b))
|
|
1638
2014
|
};
|
|
1639
2015
|
})
|
|
1640
2016
|
};
|
|
@@ -1642,14 +2018,29 @@ function designToEmailDocument(rows, settings) {
|
|
|
1642
2018
|
};
|
|
1643
2019
|
return doc;
|
|
1644
2020
|
}
|
|
1645
|
-
function hydrateBlock(b) {
|
|
2021
|
+
function hydrateBlock(b, depth = 0) {
|
|
1646
2022
|
if (!b || typeof b !== "object") return null;
|
|
1647
2023
|
const t = b.type === "nestedRow" ? "layout" : b.type;
|
|
1648
2024
|
if (!isKnownBlockType(t)) return null;
|
|
1649
2025
|
if (t === "layout" && b.props && Array.isArray(b.props.cells)) {
|
|
1650
2026
|
const defaults2 = DEFAULT_BLOCK_PROPS.layout;
|
|
2027
|
+
if (depth >= MAX_LAYOUT_TREE_DEPTH) {
|
|
2028
|
+
const ratios = Array.isArray(b.props.ratios) && b.props.ratios.length ? [...b.props.ratios] : [1];
|
|
2029
|
+
return {
|
|
2030
|
+
...b,
|
|
2031
|
+
type: "layout",
|
|
2032
|
+
id: typeof b.id === "string" && b.id ? b.id : uid(),
|
|
2033
|
+
props: {
|
|
2034
|
+
...defaults2,
|
|
2035
|
+
...b.props,
|
|
2036
|
+
bgSize: b.props.bgSize ?? defaults2.bgSize,
|
|
2037
|
+
bgRepeat: b.props.bgRepeat ?? defaults2.bgRepeat,
|
|
2038
|
+
cells: ratios.map(() => [])
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
1651
2042
|
const cells = b.props.cells.map(
|
|
1652
|
-
(col) => Array.isArray(col) ? col.map(hydrateBlock).filter((x) => x != null) : []
|
|
2043
|
+
(col) => Array.isArray(col) ? col.map((x) => hydrateBlock(x, depth + 1)).filter((x) => x != null) : []
|
|
1653
2044
|
);
|
|
1654
2045
|
return {
|
|
1655
2046
|
...b,
|
|
@@ -1680,6 +2071,54 @@ function hydrateBlock(b) {
|
|
|
1680
2071
|
props: merged
|
|
1681
2072
|
};
|
|
1682
2073
|
}
|
|
2074
|
+
function mapEmbeddedLayoutCellBlock(raw, layoutDepth = 0) {
|
|
2075
|
+
if (!raw || typeof raw !== "object") return null;
|
|
2076
|
+
const r = raw;
|
|
2077
|
+
if (r.props && typeof r.props === "object" && typeof r.type === "string" && !("styles" in r)) {
|
|
2078
|
+
return hydrateBlock(r, layoutDepth);
|
|
2079
|
+
}
|
|
2080
|
+
return mapBlockToInternal(r, layoutDepth);
|
|
2081
|
+
}
|
|
2082
|
+
function applyImportedEditorPropsFromDoc(block, t, b, layoutDepth = 0) {
|
|
2083
|
+
const exp = b.props;
|
|
2084
|
+
if (!exp || typeof exp !== "object" || Array.isArray(exp)) return;
|
|
2085
|
+
if (t === "layout" && Array.isArray(exp.cells)) {
|
|
2086
|
+
const hb = hydrateBlock({ type: "layout", id: block.id, props: exp }, layoutDepth);
|
|
2087
|
+
if (hb) {
|
|
2088
|
+
block.props = hb.props;
|
|
2089
|
+
if (typeof hb.id === "string" && hb.id) block.id = hb.id;
|
|
2090
|
+
}
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
Object.assign(block.props, exp);
|
|
2094
|
+
normalizeBoxStyles(block.props, t);
|
|
2095
|
+
if (t === "html" || t === "text") {
|
|
2096
|
+
block.props.content = normalizeRichHtmlForStorage(String(block.props.content ?? ""));
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function exportEmailDocBlock(b, depth = 0) {
|
|
2100
|
+
if (!b || typeof b !== "object") return { id: uid(), type: "text", content: {}, styles: {} };
|
|
2101
|
+
const doc = internalBlockToEmailDoc(b, depth);
|
|
2102
|
+
const out = { ...doc };
|
|
2103
|
+
if (b.props && typeof b.props === "object" && !Array.isArray(b.props)) {
|
|
2104
|
+
out.props = cloneJson(b.props);
|
|
2105
|
+
}
|
|
2106
|
+
if (b.type === "layout" && Array.isArray(b.props?.cells)) {
|
|
2107
|
+
const baseContent = typeof doc.content === "object" && doc.content ? doc.content : {};
|
|
2108
|
+
if (depth >= MAX_LAYOUT_TREE_DEPTH) {
|
|
2109
|
+
const ratios = Array.isArray(b.props.ratios) && b.props.ratios.length ? b.props.ratios : [1];
|
|
2110
|
+
out.content = { ...baseContent, cells: ratios.map(() => []) };
|
|
2111
|
+
} else {
|
|
2112
|
+
out.content = {
|
|
2113
|
+
...baseContent,
|
|
2114
|
+
cells: b.props.cells.map(
|
|
2115
|
+
(col) => Array.isArray(col) ? col.map((child) => exportEmailDocBlock(child, depth + 1)) : []
|
|
2116
|
+
)
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
return out;
|
|
2121
|
+
}
|
|
1683
2122
|
function hydrateLayoutRow(row) {
|
|
1684
2123
|
if (!row || typeof row !== "object") return row;
|
|
1685
2124
|
const cells = (row.cells || []).map(
|
|
@@ -4452,32 +4891,42 @@ function ContentBlockEditor({ block, onChange, mergeTags, onClose, onUpload, C }
|
|
|
4452
4891
|
] });
|
|
4453
4892
|
case "text":
|
|
4454
4893
|
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
4455
|
-
/* @__PURE__ */ jsx6(
|
|
4456
|
-
|
|
4894
|
+
/* @__PURE__ */ jsx6(PR, { label: "Content (HTML)", C, children: /* @__PURE__ */ jsx6(
|
|
4895
|
+
"textarea",
|
|
4457
4896
|
{
|
|
4897
|
+
style: { ...IS, minHeight: 200, resize: "vertical", fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace", fontSize: 12, lineHeight: 1.45 },
|
|
4458
4898
|
value: normalizeRichHtmlForStorage(p.content),
|
|
4459
|
-
onChange: (
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4899
|
+
onChange: (e) => set("content", normalizeRichHtmlForStorage(e.target.value)),
|
|
4900
|
+
spellCheck: false,
|
|
4901
|
+
placeholder: "e.g. <p>Your message</p>"
|
|
4902
|
+
},
|
|
4903
|
+
block.id
|
|
4904
|
+
) }),
|
|
4905
|
+
mergeTags && mergeTags.length > 0 ? /* @__PURE__ */ jsx6(PR, { label: "Insert merge tag", C, children: /* @__PURE__ */ jsxs4(
|
|
4906
|
+
"select",
|
|
4907
|
+
{
|
|
4908
|
+
style: IS,
|
|
4909
|
+
defaultValue: "",
|
|
4910
|
+
onChange: (e) => {
|
|
4911
|
+
const v = e.target.value;
|
|
4912
|
+
if (v) {
|
|
4913
|
+
set("content", normalizeRichHtmlForStorage((p.content || "") + " " + v));
|
|
4914
|
+
e.target.value = "";
|
|
4915
|
+
}
|
|
4468
4916
|
},
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
C
|
|
4917
|
+
children: [
|
|
4918
|
+
/* @__PURE__ */ jsx6("option", { value: "", children: "Choose\u2026" }),
|
|
4919
|
+
mergeTags.map((t) => /* @__PURE__ */ jsx6("option", { value: t.value, children: t.name }, t.name))
|
|
4920
|
+
]
|
|
4474
4921
|
}
|
|
4475
|
-
) }
|
|
4922
|
+
) }) : null,
|
|
4476
4923
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Font size", value: p.fontSize ?? 15, onChange: (n) => set("fontSize", n), min: 8, max: 96, step: 1, C }),
|
|
4477
4924
|
Col("color", "Color"),
|
|
4478
4925
|
/* @__PURE__ */ jsx6(AlignButtons, { value: p.align, onChange: (v) => set("align", v), options: ["left", "center", "right", "justify"], C }),
|
|
4479
4926
|
Sel("fontWeight", "Weight", ["400", "500", "600", "700", "800"]),
|
|
4480
4927
|
Sel("fontFamily", "Font", FONTS2),
|
|
4928
|
+
Tog("italic", "Italic"),
|
|
4929
|
+
Tog("underline", "Underline"),
|
|
4481
4930
|
/* @__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) }) }),
|
|
4482
4931
|
/* @__PURE__ */ jsx6(NumRangePx, { label: "Letter spacing", value: p.letterSpacing ?? 0, onChange: (n) => set("letterSpacing", n), min: 0, max: 30, step: 0.5, C }),
|
|
4483
4932
|
/* @__PURE__ */ jsx6(BlockSurfaceBgInspector, { variant: "surface", p, set, C, onUpload, syncKey: block.id }),
|
|
@@ -6319,6 +6768,9 @@ var ReactEmailEditor = forwardRef(
|
|
|
6319
6768
|
const nested = action.nested;
|
|
6320
6769
|
const toLoc = toColumnLoc(rowId, cellIdx, nested);
|
|
6321
6770
|
if (action.kind === "new") {
|
|
6771
|
+
if ((action.contentType === "layout" || action.contentType === "nestedRow") && nestedLayoutDepth(nested) >= MAX_NESTED_LAYOUT_DEPTH) {
|
|
6772
|
+
return;
|
|
6773
|
+
}
|
|
6322
6774
|
let nb;
|
|
6323
6775
|
if (action.preset && (action.contentType === "layout" || action.contentType === "nestedRow")) {
|
|
6324
6776
|
nb = makeNestedRowBlock(action.preset);
|