Skip to content

Commit

Permalink
feat: parse code blocks children to plain text (#17)
Browse files Browse the repository at this point in the history
* feat: parse code blocks children to plain text

* use contat
  • Loading branch information
remidej authored Dec 14, 2023
1 parent f41d99f commit 6524cba
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 8 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ You can provide your own React components to the renderer, both for blocks and m

- **Blocks** are full-width elements, usually at the root of the content. The available options are:
- paragraph
- heading
- list
- heading (receives `level`)
- list (receives `format`)
- quote
- code
- image
- link
- code (receives `plainText`)
- image (receives `image`)
- link (receives `url`)
- **Modifiers** are inline elements, used to change the appearance of fragments of text within a block. The available options are:
- bold
- italic
Expand Down
35 changes: 34 additions & 1 deletion src/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,37 @@ interface BlockProps {

const voidTypes = ['image'];

/**
* Add props that are specific to a block type, and not present in that node type
*/
const augmentProps = (content: Node) => {
const { children: childrenNodes, type, ...props } = content;

if (type === 'code') {
// Builds a plain text string from an array of nodes, regardless of links or modifiers
const getPlainText = (children: typeof childrenNodes): string => {
return children.reduce((currentPlainText, node) => {
if (node.type === 'text') {
return currentPlainText.concat(node.text);
}

if (node.type === 'link') {
return currentPlainText.concat(getPlainText(node.children));
}

return currentPlainText;
}, '');
};

return {
...props,
plainText: getPlainText(content.children),
};
}

return props;
};

const Block = ({ content }: BlockProps) => {
const { children: childrenNodes, type, ...props } = content;

Expand All @@ -34,8 +65,10 @@ const Block = ({ content }: BlockProps) => {
return <BlockComponent {...props} />;
}

const augmentedProps = augmentProps(content);

return (
<BlockComponent {...props}>
<BlockComponent {...augmentedProps}>
{childrenNodes.map((childNode, index) => {
if (childNode.type === 'text') {
const { type: _type, ...childNodeProps } = childNode;
Expand Down
8 changes: 6 additions & 2 deletions src/BlocksRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ type RootNode =
type Node = RootNode | NonTextInlineNode;

// Util to convert a node to the props of the corresponding React component
type GetPropsFromNode<T> = Omit<T, 'type' | 'children'> & { children?: React.ReactNode };
type GetPropsFromNode<T> = Omit<T, 'type' | 'children'> & {
children?: React.ReactNode;
// For code blocks, add a plainText property that is created by this renderer
plainText?: T extends { type: 'code' } ? string : never;
};

// Map of all block types to their matching React component
type BlocksComponents = {
Expand Down Expand Up @@ -118,7 +122,7 @@ const defaultComponents: ComponentsContextValue = {
quote: (props) => <blockquote>{props.children}</blockquote>,
code: (props) => (
<pre>
<code>{props.children}</code>
<code>{props.plainText}</code>
</pre>
),
heading: ({ level, children }) => {
Expand Down
32 changes: 32 additions & 0 deletions tests/BlocksRenderer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,5 +386,37 @@ describe('BlocksRenderer', () => {

console.warn = originalWarn;
});

it('parses code blocks to plain text', () => {
render(
<BlocksRenderer
content={[
{
type: 'code',
children: [
{
type: 'text',
text: 'const a = 1;',
},
{
type: 'link',
url: 'https://test.com',
children: [{ type: 'text', text: 'const b = 2;', bold: true }],
},
],
},
]}
blocks={{
code: (props) => (
<pre>
<code>{props.plainText}</code>
</pre>
),
}}
/>
);

expect(screen.getByText('const a = 1;const b = 2;')).toBeInTheDocument();
});
});
});

0 comments on commit 6524cba

Please sign in to comment.