@unlayer/react-elements 0.1.20 → 0.1.22

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/README.md CHANGED
@@ -120,6 +120,7 @@ These props have non-obvious shapes that **must** be followed exactly:
120
120
  | `<Social>` | Social media icons with `icons` shorthand array |
121
121
  | `<Menu>` | Navigation menu with `items` shorthand array |
122
122
  | `<Table>` | Data table with `headers` / `data` shorthands |
123
+ | `<PageBreak>` | Force subsequent document content onto a new PDF page |
123
124
  | `<Video>` | Video embed with `videoUrl` shorthand |
124
125
  | `<Html>` | Custom HTML passthrough |
125
126
 
@@ -139,7 +140,9 @@ Root wrapper for email-safe HTML. Same props as Body (without `mode`).
139
140
  Root wrapper for responsive web display. Same props as Email.
140
141
 
141
142
  ### Document
142
- Root wrapper for print/PDF rendering. Same props as Email.
143
+ Root wrapper for print/PDF rendering. It accepts the shared Body props plus:
144
+ - `documentSize?: "A3" | "A4" | "A5" | "Legal" | "Letter" | "Tabloid"` — `"A4"`
145
+ - `documentOrientation?: "portrait" | "landscape"` — `"portrait"`
143
146
 
144
147
  ### Row
145
148
  Layout container. Must be child of Email/Page/Document/Body.
@@ -221,6 +224,24 @@ Use `html` for formatted text, children for plain text.
221
224
  - `columns?: number` — `3`
222
225
  - `rows?: number` — `3`
223
226
  - `enableHeader?: boolean` — `true`
227
+ - `repeatHeaderOnEachPage?: boolean` — `true`
228
+ - `enableFooter?: boolean` — `false`
229
+ - `repeatFooterOnEachPage?: boolean` — `true`
230
+
231
+ ### PageBreak
232
+ Forces the next block onto a new page in document output. It is inert in email and web output.
233
+
234
+ ```tsx
235
+ <Document>
236
+ <Row>
237
+ <Column>
238
+ <Paragraph>Page one</Paragraph>
239
+ <PageBreak />
240
+ <Paragraph>Page two</Paragraph>
241
+ </Column>
242
+ </Row>
243
+ </Document>
244
+ ```
224
245
 
225
246
  ### Social
226
247
  - `icons?: { name: string, url: string }[]` — shorthand
package/dist/index.cjs CHANGED
@@ -512,6 +512,7 @@ function normalizeValuesForExporter(values, componentName) {
512
512
  return out;
513
513
  }
514
514
  var HTML_ENTITIES = {
515
+ // Core markup + whitespace
515
516
  "&amp;": "&",
516
517
  "&lt;": "<",
517
518
  "&gt;": ">",
@@ -519,16 +520,67 @@ var HTML_ENTITIES = {
519
520
  "&#39;": "'",
520
521
  "&apos;": "'",
521
522
  "&nbsp;": " ",
523
+ // Dashes, quotes, and typographic punctuation
522
524
  "&mdash;": "\u2014",
523
525
  "&ndash;": "\u2013",
524
526
  "&laquo;": "\xAB",
525
527
  "&raquo;": "\xBB",
528
+ "&lsquo;": "\u2018",
529
+ "&rsquo;": "\u2019",
530
+ "&ldquo;": "\u201C",
531
+ "&rdquo;": "\u201D",
526
532
  "&bull;": "\u2022",
527
533
  "&middot;": "\xB7",
528
534
  "&hellip;": "\u2026",
535
+ // Currency
536
+ "&cent;": "\xA2",
537
+ "&pound;": "\xA3",
538
+ "&yen;": "\xA5",
539
+ "&euro;": "\u20AC",
540
+ // Legal / trademark
529
541
  "&copy;": "\xA9",
530
542
  "&reg;": "\xAE",
531
- "&trade;": "\u2122"
543
+ "&trade;": "\u2122",
544
+ "&sect;": "\xA7",
545
+ "&para;": "\xB6",
546
+ // Math and misc symbols
547
+ "&deg;": "\xB0",
548
+ "&plusmn;": "\xB1",
549
+ "&times;": "\xD7",
550
+ "&divide;": "\xF7",
551
+ "&micro;": "\xB5",
552
+ "&frac14;": "\xBC",
553
+ "&frac12;": "\xBD",
554
+ "&frac34;": "\xBE",
555
+ // Latin-1 accented letters (common in European names/words)
556
+ "&szlig;": "\xDF",
557
+ "&agrave;": "\xE0",
558
+ "&aacute;": "\xE1",
559
+ "&acirc;": "\xE2",
560
+ "&atilde;": "\xE3",
561
+ "&auml;": "\xE4",
562
+ "&aring;": "\xE5",
563
+ "&aelig;": "\xE6",
564
+ "&ccedil;": "\xE7",
565
+ "&egrave;": "\xE8",
566
+ "&eacute;": "\xE9",
567
+ "&ecirc;": "\xEA",
568
+ "&euml;": "\xEB",
569
+ "&igrave;": "\xEC",
570
+ "&iacute;": "\xED",
571
+ "&icirc;": "\xEE",
572
+ "&iuml;": "\xEF",
573
+ "&ntilde;": "\xF1",
574
+ "&ograve;": "\xF2",
575
+ "&oacute;": "\xF3",
576
+ "&ocirc;": "\xF4",
577
+ "&otilde;": "\xF5",
578
+ "&ouml;": "\xF6",
579
+ "&oslash;": "\xF8",
580
+ "&ugrave;": "\xF9",
581
+ "&uacute;": "\xFA",
582
+ "&ucirc;": "\xFB",
583
+ "&uuml;": "\xFC"
532
584
  };
533
585
  function decodeEntities(text) {
534
586
  let result = text.replace(/&\w+;/g, (match) => HTML_ENTITIES[match] ?? match);
@@ -751,7 +803,8 @@ function createItemComponent(config) {
751
803
  contentType: config.contentType,
752
804
  slug: config.slug,
753
805
  metaName: config.metaName,
754
- head: config.head
806
+ head: config.head,
807
+ omitEmptyOutput: config.omitEmptyOutput
755
808
  };
756
809
  return ItemComponent;
757
810
  }
@@ -963,13 +1016,45 @@ var Paragraph = createItemComponent({
963
1016
  exporters: exporters.ParagraphExporters
964
1017
  });
965
1018
  var Paragraph_default = Paragraph;
966
- var DEFAULT_ICONS = exporters.SocialDefaults.icons ?? { iconType: "circle", icons: [] };
1019
+
1020
+ // src/components/PageBreak.tsx
967
1021
  var DEFAULT_VALUES8 = {
1022
+ color: "#6b7280"
1023
+ };
1024
+ var pageBreakExporters = {
1025
+ // Page breaks are a document-only concept. Keep the unsupported renderers
1026
+ // inert so a component rendered outside <Document> does not throw.
1027
+ web: () => "",
1028
+ email: () => "",
1029
+ document: () => '<div class="u-content-page-break" aria-hidden="true"></div>'
1030
+ };
1031
+ var pageBreakHead = {
1032
+ css: (_values, _bodyValues, meta) => meta.displayMode === "document" ? `
1033
+ .u-content-page-break {
1034
+ break-after: page;
1035
+ page-break-after: always;
1036
+ }
1037
+ ` : void 0
1038
+ };
1039
+ var PageBreak = createItemComponent({
1040
+ name: "PageBreak",
1041
+ contentType: "page_break",
1042
+ metaName: "page_break",
1043
+ defaultValues: DEFAULT_VALUES8,
1044
+ propMapper: (props) => mapSemanticProps(props, DEFAULT_VALUES8, "PageBreak"),
1045
+ displayName: "PageBreak",
1046
+ exporters: pageBreakExporters,
1047
+ head: pageBreakHead,
1048
+ omitEmptyOutput: true
1049
+ });
1050
+ var PageBreak_default = PageBreak;
1051
+ var DEFAULT_ICONS = exporters.SocialDefaults.icons ?? { iconType: "circle", icons: [] };
1052
+ var DEFAULT_VALUES9 = {
968
1053
  ...exporters.SocialDefaults
969
1054
  };
970
1055
  var Social = createItemComponent({
971
1056
  name: "Social",
972
- defaultValues: DEFAULT_VALUES8,
1057
+ defaultValues: DEFAULT_VALUES9,
973
1058
  propMapper: (props) => {
974
1059
  const { icons, iconType, ...rest } = props;
975
1060
  const coerceSizes = (base) => {
@@ -990,7 +1075,7 @@ var Social = createItemComponent({
990
1075
  }));
991
1076
  const base = mapSemanticProps(
992
1077
  rest,
993
- DEFAULT_VALUES8,
1078
+ DEFAULT_VALUES9,
994
1079
  "Social"
995
1080
  );
996
1081
  base.icons = {
@@ -1002,14 +1087,14 @@ var Social = createItemComponent({
1002
1087
  if (iconType !== void 0) {
1003
1088
  const base = mapSemanticProps(
1004
1089
  rest,
1005
- DEFAULT_VALUES8,
1090
+ DEFAULT_VALUES9,
1006
1091
  "Social"
1007
1092
  );
1008
1093
  base.icons = { ...DEFAULT_ICONS, ...base.icons, iconType };
1009
1094
  return coerceSizes(base);
1010
1095
  }
1011
1096
  return coerceSizes(
1012
- mapSemanticProps(props, DEFAULT_VALUES8, "Social")
1097
+ mapSemanticProps(props, DEFAULT_VALUES9, "Social")
1013
1098
  );
1014
1099
  },
1015
1100
  displayName: "Social",
@@ -1017,20 +1102,20 @@ var Social = createItemComponent({
1017
1102
  });
1018
1103
  var Social_default = Social;
1019
1104
  var DEFAULT_TABLE = { headers: [], rows: [], footers: [] };
1020
- var DEFAULT_VALUES9 = {
1105
+ var DEFAULT_VALUES10 = {
1021
1106
  ...exporters.TableDefaults,
1022
1107
  table: DEFAULT_TABLE
1023
1108
  // Schema doesn't include table data structure
1024
1109
  };
1025
1110
  var Table = createItemComponent({
1026
1111
  name: "Table",
1027
- defaultValues: DEFAULT_VALUES9,
1112
+ defaultValues: DEFAULT_VALUES10,
1028
1113
  propMapper: (props) => {
1029
1114
  const { headers, data, columns, rows, ...rest } = props;
1030
1115
  if (headers || data || typeof columns === "number" || typeof rows === "number") {
1031
1116
  const base = mapSemanticProps(
1032
1117
  rest,
1033
- DEFAULT_VALUES9,
1118
+ DEFAULT_VALUES10,
1034
1119
  "Table"
1035
1120
  );
1036
1121
  const colCount = headers ? headers.length : typeof columns === "number" ? columns : data?.[0]?.length ?? 0;
@@ -1062,7 +1147,7 @@ var Table = createItemComponent({
1062
1147
  }
1063
1148
  return mapSemanticProps(
1064
1149
  props,
1065
- DEFAULT_VALUES9,
1150
+ DEFAULT_VALUES10,
1066
1151
  "Table"
1067
1152
  );
1068
1153
  },
@@ -1077,7 +1162,7 @@ var DEFAULT_VIDEO = {
1077
1162
  loading: false,
1078
1163
  ...exporters.VideoDefaults.video
1079
1164
  };
1080
- var DEFAULT_VALUES10 = {
1165
+ var DEFAULT_VALUES11 = {
1081
1166
  ...exporters.VideoDefaults,
1082
1167
  video: DEFAULT_VIDEO
1083
1168
  };
@@ -1105,14 +1190,14 @@ function parseVideoUrl(url) {
1105
1190
  }
1106
1191
  var Video = createItemComponent({
1107
1192
  name: "Video",
1108
- defaultValues: DEFAULT_VALUES10,
1193
+ defaultValues: DEFAULT_VALUES11,
1109
1194
  propMapper: (props) => {
1110
1195
  const { videoUrl, ...rest } = props;
1111
1196
  if (typeof videoUrl === "string") {
1112
1197
  const parsed = parseVideoUrl(videoUrl);
1113
1198
  const base = mapSemanticProps(
1114
1199
  rest,
1115
- DEFAULT_VALUES10,
1200
+ DEFAULT_VALUES11,
1116
1201
  "Video"
1117
1202
  );
1118
1203
  if (parsed) {
@@ -1122,7 +1207,7 @@ var Video = createItemComponent({
1122
1207
  }
1123
1208
  return mapSemanticProps(
1124
1209
  props,
1125
- DEFAULT_VALUES10,
1210
+ DEFAULT_VALUES11,
1126
1211
  "Video"
1127
1212
  );
1128
1213
  },
@@ -1150,7 +1235,7 @@ var {
1150
1235
  var BODY_DEFAULTS = bodyRest;
1151
1236
  var ROW_DEFAULTS = { ...exporters.RowDefaults };
1152
1237
  var COLUMN_DEFAULTS = { ...exporters.ColumnDefaults };
1153
- var DEFAULT_VALUES11 = ROW_DEFAULTS;
1238
+ var DEFAULT_VALUES12 = ROW_DEFAULTS;
1154
1239
  var DEFAULT_BODY_VALUES = BODY_DEFAULTS;
1155
1240
  function getWidthPercentages(cells) {
1156
1241
  if (cells.length === 0) return [];
@@ -1288,7 +1373,7 @@ var Row = (props) => {
1288
1373
  const safeBodyValues = { ...DEFAULT_BODY_VALUES, ...bodyValues };
1289
1374
  const values = mapSemanticProps(
1290
1375
  semanticProps,
1291
- DEFAULT_VALUES11,
1376
+ DEFAULT_VALUES12,
1292
1377
  "Row"
1293
1378
  );
1294
1379
  const valuesWithMeta = {
@@ -1326,7 +1411,7 @@ var Row = (props) => {
1326
1411
  Row.displayName = "Row";
1327
1412
  var Row_default = Row;
1328
1413
  var DEFAULT_CONTAINER_PADDING2 = "10px";
1329
- var DEFAULT_VALUES12 = COLUMN_DEFAULTS;
1414
+ var DEFAULT_VALUES13 = COLUMN_DEFAULTS;
1330
1415
  function renderColumnToHtml(innerHTML, values, index, cells, bodyValues, rowValues, mode) {
1331
1416
  const columnExporter = exporters.ColumnExporters[mode] || exporters.ColumnExporters.web;
1332
1417
  return columnExporter(innerHTML, values, index, cells, bodyValues, rowValues);
@@ -1351,7 +1436,7 @@ var Column = (props) => {
1351
1436
  const mode = modeProp ?? _config?.mode ?? "web";
1352
1437
  const values = mapSemanticProps(
1353
1438
  semanticProps,
1354
- DEFAULT_VALUES12,
1439
+ DEFAULT_VALUES13,
1355
1440
  "Column"
1356
1441
  );
1357
1442
  const valuesWithMeta = {
@@ -1387,6 +1472,7 @@ var Column = (props) => {
1387
1472
  });
1388
1473
  if (rendered && typeof rendered === "object" && rendered.props && rendered.props.dangerouslySetInnerHTML) {
1389
1474
  const componentHTML = rendered.props.dangerouslySetInnerHTML.__html;
1475
+ if (!componentHTML && ComponentType?.[UNLAYER_CONFIG_KEY]?.omitEmptyOutput) return;
1390
1476
  const childProps = child.props;
1391
1477
  const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING2;
1392
1478
  const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
@@ -1434,7 +1520,7 @@ var Column = (props) => {
1434
1520
  };
1435
1521
  Column.displayName = "Column";
1436
1522
  var Column_default = Column;
1437
- var DEFAULT_VALUES13 = BODY_DEFAULTS;
1523
+ var DEFAULT_VALUES14 = BODY_DEFAULTS;
1438
1524
  var MAX_PREVIEW_LENGTH = 150;
1439
1525
  var PADDING_CHARS = [
1440
1526
  "\xA0",
@@ -1480,8 +1566,8 @@ var Body = (props) => {
1480
1566
  const _config = { ...resolvedConfig, mode };
1481
1567
  _config.__ids = {};
1482
1568
  const values = mergeValues(
1483
- DEFAULT_VALUES13,
1484
- mapSemanticProps(semanticProps, DEFAULT_VALUES13, "Body")
1569
+ DEFAULT_VALUES14,
1570
+ mapSemanticProps(semanticProps, DEFAULT_VALUES14, "Body")
1485
1571
  );
1486
1572
  const valuesWithMeta = {
1487
1573
  ...values,
@@ -2240,6 +2326,7 @@ exports.Html = Html_default;
2240
2326
  exports.Image = Image_default;
2241
2327
  exports.Menu = Menu_default;
2242
2328
  exports.Page = Page;
2329
+ exports.PageBreak = PageBreak_default;
2243
2330
  exports.Paragraph = Paragraph_default;
2244
2331
  exports.Row = Row_default;
2245
2332
  exports.Social = Social_default;