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:
@@ -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":
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { InlineRenderer } from "../../src/features/tech-log/presentation/shared/public-render/inline-renderer.tsx";
|
||||
|
||||
/**
|
||||
* 작성자가 엔터로 나눠 쓴 글이 한 줄로 이어져 보였다. Markdown 이 한 번의 줄바꿈을 문단 내 공백으로
|
||||
* 읽고, 파서가 그 줄바꿈을 텍스트에 남긴 뒤, HTML 이 다시 공백으로 접기 때문이다. 미리보기와 공개
|
||||
* 화면이 같은 렌더러를 쓰므로 두 곳 모두에서 그랬다.
|
||||
*/
|
||||
describe("문단 안의 줄바꿈", () => {
|
||||
it("줄바꿈을 <br> 로 그린다", () => {
|
||||
const { container } = render(
|
||||
<InlineRenderer content={[{ type: "TEXT", text: "첫째 줄\n둘째 줄" }]} />,
|
||||
);
|
||||
expect(container.querySelectorAll("br")).toHaveLength(1);
|
||||
expect(container.textContent).toBe("첫째 줄둘째 줄");
|
||||
});
|
||||
|
||||
it("줄바꿈이 없으면 <br> 를 넣지 않는다", () => {
|
||||
const { container } = render(
|
||||
<InlineRenderer content={[{ type: "TEXT", text: "한 줄" }]} />,
|
||||
);
|
||||
expect(container.querySelectorAll("br")).toHaveLength(0);
|
||||
expect(container.textContent).toBe("한 줄");
|
||||
});
|
||||
|
||||
it("여러 번 엔터를 친 만큼 내려간다", () => {
|
||||
const { container } = render(
|
||||
<InlineRenderer content={[{ type: "TEXT", text: "가\n나\n다" }]} />,
|
||||
);
|
||||
expect(container.querySelectorAll("br")).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user