fix: keep the line breaks an author typed

Text written across several lines rendered as one run-on line. Markdown reads a
single newline as a space that joins a paragraph, the parser leaves that
newline inside the text node, and HTML then collapses it — so the break the
author pressed Enter for disappeared at the last step.

This was never a preview artifact: the Studio preview and the public page go
through the same renderer, so a published record ran its lines together too.

Newlines inside a paragraph now render as <br>. Paragraphs separated by a blank
line are already two paragraphs by the time they reach here, so this only
affects the breaks an author put inside one.
This commit is contained in:
DongHyeonka
2026-08-21 15:10:27 +09:00
parent 5cffe30200
commit d2c289c650
2 changed files with 62 additions and 1 deletions
@@ -8,10 +8,35 @@ function assertNever(value: never): never {
throw new Error(`Unsupported inline value: ${JSON.stringify(value)}`);
}
/**
* 문단 안의 줄바꿈을 그대로 보여준다.
*
* <p>Markdown 은 한 번의 줄바꿈을 문단을 잇는 공백으로 읽는다. 파서는 그 줄바꿈을 텍스트에
* 남겨 두는데, 여기서 그대로 내보내면 HTML 이 다시 공백으로 접는다 — 작성자가 엔터로 나눠 쓴
* 글이 한 줄로 이어져 보였다. 미리보기만의 현상이 아니었다: 공개 화면도 같은 렌더러를 쓴다.
*
* <p>빈 줄로 나눈 문단은 파서가 이미 문단 둘로 만들어 두므로 여기 오지 않는다. 이 함수가 보는
* 것은 한 문단 안의 줄바꿈뿐이고, 작성자가 의도한 것도 그것이다.
*/
function renderText(text: string, key: number) {
const lines = text.split("\n");
if (lines.length === 1) return <Fragment key={key}>{text}</Fragment>;
return (
<Fragment key={key}>
{lines.map((line, index) => (
<Fragment key={index}>
{index > 0 ? <br /> : null}
{line}
</Fragment>
))}
</Fragment>
);
}
function renderInline(inline: Inline, key: number) {
switch (inline.type) {
case "TEXT":
return <Fragment key={key}>{inline.text}</Fragment>;
return renderText(inline.text, key);
case "INLINE_CODE":
return <code key={key}>{inline.code}</code>;
case "EMPHASIS":