@unlayer/react-elements 0.1.13 → 0.1.15

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.d.cts CHANGED
@@ -160,7 +160,7 @@ declare const DEFAULT_CONFIG: UnlayerConfig;
160
160
  * configurations that match exactly what the Unlayer editor supports.
161
161
  *
162
162
  * Usage:
163
- * import { ColumnLayouts } from '@unlayer-internal/shared-elements';
163
+ * import { ColumnLayouts } from '@unlayer/react-elements';
164
164
  * <Row layout={ColumnLayouts.TwoEqual}>
165
165
  * <Column>...</Column>
166
166
  * <Column>...</Column>
@@ -368,7 +368,8 @@ interface ButtonProps extends ItemComponentProps<ButtonSemanticProps> {
368
368
  *
369
369
  * @example Flat Props (Simple - most common)
370
370
  * ```tsx
371
- * <Button color="white" backgroundColor="#3b82f6" fontSize="16px">
371
+ * // `href` accepts a plain URL string (the ergonomic form).
372
+ * <Button href="https://example.com" color="white" backgroundColor="#3b82f6" fontSize="16px">
372
373
  * Click me
373
374
  * </Button>
374
375
  * ```
@@ -466,6 +467,13 @@ interface HtmlProps extends ItemComponentProps<SemanticProps<HtmlValues>> {
466
467
  /**
467
468
  * Html - Universal SSR/Client Component for custom HTML with Automatic Semantic Props
468
469
  *
470
+ * ⚠️ Renders the HTML verbatim — it is NOT sanitized by default. Only pass HTML
471
+ * you trust, and make sure it is valid: notably, an inline SVG inside a `url(...)`
472
+ * must be URL-encoded, because a raw `"` inside a double-quoted `style="…"`
473
+ * closes the attribute and the rest leaks out as text. To sanitize (matching the
474
+ * editor's HTML block, which strips scripts/event handlers), pass a `toSafeHtml`
475
+ * function via the `UnlayerProvider` config.
476
+ *
469
477
  * @example Flat Props
470
478
  * ```tsx
471
479
  * <Html html="<div>Custom HTML</div>" />
@@ -578,15 +586,21 @@ interface ParagraphProps extends ItemComponentProps<ParagraphSemanticProps> {
578
586
  */
579
587
  declare const Paragraph: React$1.FC<ItemComponentProps<ParagraphSemanticProps>>;
580
588
 
581
- type SocialSemanticProps = SemanticProps<SocialValues> & {
589
+ type SocialSemanticProps = Omit<SemanticProps<SocialValues>, "iconSize" | "spacing"> & {
582
590
  /** Social icons shorthand (array of {name, url}) */
583
591
  icons?: SocialIcon[];
584
592
  /** Icon shape */
585
593
  iconType?: "circle" | "rounded" | "squared";
594
+ /** Icon size in px — a number (34) or px string ("34px"). */
595
+ iconSize?: SizeInput;
596
+ /** Gap between icons in px — a number or px string. */
597
+ spacing?: SizeInput;
586
598
  };
587
- interface SocialProps extends Omit<ItemComponentProps<SemanticProps<SocialValues>>, "icons"> {
599
+ interface SocialProps extends Omit<ItemComponentProps<SemanticProps<SocialValues>>, "icons" | "iconSize" | "spacing"> {
588
600
  icons?: SocialIcon[] | SocialValues["icons"];
589
601
  iconType?: "circle" | "rounded" | "squared";
602
+ iconSize?: SizeInput;
603
+ spacing?: SizeInput;
590
604
  }
591
605
  /**
592
606
  * Social - Renders social-media icon links.
@@ -958,4 +972,4 @@ declare function renderToHtmlParts(element: React__default.ReactElement, config?
958
972
  declare function renderRowToJson(element: React__default.ReactElement): DesignRow;
959
973
  declare function renderToJson(element: React__default.ReactElement): DesignJSON;
960
974
 
961
- export { Body, Button, type ButtonProps, Column, type ColumnLayout, ColumnLayouts, DEFAULT_CONFIG, type DesignBody, type DesignColumn, type DesignContent, type DesignJSON, type DesignRow, Divider, type DividerProps, Document, type DocumentProps, Email, type EmailProps, Heading, type HeadingProps, type Href, Html, type HtmlParts, type HtmlProps, type Icons, Image, type ImageProps, type LinkStyle, Menu, type MenuItem, type MenuProps, Page, type PageProps, Paragraph, type ParagraphProps, Row, type RowProps, Social, type SocialIcon, type SocialProps, Table, type TableProps, type TextAlign, type UnlayerConfig, UnlayerProvider, type UnlayerProviderProps, type ValidColumnLayout, Video, type VideoProps, type VideoSource, htmlToTextJson, renderRowToJson, renderToHtml, renderToHtmlParts, renderToJson, renderToPlainText, useUnlayerConfig, validateColumnLayout };
975
+ export { Body, type BorderInput, Button, type ButtonProps, Column, type ColumnLayout, ColumnLayouts, DEFAULT_CONFIG, type DesignBody, type DesignColumn, type DesignContent, type DesignJSON, type DesignRow, Divider, type DividerProps, Document, type DocumentProps, Email, type EmailProps, type FontFamilyInput, type FontWeightInput, Heading, type HeadingLevel, type HeadingProps, type Href, Html, type HtmlParts, type HtmlProps, type Icons, Image, type ImageProps, type ImageSrcInput, type LinkStyle, Menu, type MenuItem, type MenuProps, Page, type PageProps, Paragraph, type ParagraphProps, Row, type RowProps, type SizeInput, Social, type SocialIcon, type SocialProps, Table, type TableProps, type TextAlign, type TextStyleProps, type UnlayerConfig, UnlayerProvider, type UnlayerProviderProps, type ValidColumnLayout, Video, type VideoProps, type VideoSource, htmlToTextJson, renderRowToJson, renderToHtml, renderToHtmlParts, renderToJson, renderToPlainText, useUnlayerConfig, validateColumnLayout };
package/dist/index.d.ts CHANGED
@@ -160,7 +160,7 @@ declare const DEFAULT_CONFIG: UnlayerConfig;
160
160
  * configurations that match exactly what the Unlayer editor supports.
161
161
  *
162
162
  * Usage:
163
- * import { ColumnLayouts } from '@unlayer-internal/shared-elements';
163
+ * import { ColumnLayouts } from '@unlayer/react-elements';
164
164
  * <Row layout={ColumnLayouts.TwoEqual}>
165
165
  * <Column>...</Column>
166
166
  * <Column>...</Column>
@@ -368,7 +368,8 @@ interface ButtonProps extends ItemComponentProps<ButtonSemanticProps> {
368
368
  *
369
369
  * @example Flat Props (Simple - most common)
370
370
  * ```tsx
371
- * <Button color="white" backgroundColor="#3b82f6" fontSize="16px">
371
+ * // `href` accepts a plain URL string (the ergonomic form).
372
+ * <Button href="https://example.com" color="white" backgroundColor="#3b82f6" fontSize="16px">
372
373
  * Click me
373
374
  * </Button>
374
375
  * ```
@@ -466,6 +467,13 @@ interface HtmlProps extends ItemComponentProps<SemanticProps<HtmlValues>> {
466
467
  /**
467
468
  * Html - Universal SSR/Client Component for custom HTML with Automatic Semantic Props
468
469
  *
470
+ * ⚠️ Renders the HTML verbatim — it is NOT sanitized by default. Only pass HTML
471
+ * you trust, and make sure it is valid: notably, an inline SVG inside a `url(...)`
472
+ * must be URL-encoded, because a raw `"` inside a double-quoted `style="…"`
473
+ * closes the attribute and the rest leaks out as text. To sanitize (matching the
474
+ * editor's HTML block, which strips scripts/event handlers), pass a `toSafeHtml`
475
+ * function via the `UnlayerProvider` config.
476
+ *
469
477
  * @example Flat Props
470
478
  * ```tsx
471
479
  * <Html html="<div>Custom HTML</div>" />
@@ -578,15 +586,21 @@ interface ParagraphProps extends ItemComponentProps<ParagraphSemanticProps> {
578
586
  */
579
587
  declare const Paragraph: React$1.FC<ItemComponentProps<ParagraphSemanticProps>>;
580
588
 
581
- type SocialSemanticProps = SemanticProps<SocialValues> & {
589
+ type SocialSemanticProps = Omit<SemanticProps<SocialValues>, "iconSize" | "spacing"> & {
582
590
  /** Social icons shorthand (array of {name, url}) */
583
591
  icons?: SocialIcon[];
584
592
  /** Icon shape */
585
593
  iconType?: "circle" | "rounded" | "squared";
594
+ /** Icon size in px — a number (34) or px string ("34px"). */
595
+ iconSize?: SizeInput;
596
+ /** Gap between icons in px — a number or px string. */
597
+ spacing?: SizeInput;
586
598
  };
587
- interface SocialProps extends Omit<ItemComponentProps<SemanticProps<SocialValues>>, "icons"> {
599
+ interface SocialProps extends Omit<ItemComponentProps<SemanticProps<SocialValues>>, "icons" | "iconSize" | "spacing"> {
588
600
  icons?: SocialIcon[] | SocialValues["icons"];
589
601
  iconType?: "circle" | "rounded" | "squared";
602
+ iconSize?: SizeInput;
603
+ spacing?: SizeInput;
590
604
  }
591
605
  /**
592
606
  * Social - Renders social-media icon links.
@@ -958,4 +972,4 @@ declare function renderToHtmlParts(element: React__default.ReactElement, config?
958
972
  declare function renderRowToJson(element: React__default.ReactElement): DesignRow;
959
973
  declare function renderToJson(element: React__default.ReactElement): DesignJSON;
960
974
 
961
- export { Body, Button, type ButtonProps, Column, type ColumnLayout, ColumnLayouts, DEFAULT_CONFIG, type DesignBody, type DesignColumn, type DesignContent, type DesignJSON, type DesignRow, Divider, type DividerProps, Document, type DocumentProps, Email, type EmailProps, Heading, type HeadingProps, type Href, Html, type HtmlParts, type HtmlProps, type Icons, Image, type ImageProps, type LinkStyle, Menu, type MenuItem, type MenuProps, Page, type PageProps, Paragraph, type ParagraphProps, Row, type RowProps, Social, type SocialIcon, type SocialProps, Table, type TableProps, type TextAlign, type UnlayerConfig, UnlayerProvider, type UnlayerProviderProps, type ValidColumnLayout, Video, type VideoProps, type VideoSource, htmlToTextJson, renderRowToJson, renderToHtml, renderToHtmlParts, renderToJson, renderToPlainText, useUnlayerConfig, validateColumnLayout };
975
+ export { Body, type BorderInput, Button, type ButtonProps, Column, type ColumnLayout, ColumnLayouts, DEFAULT_CONFIG, type DesignBody, type DesignColumn, type DesignContent, type DesignJSON, type DesignRow, Divider, type DividerProps, Document, type DocumentProps, Email, type EmailProps, type FontFamilyInput, type FontWeightInput, Heading, type HeadingLevel, type HeadingProps, type Href, Html, type HtmlParts, type HtmlProps, type Icons, Image, type ImageProps, type ImageSrcInput, type LinkStyle, Menu, type MenuItem, type MenuProps, Page, type PageProps, Paragraph, type ParagraphProps, Row, type RowProps, type SizeInput, Social, type SocialIcon, type SocialProps, Table, type TableProps, type TextAlign, type TextStyleProps, type UnlayerConfig, UnlayerProvider, type UnlayerProviderProps, type ValidColumnLayout, Video, type VideoProps, type VideoSource, htmlToTextJson, renderRowToJson, renderToHtml, renderToHtmlParts, renderToJson, renderToPlainText, useUnlayerConfig, validateColumnLayout };
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",
@@ -264,14 +339,27 @@ function mapSemanticProps(props, defaultValues, componentType) {
264
339
  delete userProps.html;
265
340
  delete result.html;
266
341
  }
267
- for (const key of ["href", "action"]) {
268
- const v = userProps[key];
342
+ const canonicalizeLink = (v) => {
269
343
  if (typeof v === "string") {
270
- userProps[key] = {
271
- name: "web",
272
- values: { href: v, target: "_blank" }
273
- };
344
+ return { name: "web", values: { href: v, target: "_blank" } };
345
+ }
346
+ if (v && typeof v === "object" && "name" in v && v.attrs && typeof v.attrs === "object") {
347
+ const { href: attrsHref, target: attrsTarget, ...customAttrs } = v.attrs;
348
+ if (attrsHref !== void 0 || attrsTarget !== void 0) {
349
+ const linkValues = { ...v.values };
350
+ if (!linkValues.href && attrsHref !== void 0) linkValues.href = attrsHref;
351
+ if (!linkValues.target && attrsTarget !== void 0) linkValues.target = attrsTarget;
352
+ const next = { ...v, values: linkValues };
353
+ if (Object.keys(customAttrs).length) next.attrs = customAttrs;
354
+ else delete next.attrs;
355
+ return next;
356
+ }
274
357
  }
358
+ return v;
359
+ };
360
+ for (const key of ["href", "action"]) {
361
+ if (userProps[key] !== void 0) userProps[key] = canonicalizeLink(userProps[key]);
362
+ if (result[key] !== void 0) result[key] = canonicalizeLink(result[key]);
275
363
  }
276
364
  normalizeCssProps(userProps);
277
365
  const nestedGroups = analyzeNestedStructure(defaultValues);
@@ -331,12 +419,14 @@ function normalizeLinkValue(value) {
331
419
  if (typeof value !== "object") return void 0;
332
420
  const v = value;
333
421
  if ("url" in v) return v;
334
- if ("name" in v && v.values && typeof v.values === "object") {
335
- const inner = v.values;
422
+ if ("name" in v && (v.values && typeof v.values === "object" || v.attrs && typeof v.attrs === "object")) {
423
+ const inner = v.values && typeof v.values === "object" ? v.values : {};
424
+ const attrs = v.attrs && typeof v.attrs === "object" ? v.attrs : {};
425
+ const { href: attrsHref, target: attrsTarget, ...customAttrs } = attrs;
336
426
  return {
337
- url: inner.href ?? "",
338
- target: inner.target ?? "_blank",
339
- ...v.attrs ?? {}
427
+ url: inner.href || attrsHref || "",
428
+ target: inner.target || attrsTarget || "_blank",
429
+ ...customAttrs
340
430
  };
341
431
  }
342
432
  return void 0;
@@ -564,6 +654,18 @@ function createItemComponent(config) {
564
654
  valuesWithMeta,
565
655
  config.name
566
656
  );
657
+ const exportSrc = valuesForExporter.src;
658
+ if (exportSrc && typeof exportSrc === "object" && exportSrc.autoWidth === false) {
659
+ const availableWidth = contentSlotWidth({
660
+ bodyValues: safeBodyValues,
661
+ rowValues,
662
+ rowCells: cells,
663
+ columnIndex: colIndex,
664
+ columnValues,
665
+ containerPadding: props.containerPadding ?? props.values?.containerPadding
666
+ });
667
+ valuesForExporter.src = pinImageSrc(exportSrc, availableWidth);
668
+ }
567
669
  const exporter = config.exporters[mode] || config.exporters.web;
568
670
  return renderComponent({
569
671
  type: config.name,
@@ -676,11 +778,11 @@ var Html = createItemComponent({
676
778
  exporters: HtmlExporters
677
779
  });
678
780
  var Html_default = Html;
781
+ var { height: _placeholderHeight, ...defaultSrc } = ImageDefaults.src;
679
782
  var DEFAULT_VALUES5 = {
680
783
  ...ImageDefaults,
681
- // Override src with autoWidth/maxWidth for responsive rendering
682
784
  src: {
683
- ...ImageDefaults.src,
785
+ ...defaultSrc,
684
786
  autoWidth: true,
685
787
  maxWidth: "100%"
686
788
  }
@@ -689,7 +791,7 @@ var Image = createItemComponent({
689
791
  name: "Image",
690
792
  defaultValues: DEFAULT_VALUES5,
691
793
  propMapper: (props) => {
692
- const { alt, src, ...rest } = props;
794
+ const { alt, src, width: widthProp, maxWidth: maxWidthProp, ...rest } = props;
693
795
  const restValues = rest.values;
694
796
  const normalizedRest = restValues && typeof restValues.src === "string" ? { ...rest, values: { ...restValues, src: { url: restValues.src } } } : rest;
695
797
  const base = mapSemanticProps(
@@ -709,21 +811,39 @@ var Image = createItemComponent({
709
811
  const start = isStringUrl ? { autoWidth: true, maxWidth: "100%" } : { ...DEFAULT_VALUES5.src };
710
812
  const merged = { ...start, ...userSrc };
711
813
  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]);
814
+ const asPercent = (v) => typeof v === "string" && pctRe.test(v.trim()) ? v.trim() : void 0;
815
+ const asPx = (v) => {
816
+ if (typeof v === "number" && Number.isFinite(v)) return v;
817
+ if (typeof v === "string") {
818
+ const t = v.trim();
819
+ if (pctRe.test(t)) return void 0;
820
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(t);
821
+ if (m) return parseFloat(m[1]);
822
+ }
823
+ return void 0;
824
+ };
825
+ let displayPct;
826
+ let displayPx;
827
+ for (const candidate of [widthProp, maxWidthProp, userSrc.maxWidth, userSrc.width]) {
828
+ if (candidate === void 0) continue;
829
+ const pct = asPercent(candidate);
830
+ if (pct) {
831
+ displayPct = pct;
832
+ break;
833
+ }
834
+ const px = asPx(candidate);
835
+ if (px != null) {
836
+ displayPx = px;
837
+ break;
720
838
  }
721
839
  }
722
- const displayPct = typeof merged.maxWidth === "string" && pctRe.test(merged.maxWidth.trim()) ? merged.maxWidth.trim() : void 0;
723
840
  if (userSrc.autoWidth === void 0) {
724
841
  if (displayPct && displayPct !== "100%") {
725
842
  merged.autoWidth = false;
726
843
  merged.maxWidth = displayPct;
844
+ } else if (displayPx != null) {
845
+ merged.autoWidth = false;
846
+ merged.maxWidth = displayPx;
727
847
  } else {
728
848
  merged.autoWidth = true;
729
849
  merged.maxWidth = "100%";
@@ -795,6 +915,17 @@ var Social = createItemComponent({
795
915
  defaultValues: DEFAULT_VALUES8,
796
916
  propMapper: (props) => {
797
917
  const { icons, iconType, ...rest } = props;
918
+ const coerceSizes = (base) => {
919
+ for (const key of ["iconSize", "spacing"]) {
920
+ const v = base[key];
921
+ if (typeof v === "string") {
922
+ const m = /^(\d+(?:\.\d+)?)(?:px)?$/.exec(v.trim());
923
+ if (m) base[key] = parseFloat(m[1]);
924
+ else delete base[key];
925
+ }
926
+ }
927
+ return base;
928
+ };
798
929
  if (Array.isArray(icons)) {
799
930
  const mapped = icons.map((icon) => ({
800
931
  name: icon.name,
@@ -809,7 +940,7 @@ var Social = createItemComponent({
809
940
  iconType: iconType ?? base.icons?.iconType ?? "circle",
810
941
  icons: mapped
811
942
  };
812
- return base;
943
+ return coerceSizes(base);
813
944
  }
814
945
  if (iconType !== void 0) {
815
946
  const base = mapSemanticProps(
@@ -818,12 +949,10 @@ var Social = createItemComponent({
818
949
  "Social"
819
950
  );
820
951
  base.icons = { ...DEFAULT_ICONS, ...base.icons, iconType };
821
- return base;
952
+ return coerceSizes(base);
822
953
  }
823
- return mapSemanticProps(
824
- props,
825
- DEFAULT_VALUES8,
826
- "Social"
954
+ return coerceSizes(
955
+ mapSemanticProps(props, DEFAULT_VALUES8, "Social")
827
956
  );
828
957
  },
829
958
  displayName: "Social",
@@ -1032,13 +1161,7 @@ ${widths.map(({ value, className }) => ` .no-stack .u-col-${className} { width:
1032
1161
  return baseCSS + "\n" + columnCSS + "\n" + responsiveCSS;
1033
1162
  }
1034
1163
  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;
1164
+ return bodyContentWidthPx(bodyValues?.contentWidth, fallback);
1042
1165
  }
1043
1166
  function renderRowToHtml(innerHTML, values, bodyValues, mode, cells, collection = "rows") {
1044
1167
  const rowExporter = RowExporters[mode] || RowExporters.web;
@@ -1145,7 +1268,7 @@ var Row = (props) => {
1145
1268
  };
1146
1269
  Row.displayName = "Row";
1147
1270
  var Row_default = Row;
1148
- var DEFAULT_CONTAINER_PADDING = "10px";
1271
+ var DEFAULT_CONTAINER_PADDING2 = "10px";
1149
1272
  var DEFAULT_VALUES12 = COLUMN_DEFAULTS;
1150
1273
  function renderColumnToHtml(innerHTML, values, index, cells, bodyValues, rowValues, mode) {
1151
1274
  const columnExporter = ColumnExporters[mode] || ColumnExporters.web;
@@ -1207,7 +1330,7 @@ var Column = (props) => {
1207
1330
  const componentType = child.type;
1208
1331
  const componentName = (componentType?.displayName || componentType?.name || "component").toLowerCase();
1209
1332
  const childProps = child.props;
1210
- const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING;
1333
+ const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING2;
1211
1334
  const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
1212
1335
  const contentValues = {
1213
1336
  containerPadding,
@@ -1662,7 +1785,7 @@ function extractTextFromTextJson(textJson) {
1662
1785
  return "";
1663
1786
  }
1664
1787
  }
1665
- function processItem(element, counters) {
1788
+ function processItem(element, counters, layout = {}) {
1666
1789
  const componentType = element.type;
1667
1790
  const config = componentType[UNLAYER_CONFIG_KEY];
1668
1791
  if (!config) {
@@ -1696,9 +1819,17 @@ function processItem(element, counters) {
1696
1819
  deletable: true,
1697
1820
  hideable: true
1698
1821
  };
1822
+ const itemSrc = values.src;
1823
+ if (itemSrc && typeof itemSrc === "object" && itemSrc.autoWidth === false) {
1824
+ const availableWidth = contentSlotWidth({
1825
+ ...layout,
1826
+ containerPadding: values.containerPadding
1827
+ });
1828
+ values.src = pinImageSrc(itemSrc, availableWidth);
1829
+ }
1699
1830
  return { type: contentType, values };
1700
1831
  }
1701
- function processColumn(element, counters) {
1832
+ function processColumn(element, counters, layout = {}) {
1702
1833
  const count = nextCounter2(counters, "u_column");
1703
1834
  const id = makeId("u_column", count);
1704
1835
  const semanticProps = extractSemanticProps2(element.props);
@@ -1714,12 +1845,13 @@ function processColumn(element, counters) {
1714
1845
  };
1715
1846
  const contents = [];
1716
1847
  const children = collectChildren2(element.props.children);
1848
+ const itemLayout = { ...layout, columnValues: valuesWithMeta };
1717
1849
  for (const child of children) {
1718
- contents.push(processItem(child, counters));
1850
+ contents.push(processItem(child, counters, itemLayout));
1719
1851
  }
1720
1852
  return { contents, values: valuesWithMeta };
1721
1853
  }
1722
- function processRow(element, counters) {
1854
+ function processRow(element, counters, parentLayout = {}) {
1723
1855
  const count = nextCounter2(counters, "u_row");
1724
1856
  const id = makeId("u_row", count);
1725
1857
  const { layout, cells: propsCells } = element.props;
@@ -1731,7 +1863,9 @@ function processRow(element, counters) {
1731
1863
  } else {
1732
1864
  const columnCount = Math.max(
1733
1865
  1,
1734
- collectChildren2(element.props.children).length
1866
+ collectChildren2(element.props.children).filter(
1867
+ (child) => getDisplayName2(child) === "Column"
1868
+ ).length
1735
1869
  );
1736
1870
  cells = Array(columnCount).fill(1);
1737
1871
  }
@@ -1755,10 +1889,19 @@ function processRow(element, counters) {
1755
1889
  };
1756
1890
  const columns = [];
1757
1891
  const children = collectChildren2(element.props.children);
1892
+ const columnLayout = {
1893
+ bodyValues: parentLayout.bodyValues,
1894
+ rowValues: valuesWithMeta,
1895
+ rowCells: cells
1896
+ };
1897
+ let columnIndex = 0;
1758
1898
  for (const child of children) {
1759
1899
  const name = getDisplayName2(child);
1760
1900
  if (name === "Column") {
1761
- columns.push(processColumn(child, counters));
1901
+ columns.push(
1902
+ processColumn(child, counters, { ...columnLayout, columnIndex })
1903
+ );
1904
+ columnIndex += 1;
1762
1905
  } else {
1763
1906
  console.warn(
1764
1907
  `[Unlayer] renderToJson: <${name}> is not a valid Row child. Only <Column> is allowed.`
@@ -1789,7 +1932,7 @@ function processBody(element, counters) {
1789
1932
  for (const child of children) {
1790
1933
  const name = getDisplayName2(child);
1791
1934
  if (name === "Row") {
1792
- rows.push(processRow(child, counters));
1935
+ rows.push(processRow(child, counters, { bodyValues: valuesWithMeta }));
1793
1936
  } else {
1794
1937
  console.warn(
1795
1938
  `[Unlayer] renderToJson: <${name}> is not a valid Body child. Only <Row> is allowed.`