@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.cjs +188 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -5
- package/dist/index.d.ts +19 -5
- package/dist/index.js +188 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
268
|
-
const v = userProps[key];
|
|
342
|
+
const canonicalizeLink = (v) => {
|
|
269
343
|
if (typeof v === "string") {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
|
339
|
-
...
|
|
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
|
-
...
|
|
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
|
-
|
|
713
|
-
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
const
|
|
719
|
-
if (
|
|
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
|
|
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
|
-
|
|
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
|
|
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 ??
|
|
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).
|
|
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(
|
|
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.`
|