Skip to content

Commit 8df8041

Browse files
r-o-b-o-t-oremidej
andauthored
fix: handle line breaks (#42)
* 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]>
1 parent 0a4de24 commit 8df8041

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

Diff for: src/Text.tsx

+15-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ type Modifier = Exclude<keyof TextInlineNode, 'type' | 'text'>;
1616

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

19+
const replaceLineBreaks = (text: string) => {
20+
const split = text.split(/\r?\n|\r/g);
21+
return (
22+
<>
23+
{split.map((part, idx) => (
24+
<React.Fragment key={idx}>
25+
{idx > 0 && <br />}
26+
{part}
27+
</React.Fragment>
28+
))}
29+
</>
30+
);
31+
};
32+
1933
const Text = ({ text, ...modifiers }: TextInlineProps) => {
2034
// Get matching React component from the context
2135
const { modifiers: modifierComponents, missingModifierTypes } = useComponentsContext();
@@ -48,7 +62,7 @@ const Text = ({ text, ...modifiers }: TextInlineProps) => {
4862
return <ModifierComponent>{children}</ModifierComponent>;
4963
},
5064
// By default, return the text without any wrapper to avoid useless nesting
51-
<>{text}</>
65+
replaceLineBreaks(text)
5266
);
5367
};
5468

Diff for: tests/BlocksRenderer.test.tsx

+19-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* eslint-disable testing-library/no-node-access */
2+
13
import * as React from 'react';
24

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

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

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

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

117+
it('renders paragraphs with line breaks', () => {
118+
render(
119+
<BlocksRenderer
120+
content={[
121+
{
122+
type: 'paragraph',
123+
children: [{ type: 'text', text: 'First line\nSecond line' }],
124+
},
125+
]}
126+
/>
127+
);
128+
129+
const paragraph = screen.getByText(/First line/).closest('p');
130+
const paragraphParts = paragraph?.innerHTML?.split('<br>');
131+
expect(paragraphParts).toEqual(['First line', 'Second line']);
132+
});
133+
118134
it('renders quotes', () => {
119135
render(
120136
<BlocksRenderer
@@ -129,7 +145,6 @@ describe('BlocksRenderer', () => {
129145

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

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

143158
const code = screen.getByText('my code');
144159
expect(code).toBeInTheDocument();
145-
// eslint-disable-next-line testing-library/no-node-access
146160
expect(code.closest('code')).toBeInTheDocument();
147-
// eslint-disable-next-line testing-library/no-node-access
148161
expect(code.closest('pre')).toBeInTheDocument();
149162
});
150163

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

325-
/* eslint-disable testing-library/no-node-access */
326338
expect(text.closest('strong')).toBeInTheDocument();
327339
expect(text.closest('em')).toBeInTheDocument();
328340
expect(text.closest('u')).toBeInTheDocument();
329341
expect(text.closest('del')).toBeInTheDocument();
330342
expect(text.closest('code')).toBeInTheDocument();
331-
/* eslint-enable testing-library/no-node-access */
332343
});
333344

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

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

363373
console.warn = originalWarn;

0 commit comments

Comments
 (0)