From b29c44d8958b2414b1feb1cb8477fc61dadf805e Mon Sep 17 00:00:00 2001 From: John Philip Date: Wed, 17 Aug 2022 21:19:11 -0400 Subject: [PATCH] Autogenerate ids for headings in markdown content Signed-off-by: John Philip --- .changeset/lazy-snakes-film.md | 5 ++++ .../MarkdownContent/MarkdownContent.test.tsx | 30 +++++++++++++++++++ .../MarkdownContent/MarkdownContent.tsx | 19 ++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 .changeset/lazy-snakes-film.md diff --git a/.changeset/lazy-snakes-film.md b/.changeset/lazy-snakes-film.md new file mode 100644 index 0000000000..a21d197c51 --- /dev/null +++ b/.changeset/lazy-snakes-film.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': minor +--- + +Adds code to autogenerate ids for headers parsed through the MarkdownContent component. diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx index 9c08b83c40..fa8cb35ca8 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx @@ -100,4 +100,34 @@ describe('', () => { 'https://example.com/blog/assets/6/header.png', ); }); + + it('render MarkdownContent component with headings given proper ids', async () => { + const rendered = await renderWithEffects( + wrapInTestApp( + , + ), + ); + + 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', + ); + }); }); diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx index 013e81817a..e2ee460a1f 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx @@ -73,6 +73,19 @@ type Props = { className?: string; }; +const flatten = (text, child) => { + return typeof child === 'string' + ? text + child + : React.Children.toArray(child.props.children).reduce(flatten, text); +}; + +const headingRenderer = ({ level, children }) => { + 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 +98,12 @@ const components: Options['components'] = { ); }, + h1: headingRenderer, + h2: headingRenderer, + h3: headingRenderer, + h4: headingRenderer, + h5: headingRenderer, + h6: headingRenderer, }; /**