@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.js CHANGED
@@ -5,6 +5,81 @@ import ReactDOMServer, { renderToStaticMarkup } from 'react-dom/server';
5
5
 
6
6
  // src/components/Button.tsx
7
7
 
8
+ // src/utils/image-sizing.ts
9
+ function toPx(value) {
10
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
11
+ if (typeof value !== "string") return void 0;
12
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(value.trim());
13
+ return m ? parseFloat(m[1]) : void 0;
14
+ }
15
+ function edges(value) {
16
+ if (value == null) return { left: 0, right: 0 };
17
+ if (typeof value === "number") return { left: value, right: value };
18
+ const parts = String(value).trim().split(/\s+/).map((p) => parseFloat(p) || 0);
19
+ if (parts.length === 1) return { left: parts[0], right: parts[0] };
20
+ if (parts.length === 2 || parts.length === 3)
21
+ return { left: parts[1], right: parts[1] };
22
+ return { left: parts[3] || 0, right: parts[1] || 0 };
23
+ }
24
+ function borderEdges(border) {
25
+ if (!border || typeof border !== "object") return { left: 0, right: 0 };
26
+ const b = border;
27
+ const width = (v) => parseFloat(`${v ?? ""}`) || 0;
28
+ return {
29
+ left: width(b.borderLeftWidth),
30
+ right: width(b.borderRightWidth)
31
+ };
32
+ }
33
+ function fixedContentWidth(contentWidth) {
34
+ if (typeof contentWidth === "number")
35
+ return Number.isFinite(contentWidth) ? contentWidth : void 0;
36
+ if (typeof contentWidth === "string") {
37
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(contentWidth.trim());
38
+ if (m) return parseFloat(m[1]);
39
+ }
40
+ return void 0;
41
+ }
42
+ var FALLBACK_BODY_CONTENT_WIDTH = 500;
43
+ var DEFAULT_CONTAINER_PADDING = "10px";
44
+ function bodyContentWidthPx(contentWidth, fallback = FALLBACK_BODY_CONTENT_WIDTH) {
45
+ return fixedContentWidth(contentWidth) ?? fallback;
46
+ }
47
+ function contentSlotWidth(ctx) {
48
+ const { bodyValues = {}, rowValues = {}, columnValues = {} } = ctx;
49
+ const rowCells = ctx.rowCells && ctx.rowCells.length ? ctx.rowCells : [1];
50
+ const columnIndex = ctx.columnIndex ?? 0;
51
+ const bodyWidth = bodyContentWidthPx(bodyValues.contentWidth);
52
+ const bp = edges(bodyValues.padding);
53
+ const bb = borderEdges(bodyValues.border);
54
+ const bodyAvail = bodyWidth - bp.left - bp.right - bb.left - bb.right;
55
+ const rp = edges(rowValues.padding);
56
+ const rb = borderEdges(rowValues.border);
57
+ const rowAvail = bodyAvail - rp.left - rp.right - rb.left - rb.right;
58
+ const rowSpan = rowCells.reduce((a, b) => a + b, 0) || 1;
59
+ const colSpan = rowCells[columnIndex] || 1;
60
+ const colWidth = colSpan / rowSpan * rowAvail;
61
+ const cp = edges(columnValues.padding);
62
+ const cb = borderEdges(columnValues.border);
63
+ const colAvail = colWidth - cp.left - cp.right - cb.left - cb.right;
64
+ const ip = edges(ctx.containerPadding ?? DEFAULT_CONTAINER_PADDING);
65
+ return colAvail - ip.left - ip.right;
66
+ }
67
+ var PERCENT = /^\d+(?:\.\d+)?%$/;
68
+ function round2(n) {
69
+ return Math.round(n * 100) / 100;
70
+ }
71
+ function pinImageSrc(src, availableWidth) {
72
+ if (!src || typeof src !== "object") return src;
73
+ if (src.autoWidth !== false) return src;
74
+ const maxWidth = src.maxWidth;
75
+ if (typeof maxWidth === "string" && PERCENT.test(maxWidth.trim())) return src;
76
+ const pinPx = toPx(maxWidth);
77
+ if (pinPx == null) return src;
78
+ const avail = availableWidth && availableWidth > 0 ? availableWidth : void 0;
79
+ const pct = avail ? pinPx >= avail ? 100 : round2(pinPx / avail * 100) : 100;
80
+ return { ...src, autoWidth: false, maxWidth: `${pct}%` };
81
+ }
82
+
8
83
  // ../shared/dist/index.js
9
84
  var DEFAULT_CONFIG = {
10
85
  cdnBaseUrl: "https://cdn.tools.unlayer.com",
@@ -564,6 +639,18 @@ function createItemComponent(config) {
564
639
  valuesWithMeta,
565
640
  config.name
566
641
  );
642
+ const exportSrc = valuesForExporter.src;
643
+ if (exportSrc && typeof exportSrc === "object" && exportSrc.autoWidth === false) {
644
+ const availableWidth = contentSlotWidth({
645
+ bodyValues: safeBodyValues,
646
+ rowValues,
647
+ rowCells: cells,
648
+ columnIndex: colIndex,
649
+ columnValues,
650
+ containerPadding: props.containerPadding ?? props.values?.containerPadding
651
+ });
652
+ valuesForExporter.src = pinImageSrc(exportSrc, availableWidth);
653
+ }
567
654
  const exporter = config.exporters[mode] || config.exporters.web;
568
655
  return renderComponent({
569
656
  type: config.name,
@@ -689,7 +776,7 @@ var Image = createItemComponent({
689
776
  name: "Image",
690
777
  defaultValues: DEFAULT_VALUES5,
691
778
  propMapper: (props) => {
692
- const { alt, src, ...rest } = props;
779
+ const { alt, src, width: widthProp, maxWidth: maxWidthProp, ...rest } = props;
693
780
  const restValues = rest.values;
694
781
  const normalizedRest = restValues && typeof restValues.src === "string" ? { ...rest, values: { ...restValues, src: { url: restValues.src } } } : rest;
695
782
  const base = mapSemanticProps(
@@ -709,21 +796,39 @@ var Image = createItemComponent({
709
796
  const start = isStringUrl ? { autoWidth: true, maxWidth: "100%" } : { ...DEFAULT_VALUES5.src };
710
797
  const merged = { ...start, ...userSrc };
711
798
  const pctRe = /^\d+(?:\.\d+)?%$/;
712
- if (typeof merged.width === "string") {
713
- const t = merged.width.trim();
714
- if (pctRe.test(t)) {
715
- if (userSrc.maxWidth === void 0) merged.maxWidth = t;
716
- delete merged.width;
717
- } else {
718
- const px = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(t);
719
- if (px) merged.width = parseFloat(px[1]);
799
+ const asPercent = (v) => typeof v === "string" && pctRe.test(v.trim()) ? v.trim() : void 0;
800
+ const asPx = (v) => {
801
+ if (typeof v === "number" && Number.isFinite(v)) return v;
802
+ if (typeof v === "string") {
803
+ const t = v.trim();
804
+ if (pctRe.test(t)) return void 0;
805
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(t);
806
+ if (m) return parseFloat(m[1]);
807
+ }
808
+ return void 0;
809
+ };
810
+ let displayPct;
811
+ let displayPx;
812
+ for (const candidate of [widthProp, maxWidthProp, userSrc.maxWidth]) {
813
+ if (candidate === void 0) continue;
814
+ const pct = asPercent(candidate);
815
+ if (pct) {
816
+ displayPct = pct;
817
+ break;
818
+ }
819
+ const px = asPx(candidate);
820
+ if (px != null) {
821
+ displayPx = px;
822
+ break;
720
823
  }
721
824
  }
722
- const displayPct = typeof merged.maxWidth === "string" && pctRe.test(merged.maxWidth.trim()) ? merged.maxWidth.trim() : void 0;
723
825
  if (userSrc.autoWidth === void 0) {
724
826
  if (displayPct && displayPct !== "100%") {
725
827
  merged.autoWidth = false;
726
828
  merged.maxWidth = displayPct;
829
+ } else if (displayPx != null) {
830
+ merged.autoWidth = false;
831
+ merged.maxWidth = displayPx;
727
832
  } else {
728
833
  merged.autoWidth = true;
729
834
  merged.maxWidth = "100%";
@@ -1032,13 +1137,7 @@ ${widths.map(({ value, className }) => ` .no-stack .u-col-${className} { width:
1032
1137
  return baseCSS + "\n" + columnCSS + "\n" + responsiveCSS;
1033
1138
  }
1034
1139
  function toContentWidthPx(bodyValues, fallback = 500) {
1035
- const raw = bodyValues?.contentWidth;
1036
- if (typeof raw === "number" && Number.isFinite(raw)) return raw;
1037
- if (typeof raw === "string") {
1038
- const n = parseInt(raw, 10);
1039
- if (Number.isFinite(n)) return n;
1040
- }
1041
- return fallback;
1140
+ return bodyContentWidthPx(bodyValues?.contentWidth, fallback);
1042
1141
  }
1043
1142
  function renderRowToHtml(innerHTML, values, bodyValues, mode, cells, collection = "rows") {
1044
1143
  const rowExporter = RowExporters[mode] || RowExporters.web;
@@ -1145,7 +1244,7 @@ var Row = (props) => {
1145
1244
  };
1146
1245
  Row.displayName = "Row";
1147
1246
  var Row_default = Row;
1148
- var DEFAULT_CONTAINER_PADDING = "10px";
1247
+ var DEFAULT_CONTAINER_PADDING2 = "10px";
1149
1248
  var DEFAULT_VALUES12 = COLUMN_DEFAULTS;
1150
1249
  function renderColumnToHtml(innerHTML, values, index, cells, bodyValues, rowValues, mode) {
1151
1250
  const columnExporter = ColumnExporters[mode] || ColumnExporters.web;
@@ -1207,7 +1306,7 @@ var Column = (props) => {
1207
1306
  const componentType = child.type;
1208
1307
  const componentName = (componentType?.displayName || componentType?.name || "component").toLowerCase();
1209
1308
  const childProps = child.props;
1210
- const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING;
1309
+ const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING2;
1211
1310
  const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
1212
1311
  const contentValues = {
1213
1312
  containerPadding,
@@ -1662,7 +1761,7 @@ function extractTextFromTextJson(textJson) {
1662
1761
  return "";
1663
1762
  }
1664
1763
  }
1665
- function processItem(element, counters) {
1764
+ function processItem(element, counters, layout = {}) {
1666
1765
  const componentType = element.type;
1667
1766
  const config = componentType[UNLAYER_CONFIG_KEY];
1668
1767
  if (!config) {
@@ -1696,9 +1795,17 @@ function processItem(element, counters) {
1696
1795
  deletable: true,
1697
1796
  hideable: true
1698
1797
  };
1798
+ const itemSrc = values.src;
1799
+ if (itemSrc && typeof itemSrc === "object" && itemSrc.autoWidth === false) {
1800
+ const availableWidth = contentSlotWidth({
1801
+ ...layout,
1802
+ containerPadding: values.containerPadding
1803
+ });
1804
+ values.src = pinImageSrc(itemSrc, availableWidth);
1805
+ }
1699
1806
  return { type: contentType, values };
1700
1807
  }
1701
- function processColumn(element, counters) {
1808
+ function processColumn(element, counters, layout = {}) {
1702
1809
  const count = nextCounter2(counters, "u_column");
1703
1810
  const id = makeId("u_column", count);
1704
1811
  const semanticProps = extractSemanticProps2(element.props);
@@ -1714,12 +1821,13 @@ function processColumn(element, counters) {
1714
1821
  };
1715
1822
  const contents = [];
1716
1823
  const children = collectChildren2(element.props.children);
1824
+ const itemLayout = { ...layout, columnValues: valuesWithMeta };
1717
1825
  for (const child of children) {
1718
- contents.push(processItem(child, counters));
1826
+ contents.push(processItem(child, counters, itemLayout));
1719
1827
  }
1720
1828
  return { contents, values: valuesWithMeta };
1721
1829
  }
1722
- function processRow(element, counters) {
1830
+ function processRow(element, counters, parentLayout = {}) {
1723
1831
  const count = nextCounter2(counters, "u_row");
1724
1832
  const id = makeId("u_row", count);
1725
1833
  const { layout, cells: propsCells } = element.props;
@@ -1731,7 +1839,9 @@ function processRow(element, counters) {
1731
1839
  } else {
1732
1840
  const columnCount = Math.max(
1733
1841
  1,
1734
- collectChildren2(element.props.children).length
1842
+ collectChildren2(element.props.children).filter(
1843
+ (child) => getDisplayName2(child) === "Column"
1844
+ ).length
1735
1845
  );
1736
1846
  cells = Array(columnCount).fill(1);
1737
1847
  }
@@ -1755,10 +1865,19 @@ function processRow(element, counters) {
1755
1865
  };
1756
1866
  const columns = [];
1757
1867
  const children = collectChildren2(element.props.children);
1868
+ const columnLayout = {
1869
+ bodyValues: parentLayout.bodyValues,
1870
+ rowValues: valuesWithMeta,
1871
+ rowCells: cells
1872
+ };
1873
+ let columnIndex = 0;
1758
1874
  for (const child of children) {
1759
1875
  const name = getDisplayName2(child);
1760
1876
  if (name === "Column") {
1761
- columns.push(processColumn(child, counters));
1877
+ columns.push(
1878
+ processColumn(child, counters, { ...columnLayout, columnIndex })
1879
+ );
1880
+ columnIndex += 1;
1762
1881
  } else {
1763
1882
  console.warn(
1764
1883
  `[Unlayer] renderToJson: <${name}> is not a valid Row child. Only <Column> is allowed.`
@@ -1789,7 +1908,7 @@ function processBody(element, counters) {
1789
1908
  for (const child of children) {
1790
1909
  const name = getDisplayName2(child);
1791
1910
  if (name === "Row") {
1792
- rows.push(processRow(child, counters));
1911
+ rows.push(processRow(child, counters, { bodyValues: valuesWithMeta }));
1793
1912
  } else {
1794
1913
  console.warn(
1795
1914
  `[Unlayer] renderToJson: <${name}> is not a valid Body child. Only <Row> is allowed.`