Skip to content

Commit

Permalink
fix: handle line breaks (#42)
Browse files Browse the repository at this point in the history
* fix: transform cr/lf characters into <br />

* style: rename function

* style: change index check to > 0

* test: add line break unit test

* fix: disable no-node-access rule

---------

Co-authored-by: Rémi de Juvigny <[email protected]>
  • Loading branch information
r-o-b-o-t-o and remidej authored Jan 30, 2025
1 parent 0a4de24 commit 8df8041
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 10 deletions.
16 changes: 15 additions & 1 deletion src/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ type Modifier = Exclude<keyof TextInlineNode, 'type' | 'text'>;

type TextInlineProps = Omit<TextInlineNode, 'type'>;

const replaceLineBreaks = (text: string) => {
const split = text.split(/\r?\n|\r/g);
return (
<>
{split.map((part, idx) => (
<React.Fragment key={idx}>
{idx > 0 && <br />}
{part}
</React.Fragment>
))}
</>
);
};

const Text = ({ text, ...modifiers }: TextInlineProps) => {
// Get matching React component from the context
const { modifiers: modifierComponents, missingModifierTypes } = useComponentsContext();
Expand Down Expand Up @@ -48,7 +62,7 @@ const Text = ({ text, ...modifiers }: TextInlineProps) => {
return <ModifierComponent>{children}</ModifierComponent>;
},
// By default, return the text without any wrapper to avoid useless nesting
<>{text}</>
replaceLineBreaks(text)
);
};

Expand Down
28 changes: 19 additions & 9 deletions tests/BlocksRenderer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable testing-library/no-node-access */

import * as React from 'react';

import { render, screen } from '@testing-library/react';
Expand Down Expand Up @@ -61,7 +63,6 @@ describe('BlocksRenderer', () => {
expect(boldTag[1]).toHaveTextContent(/and bold underlines/i);

// Should still fallback to default components
// eslint-disable-next-line testing-library/no-node-access
const underlineTag = document.querySelector('u');
expect(underlineTag).toHaveTextContent(/and bold underlines/i);
});
Expand All @@ -83,7 +84,6 @@ describe('BlocksRenderer', () => {
/>
);

// eslint-disable-next-line testing-library/no-node-access
const paragraph = screen.getByText('A paragraph').closest('p');
expect(paragraph).toHaveTextContent('A paragraph with bold');
});
Expand All @@ -109,12 +109,28 @@ describe('BlocksRenderer', () => {
/>
);

// eslint-disable-next-line testing-library/no-node-access
const brElement = screen.getByText('First paragraph').nextElementSibling;
expect(brElement).toBeInTheDocument();
expect(brElement?.tagName).toBe('BR');
});

it('renders paragraphs with line breaks', () => {
render(
<BlocksRenderer
content={[
{
type: 'paragraph',
children: [{ type: 'text', text: 'First line\nSecond line' }],
},
]}
/>
);

const paragraph = screen.getByText(/First line/).closest('p');
const paragraphParts = paragraph?.innerHTML?.split('<br>');
expect(paragraphParts).toEqual(['First line', 'Second line']);
});

it('renders quotes', () => {
render(
<BlocksRenderer
Expand All @@ -129,7 +145,6 @@ describe('BlocksRenderer', () => {

const quote = screen.getByText('A quote');
expect(quote).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-node-access
expect(quote.closest('blockquote')).toBeInTheDocument();
});

Expand All @@ -142,9 +157,7 @@ describe('BlocksRenderer', () => {

const code = screen.getByText('my code');
expect(code).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-node-access
expect(code.closest('code')).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-node-access
expect(code.closest('pre')).toBeInTheDocument();
});

Expand Down Expand Up @@ -322,13 +335,11 @@ describe('BlocksRenderer', () => {
const text = screen.getByText('My text');
expect(text).toBeInTheDocument();

/* eslint-disable testing-library/no-node-access */
expect(text.closest('strong')).toBeInTheDocument();
expect(text.closest('em')).toBeInTheDocument();
expect(text.closest('u')).toBeInTheDocument();
expect(text.closest('del')).toBeInTheDocument();
expect(text.closest('code')).toBeInTheDocument();
/* eslint-enable testing-library/no-node-access */
});

it('ignores disabled or unknown modifiers', () => {
Expand Down Expand Up @@ -357,7 +368,6 @@ describe('BlocksRenderer', () => {
const text = screen.getByText('My text');
expect(text).toBeInTheDocument();

// eslint-disable-next-line testing-library/no-node-access
expect(text.closest('strong')).not.toBeInTheDocument();

console.warn = originalWarn;
Expand Down

0 comments on commit 8df8041

Please sign in to comment.