修复对话 markdown 无序列表渲染

- ChatMarkdownMessage:无序列表改用真正的列表标记(list-disc + pl-4),不再手写 '- ' 文本前缀
- ChatMarkdownMessage:删除列表项里手写的短横线,换行后的第二行恢复悬挂缩进,同时恢复列表语义
- ChatMarkdownMessage:移除随之无用的 ListKindContext
- ChatMarkdownMessage.test.tsx:用例改为断言 list-disc/pl-4 与「列表项文本不含手写短横线」
- 实测:真实面板注入同 class 标记后 list-style-type=disc、li 为 list-item、换行行与首行文字左边缘对齐
This commit is contained in:
2026-09-15 15:29:53 +08:00
parent 99fd319607
commit a60c04b53d
2 changed files with 23 additions and 24 deletions
@@ -66,7 +66,6 @@ export class MarkdownErrorBoundary extends Component<
}
const ListDepthContext = createContext(0);
const ListKindContext = createContext<'unordered' | 'ordered' | null>(null);
type ListItemParagraphPosition = 'first' | 'continuation';
const ListItemContext = createContext<ListItemParagraphPosition | null>(null);
@@ -75,15 +74,11 @@ function MarkdownUnorderedList({ children }: { children?: ReactNode }) {
const depth = useContext(ListDepthContext);
return (
<ListDepthContext.Provider value={depth + 1}>
<ListKindContext.Provider value="unordered">
<ul
className={`m-0 mt-2 list-none space-y-1 first:mt-0 ${
depth > 0 ? 'pl-4' : 'pl-0'
}`}
>
{children}
</ul>
</ListKindContext.Provider>
{/* 用真正的列表标记(`list-disc`)而不是手写 `'- '` 文本:手写前缀既没有悬挂缩进
(换行后的第二行会顶回最左边),也不算列表语义(读屏读成普通文本)。 */}
<ul className="m-0 mt-2 list-disc space-y-1 pl-4 first:mt-0">
{children}
</ul>
</ListDepthContext.Provider>
);
}
@@ -98,14 +93,12 @@ function MarkdownOrderedList({
const depth = useContext(ListDepthContext);
return (
<ListDepthContext.Provider value={depth + 1}>
<ListKindContext.Provider value="ordered">
<ol
start={start}
className="m-0 mt-2 list-decimal space-y-1 pl-5 first:mt-0"
>
{children}
</ol>
</ListKindContext.Provider>
<ol
start={start}
className="m-0 mt-2 list-decimal space-y-1 pl-5 first:mt-0"
>
{children}
</ol>
</ListDepthContext.Provider>
);
}
@@ -145,7 +138,6 @@ function StreamingMarkdownParagraph({ children }: { children?: ReactNode }) {
}
function MarkdownListItem({ children }: { children?: ReactNode }) {
const listKind = useContext(ListKindContext);
let paragraphIndex = 0;
const childrenWithParagraphContext = Children.map(
children,
@@ -168,7 +160,6 @@ function MarkdownListItem({ children }: { children?: ReactNode }) {
);
return (
<li className="break-words whitespace-normal">
{listKind === 'unordered' ? '- ' : null}
{childrenWithParagraphContext}
</li>
);
@@ -31,7 +31,7 @@ describe('ChatMarkdownMessage', () => {
);
});
it('为嵌套无序列表保留逐层缩进', () => {
it('无序列表用真正的列表标记并逐层缩进,不再手写短横线', () => {
const { container } = render(
<ChatMarkdownMessage
role="assistant"
@@ -43,9 +43,17 @@ describe('ChatMarkdownMessage', () => {
const lists = container.querySelectorAll('ul');
expect(lists).toHaveLength(3);
expect(lists[0]?.className).toContain('pl-0');
expect(lists[1]?.className).toContain('pl-4');
expect(lists[2]?.className).toContain('pl-4');
// 真正的列表标记:靠 `list-disc` 画项目符号、`pl-4` 让换行后的第二行保持悬挂缩进。
for (const list of Array.from(lists)) {
expect(list.className).toContain('list-disc');
expect(list.className).toContain('pl-4');
expect(list.className).not.toContain('list-none');
}
// 列表项文本里不能再出现手写的 `- ` 前缀(那会让换行行顶回最左边,也不符合列表语义)。
for (const item of Array.from(container.querySelectorAll('ul > li'))) {
expect(item.textContent ?? '').not.toMatch(/^\s*-\s/);
}
expect(container.querySelector('ul > li')?.textContent).toBe('无序号 A');
});
it('为四到六级标题提供递进的字号与字重', () => {