nx/nx-dev/ui-markdoc/src/lib/nodes/heading.schema.ts
Caleb Ukle 7699b33ea1
fix(nx-dev): allow linking to headers that are code wrapped (#26608)
before if a header that was using `code` in the title (i.e. launch
template) the header should so the link icon but would not link anywhere
because the rendered id tag would be an empty string

![empty id tag for
headers](https://github.com/nrwl/nx/assets/23272162/6ee2aa5f-7b1f-4a98-ad11-2e088dd5c36d)

after the id tag is correctly linked by checking the rendering children
contains a `code` tag and pulls the code children out.

added benefit includes the code headers being linked in the side nav
correct too

![side by side diff with
changes](https://github.com/nrwl/nx/assets/23272162/c4f7a166-44fa-4541-ae72-d095962bee5b)



Example showing working from preview:
https://nx-dev-git-docs-allow-linking-code-headers-nrwl.vercel.app/ci/reference/launch-templates#launchtemplatestemplatenameinitsteps
2024-06-20 13:00:26 -05:00

65 lines
1.6 KiB
TypeScript

import { RenderableTreeNode, Schema, Tag } from '@markdoc/markdoc';
export function generateID(
children: RenderableTreeNode[],
attributes: Record<string, any>
) {
if (attributes['id'] && typeof attributes['id'] === 'string') {
return attributes['id'];
}
const validChildrenNodes: RenderableTreeNode[] = [];
for (const child of children) {
if (!child) {
continue;
}
if (typeof child === 'string') {
validChildrenNodes.push(child);
} else if (
// allow rendering titles that are wrapped in `code` tags
typeof child === 'object' &&
'children' in child &&
child.name === 'code' &&
Array.isArray(child.children)
) {
const validNestedChild = child.children.filter(
(c) => typeof c === 'string'
);
validChildrenNodes.push(...validNestedChild);
}
}
return validChildrenNodes
.join(' ')
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.replace(/[^a-z0-9 ]/g, '')
.trim()
.replace(/\s+/g, '-');
}
export const heading: Schema = {
render: 'Heading',
children: ['inline'],
attributes: {
id: { type: 'String' },
level: { type: 'Number', required: true, default: 1 },
className: { type: 'String' },
},
transform(node, config) {
const attributes = node.transformAttributes(config);
const children = node.transformChildren(config);
const id = generateID(children, attributes);
return new Tag(
this.render,
// `h${node.attributes['level']}`,
{ ...attributes, id },
children
);
},
};