修复有序列表消息排版
区分有序与无序列表标记,避免有序项显示短横线 让列表项段落与文本保持同行 补充有序列表嵌套渲染回归测试
This commit is contained in:
@@ -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 (
|
||||
<ListDepthContext.Provider value={depth + 1}>
|
||||
<ul
|
||||
className={`m-0 mt-2 list-none space-y-1 first:mt-0 ${
|
||||
depth > 0 ? 'pl-4' : 'pl-0'
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
<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>
|
||||
</ListDepthContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -65,13 +69,38 @@ function MarkdownOrderedList({ children }: { children?: ReactNode }) {
|
||||
const depth = useContext(ListDepthContext);
|
||||
return (
|
||||
<ListDepthContext.Provider value={depth + 1}>
|
||||
<ol className="m-0 mt-2 list-decimal space-y-1 pl-5 first:mt-0">
|
||||
{children}
|
||||
</ol>
|
||||
<ListKindContext.Provider value="ordered">
|
||||
<ol className="m-0 mt-2 list-decimal space-y-1 pl-5 first:mt-0">
|
||||
{children}
|
||||
</ol>
|
||||
</ListKindContext.Provider>
|
||||
</ListDepthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function MarkdownParagraph({ children }: { children?: ReactNode }) {
|
||||
const inListItem = useContext(ListItemContext);
|
||||
return (
|
||||
<p
|
||||
className={`m-0 break-words ${inListItem ? 'inline' : 'mt-2 first:mt-0'}`}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
function MarkdownListItem({ children }: { children?: ReactNode }) {
|
||||
const listKind = useContext(ListKindContext);
|
||||
return (
|
||||
<ListItemContext.Provider value>
|
||||
<li className="break-words">
|
||||
{listKind === 'unordered' ? '- ' : null}
|
||||
{children}
|
||||
</li>
|
||||
</ListItemContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
const markdownComponents: Components = {
|
||||
// TODO: 产品确认安全外链策略后,再将链接文本恢复为可点击元素。
|
||||
a: ({ children }) => children,
|
||||
@@ -85,12 +114,10 @@ const markdownComponents: Components = {
|
||||
h3: ({ children }) => (
|
||||
<h3 className="m-0 mt-3 text-base font-semibold first:mt-0">{children}</h3>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<p className="m-0 mt-2 break-words first:mt-0">{children}</p>
|
||||
),
|
||||
p: MarkdownParagraph,
|
||||
ul: MarkdownUnorderedList,
|
||||
ol: MarkdownOrderedList,
|
||||
li: ({ children }) => <li className="break-words">- {children}</li>,
|
||||
li: MarkdownListItem,
|
||||
blockquote: ({ children }) => (
|
||||
<blockquote className="m-0 mt-2 border-l-2 border-(--platform-surface-border) pl-3 text-(--platform-text-soft) first:mt-0">
|
||||
{children}
|
||||
|
||||
@@ -38,6 +38,21 @@ describe('ChatMarkdownMessage', () => {
|
||||
expect(lists[2]?.className).toContain('pl-4');
|
||||
});
|
||||
|
||||
it('有序列表不添加无序列表短横线,列表项段落与文本同行', () => {
|
||||
const { container } = render(
|
||||
<ChatMarkdownMessage
|
||||
role="assistant"
|
||||
text={'1. 第一件事\n\n2. 第二件事\n\n 1. 子步骤 2.1'}
|
||||
/>,
|
||||
);
|
||||
|
||||
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(
|
||||
<ChatMarkdownMessage
|
||||
|
||||
Reference in New Issue
Block a user