diff --git a/src/components/RichText/RichText.stories.tsx b/src/components/RichText/RichText.stories.tsx index 019af12..2ea2189 100644 --- a/src/components/RichText/RichText.stories.tsx +++ b/src/components/RichText/RichText.stories.tsx @@ -9,6 +9,7 @@ export default { title: 'components/RichText', component: RichText, argTypes: { + options: { control: { type: 'object' } }, headingProps: { control: { type: 'object' } }, textProps: { control: { type: 'object' } }, listProps: { control: { type: 'object' } }, diff --git a/src/components/RichText/RichText.test.tsx b/src/components/RichText/RichText.test.tsx index 9a06fa6..e0de3c1 100644 --- a/src/components/RichText/RichText.test.tsx +++ b/src/components/RichText/RichText.test.tsx @@ -120,4 +120,31 @@ function add(a, b) { expect(screen.getByText('(a, b) {')).toBeInTheDocument(); }); + + describe('provides an option interface that', () => { + it('forces multi line content as inline', () => { + setup({ options: { forceInline: true } }); + + expect(screen.getByTestId('rt-wrapper-span')).toBeInTheDocument(); + expect(screen.queryByTestId('rt-wrapper-div')).not.toBeInTheDocument(); + + expect(screen.getByRole('heading', { level: 2 }).parentElement).toBe( + screen.getByTestId('rt-wrapper-span') + ); + }); + + it('forces single line content as a block', () => { + setup({ + options: { forceBlock: true }, + content: '*Emphasised Text*', + }); + + expect(screen.getByTestId('rt-wrapper-div')).toBeInTheDocument(); + expect(screen.queryByTestId('rt-wrapper-span')).not.toBeInTheDocument(); + + expect(screen.getByText('Emphasised Text').parentElement).toBe( + screen.getByTestId('rt-wrapper-div') + ); + }); + }); }); diff --git a/src/components/RichText/RichText.tsx b/src/components/RichText/RichText.tsx index 0915c8e..9de335d 100644 --- a/src/components/RichText/RichText.tsx +++ b/src/components/RichText/RichText.tsx @@ -23,6 +23,10 @@ export interface RichTextProps { headingProps?: HeadingProps; textProps?: TextProps; listProps?: BoemlyListStyleProps; + options?: { + forceBlock?: boolean; + forceInline?: boolean; + }; } interface ComponentProps { @@ -55,94 +59,106 @@ const SHOULD_RENDER_AS_BLOCK_R = /(\n|^[-*]\s|^#|^ {2,}|^-{2,}|^>\s)/; export const RichText: React.FC = ({ content, + options = {}, headingProps = {}, textProps = {}, listProps = {}, -}: RichTextProps) => ( - - SHOULD_RENDER_AS_BLOCK_R.test(content) ? ( - - {children} - - ) : ( - - {children} - - ), - forceWrapper: true, - overrides: { - h1: ({ children }: ComponentProps) => ( - - {children} - - ), - h2: ({ children }: ComponentProps) => ( - - {children} - - ), - h3: ({ children }: ComponentProps) => ( - - {children} - - ), - h4: ({ children }: ComponentProps) => ( - - {children} - - ), - p: ({ children }: ComponentProps) => ( - - {children} - - ), - span: ({ children }: ComponentProps) => ( - - {children} - - ), - code: ({ className, children }: CodeComponentProps) => { - const language = className ? className.split('-')[1] : 'js'; - return ( - - - {children} - +}: RichTextProps) => { + let renderInline: boolean = false; + + // From https://github.com/probablyup/markdown-to-jsx/blob/7460ee6141fa2449c1b80425c62508af56347268/index.tsx#L1178C47-L1178C47 + if (options.forceInline) { + renderInline = true; + } else if (!options.forceBlock) { + renderInline = SHOULD_RENDER_AS_BLOCK_R.test(content) === false; + } + + return ( + + renderInline ? ( + + {children} + + ) : ( + + {children} - ); + ), + forceWrapper: true, + overrides: { + h1: ({ children }: ComponentProps) => ( + + {children} + + ), + h2: ({ children }: ComponentProps) => ( + + {children} + + ), + h3: ({ children }: ComponentProps) => ( + + {children} + + ), + h4: ({ children }: ComponentProps) => ( + + {children} + + ), + p: ({ children }: ComponentProps) => ( + + {children} + + ), + span: ({ children }: ComponentProps) => ( + + {children} + + ), + code: ({ className, children }: CodeComponentProps) => { + const language = className ? className.split('-')[1] : 'js'; + return ( + + + {children} + + + ); + }, + blockquote: ({ children }: ComponentProps) => ( + + {children} + + ), + ul: ({ children }: ListComponentProps) => ( + + ), + ol: ({ children }: ListComponentProps) => ( + + ), + a: ({ children, href }: LinkComponentProps) => ( + + {children} + + ), + img: ({ src, alt }: ImageComponentProps) => , }, - blockquote: ({ children }: ComponentProps) => ( - - {children} - - ), - ul: ({ children }: ListComponentProps) => ( - - ), - ol: ({ children }: ListComponentProps) => ( - - ), - a: ({ children, href }: LinkComponentProps) => ( - - {children} - - ), - img: ({ src, alt }: ImageComponentProps) => , - }, - }} - > - {content} - -); + }} + > + {content} + + ); +};