Skip to content

Commit 61238e4

Browse files
committed
🐛 Allow custom components for headings
1 parent 3768824 commit 61238e4

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed

src/headings.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,36 @@ export function collectHeadings(
5858
}
5959

6060
// Handle single node
61-
if (typeof node === "object" && node !== null && "name" in node) {
62-
const tag = node as Tag;
63-
if (tag.name.match(/^h\d$/)) {
61+
if (typeof node === "object" && node !== null) {
62+
// Handle headings passed as custom components
63+
if (
64+
node.attributes?.__collectHeading === true &&
65+
typeof node.attributes?.level === "number"
66+
) {
6467
sections.push({
65-
level: parseInt(tag.name[1]),
66-
title: getTextContent(tag.children),
67-
id: getSlug(tag.attributes, tag.children),
68+
level: node.attributes?.level,
69+
title: getTextContent(node.children),
70+
id: getSlug(node.attributes, node.children),
6871
});
6972
}
7073

71-
// Handle node children
72-
if (tag.children) {
73-
for (const child of tag.children) {
74-
collectHeadings(child, sections);
74+
if ("name" in node) {
75+
const tag = node as Tag;
76+
77+
// Handle basic headings
78+
if (tag.name.match(/^h\d$/)) {
79+
sections.push({
80+
level: parseInt(tag.name[1]),
81+
title: getTextContent(tag.children),
82+
id: getSlug(tag.attributes, tag.children),
83+
});
84+
}
85+
86+
// Handle node children
87+
if (tag.children) {
88+
for (const child of tag.children) {
89+
collectHeadings(child, sections);
90+
}
7591
}
7692
}
7793
}
@@ -94,6 +110,8 @@ export const heading: Schema = {
94110
const render = config.nodes?.heading?.render ?? `h${level}`;
95111

96112
/**
113+
* TODO: THis doesn't work because render is a string even for custom components
114+
*
97115
* When the tag has a component as its render option,
98116
* add an attribute to collect it as a header
99117
* and also the level as a prop, not an HTML attribute.

test/__snapshots__/heading.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ exports[`Headings > adds IDs and exports headings even when a custom heading is
55
export const slug = "test";
66
export const headings = [{"level":1,"title":"This is some basic Markdoc","id":"this-is-some-basic-markdoc"},{"level":1,"title":"More fancy stuff","id":"more-fancy-stuff"}];
77
</script>
8-
<article><h1 class="custom-heading" id="this-is-some-basic-markdoc">This is some basic Markdoc</h1><p>With a paragraph.</p><p>Some text <strong>in bold</strong> and <em>in italic</em>.</p><p>And a <a href="https://example.com">link</a>.</p><h1 class="custom-heading" id="more-fancy-stuff">More fancy stuff</h1><p>Some <code>&lt;p&gt;</code> inline code.</p><p>And a code block:</p><pre data-language="javascript"><code>&lcub;&lcub;% test %&rcub;&rcub;</code></pre><p>And even a table with a nested list:</p><table><thead><tr><th>Table header 1</th><th>Table header 2</th></tr></thead><tbody><tr><td><ul><li>Row 1 Cell 1 Item 1</li><li>Row 1 Cell 1 Item 2</li></ul></td><td>Row 1 Cell 2</td></tr><tr><td>Row 2 Cell 1</td><td>Row 2 cell 2</td></tr></tbody></table></article>"
8+
<article><h1 class="custom-heading" id="this-is-some-basic-markdoc">This is some basic Markdoc</h1><p>With a paragraph.</p><h1 class="custom-heading" id="more-fancy-stuff">More fancy stuff</h1><p>Content. Such great content.</p></article>"
99
`;
1010

1111
exports[`Headings > adds IDs and exports headings even when the custom heading is a custom component 1`] = `
@@ -15,5 +15,5 @@ exports[`Headings > adds IDs and exports headings even when the custom heading i
1515
<script>
1616
import HeadingComponent from '$lib/components/HeadingComponent.svelte';
1717
</script>
18-
<article><HeadingComponent id="this-is-some-basic-markdoc">This is some basic Markdoc</HeadingComponent><p>With a paragraph.</p><p>Some text <strong>in bold</strong> and <em>in italic</em>.</p><p>And a <a href="https://example.com">link</a>.</p><HeadingComponent id="more-fancy-stuff">More fancy stuff</HeadingComponent><p>Some <code>&lt;p&gt;</code> inline code.</p><p>And a code block:</p><pre data-language="javascript"><code>&lcub;&lcub;% test %&rcub;&rcub;</code></pre><p>And even a table with a nested list:</p><table><thead><tr><th>Table header 1</th><th>Table header 2</th></tr></thead><tbody><tr><td><ul><li>Row 1 Cell 1 Item 1</li><li>Row 1 Cell 1 Item 2</li></ul></td><td>Row 1 Cell 2</td></tr><tr><td>Row 2 Cell 1</td><td>Row 2 cell 2</td></tr></tbody></table></article>"
18+
<article><HeadingComponent id="this-is-some-basic-markdoc">This is some basic Markdoc</HeadingComponent><p>With a paragraph.</p><HeadingComponent id="more-fancy-stuff">More fancy stuff</HeadingComponent><p>Content. Such great content.</p></article>"
1919
`;

test/constants.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,16 @@ keywords:
188188
Content. Such great content.
189189
`;
190190

191+
export const markdocWithHeadings = `
192+
# This is some basic Markdoc
193+
194+
With a paragraph.
195+
196+
## More fancy stuff
197+
198+
Content. Such great content.
199+
`;
200+
191201
export const markdocWithTypography = `${basicMarkdoc}
192202
## Typographic replacements
193203

test/heading.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { describe, it, expect } from "vitest";
44
import type { Options } from "../src/types.ts";
55
import type { Processed } from "svelte/compiler";
66

7-
import { basicMarkdoc } from "./constants.ts";
7+
import { markdocWithHeadings } from "./constants.ts";
88
import basicHeadingNode from "./markdoc/heading-tests/basicHeading.ts";
99
import customComponentNode from "./markdoc/heading-tests/customComponentHeading.ts";
1010

@@ -14,7 +14,7 @@ describe("Headings", () => {
1414
headingIds: true,
1515
nodes: { heading: basicHeadingNode.heading },
1616
} as Options).markup!({
17-
content: basicMarkdoc,
17+
content: markdocWithHeadings,
1818
filename: "test.md",
1919
})) as Processed;
2020

@@ -26,7 +26,7 @@ describe("Headings", () => {
2626
headingIds: true,
2727
nodes: { heading: customComponentNode.heading },
2828
} as Options).markup!({
29-
content: basicMarkdoc,
29+
content: markdocWithHeadings,
3030
filename: "test.md",
3131
})) as Processed;
3232

0 commit comments

Comments
 (0)