From 397e321a88e1c35069c4697b8ebabfd10fe4f267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Fri, 4 Sep 2026 13:18:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9C=89=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=B6=88=E6=81=AF=E6=8E=92=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 区分有序与无序列表标记,避免有序项显示短横线 让列表项段落与文本保持同行 补充有序列表嵌套渲染回归测试 --- .../components/ChatMarkdownMessage/index.tsx | 55 ++++++++++++++----- .../tests/ChatMarkdownMessage.test.tsx | 15 +++++ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx b/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx index f3efd6236..39926feee 100644 --- a/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx +++ b/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx @@ -45,18 +45,22 @@ class MarkdownErrorBoundary extends Component< } const ListDepthContext = createContext(0); +const ListKindContext = createContext<'unordered' | 'ordered' | null>(null); +const ListItemContext = createContext(false); function MarkdownUnorderedList({ children }: { children?: ReactNode }) { const depth = useContext(ListDepthContext); return ( - + +
    0 ? 'pl-4' : 'pl-0' + }`} + > + {children} +
+
); } @@ -65,13 +69,38 @@ function MarkdownOrderedList({ children }: { children?: ReactNode }) { const depth = useContext(ListDepthContext); return ( -
    - {children} -
+ +
    + {children} +
+
); } +function MarkdownParagraph({ children }: { children?: ReactNode }) { + const inListItem = useContext(ListItemContext); + return ( +

+ {children} +

+ ); +} + +function MarkdownListItem({ children }: { children?: ReactNode }) { + const listKind = useContext(ListKindContext); + return ( + +
  • + {listKind === 'unordered' ? '- ' : null} + {children} +
  • +
    + ); +} + const markdownComponents: Components = { // TODO: 产品确认安全外链策略后,再将链接文本恢复为可点击元素。 a: ({ children }) => children, @@ -85,12 +114,10 @@ const markdownComponents: Components = { h3: ({ children }) => (

    {children}

    ), - p: ({ children }) => ( -

    {children}

    - ), + p: MarkdownParagraph, ul: MarkdownUnorderedList, ol: MarkdownOrderedList, - li: ({ children }) =>
  • - {children}
  • , + li: MarkdownListItem, blockquote: ({ children }) => (
    {children} diff --git a/apps/ai-game-creator-shell/tests/ChatMarkdownMessage.test.tsx b/apps/ai-game-creator-shell/tests/ChatMarkdownMessage.test.tsx index f3778c4ab..43f4a9bde 100644 --- a/apps/ai-game-creator-shell/tests/ChatMarkdownMessage.test.tsx +++ b/apps/ai-game-creator-shell/tests/ChatMarkdownMessage.test.tsx @@ -38,6 +38,21 @@ describe('ChatMarkdownMessage', () => { expect(lists[2]?.className).toContain('pl-4'); }); + it('有序列表不添加无序列表短横线,列表项段落与文本同行', () => { + const { container } = render( + , + ); + + const items = container.querySelectorAll('ol > li'); + expect(items[0]?.textContent?.trim()).toBe('第一件事'); + expect(items[1]?.textContent?.trim()).toContain('第二件事'); + expect(items[0]?.querySelector('p')?.className ?? '').toContain('inline'); + expect(items[0]?.textContent).not.toContain('-'); + }); + it('不会把 react-markdown 的 node 元数据泄漏到代码节点', () => { const { container } = render(