@unlayer/react-elements 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -12,6 +12,81 @@ var ReactDOMServer__default = /*#__PURE__*/_interopDefault(ReactDOMServer);
12
12
 
13
13
  // src/components/Button.tsx
14
14
 
15
+ // src/utils/image-sizing.ts
16
+ function toPx(value) {
17
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
18
+ if (typeof value !== "string") return void 0;
19
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(value.trim());
20
+ return m ? parseFloat(m[1]) : void 0;
21
+ }
22
+ function edges(value) {
23
+ if (value == null) return { left: 0, right: 0 };
24
+ if (typeof value === "number") return { left: value, right: value };
25
+ const parts = String(value).trim().split(/\s+/).map((p) => parseFloat(p) || 0);
26
+ if (parts.length === 1) return { left: parts[0], right: parts[0] };
27
+ if (parts.length === 2 || parts.length === 3)
28
+ return { left: parts[1], right: parts[1] };
29
+ return { left: parts[3] || 0, right: parts[1] || 0 };
30
+ }
31
+ function borderEdges(border) {
32
+ if (!border || typeof border !== "object") return { left: 0, right: 0 };
33
+ const b = border;
34
+ const width = (v) => parseFloat(`${v ?? ""}`) || 0;
35
+ return {
36
+ left: width(b.borderLeftWidth),
37
+ right: width(b.borderRightWidth)
38
+ };
39
+ }
40
+ function fixedContentWidth(contentWidth) {
41
+ if (typeof contentWidth === "number")
42
+ return Number.isFinite(contentWidth) ? contentWidth : void 0;
43
+ if (typeof contentWidth === "string") {
44
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(contentWidth.trim());
45
+ if (m) return parseFloat(m[1]);
46
+ }
47
+ return void 0;
48
+ }
49
+ var FALLBACK_BODY_CONTENT_WIDTH = 500;
50
+ var DEFAULT_CONTAINER_PADDING = "10px";
51
+ function bodyContentWidthPx(contentWidth, fallback = FALLBACK_BODY_CONTENT_WIDTH) {
52
+ return fixedContentWidth(contentWidth) ?? fallback;
53
+ }
54
+ function contentSlotWidth(ctx) {
55
+ const { bodyValues = {}, rowValues = {}, columnValues = {} } = ctx;
56
+ const rowCells = ctx.rowCells && ctx.rowCells.length ? ctx.rowCells : [1];
57
+ const columnIndex = ctx.columnIndex ?? 0;
58
+ const bodyWidth = bodyContentWidthPx(bodyValues.contentWidth);
59
+ const bp = edges(bodyValues.padding);
60
+ const bb = borderEdges(bodyValues.border);
61
+ const bodyAvail = bodyWidth - bp.left - bp.right - bb.left - bb.right;
62
+ const rp = edges(rowValues.padding);
63
+ const rb = borderEdges(rowValues.border);
64
+ const rowAvail = bodyAvail - rp.left - rp.right - rb.left - rb.right;
65
+ const rowSpan = rowCells.reduce((a, b) => a + b, 0) || 1;
66
+ const colSpan = rowCells[columnIndex] || 1;
67
+ const colWidth = colSpan / rowSpan * rowAvail;
68
+ const cp = edges(columnValues.padding);
69
+ const cb = borderEdges(columnValues.border);
70
+ const colAvail = colWidth - cp.left - cp.right - cb.left - cb.right;
71
+ const ip = edges(ctx.containerPadding ?? DEFAULT_CONTAINER_PADDING);
72
+ return colAvail - ip.left - ip.right;
73
+ }
74
+ var PERCENT = /^\d+(?:\.\d+)?%$/;
75
+ function round2(n) {
76
+ return Math.round(n * 100) / 100;
77
+ }
78
+ function pinImageSrc(src, availableWidth) {
79
+ if (!src || typeof src !== "object") return src;
80
+ if (src.autoWidth !== false) return src;
81
+ const maxWidth = src.maxWidth;
82
+ if (typeof maxWidth === "string" && PERCENT.test(maxWidth.trim())) return src;
83
+ const pinPx = toPx(maxWidth);
84
+ if (pinPx == null) return src;
85
+ const avail = availableWidth && availableWidth > 0 ? availableWidth : void 0;
86
+ const pct = avail ? pinPx >= avail ? 100 : round2(pinPx / avail * 100) : 100;
87
+ return { ...src, autoWidth: false, maxWidth: `${pct}%` };
88
+ }
89
+
15
90
  // ../shared/dist/index.js
16
91
  var DEFAULT_CONFIG = {
17
92
  cdnBaseUrl: "https://cdn.tools.unlayer.com",
@@ -571,6 +646,18 @@ function createItemComponent(config) {
571
646
  valuesWithMeta,
572
647
  config.name
573
648
  );
649
+ const exportSrc = valuesForExporter.src;
650
+ if (exportSrc && typeof exportSrc === "object" && exportSrc.autoWidth === false) {
651
+ const availableWidth = contentSlotWidth({
652
+ bodyValues: safeBodyValues,
653
+ rowValues,
654
+ rowCells: cells,
655
+ columnIndex: colIndex,
656
+ columnValues,
657
+ containerPadding: props.containerPadding ?? props.values?.containerPadding
658
+ });
659
+ valuesForExporter.src = pinImageSrc(exportSrc, availableWidth);
660
+ }
574
661
  const exporter = config.exporters[mode] || config.exporters.web;
575
662
  return renderComponent({
576
663
  type: config.name,
@@ -696,7 +783,7 @@ var Image = createItemComponent({
696
783
  name: "Image",
697
784
  defaultValues: DEFAULT_VALUES5,
698
785
  propMapper: (props) => {
699
- const { alt, src, ...rest } = props;
786
+ const { alt, src, width: widthProp, maxWidth: maxWidthProp, ...rest } = props;
700
787
  const restValues = rest.values;
701
788
  const normalizedRest = restValues && typeof restValues.src === "string" ? { ...rest, values: { ...restValues, src: { url: restValues.src } } } : rest;
702
789
  const base = mapSemanticProps(
@@ -716,21 +803,39 @@ var Image = createItemComponent({
716
803
  const start = isStringUrl ? { autoWidth: true, maxWidth: "100%" } : { ...DEFAULT_VALUES5.src };
717
804
  const merged = { ...start, ...userSrc };
718
805
  const pctRe = /^\d+(?:\.\d+)?%$/;
719
- if (typeof merged.width === "string") {
720
- const t = merged.width.trim();
721
- if (pctRe.test(t)) {
722
- if (userSrc.maxWidth === void 0) merged.maxWidth = t;
723
- delete merged.width;
724
- } else {
725
- const px = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(t);
726
- if (px) merged.width = parseFloat(px[1]);
806
+ const asPercent = (v) => typeof v === "string" && pctRe.test(v.trim()) ? v.trim() : void 0;
807
+ const asPx = (v) => {
808
+ if (typeof v === "number" && Number.isFinite(v)) return v;
809
+ if (typeof v === "string") {
810
+ const t = v.trim();
811
+ if (pctRe.test(t)) return void 0;
812
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(t);
813
+ if (m) return parseFloat(m[1]);
814
+ }
815
+ return void 0;
816
+ };
817
+ let displayPct;
818
+ let displayPx;
819
+ for (const candidate of [widthProp, maxWidthProp, userSrc.maxWidth]) {
820
+ if (candidate === void 0) continue;
821
+ const pct = asPercent(candidate);
822
+ if (pct) {
823
+ displayPct = pct;
824
+ break;
825
+ }
826
+ const px = asPx(candidate);
827
+ if (px != null) {
828
+ displayPx = px;
829
+ break;
727
830
  }
728
831
  }
729
- const displayPct = typeof merged.maxWidth === "string" && pctRe.test(merged.maxWidth.trim()) ? merged.maxWidth.trim() : void 0;
730
832
  if (userSrc.autoWidth === void 0) {
731
833
  if (displayPct && displayPct !== "100%") {
732
834
  merged.autoWidth = false;
733
835
  merged.maxWidth = displayPct;
836
+ } else if (displayPx != null) {
837
+ merged.autoWidth = false;
838
+ merged.maxWidth = displayPx;
734
839
  } else {
735
840
  merged.autoWidth = true;
736
841
  merged.maxWidth = "100%";
@@ -1039,13 +1144,7 @@ ${widths.map(({ value, className }) => ` .no-stack .u-col-${className} { width:
1039
1144
  return baseCSS + "\n" + columnCSS + "\n" + responsiveCSS;
1040
1145
  }
1041
1146
  function toContentWidthPx(bodyValues, fallback = 500) {
1042
- const raw = bodyValues?.contentWidth;
1043
- if (typeof raw === "number" && Number.isFinite(raw)) return raw;
1044
- if (typeof raw === "string") {
1045
- const n = parseInt(raw, 10);
1046
- if (Number.isFinite(n)) return n;
1047
- }
1048
- return fallback;
1147
+ return bodyContentWidthPx(bodyValues?.contentWidth, fallback);
1049
1148
  }
1050
1149
  function renderRowToHtml(innerHTML, values, bodyValues, mode, cells, collection = "rows") {
1051
1150
  const rowExporter = exporters.RowExporters[mode] || exporters.RowExporters.web;
@@ -1152,7 +1251,7 @@ var Row = (props) => {
1152
1251
  };
1153
1252
  Row.displayName = "Row";
1154
1253
  var Row_default = Row;
1155
- var DEFAULT_CONTAINER_PADDING = "10px";
1254
+ var DEFAULT_CONTAINER_PADDING2 = "10px";
1156
1255
  var DEFAULT_VALUES12 = COLUMN_DEFAULTS;
1157
1256
  function renderColumnToHtml(innerHTML, values, index, cells, bodyValues, rowValues, mode) {
1158
1257
  const columnExporter = exporters.ColumnExporters[mode] || exporters.ColumnExporters.web;
@@ -1214,7 +1313,7 @@ var Column = (props) => {
1214
1313
  const componentType = child.type;
1215
1314
  const componentName = (componentType?.displayName || componentType?.name || "component").toLowerCase();
1216
1315
  const childProps = child.props;
1217
- const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING;
1316
+ const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING2;
1218
1317
  const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
1219
1318
  const contentValues = {
1220
1319
  containerPadding,
@@ -1669,7 +1768,7 @@ function extractTextFromTextJson(textJson) {
1669
1768
  return "";
1670
1769
  }
1671
1770
  }
1672
- function processItem(element, counters) {
1771
+ function processItem(element, counters, layout = {}) {
1673
1772
  const componentType = element.type;
1674
1773
  const config = componentType[UNLAYER_CONFIG_KEY];
1675
1774
  if (!config) {
@@ -1703,9 +1802,17 @@ function processItem(element, counters) {
1703
1802
  deletable: true,
1704
1803
  hideable: true
1705
1804
  };
1805
+ const itemSrc = values.src;
1806
+ if (itemSrc && typeof itemSrc === "object" && itemSrc.autoWidth === false) {
1807
+ const availableWidth = contentSlotWidth({
1808
+ ...layout,
1809
+ containerPadding: values.containerPadding
1810
+ });
1811
+ values.src = pinImageSrc(itemSrc, availableWidth);
1812
+ }
1706
1813
  return { type: contentType, values };
1707
1814
  }
1708
- function processColumn(element, counters) {
1815
+ function processColumn(element, counters, layout = {}) {
1709
1816
  const count = nextCounter2(counters, "u_column");
1710
1817
  const id = makeId("u_column", count);
1711
1818
  const semanticProps = extractSemanticProps2(element.props);
@@ -1721,12 +1828,13 @@ function processColumn(element, counters) {
1721
1828
  };
1722
1829
  const contents = [];
1723
1830
  const children = collectChildren2(element.props.children);
1831
+ const itemLayout = { ...layout, columnValues: valuesWithMeta };
1724
1832
  for (const child of children) {
1725
- contents.push(processItem(child, counters));
1833
+ contents.push(processItem(child, counters, itemLayout));
1726
1834
  }
1727
1835
  return { contents, values: valuesWithMeta };
1728
1836
  }
1729
- function processRow(element, counters) {
1837
+ function processRow(element, counters, parentLayout = {}) {
1730
1838
  const count = nextCounter2(counters, "u_row");
1731
1839
  const id = makeId("u_row", count);
1732
1840
  const { layout, cells: propsCells } = element.props;
@@ -1738,7 +1846,9 @@ function processRow(element, counters) {
1738
1846
  } else {
1739
1847
  const columnCount = Math.max(
1740
1848
  1,
1741
- collectChildren2(element.props.children).length
1849
+ collectChildren2(element.props.children).filter(
1850
+ (child) => getDisplayName2(child) === "Column"
1851
+ ).length
1742
1852
  );
1743
1853
  cells = Array(columnCount).fill(1);
1744
1854
  }
@@ -1762,10 +1872,19 @@ function processRow(element, counters) {
1762
1872
  };
1763
1873
  const columns = [];
1764
1874
  const children = collectChildren2(element.props.children);
1875
+ const columnLayout = {
1876
+ bodyValues: parentLayout.bodyValues,
1877
+ rowValues: valuesWithMeta,
1878
+ rowCells: cells
1879
+ };
1880
+ let columnIndex = 0;
1765
1881
  for (const child of children) {
1766
1882
  const name = getDisplayName2(child);
1767
1883
  if (name === "Column") {
1768
- columns.push(processColumn(child, counters));
1884
+ columns.push(
1885
+ processColumn(child, counters, { ...columnLayout, columnIndex })
1886
+ );
1887
+ columnIndex += 1;
1769
1888
  } else {
1770
1889
  console.warn(
1771
1890
  `[Unlayer] renderToJson: <${name}> is not a valid Row child. Only <Column> is allowed.`
@@ -1796,7 +1915,7 @@ function processBody(element, counters) {
1796
1915
  for (const child of children) {
1797
1916
  const name = getDisplayName2(child);
1798
1917
  if (name === "Row") {
1799
- rows.push(processRow(child, counters));
1918
+ rows.push(processRow(child, counters, { bodyValues: valuesWithMeta }));
1800
1919
  } else {
1801
1920
  console.warn(
1802
1921
  `[Unlayer] renderToJson: <${name}> is not a valid Body child. Only <Row> is allowed.`