@bettercms-ai/ui 0.22.0 → 0.23.1
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 +2 -2
- package/dist/blocks.d.ts +10 -4
- package/dist/blocks.js +242 -32
- package/dist/blocks.js.map +1 -1
- package/dist/index.js +242 -32
- package/dist/index.js.map +1 -1
- package/dist/registry.js +244 -34
- package/dist/registry.js.map +1 -1
- package/dist/renderer.js +244 -34
- package/dist/renderer.js.map +1 -1
- package/package.json +4 -3
package/dist/registry.js
CHANGED
|
@@ -193,6 +193,14 @@ var PT_TYPES = {
|
|
|
193
193
|
gallery: "gallery",
|
|
194
194
|
/** A table of contents built from the headings — see `PortableTextTableOfContents`. The V2 kit's `<nav data-rt="toc">`. */
|
|
195
195
|
tableOfContents: "tableOfContents",
|
|
196
|
+
/** A footnote, an INLINE object in body text — see `PortableTextFootnote`. The V2 kit's `<sup data-rt="fn">`. */
|
|
197
|
+
footnote: "footnote",
|
|
198
|
+
/** Columns of text — see `PortableTextColumns`. The V2 kit's `<div data-rt="columns">`; the legacy `builtin:columns` reads the same way. */
|
|
199
|
+
columns: "columns",
|
|
200
|
+
/** An author bio — see `PortableTextAuthorBio`. The V2 kit's `<aside data-rt="author">`. */
|
|
201
|
+
authorBio: "authorBio",
|
|
202
|
+
/** Related posts — see `PortableTextRelatedPosts`. The V2 kit's `<aside data-rt="related">`. */
|
|
203
|
+
relatedPosts: "relatedPosts",
|
|
196
204
|
/**
|
|
197
205
|
* A table. Spelled `table`, unprefixed, because that is what every other Portable Text
|
|
198
206
|
* producer calls one — the Sanity-shaped `{_type:"table", rows}` this platform used to refuse
|
|
@@ -222,7 +230,10 @@ var STORABLE_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
|
222
230
|
PT_TYPES.keyTakeaways,
|
|
223
231
|
PT_TYPES.embed,
|
|
224
232
|
PT_TYPES.gallery,
|
|
225
|
-
PT_TYPES.tableOfContents
|
|
233
|
+
PT_TYPES.tableOfContents,
|
|
234
|
+
PT_TYPES.columns,
|
|
235
|
+
PT_TYPES.authorBio,
|
|
236
|
+
PT_TYPES.relatedPosts
|
|
226
237
|
]);
|
|
227
238
|
var EMBEDDED_COMPONENT_KEY = "component";
|
|
228
239
|
|
|
@@ -697,6 +708,28 @@ function keyTakeawaysView(value) {
|
|
|
697
708
|
return { title, points };
|
|
698
709
|
}
|
|
699
710
|
|
|
711
|
+
// ../richtext/src/image-layout.ts
|
|
712
|
+
import {
|
|
713
|
+
focalInCrop,
|
|
714
|
+
formatImageRect,
|
|
715
|
+
imageValueUrl,
|
|
716
|
+
normalizeImageCrop,
|
|
717
|
+
normalizeImageFocal,
|
|
718
|
+
objectPosition,
|
|
719
|
+
parseImageRect
|
|
720
|
+
} from "@bettercms-ai/image-url";
|
|
721
|
+
function richTextImageFrame(src, crop, focal) {
|
|
722
|
+
const c = normalizeImageCrop(crop);
|
|
723
|
+
const f = normalizeImageFocal(focal);
|
|
724
|
+
if (!c && !f) return { src, crop: null, focal: null, position: null, data: [] };
|
|
725
|
+
const drawn = imageValueUrl({ url: src, crop: c, focal: f }) ?? src;
|
|
726
|
+
const data = [];
|
|
727
|
+
if (drawn !== src) data.push(["data-src", src]);
|
|
728
|
+
if (c) data.push(["data-crop", formatImageRect(c)]);
|
|
729
|
+
if (f) data.push(["data-focal", `${f.x},${f.y}`]);
|
|
730
|
+
return { src: drawn, crop: c, focal: f, position: f ? objectPosition(focalInCrop(f, c)) : null, data };
|
|
731
|
+
}
|
|
732
|
+
|
|
700
733
|
// ../richtext/src/gallery.ts
|
|
701
734
|
var isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
702
735
|
var galleryMediaSrc = (raw) => safeHref(raw) ?? (raw !== "" && !raw.startsWith("//") && !/[:\s]/.test(raw) ? raw : null);
|
|
@@ -722,9 +755,12 @@ function galleryView(value) {
|
|
|
722
755
|
if (!isRecord3(item) || !isRecord3(item.image)) return;
|
|
723
756
|
const src = galleryMediaSrc(typeof item.image.src === "string" ? item.image.src.trim() : "");
|
|
724
757
|
if (!src) return;
|
|
758
|
+
const frame = richTextImageFrame(src, item.image.crop, item.image.focal);
|
|
725
759
|
images.push({
|
|
726
760
|
key: typeof item._key === "string" && item._key ? item._key : `i${i}`,
|
|
727
|
-
src,
|
|
761
|
+
src: frame.src,
|
|
762
|
+
position: frame.position,
|
|
763
|
+
data: frame.data,
|
|
728
764
|
alt: typeof item.image.alt === "string" ? item.image.alt : "",
|
|
729
765
|
caption: typeof item.caption === "string" ? item.caption.trim() : ""
|
|
730
766
|
});
|
|
@@ -732,16 +768,49 @@ function galleryView(value) {
|
|
|
732
768
|
return { layout, images };
|
|
733
769
|
}
|
|
734
770
|
|
|
735
|
-
// ../richtext/src/
|
|
771
|
+
// ../richtext/src/columns.ts
|
|
772
|
+
var PT_COLUMNS_LIMITS = { min: 2, max: 4 };
|
|
773
|
+
var BUILTIN_COLUMNS_KEY = "builtin:columns";
|
|
736
774
|
var isRecord4 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
737
|
-
var
|
|
775
|
+
var COLUMNS_STYLES = {
|
|
776
|
+
s: { row: "display:flex;flex-wrap:wrap;gap:0.75rem", col: "flex:1 1 14rem;min-width:0" },
|
|
777
|
+
m: { row: "display:flex;flex-wrap:wrap;gap:1.25rem", col: "flex:1 1 14rem;min-width:0" },
|
|
778
|
+
l: { row: "display:flex;flex-wrap:wrap;gap:2rem", col: "flex:1 1 14rem;min-width:0" }
|
|
779
|
+
};
|
|
780
|
+
var legacyContent = (text, key) => text.split(/\n{2,}/).filter((p) => p.trim() !== "").map((p, i) => ({ _type: "block", _key: `${key}p${i}`, style: "normal", markDefs: [], children: [{ _type: "span", _key: `${key}s${i}`, text: p, marks: [] }] }));
|
|
781
|
+
function columnsView(node) {
|
|
782
|
+
if (!isRecord4(node)) return null;
|
|
783
|
+
if (node._type === PT_TYPES.columns) {
|
|
784
|
+
const gap = node.gap === "s" || node.gap === "l" ? node.gap : "m";
|
|
785
|
+
const columns = (Array.isArray(node.columns) ? node.columns : []).map((c, i) => ({
|
|
786
|
+
key: isRecord4(c) && typeof c._key === "string" && c._key ? c._key : `c${i}`,
|
|
787
|
+
content: isRecord4(c) && Array.isArray(c.content) ? c.content : []
|
|
788
|
+
}));
|
|
789
|
+
return { gap, columns };
|
|
790
|
+
}
|
|
791
|
+
if (node._type === PT_TYPES.block && node.schemaKey === BUILTIN_COLUMNS_KEY) {
|
|
792
|
+
const f = isRecord4(node.fields) ? node.fields : {};
|
|
793
|
+
if (!Array.isArray(f.columns) || !f.columns.every((c) => typeof c === "string")) return null;
|
|
794
|
+
const gap = f.gap === "small" ? "s" : f.gap === "large" ? "l" : "m";
|
|
795
|
+
const columns = (Array.isArray(f.columns) ? f.columns : []).slice(0, PT_COLUMNS_LIMITS.max).map((c, i) => ({
|
|
796
|
+
key: `c${i}`,
|
|
797
|
+
content: legacyContent(typeof c === "string" ? c : "", `c${i}`)
|
|
798
|
+
}));
|
|
799
|
+
return { gap, columns };
|
|
800
|
+
}
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// ../richtext/src/component-copy.ts
|
|
805
|
+
var isRecord5 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
806
|
+
var fieldsOf = (value) => isRecord5(value) && value.schemaKey === EMBEDDED_COMPONENT_KEY && isRecord5(value.fields) ? value.fields : null;
|
|
738
807
|
function detachedComponentCopy(value) {
|
|
739
808
|
const f = fieldsOf(value);
|
|
740
809
|
if (!f || f.detached !== true || !Array.isArray(f.blocks)) return null;
|
|
741
810
|
return {
|
|
742
|
-
id:
|
|
811
|
+
id: isRecord5(value) && typeof value._key === "string" ? value._key : "",
|
|
743
812
|
componentId: typeof f.componentId === "string" ? f.componentId : "",
|
|
744
|
-
props:
|
|
813
|
+
props: isRecord5(f.props) ? f.props : {},
|
|
745
814
|
blocks: f.blocks,
|
|
746
815
|
...typeof f.sourcePublishedAt === "string" ? { sourcePublishedAt: f.sourcePublishedAt } : {},
|
|
747
816
|
...typeof f.variant === "string" ? { variant: f.variant } : {}
|
|
@@ -754,7 +823,7 @@ function componentCopyLines(copy) {
|
|
|
754
823
|
const t = v.replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
755
824
|
return t || null;
|
|
756
825
|
}
|
|
757
|
-
if (
|
|
826
|
+
if (isRecord5(v)) return line(v.label ?? v.text ?? v.title);
|
|
758
827
|
return null;
|
|
759
828
|
};
|
|
760
829
|
return Object.values(copy.props).map(line).filter((s) => !!s);
|
|
@@ -785,6 +854,14 @@ function portableTextToPlainText(value) {
|
|
|
785
854
|
lines.push(...galleryView(node).images.map((x) => x.caption).filter(Boolean));
|
|
786
855
|
continue;
|
|
787
856
|
}
|
|
857
|
+
const cols = columnsView(node);
|
|
858
|
+
if (cols) {
|
|
859
|
+
for (const c of cols.columns) {
|
|
860
|
+
const text = portableTextToPlainText(c.content);
|
|
861
|
+
if (text) lines.push(text);
|
|
862
|
+
}
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
788
865
|
const table = migrateTable(node);
|
|
789
866
|
if (table) {
|
|
790
867
|
lines.push(...tableLines(table));
|
|
@@ -825,20 +902,30 @@ var pullQuoteLines = (v) => {
|
|
|
825
902
|
|
|
826
903
|
// ../richtext/src/toc.ts
|
|
827
904
|
import { slugify } from "@bettercms-ai/types";
|
|
828
|
-
var
|
|
829
|
-
var
|
|
905
|
+
var isRecord6 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
906
|
+
var isHeadingAnchor = (v) => typeof v === "string" && /^[A-Za-z0-9][A-Za-z0-9_:.-]{0,127}$/.test(v);
|
|
907
|
+
var headingText = (node) => (Array.isArray(node.children) ? node.children : []).map((c) => isRecord6(c) && typeof c.text === "string" ? c.text : "").join("").replace(//g, "").trim();
|
|
830
908
|
function outlineOf(value) {
|
|
831
|
-
const
|
|
832
|
-
const nodes = /* @__PURE__ */ new WeakMap();
|
|
909
|
+
const heads = [];
|
|
833
910
|
const used = /* @__PURE__ */ new Set();
|
|
834
911
|
for (const node of Array.isArray(value) ? value : []) {
|
|
835
|
-
if (!
|
|
912
|
+
if (!isRecord6(node) || node._type !== "block" || node.listItem || node.style !== "h2" && node.style !== "h3") continue;
|
|
836
913
|
const text = headingText(node);
|
|
837
914
|
if (!text) continue;
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
915
|
+
const anchor = isHeadingAnchor(node.anchor) && !used.has(node.anchor) ? node.anchor : null;
|
|
916
|
+
if (anchor) used.add(anchor);
|
|
917
|
+
heads.push({ node, text, anchor });
|
|
918
|
+
}
|
|
919
|
+
const items = [];
|
|
920
|
+
const nodes = /* @__PURE__ */ new WeakMap();
|
|
921
|
+
for (const { node, text, anchor } of heads) {
|
|
922
|
+
let id = anchor;
|
|
923
|
+
if (!id) {
|
|
924
|
+
const base = slugify(text);
|
|
925
|
+
id = base;
|
|
926
|
+
for (let n = 2; used.has(id); n++) id = `${base}-${n}`;
|
|
927
|
+
used.add(id);
|
|
928
|
+
}
|
|
842
929
|
nodes.set(node, id);
|
|
843
930
|
items.push({ id, text, depth: node.style === "h2" ? 2 : 3 });
|
|
844
931
|
}
|
|
@@ -855,25 +942,79 @@ function tocTree(items, depth) {
|
|
|
855
942
|
return out;
|
|
856
943
|
}
|
|
857
944
|
function tocView(value) {
|
|
858
|
-
const v =
|
|
945
|
+
const v = isRecord6(value) ? value : {};
|
|
859
946
|
const title = typeof v.title === "string" ? v.title.trim() : "";
|
|
860
947
|
return { title, label: title || "Table of contents", depth: v.depth === "2" ? "2" : "3" };
|
|
861
948
|
}
|
|
862
949
|
|
|
950
|
+
// ../richtext/src/footnote.ts
|
|
951
|
+
var isRecord7 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
952
|
+
function footnoteOrder(value) {
|
|
953
|
+
const notes = [];
|
|
954
|
+
const nodes = /* @__PURE__ */ new WeakMap();
|
|
955
|
+
for (const node of Array.isArray(value) ? value : []) {
|
|
956
|
+
if (!isRecord7(node) || node._type !== "block" || !Array.isArray(node.children)) continue;
|
|
957
|
+
for (const child of node.children) {
|
|
958
|
+
if (!isRecord7(child) || child._type !== PT_TYPES.footnote) continue;
|
|
959
|
+
nodes.set(child, notes.push(typeof child.note === "string" ? child.note : ""));
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return { notes, nodes };
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// ../richtext/src/references.ts
|
|
966
|
+
var PT_RELATED_LIMITS = { titleChars: 40, minCount: 1, maxCount: 6, posts: 6 };
|
|
967
|
+
var isRecord8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
968
|
+
var refOf = (v) => isRecord8(v) && typeof v._ref === "string" ? v._ref : "";
|
|
969
|
+
var imageSrc = (raw) => safeHref(raw) ?? (raw !== "" && !raw.startsWith("//") && !/[:\s]/.test(raw) ? raw : null);
|
|
970
|
+
function relatedPostsView(value, resolved = {}) {
|
|
971
|
+
const v = isRecord8(value) ? value : {};
|
|
972
|
+
const title = typeof v.title === "string" ? v.title.trim() : "";
|
|
973
|
+
const mode = v.mode === "manual" || v.mode === "newest" ? v.mode : "topic";
|
|
974
|
+
const n = typeof v.count === "number" && Number.isInteger(v.count) ? v.count : 3;
|
|
975
|
+
const count = Math.min(PT_RELATED_LIMITS.maxCount, Math.max(PT_RELATED_LIMITS.minCount, n));
|
|
976
|
+
const picked = (Array.isArray(v.posts) ? v.posts : []).map(refOf).filter(Boolean);
|
|
977
|
+
const key = typeof v._key === "string" ? v._key : "";
|
|
978
|
+
const ids = mode === "manual" ? picked : (resolved.related?.[key] ?? []).slice(0, count);
|
|
979
|
+
const items = [];
|
|
980
|
+
for (const id of ids) {
|
|
981
|
+
const post = resolved.posts?.[id];
|
|
982
|
+
const url = post && typeof post.url === "string" ? safeHref(post.url) : null;
|
|
983
|
+
if (post && typeof post.title === "string" && url) items.push({ ...post, id, url });
|
|
984
|
+
}
|
|
985
|
+
return { key, title, mode, count, picked, items };
|
|
986
|
+
}
|
|
987
|
+
function authorBioView(value, resolved = {}) {
|
|
988
|
+
const key = isRecord8(value) && typeof value._key === "string" ? value._key : "";
|
|
989
|
+
const id = refOf(isRecord8(value) ? value.author : void 0);
|
|
990
|
+
const a = id ? resolved.authors?.[id] : void 0;
|
|
991
|
+
if (!a || typeof a.name !== "string") return { key, id, author: null };
|
|
992
|
+
const avatar = typeof a.avatar === "string" ? imageSrc(a.avatar.trim()) : null;
|
|
993
|
+
return {
|
|
994
|
+
key,
|
|
995
|
+
id,
|
|
996
|
+
author: {
|
|
997
|
+
name: a.name,
|
|
998
|
+
...avatar ? { avatar } : {},
|
|
999
|
+
...typeof a.bio === "string" && a.bio.trim() ? { bio: a.bio.trim() } : {}
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
|
|
863
1004
|
// ../richtext/src/read.ts
|
|
864
|
-
var
|
|
1005
|
+
var isRecord9 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
865
1006
|
function normalizePortableText(value, key = randomKey) {
|
|
866
1007
|
if (!Array.isArray(value)) return [];
|
|
867
1008
|
return value.flatMap((raw) => {
|
|
868
|
-
if (!
|
|
1009
|
+
if (!isRecord9(raw) || typeof raw._type !== "string") return [];
|
|
869
1010
|
const table = migrateTable(raw, key, (v, cellKey) => normalizePortableText(v, cellKey));
|
|
870
1011
|
if (table) return [table];
|
|
871
|
-
const node = { ...raw, _key:
|
|
1012
|
+
const node = { ...raw, _key: isRecord9(raw) && typeof raw._key === "string" && raw._key ? raw._key : key() };
|
|
872
1013
|
if (node._type === "block") {
|
|
873
1014
|
if (!Array.isArray(node.markDefs)) node.markDefs = [];
|
|
874
1015
|
if (typeof node.style !== "string") node.style = "normal";
|
|
875
1016
|
node.children = (Array.isArray(node.children) ? node.children : []).map((c) => {
|
|
876
|
-
if (!
|
|
1017
|
+
if (!isRecord9(c)) return c;
|
|
877
1018
|
const child = { ...c, _key: typeof c._key === "string" && c._key ? c._key : key() };
|
|
878
1019
|
if (child._type === "span" && !Array.isArray(child.marks)) child.marks = [];
|
|
879
1020
|
return child;
|
|
@@ -883,9 +1024,9 @@ function normalizePortableText(value, key = randomKey) {
|
|
|
883
1024
|
});
|
|
884
1025
|
}
|
|
885
1026
|
function readStructuredContent(props) {
|
|
886
|
-
if (!
|
|
1027
|
+
if (!isRecord9(props)) return null;
|
|
887
1028
|
const candidate = props.content ?? props.value;
|
|
888
|
-
const arr = Array.isArray(candidate) ? candidate :
|
|
1029
|
+
const arr = Array.isArray(candidate) ? candidate : isRecord9(candidate) ? Array.isArray(candidate.content) ? candidate.content : Array.isArray(candidate.value) ? candidate.value : null : null;
|
|
889
1030
|
return arr && arr.length > 0 ? arr : null;
|
|
890
1031
|
}
|
|
891
1032
|
|
|
@@ -1242,6 +1383,47 @@ function XCard({ url, card }) {
|
|
|
1242
1383
|
/* @__PURE__ */ jsx3("a", { href: url, children: card.date || "View on X" })
|
|
1243
1384
|
] });
|
|
1244
1385
|
}
|
|
1386
|
+
function RelatedPosts({ value, resolved }) {
|
|
1387
|
+
const { key, title, mode, count, picked, items } = relatedPostsView(value, resolved);
|
|
1388
|
+
if (!resolved) {
|
|
1389
|
+
return /* @__PURE__ */ jsx3("aside", { "data-rt": "related", "data-key": key, "data-mode": mode, "data-count": count, "data-posts": picked.join(","), "data-title": title || void 0 });
|
|
1390
|
+
}
|
|
1391
|
+
if (!items.length) return null;
|
|
1392
|
+
return /* @__PURE__ */ jsxs2("aside", { "data-rt": "related", "data-mode": mode, "data-count": count, "data-posts": picked.join(","), children: [
|
|
1393
|
+
title ? /* @__PURE__ */ jsx3("p", { "data-title": "", children: title }) : null,
|
|
1394
|
+
items.length ? /* @__PURE__ */ jsx3("ul", { children: items.map((p) => /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsx3("a", { href: p.url, children: p.title }) }, p.id)) }) : null
|
|
1395
|
+
] });
|
|
1396
|
+
}
|
|
1397
|
+
function AuthorBio({ value, resolved }) {
|
|
1398
|
+
const { key, id, author } = authorBioView(value, resolved);
|
|
1399
|
+
if (!resolved) return /* @__PURE__ */ jsx3("aside", { "data-rt": "author", "data-key": key, "data-author": id });
|
|
1400
|
+
if (!author) return null;
|
|
1401
|
+
return /* @__PURE__ */ jsxs2("aside", { "data-rt": "author", "data-author": id, children: [
|
|
1402
|
+
author?.avatar ? /* @__PURE__ */ jsx3("img", { src: author.avatar, alt: "" }) : null,
|
|
1403
|
+
author ? /* @__PURE__ */ jsx3("p", { "data-name": "", children: author.name }) : null,
|
|
1404
|
+
author?.bio ? /* @__PURE__ */ jsx3("p", { "data-bio": "", children: author.bio }) : null
|
|
1405
|
+
] });
|
|
1406
|
+
}
|
|
1407
|
+
function Columns({ value, components }) {
|
|
1408
|
+
const view = columnsView(value);
|
|
1409
|
+
if (!view) return null;
|
|
1410
|
+
const s = COLUMNS_STYLES[view.gap];
|
|
1411
|
+
return /* @__PURE__ */ jsx3("div", { "data-rt": "columns", "data-gap": view.gap, "data-cols": view.columns.length, style: styleObject(s.row), children: view.columns.map((c) => /* @__PURE__ */ jsx3("div", { "data-col": "true", style: styleObject(s.col), children: c.content.length ? /* @__PURE__ */ jsx3(PT, { value: c.content, components }) : null }, c.key)) });
|
|
1412
|
+
}
|
|
1413
|
+
function FootnoteMark({ value, footnotes }) {
|
|
1414
|
+
const note = typeof value.note === "string" ? value.note : "";
|
|
1415
|
+
const n = footnotes.nodes.get(value);
|
|
1416
|
+
if (!n) return /* @__PURE__ */ jsx3("sup", { "data-rt": "fn", "data-note": note });
|
|
1417
|
+
return /* @__PURE__ */ jsx3("sup", { "data-rt": "fn", id: `fnref-${n}`, "data-note": note, children: /* @__PURE__ */ jsx3("a", { href: `#fn-${n}`, "aria-label": `Footnote ${n}`, children: n }) });
|
|
1418
|
+
}
|
|
1419
|
+
function FootnoteList({ notes }) {
|
|
1420
|
+
if (!notes.length) return null;
|
|
1421
|
+
return /* @__PURE__ */ jsx3("ol", { className: "cs-footnotes", "data-rt": "footnotes", "aria-label": "Footnotes", children: notes.map((note, i) => /* @__PURE__ */ jsxs2("li", { id: `fn-${i + 1}`, children: [
|
|
1422
|
+
note,
|
|
1423
|
+
" ",
|
|
1424
|
+
/* @__PURE__ */ jsx3("a", { href: `#fnref-${i + 1}`, "aria-label": `Back to reference ${i + 1}`, children: "\u21A9" })
|
|
1425
|
+
] }, i)) });
|
|
1426
|
+
}
|
|
1245
1427
|
function Toc({ value, outline }) {
|
|
1246
1428
|
const { title, label, depth } = tocView(value);
|
|
1247
1429
|
const link = (o) => /* @__PURE__ */ jsx3("a", { href: `#${o.id}`, children: o.text });
|
|
@@ -1257,7 +1439,16 @@ function Gallery({ value }) {
|
|
|
1257
1439
|
const { layout, images } = galleryView(value);
|
|
1258
1440
|
const s = GALLERY_STYLES[layout];
|
|
1259
1441
|
return /* @__PURE__ */ jsx3("figure", { "data-rt": "gallery", "data-layout": layout, children: /* @__PURE__ */ jsx3("ul", { style: styleObject(s.ul), tabIndex: layout === "carousel" ? 0 : void 0, children: images.map((x) => /* @__PURE__ */ jsx3("li", { style: styleObject(s.li), children: /* @__PURE__ */ jsxs2("figure", { style: styleObject(s.figure), children: [
|
|
1260
|
-
/* @__PURE__ */ jsx3(
|
|
1442
|
+
/* @__PURE__ */ jsx3(
|
|
1443
|
+
"img",
|
|
1444
|
+
{
|
|
1445
|
+
alt: x.alt,
|
|
1446
|
+
style: styleObject(x.position ? `${s.img};object-position:${x.position}` : s.img),
|
|
1447
|
+
loading: "lazy",
|
|
1448
|
+
...Object.fromEntries(x.data),
|
|
1449
|
+
src: x.src
|
|
1450
|
+
}
|
|
1451
|
+
),
|
|
1261
1452
|
x.caption ? /* @__PURE__ */ jsx3("figcaption", { children: x.caption }) : null
|
|
1262
1453
|
] }) }, x.key)) }) });
|
|
1263
1454
|
}
|
|
@@ -1281,8 +1472,8 @@ function Embed({ value, embeds }) {
|
|
|
1281
1472
|
}
|
|
1282
1473
|
return /* @__PURE__ */ jsx3("figure", { "data-rt": "embed", "data-url": url, "data-provider": r.provider, "data-aspect": aspect, "aria-label": title, children: body });
|
|
1283
1474
|
}
|
|
1284
|
-
function buildComponents(renderBlock, embeds = {}, outline = { items: [], nodes: /* @__PURE__ */ new WeakMap() }) {
|
|
1285
|
-
|
|
1475
|
+
function buildComponents(renderBlock, embeds = {}, outline = { items: [], nodes: /* @__PURE__ */ new WeakMap() }, footnotes = { notes: [], nodes: /* @__PURE__ */ new WeakMap() }, resolved) {
|
|
1476
|
+
const components = {
|
|
1286
1477
|
// RT5: every top-level h2 and h3 carries its outline id, as html.ts writes it.
|
|
1287
1478
|
block: {
|
|
1288
1479
|
h2: ({ value, children }) => /* @__PURE__ */ jsx3("h2", { id: outline.nodes.get(value), children }),
|
|
@@ -1310,6 +1501,7 @@ function buildComponents(renderBlock, embeds = {}, outline = { items: [], nodes:
|
|
|
1310
1501
|
if (rendered !== void 0) return /* @__PURE__ */ jsx3(Fragment, { children: rendered });
|
|
1311
1502
|
const builtIn = calloutOrToggle(value);
|
|
1312
1503
|
if (builtIn) return builtIn;
|
|
1504
|
+
if (columnsView(value)) return /* @__PURE__ */ jsx3(Columns, { value, components });
|
|
1313
1505
|
const copy = detachedComponentCopy(value);
|
|
1314
1506
|
if (copy) {
|
|
1315
1507
|
return /* @__PURE__ */ jsx3("div", { className: "bcms-block bcms-block--component", "data-bcms-component-copy": copy.componentId, "data-bcms-instance": copy.id, children: /* @__PURE__ */ jsx3(BlocksRenderer, { blocks: copy.blocks }) });
|
|
@@ -1342,6 +1534,9 @@ function buildComponents(renderBlock, embeds = {}, outline = { items: [], nodes:
|
|
|
1342
1534
|
[PT_TYPES.embed]: ({ value }) => /* @__PURE__ */ jsx3(Embed, { value, embeds }),
|
|
1343
1535
|
[PT_TYPES.gallery]: ({ value }) => /* @__PURE__ */ jsx3(Gallery, { value }),
|
|
1344
1536
|
[PT_TYPES.tableOfContents]: ({ value }) => /* @__PURE__ */ jsx3(Toc, { value, outline }),
|
|
1537
|
+
[PT_TYPES.columns]: ({ value }) => /* @__PURE__ */ jsx3(Columns, { value, components }),
|
|
1538
|
+
[PT_TYPES.relatedPosts]: ({ value }) => /* @__PURE__ */ jsx3(RelatedPosts, { value, resolved }),
|
|
1539
|
+
[PT_TYPES.authorBio]: ({ value }) => /* @__PURE__ */ jsx3(AuthorBio, { value, resolved }),
|
|
1345
1540
|
/**
|
|
1346
1541
|
* Key takeaways — the React half of `portableTextToHtml`'s, and the same DOM: the V2 kit's
|
|
1347
1542
|
* `<aside data-rt="takeaways">`, read through the one `keyTakeawaysView` both renderers share.
|
|
@@ -1354,6 +1549,7 @@ function buildComponents(renderBlock, embeds = {}, outline = { items: [], nodes:
|
|
|
1354
1549
|
/* @__PURE__ */ jsx3("ul", { children: points.map((p, i) => /* @__PURE__ */ jsx3("li", { children: p }, i)) })
|
|
1355
1550
|
] });
|
|
1356
1551
|
},
|
|
1552
|
+
[PT_TYPES.footnote]: ({ value }) => /* @__PURE__ */ jsx3(FootnoteMark, { value, footnotes }),
|
|
1357
1553
|
[PT_TYPES.mention]: ({ value }) => {
|
|
1358
1554
|
const v = value;
|
|
1359
1555
|
return /* @__PURE__ */ jsx3("span", { className: "bcms-mention", children: typeof v.label === "string" ? v.label : "" });
|
|
@@ -1418,6 +1614,7 @@ function buildComponents(renderBlock, embeds = {}, outline = { items: [], nodes:
|
|
|
1418
1614
|
unknownType: ({ children }) => /* @__PURE__ */ jsx3(Fragment, { children: children ?? null }),
|
|
1419
1615
|
unknownBlockStyle: ({ children }) => /* @__PURE__ */ jsx3("p", { children })
|
|
1420
1616
|
};
|
|
1617
|
+
return components;
|
|
1421
1618
|
}
|
|
1422
1619
|
var isListItem = (node) => node._type === "block" && typeof node.listItem === "string" && !!node.listItem;
|
|
1423
1620
|
function runsOf(blocks) {
|
|
@@ -1458,10 +1655,14 @@ function calloutOrToggle(value) {
|
|
|
1458
1655
|
}
|
|
1459
1656
|
return null;
|
|
1460
1657
|
}
|
|
1461
|
-
function PortableText({ value, bindingBase, renderBlock, embeds }) {
|
|
1658
|
+
function PortableText({ value, bindingBase, renderBlock, embeds, resolved }) {
|
|
1462
1659
|
const blocks = React2.useMemo(() => normalizePortableText(readValue(value)), [value]);
|
|
1463
1660
|
const outline = React2.useMemo(() => outlineOf(blocks), [blocks]);
|
|
1464
|
-
const
|
|
1661
|
+
const footnotes = React2.useMemo(() => footnoteOrder(blocks), [blocks]);
|
|
1662
|
+
const components = React2.useMemo(
|
|
1663
|
+
() => buildComponents(renderBlock, embeds, outline, footnotes, resolved),
|
|
1664
|
+
[renderBlock, embeds, outline, footnotes, resolved]
|
|
1665
|
+
);
|
|
1465
1666
|
const listComponents = React2.useMemo(() => {
|
|
1466
1667
|
if (!bindingBase) return null;
|
|
1467
1668
|
const keys = new Set(blocks.map((b) => b._key));
|
|
@@ -1477,10 +1678,19 @@ function PortableText({ value, bindingBase, renderBlock, embeds }) {
|
|
|
1477
1678
|
};
|
|
1478
1679
|
}, [bindingBase, blocks, components]);
|
|
1479
1680
|
if (blocks.length === 0) return null;
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1681
|
+
const notes = /* @__PURE__ */ jsx3(FootnoteList, { notes: footnotes.notes });
|
|
1682
|
+
if (!bindingBase || !listComponents) {
|
|
1683
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1684
|
+
/* @__PURE__ */ jsx3(PT, { value: blocks, components }),
|
|
1685
|
+
notes
|
|
1686
|
+
] });
|
|
1687
|
+
}
|
|
1688
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1689
|
+
runsOf(blocks).map(
|
|
1690
|
+
(run) => isListItem(run[0]) ? /* @__PURE__ */ jsx3(PT, { value: run, components: listComponents }, run[0]._key) : /* @__PURE__ */ jsx3(Bound, { base: bindingBase, nodeKey: run[0]._key, children: /* @__PURE__ */ jsx3(PT, { value: run, components }) }, run[0]._key)
|
|
1691
|
+
),
|
|
1692
|
+
notes
|
|
1693
|
+
] });
|
|
1484
1694
|
}
|
|
1485
1695
|
function readValue(value) {
|
|
1486
1696
|
if (Array.isArray(value)) return value;
|
|
@@ -1654,7 +1864,7 @@ function Spacer({ height = 32, className = "" }) {
|
|
|
1654
1864
|
// src/blocks/Columns.tsx
|
|
1655
1865
|
import "react";
|
|
1656
1866
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1657
|
-
function
|
|
1867
|
+
function Columns2({
|
|
1658
1868
|
columns,
|
|
1659
1869
|
gap = 16,
|
|
1660
1870
|
className = "",
|
|
@@ -1908,7 +2118,7 @@ var BLOCK_REGISTRY = {
|
|
|
1908
2118
|
icon: "minus"
|
|
1909
2119
|
},
|
|
1910
2120
|
columns: {
|
|
1911
|
-
component:
|
|
2121
|
+
component: Columns2,
|
|
1912
2122
|
label: "Columns",
|
|
1913
2123
|
icon: "columns"
|
|
1914
2124
|
},
|