diff --git a/components/bubble/Bubble.tsx b/components/bubble/Bubble.tsx index 3b07e3cce..4b46e5ad3 100644 --- a/components/bubble/Bubble.tsx +++ b/components/bubble/Bubble.tsx @@ -1,12 +1,13 @@ import classnames from 'classnames'; import React from 'react'; -import { Avatar } from 'antd'; +import { InfoCircleOutlined } from '@ant-design/icons'; +import { Avatar, Button, List, Modal, Popover } from 'antd'; import useXComponentConfig from '../_util/hooks/use-x-component-config'; import { useXProviderContext } from '../x-provider'; import useTypedEffect from './hooks/useTypedEffect'; import useTypingConfig from './hooks/useTypingConfig'; -import type { BubbleContentType, BubbleProps } from './interface'; +import type { BubbleContentType, BubbleProps, ChatReference } from './interface'; import Loading from './loading'; import useStyle from './style'; @@ -41,6 +42,7 @@ const Bubble: React.ForwardRefRenderFunction = (props, r header, footer, _key, + references, ...otherHtmlProps } = props; @@ -151,6 +153,80 @@ const Bubble: React.ForwardRefRenderFunction = (props, r ); + // =========================== References Overlay ============================ + const ReferencesOverlay: React.FC<{ refsData: ChatReference[] }> = ({ refsData }) => { + const [isModalVisible, setIsModalVisible] = React.useState(false); + if (!refsData || refsData.length === 0) return null; + + const count = refsData.length; + const button = ( + + ); + + return ( + <> + + +
+
+
+ +
+
+
+
+ +
+ What a beautiful day! +
+ +
+
+
+ +
+
+
+
+
+ + + + + +
+
+ Hi, good morning, I'm fine! +
+
+
+ +
+ Thank you! +
+
+
+`; + +exports[`renders components/bubble/demo/reference.tsx extend context correctly 2`] = ` +[ + "Warning: [antd: Modal] \`destroyOnClose\` is deprecated. Please use \`destroyOnHidden\` instead.", +] +`; + exports[`renders components/bubble/demo/semantic-list-custom.tsx extend context correctly 1`] = `
`; +exports[`renders components/bubble/demo/reference.tsx correctly 1`] = ` +
+
+
+ + + + + +
+
+ Good morning, how are you? +
+ +
+
+ +
+ What a beautiful day! +
+ +
+
+
+ + + + + +
+
+ Hi, good morning, I'm fine! +
+
+
+ +
+ Thank you! +
+
+
+`; + exports[`renders components/bubble/demo/semantic-list-custom.tsx correctly 1`] = `
( + + , style: fooAvatar }} + references={[ + { + title: 'Ant Design', + url: 'https://ant.design', + description: 'Ant Design official website', + }, + { + title: 'React', + url: 'https://react.dev', + description: 'React official documentation', + }, + { + title: 'GitHub', + url: 'https://github.com', + description: 'GitHub homepage', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + { + title: 'GitHub - Maifee Ul Asad', + url: 'https://github.com', + }, + ]} + /> + + , style: barAvatar }} + /> + + +); + +export default App; diff --git a/components/bubble/index.en-US.md b/components/bubble/index.en-US.md index e4e7ba2e7..13c3fdda6 100644 --- a/components/bubble/index.en-US.md +++ b/components/bubble/index.en-US.md @@ -31,6 +31,7 @@ Often used when chatting. Semantic custom list content Custom List Content Using GPT-Vis to render charts +Reference debug debug list onScroll @@ -58,6 +59,7 @@ Common props ref:[Common props](/docs/react/common-props) | loadingRender | Customize loading content | () => ReactNode | - | | | messageRender | Customize display content | (content?: ContentType) => ReactNode | - | | | onTypingComplete | Callback when typing effect is completed. If typing is not set, it will be triggered immediately when rendering. | () => void | - | | +| references | Array of source links (title, url, optional description); displays an info-icon trigger with popover/modal listing. | [ChatReference](#chat-reference) [] | - | | #### ContentType @@ -90,6 +92,20 @@ type CustomContentType = { +## Chat Reference + +Reference link data for `Bubble`. Pass an array of these via the `references` prop to enable an info-icon trigger with popover and then modal listing. + +```typescript +export interface ChatReference { + description?: string; + title: string; + url: string; +} +``` + +When provided, the `references` prop will render an info icon in the bubble. Clicking the icon will show a list of references, each with a title (as a clickable link), and an optional description. + ## Design Token diff --git a/components/bubble/index.zh-CN.md b/components/bubble/index.zh-CN.md index 636039d8a..47a41ba27 100644 --- a/components/bubble/index.zh-CN.md +++ b/components/bubble/index.zh-CN.md @@ -32,6 +32,7 @@ demo: 语义化自定义 自定义列表内容 使用 GPT-Vis 渲染图表 +参考 debug debug list 监听滚动 @@ -59,6 +60,7 @@ demo: | loadingRender | 自定义渲染加载态内容 | () => ReactNode | - | | | messageRender | 自定义渲染内容 | (content?: ContentType) => ReactNode | - | | | onTypingComplete | 打字效果完成时的回调,如果没有设置 typing 将在渲染时立刻触发 | () => void | - | | +| references | 引用源链接数组(包含标题、URL 和可选描述);渲染信息图标以触发悬浮提示,并通过模态框列表展示。 | [聊天引用](#聊天引用)[] | - | | #### ContentType @@ -91,6 +93,18 @@ type CustomContentType = { +## 聊天引用 + +`Bubble` 的引用链接数据。通过 `references` 属性传入该接口数组,可启用信息图标触发 Popover,并通过 Modal 列表展示引用。 + +```typescript +export interface ChatReference { + description?: string; + title: string; + url: string; +} +``` + ## 主题变量(Design Token) diff --git a/components/bubble/interface.ts b/components/bubble/interface.ts index 137f49e4e..d34c255db 100644 --- a/components/bubble/interface.ts +++ b/components/bubble/interface.ts @@ -16,6 +16,12 @@ export interface TypingOption { suffix?: React.ReactNode; } +export interface ChatReference { + description?: string; + title: string; + url: string; +} + type SemanticType = 'avatar' | 'content' | 'header' | 'footer'; export type BubbleContentType = React.ReactNode | AnyObject | string | number; @@ -40,6 +46,7 @@ export interface BubbleProps shape?: 'round' | 'corner'; _key?: number | string; onTypingComplete?: VoidFunction; + references?: ChatReference[]; header?: React.ReactNode | ((content: ContentType, info: SlotInfoType) => React.ReactNode); footer?: React.ReactNode | ((content: ContentType, info: SlotInfoType) => React.ReactNode); } diff --git a/tests/shared/__snapshots__/demoTest.tsx.snap b/tests/shared/__snapshots__/demoTest.tsx.snap new file mode 100644 index 000000000..e69de29bb