From fc34b760c098f35739a1e4f761d971fdf04c41c9 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli <36352093+GuySartorelli@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:41:43 +1300 Subject: [PATCH] ENH Render the new callout block style (#284) --- src/components/CalloutBlock.tsx | 12 ++++++------ src/theme/assets/scss/theme/_docs.scss | 4 ++++ src/utils/cleanCalloutTags.ts | 21 --------------------- src/utils/parseHTML.ts | 25 +++++++++++++++++++++---- 4 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 src/utils/cleanCalloutTags.ts diff --git a/src/components/CalloutBlock.tsx b/src/components/CalloutBlock.tsx index e9cb11f..d7d91e5 100644 --- a/src/components/CalloutBlock.tsx +++ b/src/components/CalloutBlock.tsx @@ -4,16 +4,17 @@ import { CalloutBlockProps } from '../types'; const getCalloutClass = (type: string): string => { switch (type) { - case 'hint': + case 'TIP': return 'success'; - case 'notice': + case 'IMPORTANT': + case 'WARNING': return 'warning'; - case 'alert': + case 'CAUTION': return 'danger'; - case 'note': + case 'NOTE': return 'info' default: - return type; + return 'info'; } }; @@ -23,7 +24,6 @@ const CalloutBlock: StatelessComponent = ({ type, content })
{content}
); - }; export default CalloutBlock; \ No newline at end of file diff --git a/src/theme/assets/scss/theme/_docs.scss b/src/theme/assets/scss/theme/_docs.scss index 1de9463..527ae30 100644 --- a/src/theme/assets/scss/theme/_docs.scss +++ b/src/theme/assets/scss/theme/_docs.scss @@ -283,6 +283,10 @@ .callout-title { font-size: 1rem; } + + .content p:last-of-type { + margin-bottom: 0; + } &.callout-block-info { border-color: $theme-info-color; diff --git a/src/utils/cleanCalloutTags.ts b/src/utils/cleanCalloutTags.ts deleted file mode 100644 index cf96503..0000000 --- a/src/utils/cleanCalloutTags.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Removes the paragraph tags from around callout blocks so they end up being valid HTML - * - * @param html - * @returns - */ -const cleanCalloutTags = (html: string): string => { - // Replace callout

tags with a tag so we can swap it out with the right react component - html = html.replace( - /

\s*\[(hint|warning|info|alert|notice|note)\](.*?)\[\/\1\]\s*<\/p>/gs, - (_, type, content) => `${content}` - ); - // Replace any

and

tags inside callout tags with
, since the above operation may have - // inadvertantly broken some

tags. - return html.replace( - /.*?<\/callout>/gs, - (callout) => callout.replace(/(

|<\/p>)/g, '
') - ); -}; - -export default cleanCalloutTags; \ No newline at end of file diff --git a/src/utils/parseHTML.ts b/src/utils/parseHTML.ts index 2ffddba..7b7d463 100644 --- a/src/utils/parseHTML.ts +++ b/src/utils/parseHTML.ts @@ -4,7 +4,6 @@ import cleanWhitespace from './cleanWhitespace'; import cleanApiTags from './cleanApiTags'; import rewriteLink from './rewriteLink'; import parseChildrenOf from './parseChildrenOf'; -import cleanCalloutTags from './cleanCalloutTags'; import { ReactElement } from 'react'; import rewriteTable from './rewriteTable'; import rewriteHeader from './rewriteHeader'; @@ -19,7 +18,6 @@ import parseCalloutTags from './parseCalloutTags'; const parseHTML = (html: string): ReactElement | ReactElement[] | string => { let cleanHTML = html; cleanHTML = cleanChildrenTags(cleanHTML); - cleanHTML = cleanCalloutTags(cleanHTML); cleanHTML = cleanWhitespace(cleanHTML); cleanHTML = cleanApiTags(cleanHTML); cleanHTML = cleanHeaders(cleanHTML); @@ -38,8 +36,27 @@ const parseHTML = (html: string): ReactElement | ReactElement[] | string => { if (name.match(/^h[0-9]$/)) { return rewriteHeader(domNode); } - if (name === 'callout') { - return parseCalloutTags(domNode.attribs.type, domToReact(domNode.children)); + if (name === 'blockquote') { + for (const child of children) { + // For some reason blockquotes start with an empty new line with this parser. + if (child.type === 'text' && child.data === "\n") { + continue; + } + // If the first relevant child isn't a paragraph or is empty, it's not a callout block. + if (child.type !== 'tag' || child.name !== 'p' || !child.children?.length || child.children[0].type !== 'text') { + break; + } + // Check if the first text node marks this as a callout block + const firstTextNode = child.children[0]; + const calloutTypeRegex = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\n/; + const matches = firstTextNode.data.match(calloutTypeRegex); + if (!matches) { + break; + } + // Remove the type marker and render the component + firstTextNode.data = firstTextNode.data.replace(calloutTypeRegex, ''); + return parseCalloutTags(matches[1], domToReact(children)); + } } } if (domNode.data && domNode.parent?.name !== 'code') {