@bettercms-ai/ui 0.17.1 → 0.18.0

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/renderer.js CHANGED
@@ -43,6 +43,8 @@ function pullQuoteHref(link) {
43
43
  }
44
44
  return "";
45
45
  }
46
+ var isPortableTextBlock = (n) => !!n && typeof n === "object" && n._type === "block";
47
+ var isPortableTextSpan = (n) => !!n && typeof n === "object" && n._type === "span";
46
48
  var PT_TYPES = {
47
49
  /** A generic embedded block: `{schemaKey, schemaLabel, fields}`, the successor to Lexical's BlockNode. */
48
50
  block: "bcmsBlock",
@@ -264,7 +266,9 @@ function normalizeCell(raw, at, mint, read) {
264
266
  ...raw.header === true ? { header: true } : {},
265
267
  ...span === void 0 ? {} : { span },
266
268
  ...rowSpan === void 0 ? {} : { rowSpan },
267
- ...typeof raw.group === "string" ? { group: raw.group } : {}
269
+ ...typeof raw.group === "string" ? { group: raw.group } : {},
270
+ ...raw.highlight === true ? { highlight: true } : {},
271
+ ...raw.sortable === true ? { sortable: true } : {}
268
272
  };
269
273
  }
270
274
  function normalizeRow(raw, at, mint, read) {
@@ -273,7 +277,10 @@ function normalizeRow(raw, at, mint, read) {
273
277
  _key: isRecord(raw) && isValidKey(raw._key) ? raw._key : mint("r", at),
274
278
  cells: cells.map((c, col) => normalizeCell(c, [at, col], mint, read)),
275
279
  ...isRecord(raw) && raw.head === true ? { head: true } : {},
276
- ...isRecord(raw) && typeof raw.group === "string" ? { group: raw.group } : {}
280
+ ...isRecord(raw) && typeof raw.group === "string" ? { group: raw.group } : {},
281
+ // The V2 table's two row flags ("Totals row", "Highlight this row"); see `PortableTextTableRow`.
282
+ ...isRecord(raw) && raw.footer === true ? { footer: true } : {},
283
+ ...isRecord(raw) && raw.highlight === true ? { highlight: true } : {}
277
284
  };
278
285
  }
279
286
  function builtInTableToTable(node, key = randomKey) {
@@ -330,9 +337,53 @@ function tableExtras(node) {
330
337
  ...typeof node.caption === "string" ? { caption: node.caption } : {},
331
338
  ...typeof node.notes === "string" ? { notes: node.notes } : {},
332
339
  ...rowGroups ? { rowGroups } : {},
333
- ...columnGroups ? { columnGroups } : {}
340
+ ...columnGroups ? { columnGroups } : {},
341
+ ...node.filterable === true ? { filterable: true } : {},
342
+ ...jsonLdOf(node.jsonLd) ? { jsonLd: jsonLdOf(node.jsonLd) } : {},
343
+ ...designOf(node.design) ? { design: designOf(node.design) } : {}
334
344
  };
335
345
  }
346
+ function designOf(v) {
347
+ if (!isRecord(v)) return void 0;
348
+ const d = {
349
+ ...v.responsive === "stack" || v.responsive === "cards" ? { responsive: v.responsive } : {},
350
+ ...v.sticky === true ? { sticky: true } : {}
351
+ };
352
+ return Object.keys(d).length ? d : void 0;
353
+ }
354
+ var JSONLD_TYPES = ["ItemList", "Dataset", "Offers"];
355
+ function jsonLdOf(v) {
356
+ if (!isRecord(v) || !JSONLD_TYPES.includes(v.type)) return void 0;
357
+ return {
358
+ type: v.type,
359
+ ...v.axis === "rows" || v.axis === "columns" ? { axis: v.axis } : {},
360
+ ...typeof v.priceRow === "string" && v.priceRow ? { priceRow: v.priceRow } : {}
361
+ };
362
+ }
363
+ function tableSections(table) {
364
+ const rows = Array.isArray(table.rows) ? table.rows : [];
365
+ const headCount = rows.findIndex((r) => !isRecord(r) || r.head !== true);
366
+ const head = rows.slice(0, headCount === -1 ? rows.length : headCount);
367
+ let footFrom = rows.length;
368
+ while (footFrom > head.length && isRecord(rows[footFrom - 1]) && rows[footFrom - 1].footer === true) footFrom -= 1;
369
+ return { head, body: rows.slice(head.length, footFrom), foot: rows.slice(footFrom) };
370
+ }
371
+ function highlightedColumns(table) {
372
+ return markedColumns(table, "highlight");
373
+ }
374
+ function sortableColumns(table) {
375
+ return markedColumns(table, "sortable");
376
+ }
377
+ function markedColumns(table, flag) {
378
+ const out = /* @__PURE__ */ new Set();
379
+ const first = Array.isArray(table.rows) ? table.rows[0] : void 0;
380
+ let at = 0;
381
+ for (const cell of isRecord(first) && Array.isArray(first.cells) ? first.cells : []) {
382
+ if (isRecord(cell) && cell[flag] === true) out.add(at);
383
+ at += isRecord(cell) && typeof cell.span === "number" && Number.isInteger(cell.span) && cell.span > 1 ? cell.span : 1;
384
+ }
385
+ return out;
386
+ }
336
387
  function tableGroupLayout(table) {
337
388
  const rows = Array.isArray(table.rows) ? table.rows : [];
338
389
  const labels = (list) => new Map(
@@ -350,8 +401,7 @@ function tableGroupLayout(table) {
350
401
  else columns.push({ width: spanOf2(cell), ...key === void 0 ? {} : { key, label: colLabels.get(key) } });
351
402
  }
352
403
  const rowLabels = labels(table.rowGroups);
353
- const headCount = rows.findIndex((r) => !isRecord(r) || r.head !== true);
354
- const body = headCount === -1 ? [] : rows.slice(headCount);
404
+ const { body } = tableSections(table);
355
405
  const runs = [];
356
406
  for (const row of body) {
357
407
  const key = isRecord(row) && typeof row.group === "string" && rowLabels.has(row.group) ? row.group : void 0;
@@ -390,6 +440,74 @@ function detachedComponentCopy(value) {
390
440
  ...typeof f.variant === "string" ? { variant: f.variant } : {}
391
441
  };
392
442
  }
443
+ function componentCopyLines(copy) {
444
+ const line = (v) => {
445
+ if (typeof v === "number" && Number.isFinite(v)) return String(v);
446
+ if (typeof v === "string") {
447
+ const t = v.replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/\s+/g, " ").trim();
448
+ return t || null;
449
+ }
450
+ if (isRecord3(v)) return line(v.label ?? v.text ?? v.title);
451
+ return null;
452
+ };
453
+ return Object.values(copy.props).map(line).filter((s) => !!s);
454
+ }
455
+
456
+ // ../richtext/src/plain.ts
457
+ function portableTextToPlainText(value) {
458
+ if (!Array.isArray(value)) return "";
459
+ const lines = [];
460
+ for (const node of value) {
461
+ if (isPortableTextBlock(node)) {
462
+ lines.push(node.children.map((c) => isPortableTextSpan(c) ? c.text : "").join(""));
463
+ continue;
464
+ }
465
+ if (node._type === PT_TYPES.code && typeof node.code === "string") {
466
+ lines.push(node.code);
467
+ }
468
+ if (node._type === PT_TYPES.pullQuote) {
469
+ lines.push(...pullQuoteLines(node));
470
+ continue;
471
+ }
472
+ if (node._type === PT_TYPES.keyTakeaways) {
473
+ const { title, points } = keyTakeawaysView(node);
474
+ lines.push(...title ? [title] : [], ...points);
475
+ continue;
476
+ }
477
+ const table = migrateTable(node);
478
+ if (table) {
479
+ lines.push(...tableLines(table));
480
+ continue;
481
+ }
482
+ const copy = detachedComponentCopy(node);
483
+ if (copy) {
484
+ lines.push(...componentCopyLines(copy));
485
+ continue;
486
+ }
487
+ }
488
+ return lines.join("\n");
489
+ }
490
+ var tableLines = (table) => {
491
+ const rows = Array.isArray(table.rows) ? table.rows : [];
492
+ const rowLine = (row) => (Array.isArray(row?.cells) ? row.cells : []).map((cell) => portableTextToPlainText(cell?.content).replace(/\s+/g, " ").trim()).join(" ").trim();
493
+ const layout = tableGroupLayout(table);
494
+ const one = (s) => typeof s === "string" ? s.replace(/\s+/g, " ").trim() : "";
495
+ const head = layout.rows.length ? rows.slice(0, rows.length - layout.rows.reduce((n, r) => n + r.rows.length, 0)) : rows;
496
+ const lines = [
497
+ one(table.caption),
498
+ layout.columns.map((r) => one(r.label)).filter(Boolean).join(" "),
499
+ ...head.map(rowLine),
500
+ ...layout.rows.flatMap((run) => [...run.label === void 0 ? [] : [one(run.label)], ...run.rows.map(rowLine)]),
501
+ one(table.notes)
502
+ ];
503
+ const extras = /* @__PURE__ */ new Set([0, 1, lines.length - 1]);
504
+ return lines.filter((l, i) => l !== "" || !extras.has(i));
505
+ };
506
+ var pullQuoteLines = (v) => {
507
+ const text = (x) => typeof x === "string" ? x.trim() : "";
508
+ const by = [text(v.name), text(v.role)].filter(Boolean).join(", ");
509
+ return [text(v.quote), ...by ? [`\u2014 ${by}`] : []].filter(Boolean);
510
+ };
393
511
 
394
512
  // ../richtext/src/read.ts
395
513
  var isRecord4 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
@@ -451,41 +569,71 @@ function Table({ value }) {
451
569
  );
452
570
  const rows = Array.isArray(value?.rows) ? value.rows : [];
453
571
  if (rows.length === 0) return null;
454
- const cells = (row) => (Array.isArray(row?.cells) ? row.cells : []).map((cell) => {
455
- const Tag = cell?.header === true ? "th" : "td";
456
- const span2 = typeof cell?.span === "number" && cell.span > 1 ? cell.span : void 0;
457
- const rowSpan = typeof cell?.rowSpan === "number" && cell.rowSpan > 1 ? cell.rowSpan : void 0;
458
- const content = Array.isArray(cell?.content) ? cell.content : [];
459
- const lone = content.length === 1 && content[0]._type === "block" && content[0].style === "normal" && !content[0].listItem;
460
- return /* @__PURE__ */ jsx2(Tag, { ...span2 ? { colSpan: span2 } : {}, ...rowSpan ? { rowSpan } : {}, children: /* @__PURE__ */ jsx2(PT, { value: content, components: lone ? inline : components }) }, cell?._key);
461
- });
462
- const rowEl = (row) => /* @__PURE__ */ jsx2("tr", { children: cells(row) }, row?._key);
463
- const headCount = rows.findIndex((r) => r?.head !== true);
464
- const head = headCount === -1 ? rows.length : headCount;
572
+ const marked = highlightedColumns(value);
573
+ const sortable = sortableColumns(value);
574
+ const design = designOf(value.design);
575
+ const stacked = design?.responsive === "stack" || design?.responsive === "cards";
576
+ const role = (r) => stacked ? { role: r } : {};
577
+ const labels = [];
578
+ if (stacked) {
579
+ const headRows = tableSections(value).head;
580
+ let at = 0;
581
+ for (const c of Array.isArray(headRows[headRows.length - 1]?.cells) ? headRows[headRows.length - 1].cells : []) {
582
+ const text = portableTextToPlainText(Array.isArray(c?.content) ? c.content : []).replace(/\s+/g, " ").trim();
583
+ const w = typeof c?.span === "number" && c.span > 1 ? c.span : 1;
584
+ for (let i = 0; i < w; i += 1) labels[at + i] = text;
585
+ at += w;
586
+ }
587
+ }
588
+ const cells = (row) => {
589
+ let col = 0;
590
+ return (Array.isArray(row?.cells) ? row.cells : []).map((cell) => {
591
+ const Tag = cell?.header === true ? "th" : "td";
592
+ const span2 = typeof cell?.span === "number" && cell.span > 1 ? cell.span : void 0;
593
+ const at = col;
594
+ col += span2 ?? 1;
595
+ const rowSpan = typeof cell?.rowSpan === "number" && cell.rowSpan > 1 ? cell.rowSpan : void 0;
596
+ const content = Array.isArray(cell?.content) ? cell.content : [];
597
+ const lone = content.length === 1 && content[0]._type === "block" && content[0].style === "normal" && !content[0].listItem;
598
+ return /* @__PURE__ */ jsx2(Tag, { ...Tag === "td" ? role("cell") : {}, ...span2 ? { colSpan: span2 } : {}, ...rowSpan ? { rowSpan } : {}, ...stacked && Tag === "td" ? { "data-label": labels[at] || `Column ${at + 1}` } : {}, ...marked.has(at) ? { "data-highlight": "true" } : {}, children: /* @__PURE__ */ jsx2(PT, { value: content, components: lone ? inline : components }) }, cell?._key);
599
+ });
600
+ };
601
+ const rowEl = (row) => /* @__PURE__ */ jsx2("tr", { ...role("row"), ...row?.highlight === true ? { "data-highlight": "true" } : {}, children: cells(row) }, row?._key);
602
+ const sections = tableSections(value);
603
+ const head = sections.head.length;
604
+ const foot = sections.foot;
465
605
  const layout = tableGroupLayout(value);
466
606
  const caption = typeof value.caption === "string" ? value.caption.trim() : "";
467
607
  const notes = typeof value.notes === "string" ? value.notes.trim() : "";
468
608
  const notesId = notes && typeof value._key === "string" && value._key ? `${value._key}-notes` : void 0;
469
609
  const span = (n) => n > 1 ? n : void 0;
470
- const groupRow = layout.columns.length ? /* @__PURE__ */ jsx2("tr", { children: layout.columns.flatMap(
471
- (run, i) => run.label === void 0 ? Array.from({ length: run.width }, (_, k) => /* @__PURE__ */ jsx2("td", {}, `${i}-${k}`)) : [/* @__PURE__ */ jsx2("th", { scope: "colgroup", colSpan: span(run.width), "data-group": run.key, children: run.label }, i)]
610
+ const groupRow = layout.columns.length ? /* @__PURE__ */ jsx2("tr", { ...role("row"), children: layout.columns.flatMap(
611
+ (run, i) => run.label === void 0 ? Array.from({ length: run.width }, (_, k) => /* @__PURE__ */ jsx2("td", { ...role("cell") }, `${i}-${k}`)) : [/* @__PURE__ */ jsx2("th", { ...role("columnheader"), scope: "colgroup", colSpan: span(run.width), "data-group": run.key, children: run.label }, i)]
472
612
  ) }) : null;
473
- const bodies = layout.rows.length ? layout.rows.map((run, i) => /* @__PURE__ */ jsxs("tbody", { "data-key": run.key, children: [
474
- run.label !== void 0 && /* @__PURE__ */ jsx2("tr", { children: /* @__PURE__ */ jsx2("th", { scope: "rowgroup", colSpan: span(layout.width), children: run.label }) }),
613
+ const bodies = layout.rows.length ? layout.rows.map((run, i) => /* @__PURE__ */ jsxs("tbody", { ...role("rowgroup"), "data-key": run.key, children: [
614
+ run.label !== void 0 && /* @__PURE__ */ jsx2("tr", { ...role("row"), children: /* @__PURE__ */ jsx2("th", { ...role("rowheader"), scope: "rowgroup", colSpan: span(layout.width), children: run.label }) }),
475
615
  run.rows.map(rowEl)
476
- ] }, i)) : head < rows.length && /* @__PURE__ */ jsx2("tbody", { children: rows.slice(head).map(rowEl) });
477
- const table = /* @__PURE__ */ jsxs("table", { ...value.legacy === true ? { className: "bcms-table" } : {}, ...notesId ? { "aria-describedby": notesId } : {}, children: [
616
+ ] }, i)) : sections.body.length > 0 && /* @__PURE__ */ jsx2("tbody", { ...role("rowgroup"), children: sections.body.map(rowEl) });
617
+ const table = /* @__PURE__ */ jsxs("table", { ...role("table"), ...value.legacy === true ? { className: "bcms-table" } : {}, ...notesId ? { "aria-describedby": notesId } : {}, children: [
478
618
  caption && /* @__PURE__ */ jsx2("caption", { children: caption }),
479
- layout.columns.map((run, i) => /* @__PURE__ */ jsx2("colgroup", { span: span(run.width) }, i)),
480
- (groupRow || head > 0) && /* @__PURE__ */ jsxs("thead", { children: [
619
+ sortable.size ? (layout.columns.length ? layout.columns.map((run) => run.width) : [layout.width]).map((w, i, all) => {
620
+ const from = all.slice(0, i).reduce((n, x) => n + x, 0);
621
+ return /* @__PURE__ */ jsx2("colgroup", { children: Array.from({ length: w }, (_, k) => /* @__PURE__ */ jsx2("col", { ...sortable.has(from + k) ? { "data-sortable": "true" } : {} }, k)) }, i);
622
+ }) : layout.columns.map((run, i) => /* @__PURE__ */ jsx2("colgroup", { span: span(run.width) }, i)),
623
+ (groupRow || head > 0) && /* @__PURE__ */ jsxs("thead", { ...role("rowgroup"), children: [
481
624
  groupRow,
482
625
  rows.slice(0, head).map(rowEl)
483
626
  ] }),
484
- bodies
627
+ bodies,
628
+ foot.length > 0 && /* @__PURE__ */ jsx2("tfoot", { ...role("rowgroup"), children: foot.map(rowEl) })
485
629
  ] });
486
- return notes ? /* @__PURE__ */ jsxs("figure", { "data-rt": "table", children: [
630
+ const filter = value.filterable === true;
631
+ const ld = jsonLdOf(value.jsonLd);
632
+ const ldAttrs = ld ? { "data-jsonld": ld.type, ...ld.axis ? { "data-jsonld-axis": ld.axis } : {}, ...ld.priceRow ? { "data-jsonld-price": ld.priceRow } : {} } : {};
633
+ const designAttrs = design ? { ...design.responsive ? { "data-responsive": design.responsive } : {}, ...design.sticky ? { "data-sticky": "true" } : {} } : {};
634
+ return notes || filter || ld || design ? /* @__PURE__ */ jsxs("figure", { "data-rt": "table", ...designAttrs, ...filter ? { "data-filter": "true" } : {}, ...ldAttrs, children: [
487
635
  table,
488
- /* @__PURE__ */ jsx2("p", { "data-notes": "", id: notesId, children: notes })
636
+ notes ? /* @__PURE__ */ jsx2("p", { "data-notes": "", id: notesId, children: notes }) : null
489
637
  ] }) : table;
490
638
  }
491
639
  function buildComponents(renderBlock) {