@unlayer/react-elements 0.1.16 → 0.1.18
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/README.md +45 -1
- package/dist/index.cjs +288 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +153 -18
- package/dist/index.d.ts +153 -18
- package/dist/index.js +287 -58
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -191,6 +191,50 @@ function textNodeToHtml(node) {
|
|
|
191
191
|
}
|
|
192
192
|
return html;
|
|
193
193
|
}
|
|
194
|
+
var NUMERIC_ALIGN = {
|
|
195
|
+
1: "left",
|
|
196
|
+
2: "center",
|
|
197
|
+
3: "right",
|
|
198
|
+
4: "justify"
|
|
199
|
+
};
|
|
200
|
+
function dirAttribute(direction) {
|
|
201
|
+
return direction === "ltr" || direction === "rtl" ? ` dir="${direction}"` : "";
|
|
202
|
+
}
|
|
203
|
+
function paragraphAlign(format) {
|
|
204
|
+
if (typeof format === "string") {
|
|
205
|
+
return ["left", "center", "right", "justify"].includes(format) ? format : void 0;
|
|
206
|
+
}
|
|
207
|
+
if (typeof format === "number") {
|
|
208
|
+
return NUMERIC_ALIGN[format];
|
|
209
|
+
}
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
function paragraphNodeToHtml(node, childrenHtml) {
|
|
213
|
+
const isInlineTool = !!node.isInlineTool;
|
|
214
|
+
const tag = isInlineTool ? "span" : "p";
|
|
215
|
+
const dir = dirAttribute(node.direction);
|
|
216
|
+
const styleParts = [];
|
|
217
|
+
if (node.style) {
|
|
218
|
+
styleParts.push(String(node.style).replace(/;+\s*$/, ""));
|
|
219
|
+
}
|
|
220
|
+
if (!isInlineTool) {
|
|
221
|
+
styleParts.push(
|
|
222
|
+
"margin: 0px",
|
|
223
|
+
"margin-block-start: 0px",
|
|
224
|
+
"margin-block-end: 0px"
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const indent = Number(node.indent) || 0;
|
|
228
|
+
if (indent > 0) {
|
|
229
|
+
styleParts.push(`padding-inline-start: ${indent * 40}px`);
|
|
230
|
+
}
|
|
231
|
+
const align = paragraphAlign(node.format);
|
|
232
|
+
if (align) {
|
|
233
|
+
styleParts.push(`text-align: ${align}`);
|
|
234
|
+
}
|
|
235
|
+
const style = styleParts.length > 0 ? ` style="${escapeHtml(styleParts.join("; ") + ";")}"` : "";
|
|
236
|
+
return `<${tag}${dir}${style}>${childrenHtml || "<br>"}</${tag}>`;
|
|
237
|
+
}
|
|
194
238
|
function nodeToHtml(node) {
|
|
195
239
|
if (!node || typeof node !== "object") return "";
|
|
196
240
|
const type = node.type;
|
|
@@ -205,14 +249,11 @@ function nodeToHtml(node) {
|
|
|
205
249
|
case "root":
|
|
206
250
|
return childrenHtml;
|
|
207
251
|
case "paragraph":
|
|
208
|
-
case "extended-paragraph":
|
|
209
|
-
|
|
210
|
-
const dir = node.direction ? ` dir="${node.direction}"` : "";
|
|
211
|
-
return `<p${dir}>${childrenHtml}</p>`;
|
|
212
|
-
}
|
|
252
|
+
case "extended-paragraph":
|
|
253
|
+
return paragraphNodeToHtml(node, childrenHtml);
|
|
213
254
|
case "heading": {
|
|
214
|
-
const tag = node.tag
|
|
215
|
-
const dir = node.direction
|
|
255
|
+
const tag = /^h[1-6]$/.test(node.tag) ? node.tag : "h1";
|
|
256
|
+
const dir = dirAttribute(node.direction);
|
|
216
257
|
return `<${tag}${dir}>${childrenHtml}</${tag}>`;
|
|
217
258
|
}
|
|
218
259
|
case "link": {
|
|
@@ -572,16 +613,6 @@ function nextHtmlId(config, prefix) {
|
|
|
572
613
|
ids[prefix] = (ids[prefix] || 0) + 1;
|
|
573
614
|
return `${prefix}_${ids[prefix]}`;
|
|
574
615
|
}
|
|
575
|
-
function ensureMeta(values, type, index = 0) {
|
|
576
|
-
return {
|
|
577
|
-
...values,
|
|
578
|
-
_meta: {
|
|
579
|
-
htmlID: `u_content_${type.toLowerCase()}_${index + 1}`,
|
|
580
|
-
htmlClassNames: `u_content_${type.toLowerCase()}`,
|
|
581
|
-
...values._meta || {}
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
}
|
|
585
616
|
function renderComponent(config) {
|
|
586
617
|
const { type, values, className, style, args = [], innerHTML, _config, exporter, metaContext } = config;
|
|
587
618
|
try {
|
|
@@ -634,6 +665,7 @@ function createItemComponent(config) {
|
|
|
634
665
|
style,
|
|
635
666
|
// Internal props
|
|
636
667
|
index = 0,
|
|
668
|
+
_metaHtmlId,
|
|
637
669
|
colIndex = 0,
|
|
638
670
|
cells = [],
|
|
639
671
|
bodyValues = {},
|
|
@@ -651,11 +683,15 @@ function createItemComponent(config) {
|
|
|
651
683
|
...restProps
|
|
652
684
|
});
|
|
653
685
|
const finalValues = mergeValues(config.defaultValues, mappedValues);
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
686
|
+
const metaName = config.metaName ?? config.name.toLowerCase();
|
|
687
|
+
const valuesWithMeta = {
|
|
688
|
+
...finalValues,
|
|
689
|
+
_meta: {
|
|
690
|
+
htmlID: _metaHtmlId ?? `u_content_${metaName}_${index + 1}`,
|
|
691
|
+
htmlClassNames: `u_content_${metaName}`,
|
|
692
|
+
...finalValues._meta || {}
|
|
693
|
+
}
|
|
694
|
+
};
|
|
659
695
|
const safeBodyValues = {
|
|
660
696
|
contentWidth: "500px",
|
|
661
697
|
...bodyValues
|
|
@@ -704,7 +740,11 @@ function createItemComponent(config) {
|
|
|
704
740
|
ItemComponent[UNLAYER_CONFIG_KEY] = {
|
|
705
741
|
name: config.name,
|
|
706
742
|
defaultValues: config.defaultValues,
|
|
707
|
-
propMapper: config.propMapper
|
|
743
|
+
propMapper: config.propMapper,
|
|
744
|
+
contentType: config.contentType,
|
|
745
|
+
slug: config.slug,
|
|
746
|
+
metaName: config.metaName,
|
|
747
|
+
head: config.head
|
|
708
748
|
};
|
|
709
749
|
return ItemComponent;
|
|
710
750
|
}
|
|
@@ -1115,7 +1155,7 @@ function getWidthPercentages(cells) {
|
|
|
1115
1155
|
return { value, className };
|
|
1116
1156
|
});
|
|
1117
1157
|
}
|
|
1118
|
-
function generateGridCSS(cells, mode, contentWidth = 600, mobileBreakpoint =
|
|
1158
|
+
function generateGridCSS(cells, mode, contentWidth = 600, mobileBreakpoint = 480) {
|
|
1119
1159
|
const widths = getWidthPercentages(cells);
|
|
1120
1160
|
if (mode === "email") {
|
|
1121
1161
|
const minQuery = `@media only screen and (min-width: ${contentWidth + 20}px)`;
|
|
@@ -1152,21 +1192,14 @@ ${widths.map(({ value, className }) => ` .no-stack .u-col-${className} { width:
|
|
|
1152
1192
|
const columnCSS = widths.map(
|
|
1153
1193
|
({ value, className }) => `.u-row .u-col.u-col-${className} { flex: 0 0 ${value}%; max-width: ${value}%; }`
|
|
1154
1194
|
).join("\n");
|
|
1155
|
-
const responsiveCSS = `
|
|
1156
|
-
@media
|
|
1157
|
-
.
|
|
1158
|
-
.u-row
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
min-width: 320px !important;
|
|
1195
|
+
const responsiveCSS = mode === "document" ? "" : `
|
|
1196
|
+
@media (max-width: ${mobileBreakpoint}px) {
|
|
1197
|
+
.u_row .container { max-width: 100% !important; }
|
|
1198
|
+
.u-row:not(.no-stack) { flex-wrap: wrap; }
|
|
1199
|
+
.u-row:not(.no-stack) .u-col {
|
|
1200
|
+
flex: 0 0 100% !important;
|
|
1162
1201
|
max-width: 100% !important;
|
|
1163
1202
|
}
|
|
1164
|
-
.u-row .u-col > div { margin: 0 auto; }
|
|
1165
|
-
.no-stack .u-col {
|
|
1166
|
-
min-width: 0 !important;
|
|
1167
|
-
display: table-cell !important;
|
|
1168
|
-
}
|
|
1169
|
-
${widths.map(({ value, className }) => ` .no-stack .u-col-${className} { width: ${value}% !important; }`).join("\n")}
|
|
1170
1203
|
}`;
|
|
1171
1204
|
return baseCSS + "\n" + columnCSS + "\n" + responsiveCSS;
|
|
1172
1205
|
}
|
|
@@ -1333,9 +1366,12 @@ var Column = (props) => {
|
|
|
1333
1366
|
if (typeof child.type === "function") {
|
|
1334
1367
|
const ComponentType = child.type;
|
|
1335
1368
|
const renderFn = ComponentType[UNLAYER_RENDER_KEY] || ComponentType;
|
|
1369
|
+
const componentName = ComponentType?.[UNLAYER_CONFIG_KEY]?.metaName ?? (ComponentType?.displayName || ComponentType?.name || "component").toLowerCase();
|
|
1370
|
+
const contentHtmlId = nextHtmlId(_config, `u_content_${componentName}`);
|
|
1336
1371
|
const rendered = renderFn({
|
|
1337
1372
|
...child.props,
|
|
1338
1373
|
_config,
|
|
1374
|
+
_metaHtmlId: contentHtmlId,
|
|
1339
1375
|
colIndex: index,
|
|
1340
1376
|
cells,
|
|
1341
1377
|
bodyValues,
|
|
@@ -1344,15 +1380,13 @@ var Column = (props) => {
|
|
|
1344
1380
|
});
|
|
1345
1381
|
if (rendered && typeof rendered === "object" && rendered.props && rendered.props.dangerouslySetInnerHTML) {
|
|
1346
1382
|
const componentHTML = rendered.props.dangerouslySetInnerHTML.__html;
|
|
1347
|
-
const componentType = child.type;
|
|
1348
|
-
const componentName = (componentType?.displayName || componentType?.name || "component").toLowerCase();
|
|
1349
1383
|
const childProps = child.props;
|
|
1350
1384
|
const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING2;
|
|
1351
1385
|
const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
|
|
1352
1386
|
const contentValues = {
|
|
1353
1387
|
containerPadding,
|
|
1354
1388
|
_meta: {
|
|
1355
|
-
htmlID:
|
|
1389
|
+
htmlID: contentHtmlId,
|
|
1356
1390
|
htmlClassNames: `u_content_${componentName}`
|
|
1357
1391
|
}
|
|
1358
1392
|
};
|
|
@@ -1523,7 +1557,7 @@ UnlayerProvider.displayName = "UnlayerProvider";
|
|
|
1523
1557
|
function useUnlayerConfig() {
|
|
1524
1558
|
return useContext(getUnlayerContext());
|
|
1525
1559
|
}
|
|
1526
|
-
function
|
|
1560
|
+
function ensureMeta(values, type, index = 0) {
|
|
1527
1561
|
return {
|
|
1528
1562
|
...values,
|
|
1529
1563
|
_meta: {
|
|
@@ -1604,17 +1638,17 @@ function walkItem(element, bodyValues, displayMode, headConfig, counters, styles
|
|
|
1604
1638
|
const { children, ...restProps } = element.props;
|
|
1605
1639
|
const mappedValues = propMapper({ children, ...restProps });
|
|
1606
1640
|
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
1607
|
-
const contentType = name.toLowerCase();
|
|
1641
|
+
const contentType = config.metaName ?? name.toLowerCase();
|
|
1608
1642
|
const count = nextCounter(counters, `u_content_${contentType}`);
|
|
1609
|
-
const valuesWithMeta =
|
|
1610
|
-
const head = heads[name];
|
|
1643
|
+
const valuesWithMeta = ensureMeta(finalValues, contentType, count - 1);
|
|
1644
|
+
const head = config.head ?? heads[name];
|
|
1611
1645
|
callHead(head, valuesWithMeta, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1612
1646
|
}
|
|
1613
1647
|
function walkColumn(element, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags) {
|
|
1614
1648
|
const semanticProps = extractSemanticProps(element.props);
|
|
1615
1649
|
const mapped = mapSemanticProps(semanticProps, COLUMN_DEFAULTS, "Column");
|
|
1616
1650
|
const count = nextCounter(counters, "u_column");
|
|
1617
|
-
const columnValues =
|
|
1651
|
+
const columnValues = ensureMeta(mergeValues(COLUMN_DEFAULTS, mapped), "column", count - 1);
|
|
1618
1652
|
const columnHead = heads["Column"];
|
|
1619
1653
|
callHead(columnHead, columnValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1620
1654
|
const children = collectChildren(element.props.children);
|
|
@@ -1626,7 +1660,7 @@ function walkRow(element, bodyValues, displayMode, headConfig, counters, styles,
|
|
|
1626
1660
|
const semanticProps = extractSemanticProps(element.props, ["layout"]);
|
|
1627
1661
|
const mapped = mapSemanticProps(semanticProps, ROW_DEFAULTS, "Row");
|
|
1628
1662
|
const count = nextCounter(counters, "u_row");
|
|
1629
|
-
const rowValues =
|
|
1663
|
+
const rowValues = ensureMeta(mergeValues(ROW_DEFAULTS, mapped), "row", count - 1);
|
|
1630
1664
|
const rowHead = heads["Row"];
|
|
1631
1665
|
callHead(rowHead, rowValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1632
1666
|
const children = collectChildren(element.props.children);
|
|
@@ -1649,7 +1683,7 @@ function extractHeadFromTree(element, options) {
|
|
|
1649
1683
|
const counters = {};
|
|
1650
1684
|
const semanticProps = extractSemanticProps(element.props);
|
|
1651
1685
|
const mapped = mapSemanticProps(semanticProps, BODY_DEFAULTS, "Body");
|
|
1652
|
-
const bodyValues =
|
|
1686
|
+
const bodyValues = ensureMeta(mergeValues(BODY_DEFAULTS, mapped), "body", 0);
|
|
1653
1687
|
const bodyHead = heads["Body"];
|
|
1654
1688
|
callHead(bodyHead, bodyValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1655
1689
|
const children = collectChildren(element.props.children);
|
|
@@ -1667,8 +1701,81 @@ function extractHeadFromTree(element, options) {
|
|
|
1667
1701
|
};
|
|
1668
1702
|
}
|
|
1669
1703
|
|
|
1704
|
+
// src/utils/document-layouts.ts
|
|
1705
|
+
function emailLayout(args) {
|
|
1706
|
+
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1707
|
+
const head = [
|
|
1708
|
+
titleTag,
|
|
1709
|
+
tagLines,
|
|
1710
|
+
styleTag,
|
|
1711
|
+
scriptTag,
|
|
1712
|
+
fontLinks && `<!--[if !mso]><!-->${fontLinks}<!--<![endif]-->`
|
|
1713
|
+
].filter(Boolean).join("\n ");
|
|
1714
|
+
return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
1715
|
+
<html${dir} xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
1716
|
+
<head>
|
|
1717
|
+
<!--[if gte mso 9]>
|
|
1718
|
+
<xml>
|
|
1719
|
+
<o:OfficeDocumentSettings>
|
|
1720
|
+
<o:AllowPNG/>
|
|
1721
|
+
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
1722
|
+
</o:OfficeDocumentSettings>
|
|
1723
|
+
</xml>
|
|
1724
|
+
<![endif]-->
|
|
1725
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
1726
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1727
|
+
<meta name="x-apple-disable-message-reformatting">
|
|
1728
|
+
<!--[if !mso]><!--><meta http-equiv="X-UA-Compatible" content="IE=edge"><!--<![endif]-->
|
|
1729
|
+
${head}
|
|
1730
|
+
</head>
|
|
1731
|
+
${body}
|
|
1732
|
+
</html>
|
|
1733
|
+
`;
|
|
1734
|
+
}
|
|
1735
|
+
function documentLayout(args) {
|
|
1736
|
+
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1737
|
+
const head = [titleTag, tagLines, styleTag, scriptTag, fontLinks].filter(Boolean).join("\n ");
|
|
1738
|
+
return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
1739
|
+
<html${dir} xmlns="http://www.w3.org/1999/xhtml">
|
|
1740
|
+
<head>
|
|
1741
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
1742
|
+
${head}
|
|
1743
|
+
</head>
|
|
1744
|
+
${body}
|
|
1745
|
+
</html>
|
|
1746
|
+
`;
|
|
1747
|
+
}
|
|
1748
|
+
function webLayout(args) {
|
|
1749
|
+
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1750
|
+
const head = [titleTag, fontLinks, tagLines, styleTag, scriptTag].filter(Boolean).join("\n ");
|
|
1751
|
+
return `<!doctype html>
|
|
1752
|
+
<html${dir}>
|
|
1753
|
+
<head>
|
|
1754
|
+
<meta charset="utf-8">
|
|
1755
|
+
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
1756
|
+
<meta name="description" content="">
|
|
1757
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1758
|
+
${head}
|
|
1759
|
+
</head>
|
|
1760
|
+
<body>
|
|
1761
|
+
${body}
|
|
1762
|
+
</body>
|
|
1763
|
+
</html>
|
|
1764
|
+
`;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1670
1767
|
// src/utils/render-to-html.tsx
|
|
1671
|
-
|
|
1768
|
+
var MODE_BY_WRAPPER = {
|
|
1769
|
+
Email: "email",
|
|
1770
|
+
Page: "web",
|
|
1771
|
+
Document: "document"
|
|
1772
|
+
};
|
|
1773
|
+
function resolveDisplayMode(element, mergedConfig) {
|
|
1774
|
+
const displayName = element.type?.displayName;
|
|
1775
|
+
const wrapperMode = displayName ? MODE_BY_WRAPPER[displayName] : void 0;
|
|
1776
|
+
return wrapperMode ?? element.props.mode ?? mergedConfig.mode ?? "web";
|
|
1777
|
+
}
|
|
1778
|
+
function renderBody(element, config) {
|
|
1672
1779
|
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
1673
1780
|
try {
|
|
1674
1781
|
const enriched = React.cloneElement(element, { config: mergedConfig });
|
|
@@ -1681,14 +1788,52 @@ Tip: Ensure your tree uses Body > Row > Column > Item structure.`
|
|
|
1681
1788
|
);
|
|
1682
1789
|
}
|
|
1683
1790
|
}
|
|
1791
|
+
function stripOuterDiv(html) {
|
|
1792
|
+
const match = html.match(/^\s*<div[^>]*>([\s\S]*)<\/div>\s*$/);
|
|
1793
|
+
return match ? match[1] : html;
|
|
1794
|
+
}
|
|
1795
|
+
function escapeForHtml(text) {
|
|
1796
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1797
|
+
}
|
|
1798
|
+
function renderToHtml(element, options) {
|
|
1799
|
+
const { title, fonts = [], ...config } = options ?? {};
|
|
1800
|
+
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
1801
|
+
const displayMode = resolveDisplayMode(element, mergedConfig);
|
|
1802
|
+
const wrapperName = element.type?.displayName;
|
|
1803
|
+
const isUnlayerWrapper = wrapperName === "Body" || (wrapperName ? wrapperName in MODE_BY_WRAPPER : false);
|
|
1804
|
+
const rawBody = renderBody(element, config);
|
|
1805
|
+
const body = isUnlayerWrapper ? stripOuterDiv(rawBody) : rawBody;
|
|
1806
|
+
const { css, js, tags } = extractHeadFromTree(element, {
|
|
1807
|
+
displayMode,
|
|
1808
|
+
headConfig: mergedConfig.headConfig
|
|
1809
|
+
});
|
|
1810
|
+
const layoutArgs = {
|
|
1811
|
+
dir: mergedConfig.textDirection ? ` dir="${escapeForHtml(String(mergedConfig.textDirection))}"` : "",
|
|
1812
|
+
titleTag: title ? `<title>${escapeForHtml(title.trim())}</title>` : "",
|
|
1813
|
+
styleTag: css ? `<style type="text/css">
|
|
1814
|
+
${css}
|
|
1815
|
+
</style>` : "",
|
|
1816
|
+
scriptTag: js ? `<script type="application/javascript">
|
|
1817
|
+
${js}
|
|
1818
|
+
</script>` : "",
|
|
1819
|
+
tagLines: tags.join("\n"),
|
|
1820
|
+
fontLinks: fonts.filter((font) => font?.url).map(
|
|
1821
|
+
(font) => `<link href="${escapeForHtml(font.url)}" rel="stylesheet" type="text/css">`
|
|
1822
|
+
).join(""),
|
|
1823
|
+
body
|
|
1824
|
+
};
|
|
1825
|
+
if (displayMode === "email") return emailLayout(layoutArgs);
|
|
1826
|
+
if (displayMode === "document") return documentLayout(layoutArgs);
|
|
1827
|
+
return webLayout(layoutArgs);
|
|
1828
|
+
}
|
|
1684
1829
|
function renderToPlainText(element, config) {
|
|
1685
|
-
const html =
|
|
1830
|
+
const html = renderBody(element, config);
|
|
1686
1831
|
return htmlToPlainText(html);
|
|
1687
1832
|
}
|
|
1688
1833
|
function renderToHtmlParts(element, config) {
|
|
1689
|
-
const body =
|
|
1834
|
+
const body = renderBody(element, config);
|
|
1690
1835
|
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
1691
|
-
const displayMode = element
|
|
1836
|
+
const displayMode = resolveDisplayMode(element, mergedConfig);
|
|
1692
1837
|
const { css, js, tags } = extractHeadFromTree(element, {
|
|
1693
1838
|
displayMode,
|
|
1694
1839
|
headConfig: mergedConfig.headConfig
|
|
@@ -1811,10 +1956,11 @@ function processItem(element, counters, layout = {}) {
|
|
|
1811
1956
|
`[Unlayer] renderToJson: <${name2}> is not a recognized Unlayer item component. Only components created with createItemComponent are supported.`
|
|
1812
1957
|
);
|
|
1813
1958
|
}
|
|
1814
|
-
const { name, defaultValues, propMapper } = config;
|
|
1815
|
-
const contentType = toContentType(name);
|
|
1816
|
-
const
|
|
1817
|
-
const
|
|
1959
|
+
const { name, defaultValues, propMapper, slug } = config;
|
|
1960
|
+
const contentType = config.contentType ?? toContentType(name);
|
|
1961
|
+
const metaBase = `u_content_${config.metaName ?? contentType}`;
|
|
1962
|
+
const count = nextCounter2(counters, metaBase);
|
|
1963
|
+
const id = makeId(metaBase, count);
|
|
1818
1964
|
const { children, ...restProps } = element.props;
|
|
1819
1965
|
const mappedValues = propMapper({ children, ...restProps });
|
|
1820
1966
|
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
@@ -1827,7 +1973,7 @@ function processItem(element, counters, layout = {}) {
|
|
|
1827
1973
|
...finalValues,
|
|
1828
1974
|
_meta: {
|
|
1829
1975
|
htmlID: id,
|
|
1830
|
-
htmlClassNames:
|
|
1976
|
+
htmlClassNames: metaBase,
|
|
1831
1977
|
...finalValues._meta || {}
|
|
1832
1978
|
},
|
|
1833
1979
|
selectable: true,
|
|
@@ -1844,7 +1990,7 @@ function processItem(element, counters, layout = {}) {
|
|
|
1844
1990
|
});
|
|
1845
1991
|
values.src = pinImageSrc(itemSrc, availableWidth);
|
|
1846
1992
|
}
|
|
1847
|
-
return { type: contentType, values };
|
|
1993
|
+
return slug ? { type: contentType, slug, values } : { type: contentType, values };
|
|
1848
1994
|
}
|
|
1849
1995
|
function processColumn(element, counters, layout = {}) {
|
|
1850
1996
|
const count = nextCounter2(counters, "u_column");
|
|
@@ -1988,6 +2134,89 @@ function renderToJson(element) {
|
|
|
1988
2134
|
};
|
|
1989
2135
|
}
|
|
1990
2136
|
|
|
1991
|
-
|
|
2137
|
+
// src/utils/register-tool.tsx
|
|
2138
|
+
function initialValuesFromOptions(options) {
|
|
2139
|
+
const result = {};
|
|
2140
|
+
for (const group of Object.values(options ?? {})) {
|
|
2141
|
+
for (const [property, option] of Object.entries(group?.options ?? {})) {
|
|
2142
|
+
if (!option || option.enabled === false) continue;
|
|
2143
|
+
if (typeof option.defaultValue !== "undefined") {
|
|
2144
|
+
result[property] = option.defaultValue;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return result;
|
|
2149
|
+
}
|
|
2150
|
+
function withSanitizer(exporter) {
|
|
2151
|
+
return (values, ...args) => {
|
|
2152
|
+
const html = String(exporter(values, ...args) ?? "");
|
|
2153
|
+
const meta = args[args.length - 1];
|
|
2154
|
+
const toSafeHtml = meta?.exporterConfig?.toSafeHtml;
|
|
2155
|
+
return typeof toSafeHtml === "function" ? toSafeHtml(html) : html;
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
function withLinkNormalization(exporter, linkKeys) {
|
|
2159
|
+
if (linkKeys.length === 0) return exporter;
|
|
2160
|
+
return (values, ...args) => {
|
|
2161
|
+
const out = { ...values };
|
|
2162
|
+
for (const key of linkKeys) {
|
|
2163
|
+
const normalized = normalizeLinkValue(out[key]);
|
|
2164
|
+
if (normalized !== void 0) out[key] = normalized;
|
|
2165
|
+
}
|
|
2166
|
+
return exporter(out, ...args);
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
function linkWidgetKeys(options) {
|
|
2170
|
+
const keys = [];
|
|
2171
|
+
for (const group of Object.values(options ?? {})) {
|
|
2172
|
+
for (const [key, option] of Object.entries(group?.options ?? {})) {
|
|
2173
|
+
if (option && option.widget === "link") keys.push(key);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
return keys;
|
|
2177
|
+
}
|
|
2178
|
+
function registerTool(tool) {
|
|
2179
|
+
if (!tool?.name || typeof tool.name !== "string") {
|
|
2180
|
+
throw new Error("[Unlayer] registerTool: `name` is required");
|
|
2181
|
+
}
|
|
2182
|
+
const exporters = tool.renderer?.exporters;
|
|
2183
|
+
if (!exporters || !exporters.web && !exporters.email) {
|
|
2184
|
+
throw new Error(
|
|
2185
|
+
`[Unlayer] registerTool("${tool.name}"): \`renderer.exporters\` needs at least a \`web\` or \`email\` exporter`
|
|
2186
|
+
);
|
|
2187
|
+
}
|
|
2188
|
+
const linkKeys = linkWidgetKeys(tool.options);
|
|
2189
|
+
const sanitized = {};
|
|
2190
|
+
for (const mode of ["web", "email", "document"]) {
|
|
2191
|
+
const exporter = exporters[mode];
|
|
2192
|
+
if (exporter) {
|
|
2193
|
+
sanitized[mode] = withSanitizer(withLinkNormalization(exporter, linkKeys));
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
if (!sanitized.web && sanitized.email) sanitized.web = sanitized.email;
|
|
2197
|
+
return createItemComponent({
|
|
2198
|
+
name: tool.name,
|
|
2199
|
+
displayName: tool.displayName ?? tool.name,
|
|
2200
|
+
// Option-group widget defaults seed the values; tool-level `values`
|
|
2201
|
+
// win — the editor's precedence.
|
|
2202
|
+
defaultValues: {
|
|
2203
|
+
...initialValuesFromOptions(tool.options),
|
|
2204
|
+
...tool.values ?? {}
|
|
2205
|
+
},
|
|
2206
|
+
// Flat props are the tool's values; `values` is the escape hatch.
|
|
2207
|
+
propMapper: ({ children: _children, values, ...rest }) => ({
|
|
2208
|
+
...values ?? {},
|
|
2209
|
+
...rest
|
|
2210
|
+
}),
|
|
2211
|
+
exporters: sanitized,
|
|
2212
|
+
contentType: "custom",
|
|
2213
|
+
slug: tool.name,
|
|
2214
|
+
metaName: `custom_${tool.name}`,
|
|
2215
|
+
head: tool.renderer.head
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
var registerElementsTool = registerTool;
|
|
2219
|
+
|
|
2220
|
+
export { Body_default as Body, Button_default as Button, Column_default as Column, ColumnLayouts, DEFAULT_CONFIG, Divider_default as Divider, Document, Email, Heading_default as Heading, Html_default as Html, Image_default as Image, Menu_default as Menu, Page, Paragraph_default as Paragraph, Row_default as Row, Social_default as Social, Table_default as Table, UnlayerProvider, Video_default as Video, htmlToTextJson, registerElementsTool, registerTool, renderRowToJson, renderToHtml, renderToHtmlParts, renderToJson, renderToPlainText, useUnlayerConfig, validateColumnLayout };
|
|
1992
2221
|
//# sourceMappingURL=index.js.map
|
|
1993
2222
|
//# sourceMappingURL=index.js.map
|