@bettercms-ai/ui 0.18.0 → 0.20.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
@@ -36,6 +36,7 @@ import React from "react";
36
36
  import { PortableText as PT } from "@portabletext/react";
37
37
 
38
38
  // ../richtext/src/types.ts
39
+ var PT_TABLE_COLUMN_TYPES = ["text", "number", "money", "boolean", "rating", "link"];
39
40
  function pullQuoteHref(link) {
40
41
  if (typeof link === "string") return link.trim();
41
42
  if (link && typeof link === "object" && typeof link.href === "string") {
@@ -268,7 +269,12 @@ function normalizeCell(raw, at, mint, read) {
268
269
  ...rowSpan === void 0 ? {} : { rowSpan },
269
270
  ...typeof raw.group === "string" ? { group: raw.group } : {},
270
271
  ...raw.highlight === true ? { highlight: true } : {},
271
- ...raw.sortable === true ? { sortable: true } : {}
272
+ ...raw.sortable === true ? { sortable: true } : {},
273
+ // The V2 table's typed cells: the column (first-row cell), the per-cell type, the typed value.
274
+ ...columnOf(raw.column) ? { column: columnOf(raw.column) } : {},
275
+ ...isColumnType(raw.type) ? { type: raw.type } : {},
276
+ ...typeof raw.value === "boolean" || typeof raw.value === "number" && Number.isFinite(raw.value) ? { value: raw.value } : {},
277
+ ...typeof raw.note === "string" && raw.note ? { note: raw.note } : {}
272
278
  };
273
279
  }
274
280
  function normalizeRow(raw, at, mint, read) {
@@ -280,7 +286,8 @@ function normalizeRow(raw, at, mint, read) {
280
286
  ...isRecord(raw) && typeof raw.group === "string" ? { group: raw.group } : {},
281
287
  // The V2 table's two row flags ("Totals row", "Highlight this row"); see `PortableTextTableRow`.
282
288
  ...isRecord(raw) && raw.footer === true ? { footer: true } : {},
283
- ...isRecord(raw) && raw.highlight === true ? { highlight: true } : {}
289
+ ...isRecord(raw) && raw.highlight === true ? { highlight: true } : {},
290
+ ...isRecord(raw) && isColumnType(raw.type) ? { type: raw.type } : {}
284
291
  };
285
292
  }
286
293
  function builtInTableToTable(node, key = randomKey) {
@@ -340,9 +347,18 @@ function tableExtras(node) {
340
347
  ...columnGroups ? { columnGroups } : {},
341
348
  ...node.filterable === true ? { filterable: true } : {},
342
349
  ...jsonLdOf(node.jsonLd) ? { jsonLd: jsonLdOf(node.jsonLd) } : {},
343
- ...designOf(node.design) ? { design: designOf(node.design) } : {}
350
+ ...designOf(node.design) ? { design: designOf(node.design) } : {},
351
+ ...footnotesOf(node.footnotes) ? { footnotes: footnotesOf(node.footnotes) } : {}
344
352
  };
345
353
  }
354
+ function footnotesOf(v) {
355
+ if (!Array.isArray(v)) return void 0;
356
+ const out = v.filter((f) => isRecord(f) && typeof f._key === "string" && f._key !== "").map((f) => ({ _key: f._key, text: typeof f.text === "string" ? f.text : "" }));
357
+ return out.length ? out : void 0;
358
+ }
359
+ function footnoteNumbers(table) {
360
+ return new Map((footnotesOf(table.footnotes) ?? []).map((f, i) => [f._key, i + 1]));
361
+ }
346
362
  function designOf(v) {
347
363
  if (!isRecord(v)) return void 0;
348
364
  const d = {
@@ -415,6 +431,133 @@ function tableGroupLayout(table) {
415
431
  width
416
432
  };
417
433
  }
434
+ var NUMERIC_TYPES = /* @__PURE__ */ new Set(["number", "money", "rating"]);
435
+ var isColumnType = (v) => PT_TABLE_COLUMN_TYPES.includes(v);
436
+ function columnOf(v) {
437
+ if (!isRecord(v)) return void 0;
438
+ const str = (x) => typeof x === "string" && x !== "" ? x : void 0;
439
+ const int = (x, lo, hi) => Number.isInteger(x) && x >= lo && x <= hi ? x : void 0;
440
+ const c = {
441
+ ...isColumnType(v.type) ? { type: v.type } : {},
442
+ ...str(v.description) ? { description: str(v.description) } : {},
443
+ ...str(v.unit) ? { unit: str(v.unit) } : {},
444
+ ...typeof v.currency === "string" && /^[A-Z]{3}$/.test(v.currency) ? { currency: v.currency } : {},
445
+ ...int(v.decimals, 0, 10) !== void 0 ? { decimals: int(v.decimals, 0, 10) } : {},
446
+ ...v.align === "start" || v.align === "center" || v.align === "end" ? { align: v.align } : {},
447
+ ...str(v.trueLabel) ? { trueLabel: str(v.trueLabel) } : {},
448
+ ...str(v.falseLabel) ? { falseLabel: str(v.falseLabel) } : {},
449
+ ...int(v.max, 1, 10) !== void 0 ? { max: int(v.max, 1, 10) } : {}
450
+ };
451
+ return Object.keys(c).length ? c : void 0;
452
+ }
453
+ function tableColumns(table) {
454
+ const out = [];
455
+ const first = Array.isArray(table.rows) ? table.rows[0] : void 0;
456
+ for (const cell of isRecord(first) && Array.isArray(first.cells) ? first.cells : []) {
457
+ const w = isRecord(cell) && typeof cell.span === "number" && Number.isInteger(cell.span) && cell.span > 1 ? cell.span : 1;
458
+ const col = isRecord(cell) ? columnOf(cell.column) : void 0;
459
+ for (let i = 0; i < w; i += 1) out.push(col);
460
+ }
461
+ return out;
462
+ }
463
+ function isTypedTable(table) {
464
+ if (tableColumns(table).some(Boolean)) return true;
465
+ return (Array.isArray(table.rows) ? table.rows : []).some(
466
+ (r) => isRecord(r) && (r.type !== void 0 || Array.isArray(r.cells) && r.cells.some((c) => isRecord(c) && (c.type !== void 0 || c.value !== void 0)))
467
+ );
468
+ }
469
+ var cellTypeOf = (col, row, cell) => (isRecord(cell) && isColumnType(cell.type) ? cell.type : void 0) ?? (isRecord(row) && isColumnType(row.type) ? row.type : void 0) ?? col?.type ?? "text";
470
+ var columnAlign = (col, type) => col?.align ?? (NUMERIC_TYPES.has(type) ? "end" : "start");
471
+ var TRUE_WORDS = /* @__PURE__ */ new Set(["\u2713", "\u2714", "\u2714\uFE0F", "\u2611", "\u2705", "yes", "y", "true", "included", "available", "supported", "x \u2713", "check", "\u25CF"]);
472
+ var FALSE_WORDS = /* @__PURE__ */ new Set(["\u2717", "\u2715", "\u2716", "\u274C", "\xD7", "x", "no", "n", "false", "not included", "unavailable", "not available", "unsupported", "\u2014", "\u2013", "-", "\u25CB"]);
473
+ function toBool(v) {
474
+ if (typeof v === "boolean") return v;
475
+ if (typeof v !== "string") return null;
476
+ const s = v.trim().toLowerCase();
477
+ return TRUE_WORDS.has(s) ? true : FALSE_WORDS.has(s) ? false : null;
478
+ }
479
+ function toNumber(v) {
480
+ if (typeof v === "number") return Number.isFinite(v) ? v : null;
481
+ if (typeof v !== "string") return null;
482
+ const s = v.replace(/[,\s]/g, "").replace(/[^\d.+-]/g, "");
483
+ if (!s || !/^[+-]?\d*\.?\d+$/.test(s)) return null;
484
+ return Number(s);
485
+ }
486
+ var formatNumber = (n, decimals) => new Intl.NumberFormat("en-US", decimals != null ? { minimumFractionDigits: decimals, maximumFractionDigits: decimals } : { maximumFractionDigits: 6 }).format(n);
487
+ function formatMoney(n, currency = "USD", decimals) {
488
+ try {
489
+ const whole = Number.isInteger(n) && decimals == null;
490
+ return new Intl.NumberFormat("en-US", { style: "currency", currency, minimumFractionDigits: whole ? 0 : decimals ?? 2, maximumFractionDigits: whole ? 0 : decimals ?? 2 }).format(n);
491
+ } catch {
492
+ return `${formatNumber(n, decimals)} ${currency}`;
493
+ }
494
+ }
495
+ var boolLabels = (col) => ({ yes: col?.trueLabel || "Included", no: col?.falseLabel || "Not included" });
496
+ function typedCellText(col, type, v) {
497
+ if (v == null || v === "") return "";
498
+ const words = String(v).replace(/\s+/g, " ").trim();
499
+ switch (type) {
500
+ case "boolean": {
501
+ const b = toBool(v);
502
+ return b == null ? words : b ? boolLabels(col).yes : boolLabels(col).no;
503
+ }
504
+ case "number": {
505
+ const n = toNumber(v);
506
+ return n == null ? words : `${formatNumber(n, col?.decimals)}${col?.unit ? /^[%°]/.test(col.unit) ? col.unit : ` ${col.unit}` : ""}`;
507
+ }
508
+ case "money": {
509
+ const n = toNumber(v);
510
+ return n == null ? words : formatMoney(n, col?.currency || "USD", col?.decimals);
511
+ }
512
+ case "rating": {
513
+ const n = toNumber(v);
514
+ return n == null ? words : `${formatNumber(n, 1).replace(/\.0$/, "")} out of ${col?.max ?? 5}`;
515
+ }
516
+ default:
517
+ return words;
518
+ }
519
+ }
520
+ var escHtml = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
521
+ function typedCellView(column, row, cell, inHead) {
522
+ if (inHead) {
523
+ const align2 = columnAlign(column, column?.type ?? "text");
524
+ return { lead: align2 !== "start" ? [["data-align", align2]] : [], tail: column?.description ? [["title", column.description]] : [] };
525
+ }
526
+ const type = cellTypeOf(column, row, cell);
527
+ const words = portableTextWords(cell.content);
528
+ const v = typeof cell.value === "number" || typeof cell.value === "boolean" ? cell.value : words;
529
+ const tail = isColumnType(cell.type) ? [["data-type", cell.type]] : [];
530
+ let inner;
531
+ if (v === "") {
532
+ inner = cell.header === true ? "" : '<span aria-hidden="true" class="bt-dash">\u2014</span><span class="bt-sr">No value</span>';
533
+ tail.push(["data-empty", ""]);
534
+ } else if (type === "boolean") {
535
+ const b = toBool(v);
536
+ if (b == null) inner = escHtml(words);
537
+ else {
538
+ const { yes, no } = boolLabels(column);
539
+ inner = `<span aria-hidden="true" class="bt-bool" data-bool="${b}">${b ? "\u2713" : "\u2013"}</span><span class="bt-sr">${escHtml(b ? yes : no)}</span>`;
540
+ tail.push(["data-value", String(b)]);
541
+ }
542
+ } else if (type === "rating") {
543
+ const n = toNumber(v);
544
+ if (n == null) inner = escHtml(words);
545
+ else {
546
+ inner = `<span aria-hidden="true" class="bt-star">\u2605</span> ${escHtml(formatNumber(n, 1).replace(/\.0$/, ""))}<span class="bt-dim"> / ${column?.max ?? 5}</span>`;
547
+ tail.push(["data-value", String(n)]);
548
+ }
549
+ } else if (type === "number" || type === "money") {
550
+ const n = toNumber(v);
551
+ inner = escHtml(typedCellText(column, type, v));
552
+ if (n != null) tail.push(["data-value", String(n)]);
553
+ }
554
+ const align = columnAlign(column, type);
555
+ if (align !== "start") tail.push(["data-align", align]);
556
+ return { lead: [], tail, ...inner === void 0 ? {} : { inner } };
557
+ }
558
+ function portableTextWords(content) {
559
+ return (Array.isArray(content) ? content : []).map((b) => isRecord(b) && Array.isArray(b.children) ? b.children.map((c) => isRecord(c) && typeof c.text === "string" ? c.text : "").join("") : "").join(" ").replace(/\s+/g, " ").trim();
560
+ }
418
561
 
419
562
  // ../richtext/src/key-takeaways.ts
420
563
  var isRecord2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
@@ -498,9 +641,12 @@ var tableLines = (table) => {
498
641
  layout.columns.map((r) => one(r.label)).filter(Boolean).join(" "),
499
642
  ...head.map(rowLine),
500
643
  ...layout.rows.flatMap((run) => [...run.label === void 0 ? [] : [one(run.label)], ...run.rows.map(rowLine)]),
501
- one(table.notes)
644
+ one(table.notes),
645
+ // footnotes, numbered as the html numbers them (V2 tableSearchText reads them too)
646
+ ...(Array.isArray(table.footnotes) ? table.footnotes : []).map((f, i) => one(`[${i + 1}] ${typeof f?.text === "string" ? f.text : ""}`))
502
647
  ];
503
- const extras = /* @__PURE__ */ new Set([0, 1, lines.length - 1]);
648
+ const fnCount = Array.isArray(table.footnotes) ? table.footnotes.length : 0;
649
+ const extras = /* @__PURE__ */ new Set([0, 1, lines.length - 1 - fnCount]);
504
650
  return lines.filter((l, i) => l !== "" || !extras.has(i));
505
651
  };
506
652
  var pullQuoteLines = (v) => {
@@ -585,6 +731,13 @@ function Table({ value }) {
585
731
  at += w;
586
732
  }
587
733
  }
734
+ const columns = tableColumns(value);
735
+ const typed = isTypedTable(value);
736
+ const headSet = new Set(tableSections(value).head);
737
+ const props = (list) => Object.fromEntries(list);
738
+ const fnNumber = footnoteNumbers(value);
739
+ const footnotes = footnotesOf(value.footnotes) ?? [];
740
+ const tableId = typeof value._key === "string" && value._key ? value._key : "tbl";
588
741
  const cells = (row) => {
589
742
  let col = 0;
590
743
  return (Array.isArray(row?.cells) ? row.cells : []).map((cell) => {
@@ -593,19 +746,27 @@ function Table({ value }) {
593
746
  const at = col;
594
747
  col += span2 ?? 1;
595
748
  const rowSpan = typeof cell?.rowSpan === "number" && cell.rowSpan > 1 ? cell.rowSpan : void 0;
749
+ const n = typeof cell?.note === "string" ? fnNumber.get(cell.note) : void 0;
596
750
  const content = Array.isArray(cell?.content) ? cell.content : [];
597
751
  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);
752
+ const view = typed ? typedCellView(columns[at], row, cell ?? {}, headSet.has(row)) : void 0;
753
+ const noteAttr = n ? [["data-note", cell.note]] : [];
754
+ const tail = [...(view?.tail ?? []).filter(([k]) => k !== "data-align"), ...noteAttr, ...(view?.tail ?? []).filter(([k]) => k === "data-align")];
755
+ const supHtml = n ? `<sup><a href="#${tableId}-fn-${n}" aria-label="Note ${n}">${n}</a></sup>` : "";
756
+ return /* @__PURE__ */ jsx2(Tag, { ...Tag === "td" ? role("cell") : {}, ...span2 ? { colSpan: span2 } : {}, ...rowSpan ? { rowSpan } : {}, ...props(view?.lead ?? []), ...stacked && Tag === "td" ? { "data-label": labels[at] || `Column ${at + 1}` } : {}, ...marked.has(at) ? { "data-highlight": "true" } : {}, ...props(tail), ...view?.inner !== void 0 ? { dangerouslySetInnerHTML: { __html: view.inner + supHtml } } : {}, children: view?.inner !== void 0 ? void 0 : /* @__PURE__ */ jsxs(Fragment, { children: [
757
+ /* @__PURE__ */ jsx2(PT, { value: content, components: lone ? inline : components }),
758
+ n ? /* @__PURE__ */ jsx2("sup", { children: /* @__PURE__ */ jsx2("a", { href: `#${tableId}-fn-${n}`, "aria-label": `Note ${n}`, children: n }) }) : null
759
+ ] }) }, cell?._key);
599
760
  });
600
761
  };
601
- const rowEl = (row) => /* @__PURE__ */ jsx2("tr", { ...role("row"), ...row?.highlight === true ? { "data-highlight": "true" } : {}, children: cells(row) }, row?._key);
762
+ const rowEl = (row) => /* @__PURE__ */ jsx2("tr", { ...role("row"), ...typeof row?.type === "string" ? { "data-type": row.type } : {}, ...row?.highlight === true ? { "data-highlight": "true" } : {}, children: cells(row) }, row?._key);
602
763
  const sections = tableSections(value);
603
764
  const head = sections.head.length;
604
765
  const foot = sections.foot;
605
766
  const layout = tableGroupLayout(value);
606
767
  const caption = typeof value.caption === "string" ? value.caption.trim() : "";
607
768
  const notes = typeof value.notes === "string" ? value.notes.trim() : "";
608
- const notesId = notes && typeof value._key === "string" && value._key ? `${value._key}-notes` : void 0;
769
+ const notesId = (notes || footnotes.length) && typeof value._key === "string" && value._key ? `${value._key}-notes` : void 0;
609
770
  const span = (n) => n > 1 ? n : void 0;
610
771
  const groupRow = layout.columns.length ? /* @__PURE__ */ jsx2("tr", { ...role("row"), children: layout.columns.flatMap(
611
772
  (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)]
@@ -614,11 +775,26 @@ function Table({ value }) {
614
775
  run.label !== void 0 && /* @__PURE__ */ jsx2("tr", { ...role("row"), children: /* @__PURE__ */ jsx2("th", { ...role("rowheader"), scope: "rowgroup", colSpan: span(layout.width), children: run.label }) }),
615
776
  run.rows.map(rowEl)
616
777
  ] }, i)) : sections.body.length > 0 && /* @__PURE__ */ jsx2("tbody", { ...role("rowgroup"), children: sections.body.map(rowEl) });
778
+ const colProps = (i) => {
779
+ const c = columns[i];
780
+ return {
781
+ ...c ? { "data-type": c.type ?? "text" } : {},
782
+ ...c?.unit ? { "data-unit": c.unit } : {},
783
+ ...c?.currency ? { "data-currency": c.currency } : {},
784
+ ...c?.decimals != null ? { "data-decimals": String(c.decimals) } : {},
785
+ ...c?.align ? { "data-align": c.align } : {},
786
+ ...sortable.has(i) ? { "data-sortable": "true" } : {},
787
+ ...c?.trueLabel ? { "data-true": c.trueLabel } : {},
788
+ ...c?.falseLabel ? { "data-false": c.falseLabel } : {},
789
+ ...c?.max != null ? { "data-max": String(c.max) } : {},
790
+ ...c?.description ? { "data-description": c.description } : {}
791
+ };
792
+ };
617
793
  const table = /* @__PURE__ */ jsxs("table", { ...role("table"), ...value.legacy === true ? { className: "bcms-table" } : {}, ...notesId ? { "aria-describedby": notesId } : {}, children: [
618
794
  caption && /* @__PURE__ */ jsx2("caption", { children: caption }),
619
- sortable.size ? (layout.columns.length ? layout.columns.map((run) => run.width) : [layout.width]).map((w, i, all) => {
795
+ sortable.size || columns.some(Boolean) ? (layout.columns.length ? layout.columns.map((run) => run.width) : [layout.width]).map((w, i, all) => {
620
796
  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);
797
+ return /* @__PURE__ */ jsx2("colgroup", { children: Array.from({ length: w }, (_, k) => /* @__PURE__ */ jsx2("col", { ...colProps(from + k) }, k)) }, i);
622
798
  }) : layout.columns.map((run, i) => /* @__PURE__ */ jsx2("colgroup", { span: span(run.width) }, i)),
623
799
  (groupRow || head > 0) && /* @__PURE__ */ jsxs("thead", { ...role("rowgroup"), children: [
624
800
  groupRow,
@@ -631,9 +807,12 @@ function Table({ value }) {
631
807
  const ld = jsonLdOf(value.jsonLd);
632
808
  const ldAttrs = ld ? { "data-jsonld": ld.type, ...ld.axis ? { "data-jsonld-axis": ld.axis } : {}, ...ld.priceRow ? { "data-jsonld-price": ld.priceRow } : {} } : {};
633
809
  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: [
810
+ return notes || filter || ld || design || footnotes.length ? /* @__PURE__ */ jsxs("figure", { "data-rt": "table", ...designAttrs, ...filter ? { "data-filter": "true" } : {}, ...ldAttrs, children: [
635
811
  table,
636
- notes ? /* @__PURE__ */ jsx2("p", { "data-notes": "", id: notesId, children: notes }) : null
812
+ footnotes.length ? /* @__PURE__ */ jsxs("div", { className: "bt-notes", id: `${tableId}-notes`, children: [
813
+ notes ? /* @__PURE__ */ jsx2("p", { "data-notes": "", children: notes }) : null,
814
+ /* @__PURE__ */ jsx2("ol", { "data-footnotes": "", children: footnotes.map((f, i) => /* @__PURE__ */ jsx2("li", { id: `${tableId}-fn-${i + 1}`, "data-key": f._key, children: f.text }, f._key)) })
815
+ ] }) : notes ? /* @__PURE__ */ jsx2("p", { "data-notes": "", id: notesId, children: notes }) : null
637
816
  ] }) : table;
638
817
  }
639
818
  function buildComponents(renderBlock) {
@@ -656,6 +835,8 @@ function buildComponents(renderBlock) {
656
835
  [PT_TYPES.block]: ({ value }) => {
657
836
  const rendered = renderBlock?.(value);
658
837
  if (rendered !== void 0) return /* @__PURE__ */ jsx2(Fragment, { children: rendered });
838
+ const builtIn = calloutOrToggle(value);
839
+ if (builtIn) return builtIn;
659
840
  const copy = detachedComponentCopy(value);
660
841
  if (copy) {
661
842
  return /* @__PURE__ */ jsx2("div", { className: "bcms-block bcms-block--component", "data-bcms-component-copy": copy.componentId, "data-bcms-instance": copy.id, children: /* @__PURE__ */ jsx2(BlocksRenderer, { blocks: copy.blocks }) });
@@ -772,6 +953,35 @@ function runsOf(blocks) {
772
953
  }
773
954
  return runs;
774
955
  }
956
+ function paragraphs(text) {
957
+ return text.split(/\n\s*\n/).map((p) => p.trim()).filter(Boolean).map((p, i) => /* @__PURE__ */ jsx2("p", { children: p.split("\n").map((line, j) => j === 0 ? line : [/* @__PURE__ */ jsx2("br", {}, j), line]) }, i));
958
+ }
959
+ var CALLOUT_TONES = /* @__PURE__ */ new Set(["info", "tip", "warning"]);
960
+ function calloutOrToggle(value) {
961
+ const v = value ?? {};
962
+ const f = v.fields && typeof v.fields === "object" ? v.fields : {};
963
+ const text = (x) => typeof x === "string" ? x.trim() : "";
964
+ if (v.schemaKey === "builtin:callout") {
965
+ const tone = CALLOUT_TONES.has(text(f.tone)) ? text(f.tone) : "info";
966
+ const title = text(f.title);
967
+ const body = paragraphs(typeof f.message === "string" ? f.message : "");
968
+ if (!title && !body.length) return /* @__PURE__ */ jsx2(Fragment, {});
969
+ return /* @__PURE__ */ jsxs("div", { className: `bcms-callout bcms-callout--${tone}`, "data-rt": "callout", "data-callout": tone, role: "note", children: [
970
+ title ? /* @__PURE__ */ jsx2("p", { className: "bcms-callout__title", "data-title": "", children: title }) : null,
971
+ /* @__PURE__ */ jsx2("div", { className: "bcms-callout__body", "data-body": "", children: body })
972
+ ] });
973
+ }
974
+ if (v.schemaKey === "builtin:toggle") {
975
+ const title = text(f.title);
976
+ const body = paragraphs(typeof f.body === "string" ? f.body : "");
977
+ if (!title && !body.length) return /* @__PURE__ */ jsx2(Fragment, {});
978
+ return /* @__PURE__ */ jsxs("details", { className: "bcms-toggle", "data-rt": "toggle", children: [
979
+ /* @__PURE__ */ jsx2("summary", { className: "bcms-toggle__title", children: title }),
980
+ /* @__PURE__ */ jsx2("div", { className: "bcms-toggle__body", "data-body": "", children: body })
981
+ ] });
982
+ }
983
+ return null;
984
+ }
775
985
  function PortableText({ value, bindingBase, renderBlock }) {
776
986
  const blocks = React.useMemo(() => normalizePortableText(readValue(value)), [value]);
777
987
  const components = React.useMemo(() => buildComponents(renderBlock), [renderBlock]);