Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions third_party/muya/src/assets/styles/exportStyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@
white-space: pre-wrap;
}

/* Render soft line breaks (Shift+Enter -> a bare `\n` inside a block) the way
the editor does (`.mu-content` is pre-wrap) instead of emitting a
non-standard `<br>`, so exported HTML stays CommonMark-conformant while still
showing the break (#3676).

`li:not(:has(> p))` targets only tight list items, whose soft break is a
bare `\n` directly inside the `<li>`. Loose items wrap their content in
`<p>` (handled by the `p` rule); giving them `li` pre-wrap would expose
marked's pretty-printing newline between `</p>` and `</li>` as a stray blank
line, so they are deliberately excluded. */
.markdown-body p,
.markdown-body li:not(:has(> p)) {
white-space: pre-wrap;
}

.markdown-body table {
display: table;
}
Expand Down
26 changes: 26 additions & 0 deletions third_party/muya/src/state/__tests__/softBreakExportHtml.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, expect, it } from 'vitest';
import { getHighlightHtml } from '../../utils/marked';

const OPTS = { math: false, superSubScript: false, footnote: false, frontMatter: false };

describe('#3676: soft line breaks survive export as conformant newlines', () => {
it('keeps a paragraph soft break as a newline, never a <br>', () => {
const html = getHighlightHtml('line one\nline two', OPTS);

expect(html).toContain('<p>line one\nline two</p>');
expect(html).not.toMatch(/<br\s*\/?>/);
});

it('keeps a soft break inside a tight list item, never a <br>', () => {
const html = getHighlightHtml('- line A\n line B', OPTS);

expect(html).toMatch(/<li>line A\nline B<\/li>/);
expect(html).not.toMatch(/<br\s*\/?>/);
});

it('leaves a real hard break as <br>', () => {
const html = getHighlightHtml('line one \nline two', OPTS);

expect(html).toMatch(/<br\s*\/?>/);
});
});
Loading