11import { Tag } from "@markdoc/markdoc" ;
2- import type { RenderableTreeNode } from "@markdoc/markdoc" ;
2+ import type { RenderableTreeNode , Schema } from "@markdoc/markdoc" ;
33import slugify from "slugify" ;
44
55export interface Heading {
@@ -28,11 +28,14 @@ const getTextContent = (children: RenderableTreeNode[]): string => {
2828 } , "" ) ;
2929} ;
3030
31- const getSlug = ( tag : Tag ) : string => {
32- if ( tag . attributes . id && typeof tag . attributes . id === "string" ) {
33- return tag . attributes . id ;
31+ const getSlug = (
32+ attributes : Record < string , any > , // eslint-disable-line @typescript-eslint/no-explicit-any
33+ children : RenderableTreeNode [ ] ,
34+ ) : string => {
35+ if ( attributes . id && typeof attributes . id === "string" ) {
36+ return attributes . id ;
3437 }
35- return slugify ( getTextContent ( tag . children ) , {
38+ return slugify ( getTextContent ( children ) , {
3639 lower : true ,
3740 strict : true ,
3841 } ) as string ;
@@ -61,7 +64,7 @@ export function collectHeadings(
6164 sections . push ( {
6265 level : parseInt ( tag . name [ 1 ] ) ,
6366 title : getTextContent ( tag . children ) ,
64- id : getSlug ( tag ) ,
67+ id : getSlug ( tag . attributes , tag . children ) ,
6568 } ) ;
6669 }
6770
@@ -75,3 +78,36 @@ export function collectHeadings(
7578
7679 return sections ;
7780}
81+
82+ export const heading : Schema = {
83+ children : [ "inline" ] ,
84+ attributes : {
85+ id : { type : String } ,
86+ level : { type : Number , required : true , default : 1 } ,
87+ } ,
88+ transform ( node , config ) {
89+ const { level, ...attributes } = node . transformAttributes ( config ) ;
90+ const children = node . transformChildren ( config ) ;
91+
92+ const slug = getSlug ( node . attributes , children ) ;
93+
94+ const render = config . nodes ?. heading ?. render ?? `h${ level } ` ;
95+
96+ /**
97+ * When the tag has a component as its render option,
98+ * add an attribute to collect it as a header
99+ * and also the level as a prop, not an HTML attribute.
100+ */
101+ const tagProps =
102+ typeof render === "string"
103+ ? { ...attributes , id : slug }
104+ : {
105+ ...attributes ,
106+ id : slug ,
107+ __collectHeading : true ,
108+ level : level as number ,
109+ } ;
110+
111+ return new Tag ( render , tagProps , children ) ;
112+ } ,
113+ } ;
0 commit comments