Merge pull request #13212 from johnphilip283/markdown_ids

Autogenerate ids for headings in markdown content
This commit is contained in:
Tim Hansen
2022-08-18 13:54:02 -06:00
committed by GitHub
3 changed files with 57 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': minor
---
Adds code to generate ids for headers parsed through the MarkdownContent component.
@@ -100,4 +100,34 @@ describe('<MarkdownContent />', () => {
'https://example.com/blog/assets/6/header.png',
);
});
it('render MarkdownContent component with headings given proper ids', async () => {
const rendered = await renderWithEffects(
wrapInTestApp(
<MarkdownContent
content={
'# Lorem ipsum\n' +
'## bing bong\n' +
'### The FitnessGram Pacer Test is a multistage aerobic capacity test'
}
/>,
),
);
expect(rendered.getByText('Lorem ipsum').getAttribute('id')).toEqual(
'lorem-ipsum',
);
expect(rendered.getByText('bing bong').getAttribute('id')).toEqual(
'bing-bong',
);
expect(
rendered
.getByText(
'The FitnessGram Pacer Test is a multistage aerobic capacity test',
)
.getAttribute('id'),
).toEqual(
'the-fitnessgram-pacer-test-is-a-multistage-aerobic-capacity-test',
);
});
});
@@ -20,6 +20,7 @@ import gfm from 'remark-gfm';
import React from 'react';
import { BackstageTheme } from '@backstage/theme';
import { CodeSnippet } from '../CodeSnippet';
import { HeadingProps } from 'react-markdown/lib/ast-to-react';
export type MarkdownContentClassKey = 'markdown';
@@ -73,6 +74,21 @@ type Props = {
className?: string;
};
const flatten = (text: string, child: any): string => {
if (!child) return text;
return typeof child === 'string'
? text + child
: React.Children.toArray(child.props.children).reduce(flatten, text);
};
const headingRenderer = ({ level, children }: HeadingProps) => {
const childrenArray = React.Children.toArray(children);
const text = childrenArray.reduce(flatten, '');
const slug = text.toLocaleLowerCase('en-US').replace(/\W/g, '-');
return React.createElement(`h${level}`, { id: slug }, children);
};
const components: Options['components'] = {
code: ({ inline, className, children, ...props }) => {
const text = String(children).replace(/\n+$/, '');
@@ -85,6 +101,12 @@ const components: Options['components'] = {
</code>
);
},
h1: headingRenderer,
h2: headingRenderer,
h3: headingRenderer,
h4: headingRenderer,
h5: headingRenderer,
h6: headingRenderer,
};
/**