@roottale/cms-renderer-next 0.2.0 → 0.3.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/CHANGELOG.md +82 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +228 -0
- package/dist/server.js +672 -0
- package/dist/server.js.map +1 -0
- package/package.json +18 -9
- package/src/FloatingCta.tsx +0 -75
- package/src/LeadForm.tsx +0 -215
- package/src/PostCard.tsx +0 -45
- package/src/TableOfContents.tsx +0 -42
- package/src/__tests__/toc.test.ts +0 -118
- package/src/block-to-react.tsx +0 -199
- package/src/index.ts +0 -7
- package/src/server.tsx +0 -338
- package/src/toc.ts +0 -95
- /package/{src/styles → dist}/cms-public.css +0 -0
package/src/toc.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@roottale/cms-renderer/toc` — Tiptap doc → TOC entries + heading id injection.
|
|
3
|
-
*
|
|
4
|
-
* Server-only utility. Walks a Tiptap JSON doc, extracts H2/H3 headings, and
|
|
5
|
-
* derives stable kebab-case ids (Korean-safe). The companion `attachHeadingIds`
|
|
6
|
-
* mutates a shallow clone of the doc so renderers can emit `<h2 id="...">`
|
|
7
|
-
* anchors that match what `<RootTaleTableOfContents>` links to.
|
|
8
|
-
*
|
|
9
|
-
* Internal ancestor: `roottale-internal/packages/cms-renderer/src/toc.ts`
|
|
10
|
-
* (HTML-string based, vendored snapshot). Ported to Tiptap-JSON because the
|
|
11
|
-
* platform renderer no longer round-trips through HTML before render.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export interface TocEntry {
|
|
15
|
-
level: 2 | 3;
|
|
16
|
-
text: string;
|
|
17
|
-
id: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type TiptapNode = {
|
|
21
|
-
type?: string;
|
|
22
|
-
text?: string;
|
|
23
|
-
attrs?: Record<string, unknown>;
|
|
24
|
-
content?: TiptapNode[];
|
|
25
|
-
marks?: { type?: string }[];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
type TiptapDoc = { type?: string; content?: TiptapNode[] };
|
|
29
|
-
|
|
30
|
-
export function headingToId(text: string): string {
|
|
31
|
-
return text
|
|
32
|
-
.trim()
|
|
33
|
-
.toLowerCase()
|
|
34
|
-
.replace(/[^\p{L}\p{N}\s-]/gu, "")
|
|
35
|
-
.replace(/\s+/g, "-")
|
|
36
|
-
.replace(/-+/g, "-")
|
|
37
|
-
.replace(/^-|-$/g, "");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function textOf(node: TiptapNode): string {
|
|
41
|
-
if (typeof node.text === "string") return node.text;
|
|
42
|
-
if (!Array.isArray(node.content)) return "";
|
|
43
|
-
return node.content.map(textOf).join("");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function extractToc(doc: Record<string, unknown>): TocEntry[] {
|
|
47
|
-
const root = doc as TiptapDoc;
|
|
48
|
-
const content = Array.isArray(root.content) ? root.content : [];
|
|
49
|
-
const entries: TocEntry[] = [];
|
|
50
|
-
const idCounts = new Map<string, number>();
|
|
51
|
-
|
|
52
|
-
for (const node of content) {
|
|
53
|
-
if (node?.type !== "heading") continue;
|
|
54
|
-
const rawLevel = Number(node.attrs?.level ?? 2);
|
|
55
|
-
if (rawLevel !== 2 && rawLevel !== 3) continue;
|
|
56
|
-
const text = textOf(node).trim();
|
|
57
|
-
if (!text) continue;
|
|
58
|
-
|
|
59
|
-
const base = headingToId(text) || "heading";
|
|
60
|
-
const count = idCounts.get(base) ?? 0;
|
|
61
|
-
const id = count === 0 ? base : `${base}-${count}`;
|
|
62
|
-
idCounts.set(base, count + 1);
|
|
63
|
-
|
|
64
|
-
entries.push({ level: rawLevel, text, id });
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return entries;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Returns a shallow-cloned Tiptap doc where each H2/H3 carries the matching
|
|
72
|
-
* `attrs.id` from `entries` (same order as `extractToc` returns). Existing
|
|
73
|
-
* `id` attrs are overwritten so renderer + TOC always agree on anchors.
|
|
74
|
-
*/
|
|
75
|
-
export function attachHeadingIds(
|
|
76
|
-
doc: Record<string, unknown>,
|
|
77
|
-
entries: TocEntry[],
|
|
78
|
-
): Record<string, unknown> {
|
|
79
|
-
const root = doc as TiptapDoc;
|
|
80
|
-
const content = Array.isArray(root.content) ? root.content : [];
|
|
81
|
-
let cursor = 0;
|
|
82
|
-
const nextContent = content.map((node) => {
|
|
83
|
-
if (node?.type !== "heading") return node;
|
|
84
|
-
const rawLevel = Number(node.attrs?.level ?? 2);
|
|
85
|
-
if (rawLevel !== 2 && rawLevel !== 3) return node;
|
|
86
|
-
if (!textOf(node).trim()) return node;
|
|
87
|
-
const entry = entries[cursor++];
|
|
88
|
-
if (!entry) return node;
|
|
89
|
-
return {
|
|
90
|
-
...node,
|
|
91
|
-
attrs: { ...(node.attrs ?? {}), id: entry.id },
|
|
92
|
-
};
|
|
93
|
-
});
|
|
94
|
-
return { ...(root as Record<string, unknown>), content: nextContent };
|
|
95
|
-
}
|
|
File without changes
|