@unlayer/react-elements 0.1.14 → 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
@@ -339,14 +339,27 @@ function mapSemanticProps(props, defaultValues, componentType) {
339
339
  delete userProps.html;
340
340
  delete result.html;
341
341
  }
342
- for (const key of ["href", "action"]) {
343
- const v = userProps[key];
342
+ const canonicalizeLink = (v) => {
344
343
  if (typeof v === "string") {
345
- userProps[key] = {
346
- name: "web",
347
- values: { href: v, target: "_blank" }
348
- };
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
+ }
349
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]);
350
363
  }
351
364
  normalizeCssProps(userProps);
352
365
  const nestedGroups = analyzeNestedStructure(defaultValues);
@@ -406,12 +419,14 @@ function normalizeLinkValue(value) {
406
419
  if (typeof value !== "object") return void 0;
407
420
  const v = value;
408
421
  if ("url" in v) return v;
409
- if ("name" in v && v.values && typeof v.values === "object") {
410
- 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;
411
426
  return {
412
- url: inner.href ?? "",
413
- target: inner.target ?? "_blank",
414
- ...v.attrs ?? {}
427
+ url: inner.href || attrsHref || "",
428
+ target: inner.target || attrsTarget || "_blank",
429
+ ...customAttrs
415
430
  };
416
431
  }
417
432
  return void 0;
@@ -763,11 +778,11 @@ var Html = createItemComponent({
763
778
  exporters: HtmlExporters
764
779
  });
765
780
  var Html_default = Html;
781
+ var { height: _placeholderHeight, ...defaultSrc } = ImageDefaults.src;
766
782
  var DEFAULT_VALUES5 = {
767
783
  ...ImageDefaults,
768
- // Override src with autoWidth/maxWidth for responsive rendering
769
784
  src: {
770
- ...ImageDefaults.src,
785
+ ...defaultSrc,
771
786
  autoWidth: true,
772
787
  maxWidth: "100%"
773
788
  }
@@ -809,7 +824,7 @@ var Image = createItemComponent({
809
824
  };
810
825
  let displayPct;
811
826
  let displayPx;
812
- for (const candidate of [widthProp, maxWidthProp, userSrc.maxWidth]) {
827
+ for (const candidate of [widthProp, maxWidthProp, userSrc.maxWidth, userSrc.width]) {
813
828
  if (candidate === void 0) continue;
814
829
  const pct = asPercent(candidate);
815
830
  if (pct) {
@@ -900,6 +915,17 @@ var Social = createItemComponent({
900
915
  defaultValues: DEFAULT_VALUES8,
901
916
  propMapper: (props) => {
902
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
+ };
903
929
  if (Array.isArray(icons)) {
904
930
  const mapped = icons.map((icon) => ({
905
931
  name: icon.name,
@@ -914,7 +940,7 @@ var Social = createItemComponent({
914
940
  iconType: iconType ?? base.icons?.iconType ?? "circle",
915
941
  icons: mapped
916
942
  };
917
- return base;
943
+ return coerceSizes(base);
918
944
  }
919
945
  if (iconType !== void 0) {
920
946
  const base = mapSemanticProps(
@@ -923,12 +949,10 @@ var Social = createItemComponent({
923
949
  "Social"
924
950
  );
925
951
  base.icons = { ...DEFAULT_ICONS, ...base.icons, iconType };
926
- return base;
952
+ return coerceSizes(base);
927
953
  }
928
- return mapSemanticProps(
929
- props,
930
- DEFAULT_VALUES8,
931
- "Social"
954
+ return coerceSizes(
955
+ mapSemanticProps(props, DEFAULT_VALUES8, "Social")
932
956
  );
933
957
  },
934
958
  displayName: "Social",