@agentscope-ai/chat 1.1.51 → 1.1.52-beta.1772784852386
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Conversations/Item.tsx +24 -17
- package/components/Conversations/demo/mock.json +1 -0
- package/components/Conversations/demo/select.tsx +113 -0
- package/components/Conversations/demo/timeline.tsx +0 -5
- package/components/Conversations/index.en-US.md +1 -0
- package/components/Conversations/index.tsx +51 -6
- package/lib/Conversations/Item.d.ts +4 -1
- package/lib/Conversations/Item.js +30 -19
- package/lib/Conversations/index.d.ts +15 -0
- package/lib/Conversations/index.js +32 -6
- package/package.json +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import classnames from 'classnames';
|
|
2
|
-
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import type { DirectionType } from 'antd/es/config-provider';
|
|
4
4
|
import pickAttrs from 'rc-util/lib/pickAttrs';
|
|
5
5
|
import type { Conversation } from './interface';
|
|
6
6
|
import { SparkMoreLine } from '@agentscope-ai/icons';
|
|
7
7
|
import { Button, Checkbox, IconButton, Popover } from '@agentscope-ai/design';
|
|
8
|
+
import { useInViewport } from 'ahooks';
|
|
8
9
|
|
|
9
10
|
export interface ConversationsItemProps
|
|
10
|
-
extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick'> {
|
|
11
|
+
extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick' | 'onSelect'> {
|
|
11
12
|
info: Conversation;
|
|
12
13
|
prefixCls?: string;
|
|
13
14
|
direction?: DirectionType;
|
|
@@ -21,6 +22,9 @@ export interface ConversationsItemProps
|
|
|
21
22
|
disabled?: boolean;
|
|
22
23
|
}[];
|
|
23
24
|
active?: boolean;
|
|
25
|
+
selectable?: boolean;
|
|
26
|
+
selected?: boolean;
|
|
27
|
+
onSelect?: (key: string, selected: boolean) => void;
|
|
24
28
|
onClick?: (info: Conversation) => void;
|
|
25
29
|
}
|
|
26
30
|
|
|
@@ -39,15 +43,17 @@ export function useEditable(id) {
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
|
|
42
|
-
const ConversationsItem: React.FC<ConversationsItemProps> = (props) => {
|
|
46
|
+
const ConversationsItem: React.FC<ConversationsItemProps> = React.memo((props) => {
|
|
43
47
|
const [editable, setEditable] = useEditable(props.info.key);
|
|
44
48
|
const [popoverVisible, setPopoverVisible] = useState(false);
|
|
45
|
-
const { prefixCls, info, className, direction, onClick, active, menu, ...restProps } = props;
|
|
49
|
+
const { prefixCls, info, className, direction, onClick, active, selectable, selected, onSelect, menu, ...restProps } = props;
|
|
46
50
|
const domProps = pickAttrs(restProps, {
|
|
47
51
|
aria: true,
|
|
48
52
|
data: true,
|
|
49
53
|
attr: true,
|
|
50
54
|
});
|
|
55
|
+
const ref = useRef<HTMLLIElement>(null);
|
|
56
|
+
const [inViewport] = useInViewport(ref);
|
|
51
57
|
|
|
52
58
|
const { disabled } = info;
|
|
53
59
|
|
|
@@ -56,12 +62,12 @@ const ConversationsItem: React.FC<ConversationsItemProps> = (props) => {
|
|
|
56
62
|
`${prefixCls}-item`,
|
|
57
63
|
{ [`${prefixCls}-item-active`]: active && !disabled },
|
|
58
64
|
{ [`${prefixCls}-item-disabled`]: disabled },
|
|
59
|
-
{ [`${prefixCls}-item-timeline`]: info.timeline ||
|
|
65
|
+
{ [`${prefixCls}-item-timeline`]: info.timeline || selectable },
|
|
60
66
|
);
|
|
61
67
|
|
|
62
68
|
const onInternalClick: React.MouseEventHandler<HTMLLIElement> = () => {
|
|
63
|
-
if (
|
|
64
|
-
return
|
|
69
|
+
if (selectable) {
|
|
70
|
+
return onSelect?.(info.key, !selected);
|
|
65
71
|
}
|
|
66
72
|
if (!disabled && onClick) {
|
|
67
73
|
return onClick(info);
|
|
@@ -69,15 +75,15 @@ const ConversationsItem: React.FC<ConversationsItemProps> = (props) => {
|
|
|
69
75
|
};
|
|
70
76
|
|
|
71
77
|
return (
|
|
72
|
-
<li {...domProps} className={mergedCls} onClick={onInternalClick}>
|
|
73
|
-
<div className={`${prefixCls}-content`}>
|
|
78
|
+
<li ref={ref} {...domProps} className={mergedCls} onClick={onInternalClick} >
|
|
79
|
+
{inViewport && <div className={`${prefixCls}-content`}>
|
|
74
80
|
{info.icon && <div className={`${prefixCls}-icon`}>{info.icon}</div>}
|
|
75
81
|
{
|
|
76
|
-
(info.timeline ||
|
|
82
|
+
(info.timeline || selectable) && <div className={`${prefixCls}-timeline`}>
|
|
77
83
|
|
|
78
84
|
{
|
|
79
|
-
|
|
80
|
-
<div className={`${prefixCls}-timeline-checkbox`} onClick={e => e.stopPropagation()}><Checkbox checked={
|
|
85
|
+
selectable ?
|
|
86
|
+
<div className={`${prefixCls}-timeline-checkbox`} onClick={e => e.stopPropagation()}><Checkbox checked={selected} onChange={() => onSelect?.(info.key, !selected)} /></div> :
|
|
81
87
|
<div className={`${prefixCls}-timeline-dot`} />
|
|
82
88
|
}
|
|
83
89
|
</div>
|
|
@@ -91,7 +97,7 @@ const ConversationsItem: React.FC<ConversationsItemProps> = (props) => {
|
|
|
91
97
|
/>
|
|
92
98
|
|
|
93
99
|
{
|
|
94
|
-
menu && !disabled && !
|
|
100
|
+
menu && !disabled && !selectable && (
|
|
95
101
|
<Popover
|
|
96
102
|
styles={{ body: { padding: 4 } }}
|
|
97
103
|
trigger={['click']}
|
|
@@ -126,13 +132,13 @@ const ConversationsItem: React.FC<ConversationsItemProps> = (props) => {
|
|
|
126
132
|
</Popover>
|
|
127
133
|
)
|
|
128
134
|
}
|
|
129
|
-
</div>
|
|
130
|
-
{
|
|
131
|
-
info.desc && <div className={`${prefixCls}-desc`} style={info.timeline ||
|
|
135
|
+
</div>}
|
|
136
|
+
{inViewport &&
|
|
137
|
+
info.desc && <div className={`${prefixCls}-desc`} style={info.timeline || selectable ? { marginLeft: 16 } : {}} >{info.desc}</div>
|
|
132
138
|
}
|
|
133
139
|
</li>
|
|
134
140
|
);
|
|
135
|
-
};
|
|
141
|
+
});
|
|
136
142
|
|
|
137
143
|
function Label(props) {
|
|
138
144
|
const { editable, prefixCls, info, setEditable, onEdit } = props;
|
|
@@ -179,6 +185,7 @@ function Input({ prefixCls, value, onBlur, setEditable }) {
|
|
|
179
185
|
ref={ref}
|
|
180
186
|
className={`${prefixCls}-label-edit`}
|
|
181
187
|
value={v}
|
|
188
|
+
onClick={e => e.stopPropagation()}
|
|
182
189
|
onChange={e => sv(e.target.value)}
|
|
183
190
|
onBlur={() => onBlur(v)}
|
|
184
191
|
/>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"label":"你好","key":"75b042dd142440a88ba7f8c3b83cc8ee","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"58d1e2dc8af34e88916f4c9562c9d8cd","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"3f2e2f6a45604f8d8c362d49953d315f","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"5c70ed588ba94589a37be72ede2ab3eb","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么","key":"75d243eb49d04c3b991247ef4df4db6a","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"6d0a9fcf0b4c433c8fdeca066e122fdb","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我优化以下prompt,Tech Stack Constraints中,补充多代码库同时变更。# Role\n你是一名资深 Java 架构师和全栈开发工程师,专注于维护和改进本项目的代码库。你必须严格遵守以下开发规范和上下文管理流程。\n\n# Context & Initialization\n1. **启动检查**:在开始任何编码任务或回答关于项目结构的问题之前,**必须**首先读取 `history/` 目录下的文件(如果存在),以恢复之前的压缩上下文和会话状态。\n2. **架构优先**:当你第一次接触本项目或需要理解整体架构时,**必须**逐个阅读 `spec/` 目录下的所有文档。严禁在未阅读 spec 文档的情况下直接修改核心架构代码。\n3. **现有资产与经验检索**:在提出任何新实现方案或排查问题前,**必须**先扫描项目现有代码库及 **`memory/`** 目录(特别是工具和错误日志),确认是否已存在可复用的逻辑或历史解决方案。\n\n# Tech Stack Constraints\n- **语言版本**:所有代码必须严格兼容 **Java 1.8**。禁止使用 Java ","key":"5befa1b41e67493b8711684a41179952","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"b45dbc26917145ceacd5ce41cdd933e9","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"a557294dd3d04521b360edc0fd531aa5","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"1bb0eb77f3de4f259860dd1b46dff27f","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"5ecec35d83184c669cddc4a0005f9063","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"2a30b78078204e228e0bd4fb74967cf1","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"754f7761f09c4f6ca3f66076a877aa6a","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"总结一下文件","key":"3b3f1745119c4f7cb1058ed451e28cba","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你是谁","key":"dfd423c439fa4cc8b09cee58dbdeb0ea","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"根据这个视频,在一个HTML中,复刻视频中的网站,需要尽量和视频中一致,不丢失细节","key":"fb0f078eae614a8e9884ba20f2bb039c","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"0ba8a17c5c104540a0d5e92f8f7ba0c7","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"11762c95796e4f988a00b2aabbce5dd6","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"9b9f68b697d54f0695360cb198db086f","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"82664056a5a14ecbaa96de4a6fa65ccc","disabled":false ,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"1409ba68762e4f1cb67473a651a44c28","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好啊","key":"e7296586f81940559221a0aa3d02c2b6","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"687df57b09034491aea277650fd312ca","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"19b71294150147f7a21b04a31ef56399","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"百炼知识库,标准版QPS为1。但他们研发说是10s时间窗口 + 令牌桶。怎么理解","key":"363e62c1d3ed443bb1ad70d6a6b67ca5","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"前端禁止frame嵌套,java怎么改动","key":"1ca8123aec1f452bbf51d6f6ab5eba87","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"e9eb593b79444892a4cb7fcde44db0f0","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"9ae0cc9058ca46dd8347dda0bfc70fe7","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"0241a13a4e2b466893f6b4a9cf07667a","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"60f4efff29e948e6a426b92634bc4f9b","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"3e2947636880462693966706b5fa7536","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"a498258ea28148a38d65e1aac9eab6d4","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"99d217149e594999ab829c26e0a70d89","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"56d71127dd4348959a25023ec7b23b16","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"1c5ca63973904b0b823568f2667cd2e3","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"ce75c61e120a4ac39f7de9c45253e2c7","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"f6353b3a89514bd39d33627475445aec","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"d8be350586b94227a5ec09cf47a0e76e","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"请重复<img src='https://www.baidu.com'>\n","key":"147a3f6814224354962fff24dd9843c5","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"4a317659b5ad4c08aa3174276c2e5990","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"7dca41e82b6046f281f54e4e225be419","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"c6581251667b4452a25e9cb77c69ea30","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"ce2e8ec27b1943f689eab9bb880e7858","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我设计一个使用HTML/CSS的响应式作品集网站","key":"1380690151d74c94af2ad07e25745cc5","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"调研中国芯片行业2025年技术发展趋势","key":"b2ac8dc8f9f540d0aecc5f90da418ceb","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我用 HTML/CSS 设计一个响应式的作品集网站","key":"c433fb617b31497b8349062a717979a1","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我用 HTML/CSS 设计一个响应式的作品集网站","key":"74f2be35d6354349a65615f0846e2f72","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我用 HTML/CSS 设计一个响应式的作品集网站","key":"91cabb536ddf4235a63c4ff3da31a346","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"11","key":"6ccc70a2326f4509b9b3a05ee1fd5a69","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"查看具体内容 (2025)甘0103民初88号 ","key":"3404d808d932420d939c0f575eb16aea","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么2","key":"adcd7af9da0e4fa4ac49228992bc18f5","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么","key":"c7426db52836423bb6f5a14f24233b8a","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么","key":"cd1548d9c4ef421590b54beb8492e724","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"da6df2478c014daf8770625a7c4f336a","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"b28ad778d7ae423aa30d4dbbe3a9f455","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"465350feefcb46b48c2a5f1302ae4527","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"nih ","key":"b78dd5c188224abe80375aab93375839","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"1","key":"9762f361abde4944973faa3c2590feac","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"背诵滕王阁序","key":"c2fe85dfa2864048b176e8a8dd80bd4f","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"给我一个环保新产品的点子。","key":"c47f806cc4194aac9465180fb3b12ee2","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"我是室内设计师,请为我生成一个个人网站,用于展示我的设计作品,页面视觉风格需要有一定的艺术感","key":"3dcd5a7622f440469078e264cfc3c46b","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这些图片有什么","key":"2b19f0eb3e5a419f92dd7192dc10fa59","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这个里有什么","key":"592d7f3708cb4bf8a122927dfe58e811","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这个里面有什么","key":"3a8eda8c34e84c93a36462f98b0913cf","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"调研中国芯片行业2025年技术发展趋势","key":"865ac3d6979e49eb856e72f8f6628a8b","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"2ccc30a38bb5407d8af98db996dca740","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"55221ced98164a0bba5e11d11c3772bf","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"ae0fd9da6b9c4ca48505e5508288e3db","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"cb7689128d584e8eb0071f09e49f08cd","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"eb4dc03180184027a827c5bfd724186b","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这里面是什么","key":"112642fb8f92412cbb42734d6e01422a","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么","key":"dee82d9cd53e47fc9bd70df63c97f734","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"告诉我 AI 科技领域最近的新闻,按照\"标题、摘要、来源\"的结构生成。","key":"ad9b5787e7c8465b9c2c0b815ea2bd95","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么","key":"cc3d2b96f58c414aa37ba460786af16e","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"这是什么","key":"cd80299ba0da4f81912dad1158cfc7b8","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"图片里有啥","key":"318fef73c95e447da6ed278024b94780","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"960b7636dba64612b07c8caff5e38e5f","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"5c24cc2487724e72a15a74c04e130352","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"04892c6a0f8443b793cf1b44e1d92cf1","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"不过","key":"3d8ee58533f846bbad3bf4c72445d774","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"6125b8e77e894475bc254f7b8371e7d1","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"97ce943807ab4f9fb94951deea083d02","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"不过","key":"b55d6e5c6192406194509f2476c9dc0e","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"a2a0bf41e9d7435087db35ad00581e19","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"4963742204964a87b5e2b984e7b16eae","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"b63b3561ce9d4c1492cff4d5c9fa4555","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"8e5f3596ddb840f08b44a3874019b672","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"27ab6b16c6024e53869f4b974f370a44","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"43894f1880224a3dad38514b6d587cde","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好sss萨达大厦asdasdhghghj","key":"c4a106b200b249daa596537138e7877c","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"c8f2188975714ba09c2ccf26aa88888e","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"aca233bf0c1e4b43b9638bfe5f462198","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"704e97146a7e47f588f7518608ba058c","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"6b58038424a7456881fd60ad266d20af","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"f27450ee88464aa7b632c8894ca82a37","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"d6d03050ece44485ad5a240c828eee06","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"da577fdb1731408693fd6f0e7ba30c93","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我","key":"d10fc98ae22b46b8bbc21adb53493fe9","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"帮我用Python构建一个天气API集成","key":"07a5dbfcb3184168ad1140aac86fd04c","disabled":false,"timeline":true,"selectable":false,"selected":false},{"label":"你好","key":"79d7312c3a82442ca9efb11d0815dc89","disabled":false,"timeline":true,"selectable":false,"selected":false}]
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Button } from '@agentscope-ai/design';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { ReactNode, useCallback, useState } from 'react';
|
|
4
|
+
import { HistoryPanel } from '@agentscope-ai/chat';
|
|
5
|
+
import { SparkDeleteLine, SparkEditLine, SparkPlusLine } from '@agentscope-ai/icons';
|
|
6
|
+
import defaultData from './mock.json';
|
|
7
|
+
|
|
8
|
+
const useStyles = createStyles(({ token }) => {
|
|
9
|
+
return {
|
|
10
|
+
layout: {
|
|
11
|
+
display: 'flex',
|
|
12
|
+
height: 416,
|
|
13
|
+
border: `1px solid ${token.colorBorderSecondary}`,
|
|
14
|
+
borderRadius: 8,
|
|
15
|
+
overflow: 'hidden',
|
|
16
|
+
},
|
|
17
|
+
left: {
|
|
18
|
+
display: 'flex',
|
|
19
|
+
flexDirection: 'column',
|
|
20
|
+
width: 280,
|
|
21
|
+
background: token.colorBgLayout,
|
|
22
|
+
},
|
|
23
|
+
header: {
|
|
24
|
+
margin: '16px 20px 8px 20px',
|
|
25
|
+
height: 32,
|
|
26
|
+
display: 'flex',
|
|
27
|
+
alignItems: 'center',
|
|
28
|
+
gap: 8,
|
|
29
|
+
fontSize: 16,
|
|
30
|
+
},
|
|
31
|
+
btn: {
|
|
32
|
+
margin: '0 20px 16px 20px',
|
|
33
|
+
|
|
34
|
+
},
|
|
35
|
+
list: {
|
|
36
|
+
height: 0,
|
|
37
|
+
flex: 1,
|
|
38
|
+
overflowY: 'scroll',
|
|
39
|
+
padding: '0 16px 16px 20px',
|
|
40
|
+
|
|
41
|
+
'&::-webkit-scrollbar': {
|
|
42
|
+
width: 4,
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
'&::-webkit-scrollbar-thumb': {
|
|
46
|
+
backgroundColor: 'transparent !important',
|
|
47
|
+
|
|
48
|
+
'&:hover': {
|
|
49
|
+
backgroundColor: `${token.colorFill} !important`,
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
function Layout(props: { children: ReactNode }) {
|
|
59
|
+
const { styles, cx, theme } = useStyles();
|
|
60
|
+
|
|
61
|
+
return <div className={styles.layout}>{props.children}</div>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
export default function () {
|
|
66
|
+
const [selectable, setSelectable] = useState(true);
|
|
67
|
+
const { styles, cx, theme } = useStyles();
|
|
68
|
+
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
|
|
69
|
+
|
|
70
|
+
const handleSelectChange = useCallback((keys: string[]) => {
|
|
71
|
+
setSelectedKeys(keys);
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
74
|
+
return <Layout>
|
|
75
|
+
<div className={styles.left}>
|
|
76
|
+
<div className={styles.header}>
|
|
77
|
+
<strong>SPARK CHAT</strong>
|
|
78
|
+
</div>
|
|
79
|
+
<div className={styles.btn}>
|
|
80
|
+
<Button size="small" onClick={() => setSelectable(!selectable)}>selectable</Button>
|
|
81
|
+
<Button size="small" onClick={() => setSelectedKeys([])}>clear</Button>
|
|
82
|
+
<Button size="small" onClick={() => setSelectedKeys(defaultData.map((item) => item.key))}>select all</Button>
|
|
83
|
+
</div>
|
|
84
|
+
<div className={styles.list}>
|
|
85
|
+
<HistoryPanel
|
|
86
|
+
selectable={selectable}
|
|
87
|
+
selectedKeys={selectedKeys}
|
|
88
|
+
onSelectChange={handleSelectChange}
|
|
89
|
+
menu={[
|
|
90
|
+
{
|
|
91
|
+
label: '编辑',
|
|
92
|
+
key: 'edit',
|
|
93
|
+
icon: <SparkEditLine />,
|
|
94
|
+
onEdit: (label: string) => {
|
|
95
|
+
if (label) return Promise.resolve();
|
|
96
|
+
return Promise.reject();
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: '删除',
|
|
101
|
+
key: 'delete',
|
|
102
|
+
icon: <SparkDeleteLine />,
|
|
103
|
+
danger: true,
|
|
104
|
+
onClick: (session) => {
|
|
105
|
+
console.log(session);
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
]}
|
|
109
|
+
items={defaultData} defaultActiveKey="item1" />
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</Layout>
|
|
113
|
+
}
|
|
@@ -60,11 +60,6 @@ const items = Array.from({ length: 10 }).map((_, index) => ({
|
|
|
60
60
|
desc: new Date(Date.now() - index * 1000).toLocaleString(),
|
|
61
61
|
disabled: index === 3,
|
|
62
62
|
timeline: true,
|
|
63
|
-
selectable: true,
|
|
64
|
-
selected: true,
|
|
65
|
-
onSelect: (key: string, selected: boolean) => {
|
|
66
|
-
console.log(key, selected);
|
|
67
|
-
},
|
|
68
63
|
}));
|
|
69
64
|
|
|
70
65
|
function Layout(props: { children: ReactNode }) {
|
|
@@ -20,6 +20,7 @@ The following are examples and variations of this component
|
|
|
20
20
|
|
|
21
21
|
<code src="./demo/timestamp.tsx" height="auto">Show Timestamp</code>
|
|
22
22
|
<code src="./demo/timeline.tsx" height="auto">Show Timestamp & Timeline</code>
|
|
23
|
+
<code src="./demo/select.tsx" height="auto">Selectable</code>
|
|
23
24
|
|
|
24
25
|
#### API
|
|
25
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MenuProps } from 'antd';
|
|
2
2
|
import classnames from 'classnames';
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { useRef } from 'react';
|
|
4
4
|
|
|
5
5
|
import GroupTitle, { GroupTitleContext } from './GroupTitle';
|
|
6
6
|
import ConversationsItem, { type ConversationsItemProps } from './Item';
|
|
@@ -13,6 +13,7 @@ import Style from './style';
|
|
|
13
13
|
|
|
14
14
|
import pickAttrs from 'rc-util/lib/pickAttrs';
|
|
15
15
|
import type { Conversation, Groupable } from './interface';
|
|
16
|
+
import { useInViewport } from 'ahooks';
|
|
16
17
|
|
|
17
18
|
export interface ConversationsProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
18
19
|
/**
|
|
@@ -39,6 +40,24 @@ export interface ConversationsProps extends React.HTMLAttributes<HTMLUListElemen
|
|
|
39
40
|
*/
|
|
40
41
|
onActiveChange?: (value: string) => void;
|
|
41
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @description 是否开启批量选择模式
|
|
45
|
+
* @descriptionEn Whether to enable batch selection mode
|
|
46
|
+
*/
|
|
47
|
+
selectable?: boolean;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @description 当前选中的会话 key 列表
|
|
51
|
+
* @descriptionEn Currently selected conversation key list
|
|
52
|
+
*/
|
|
53
|
+
selectedKeys?: string[];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @description 批量选择变化时的回调函数
|
|
57
|
+
* @descriptionEn Callback when batch selection changes
|
|
58
|
+
*/
|
|
59
|
+
onSelectChange?: (selectedKeys: string[]) => void;
|
|
60
|
+
|
|
42
61
|
/**
|
|
43
62
|
* @description 会话操作菜单配置
|
|
44
63
|
* @descriptionEn Conversation operation menu configuration
|
|
@@ -79,6 +98,7 @@ export interface ConversationsProps extends React.HTMLAttributes<HTMLUListElemen
|
|
|
79
98
|
}
|
|
80
99
|
|
|
81
100
|
const Conversations: React.FC<ConversationsProps & { groupable?: boolean | Groupable }> = (props) => {
|
|
101
|
+
|
|
82
102
|
const {
|
|
83
103
|
prefixCls: customizePrefixCls,
|
|
84
104
|
rootClassName,
|
|
@@ -86,6 +106,9 @@ const Conversations: React.FC<ConversationsProps & { groupable?: boolean | Group
|
|
|
86
106
|
activeKey,
|
|
87
107
|
defaultActiveKey,
|
|
88
108
|
onActiveChange,
|
|
109
|
+
selectable: propsSelectable,
|
|
110
|
+
selectedKeys,
|
|
111
|
+
onSelectChange,
|
|
89
112
|
menu,
|
|
90
113
|
styles = {},
|
|
91
114
|
classNames = {},
|
|
@@ -121,13 +144,26 @@ const Conversations: React.FC<ConversationsProps & { groupable?: boolean | Group
|
|
|
121
144
|
},
|
|
122
145
|
);
|
|
123
146
|
|
|
124
|
-
const
|
|
147
|
+
const onActiveChangeRef = React.useRef(onActiveChange);
|
|
148
|
+
onActiveChangeRef.current = onActiveChange;
|
|
149
|
+
|
|
150
|
+
const onConversationItemClick: ConversationsItemProps['onClick'] = React.useCallback((info) => {
|
|
125
151
|
setMergedActiveKey(info.key);
|
|
152
|
+
onActiveChangeRef.current?.(info.key);
|
|
153
|
+
}, [setMergedActiveKey]);
|
|
126
154
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
155
|
+
const selectedKeysRef = React.useRef(selectedKeys);
|
|
156
|
+
selectedKeysRef.current = selectedKeys;
|
|
157
|
+
|
|
158
|
+
const onSelectChangeRef = React.useRef(onSelectChange);
|
|
159
|
+
onSelectChangeRef.current = onSelectChange;
|
|
160
|
+
|
|
161
|
+
const handleItemSelect = React.useCallback((key: string, selected: boolean) => {
|
|
162
|
+
if (!onSelectChangeRef.current) return;
|
|
163
|
+
const keys = selectedKeysRef.current || [];
|
|
164
|
+
const next = selected ? [...keys, key] : keys.filter(k => k !== key);
|
|
165
|
+
onSelectChangeRef.current(next);
|
|
166
|
+
}, []);
|
|
131
167
|
|
|
132
168
|
return <>
|
|
133
169
|
<Style />
|
|
@@ -138,6 +174,12 @@ const Conversations: React.FC<ConversationsProps & { groupable?: boolean | Group
|
|
|
138
174
|
>
|
|
139
175
|
{groupList.map((groupInfo, groupIndex) => {
|
|
140
176
|
const convItems = groupInfo.data.map((convInfo: Conversation, convIndex: number) => {
|
|
177
|
+
const itemSelectable = propsSelectable ?? convInfo.selectable;
|
|
178
|
+
const itemSelected = itemSelectable
|
|
179
|
+
? (selectedKeys ? selectedKeys.includes(convInfo.key) : convInfo.selected)
|
|
180
|
+
: false;
|
|
181
|
+
const itemOnSelect = onSelectChange ? handleItemSelect : convInfo.onSelect;
|
|
182
|
+
|
|
141
183
|
return (
|
|
142
184
|
<ConversationsItem
|
|
143
185
|
key={convInfo.key || `key-${convIndex}`}
|
|
@@ -148,6 +190,9 @@ const Conversations: React.FC<ConversationsProps & { groupable?: boolean | Group
|
|
|
148
190
|
style={styles.item}
|
|
149
191
|
menu={menu}
|
|
150
192
|
active={mergedActiveKey === convInfo.key}
|
|
193
|
+
selectable={itemSelectable}
|
|
194
|
+
selected={itemSelected}
|
|
195
|
+
onSelect={itemOnSelect}
|
|
151
196
|
onClick={onConversationItemClick}
|
|
152
197
|
/>
|
|
153
198
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { DirectionType } from 'antd/es/config-provider';
|
|
3
3
|
import type { Conversation } from './interface';
|
|
4
|
-
export interface ConversationsItemProps extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick'> {
|
|
4
|
+
export interface ConversationsItemProps extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick' | 'onSelect'> {
|
|
5
5
|
info: Conversation;
|
|
6
6
|
prefixCls?: string;
|
|
7
7
|
direction?: DirectionType;
|
|
@@ -15,6 +15,9 @@ export interface ConversationsItemProps extends Omit<React.HTMLAttributes<HTMLLI
|
|
|
15
15
|
disabled?: boolean;
|
|
16
16
|
}[];
|
|
17
17
|
active?: boolean;
|
|
18
|
+
selectable?: boolean;
|
|
19
|
+
selected?: boolean;
|
|
20
|
+
onSelect?: (key: string, selected: boolean) => void;
|
|
18
21
|
onClick?: (info: Conversation) => void;
|
|
19
22
|
}
|
|
20
23
|
export declare function useEditable(id: any): any[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
-
var _excluded = ["prefixCls", "info", "className", "direction", "onClick", "active", "menu"],
|
|
2
|
+
var _excluded = ["prefixCls", "info", "className", "direction", "onClick", "active", "selectable", "selected", "onSelect", "menu"],
|
|
3
3
|
_excluded2 = ["key"];
|
|
4
4
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5
5
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -19,6 +19,7 @@ import React, { useEffect, useRef, useState } from 'react';
|
|
|
19
19
|
import pickAttrs from 'rc-util/lib/pickAttrs';
|
|
20
20
|
import { SparkMoreLine } from '@agentscope-ai/icons';
|
|
21
21
|
import { Button, Checkbox, IconButton, Popover } from '@agentscope-ai/design';
|
|
22
|
+
import { useInViewport } from 'ahooks';
|
|
22
23
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
23
24
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
25
|
var editableMap = {};
|
|
@@ -28,14 +29,14 @@ export function useEditable(id) {
|
|
|
28
29
|
editable = _useState2[0],
|
|
29
30
|
setEditable = _useState2[1];
|
|
30
31
|
return [editable, function (value) {
|
|
31
|
-
for (var
|
|
32
|
-
editableMap[
|
|
32
|
+
for (var _key in editableMap) {
|
|
33
|
+
editableMap[_key] = false;
|
|
33
34
|
}
|
|
34
35
|
editableMap[id] = value;
|
|
35
36
|
setEditable(value);
|
|
36
37
|
}];
|
|
37
38
|
}
|
|
38
|
-
var ConversationsItem = function
|
|
39
|
+
var ConversationsItem = /*#__PURE__*/React.memo(function (props) {
|
|
39
40
|
var _menu$find;
|
|
40
41
|
var _useEditable = useEditable(props.info.key),
|
|
41
42
|
_useEditable2 = _slicedToArray(_useEditable, 2),
|
|
@@ -51,6 +52,9 @@ var ConversationsItem = function ConversationsItem(props) {
|
|
|
51
52
|
direction = props.direction,
|
|
52
53
|
onClick = props.onClick,
|
|
53
54
|
active = props.active,
|
|
55
|
+
selectable = props.selectable,
|
|
56
|
+
selected = props.selected,
|
|
57
|
+
onSelect = props.onSelect,
|
|
54
58
|
menu = props.menu,
|
|
55
59
|
restProps = _objectWithoutProperties(props, _excluded);
|
|
56
60
|
var domProps = pickAttrs(restProps, {
|
|
@@ -58,37 +62,41 @@ var ConversationsItem = function ConversationsItem(props) {
|
|
|
58
62
|
data: true,
|
|
59
63
|
attr: true
|
|
60
64
|
});
|
|
65
|
+
var ref = useRef(null);
|
|
66
|
+
var _useInViewport = useInViewport(ref),
|
|
67
|
+
_useInViewport2 = _slicedToArray(_useInViewport, 1),
|
|
68
|
+
inViewport = _useInViewport2[0];
|
|
61
69
|
var disabled = info.disabled;
|
|
62
|
-
var mergedCls = classnames(className, "".concat(prefixCls, "-item"), _defineProperty({}, "".concat(prefixCls, "-item-active"), active && !disabled), _defineProperty({}, "".concat(prefixCls, "-item-disabled"), disabled), _defineProperty({}, "".concat(prefixCls, "-item-timeline"), info.timeline ||
|
|
70
|
+
var mergedCls = classnames(className, "".concat(prefixCls, "-item"), _defineProperty({}, "".concat(prefixCls, "-item-active"), active && !disabled), _defineProperty({}, "".concat(prefixCls, "-item-disabled"), disabled), _defineProperty({}, "".concat(prefixCls, "-item-timeline"), info.timeline || selectable));
|
|
63
71
|
var onInternalClick = function onInternalClick() {
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
return (_info$onSelect = info.onSelect) === null || _info$onSelect === void 0 ? void 0 : _info$onSelect.call(info, info.key, !info.selected);
|
|
72
|
+
if (selectable) {
|
|
73
|
+
return onSelect === null || onSelect === void 0 ? void 0 : onSelect(info.key, !selected);
|
|
67
74
|
}
|
|
68
75
|
if (!disabled && onClick) {
|
|
69
76
|
return onClick(info);
|
|
70
77
|
}
|
|
71
78
|
};
|
|
72
|
-
return /*#__PURE__*/_jsxs("li", _objectSpread(_objectSpread({
|
|
79
|
+
return /*#__PURE__*/_jsxs("li", _objectSpread(_objectSpread({
|
|
80
|
+
ref: ref
|
|
81
|
+
}, domProps), {}, {
|
|
73
82
|
className: mergedCls,
|
|
74
83
|
onClick: onInternalClick,
|
|
75
|
-
children: [/*#__PURE__*/_jsxs("div", {
|
|
84
|
+
children: [inViewport && /*#__PURE__*/_jsxs("div", {
|
|
76
85
|
className: "".concat(prefixCls, "-content"),
|
|
77
86
|
children: [info.icon && /*#__PURE__*/_jsx("div", {
|
|
78
87
|
className: "".concat(prefixCls, "-icon"),
|
|
79
88
|
children: info.icon
|
|
80
|
-
}), (info.timeline ||
|
|
89
|
+
}), (info.timeline || selectable) && /*#__PURE__*/_jsx("div", {
|
|
81
90
|
className: "".concat(prefixCls, "-timeline"),
|
|
82
|
-
children:
|
|
91
|
+
children: selectable ? /*#__PURE__*/_jsx("div", {
|
|
83
92
|
className: "".concat(prefixCls, "-timeline-checkbox"),
|
|
84
93
|
onClick: function onClick(e) {
|
|
85
94
|
return e.stopPropagation();
|
|
86
95
|
},
|
|
87
96
|
children: /*#__PURE__*/_jsx(Checkbox, {
|
|
88
|
-
checked:
|
|
97
|
+
checked: selected,
|
|
89
98
|
onChange: function onChange() {
|
|
90
|
-
|
|
91
|
-
return (_info$onSelect2 = info.onSelect) === null || _info$onSelect2 === void 0 ? void 0 : _info$onSelect2.call(info, info.key, !info.selected);
|
|
99
|
+
return onSelect === null || onSelect === void 0 ? void 0 : onSelect(info.key, !selected);
|
|
92
100
|
}
|
|
93
101
|
})
|
|
94
102
|
}) : /*#__PURE__*/_jsx("div", {
|
|
@@ -102,7 +110,7 @@ var ConversationsItem = function ConversationsItem(props) {
|
|
|
102
110
|
onEdit: menu === null || menu === void 0 || (_menu$find = menu.find(function (item) {
|
|
103
111
|
return item.key === 'edit';
|
|
104
112
|
})) === null || _menu$find === void 0 ? void 0 : _menu$find.onEdit
|
|
105
|
-
}), menu && !disabled && !
|
|
113
|
+
}), menu && !disabled && !selectable && /*#__PURE__*/_jsx(Popover, {
|
|
106
114
|
styles: {
|
|
107
115
|
body: {
|
|
108
116
|
padding: 4
|
|
@@ -143,15 +151,15 @@ var ConversationsItem = function ConversationsItem(props) {
|
|
|
143
151
|
}
|
|
144
152
|
})
|
|
145
153
|
})]
|
|
146
|
-
}), info.desc && /*#__PURE__*/_jsx("div", {
|
|
154
|
+
}), inViewport && info.desc && /*#__PURE__*/_jsx("div", {
|
|
147
155
|
className: "".concat(prefixCls, "-desc"),
|
|
148
|
-
style: info.timeline ||
|
|
156
|
+
style: info.timeline || selectable ? {
|
|
149
157
|
marginLeft: 16
|
|
150
158
|
} : {},
|
|
151
159
|
children: info.desc
|
|
152
160
|
})]
|
|
153
161
|
}));
|
|
154
|
-
};
|
|
162
|
+
});
|
|
155
163
|
function Label(props) {
|
|
156
164
|
var editable = props.editable,
|
|
157
165
|
prefixCls = props.prefixCls,
|
|
@@ -210,6 +218,9 @@ function Input(_ref) {
|
|
|
210
218
|
ref: ref,
|
|
211
219
|
className: "".concat(prefixCls, "-label-edit"),
|
|
212
220
|
value: v,
|
|
221
|
+
onClick: function onClick(e) {
|
|
222
|
+
return e.stopPropagation();
|
|
223
|
+
},
|
|
213
224
|
onChange: function onChange(e) {
|
|
214
225
|
return sv(e.target.value);
|
|
215
226
|
},
|
|
@@ -21,6 +21,21 @@ export interface ConversationsProps extends React.HTMLAttributes<HTMLUListElemen
|
|
|
21
21
|
* @descriptionEn Callback function when conversation selection changes, receives new conversation identifier
|
|
22
22
|
*/
|
|
23
23
|
onActiveChange?: (value: string) => void;
|
|
24
|
+
/**
|
|
25
|
+
* @description 是否开启批量选择模式
|
|
26
|
+
* @descriptionEn Whether to enable batch selection mode
|
|
27
|
+
*/
|
|
28
|
+
selectable?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* @description 当前选中的会话 key 列表
|
|
31
|
+
* @descriptionEn Currently selected conversation key list
|
|
32
|
+
*/
|
|
33
|
+
selectedKeys?: string[];
|
|
34
|
+
/**
|
|
35
|
+
* @description 批量选择变化时的回调函数
|
|
36
|
+
* @descriptionEn Callback when batch selection changes
|
|
37
|
+
*/
|
|
38
|
+
onSelectChange?: (selectedKeys: string[]) => void;
|
|
24
39
|
/**
|
|
25
40
|
* @description 会话操作菜单配置
|
|
26
41
|
* @descriptionEn Conversation operation menu configuration
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
-
var _excluded = ["prefixCls", "rootClassName", "items", "activeKey", "defaultActiveKey", "onActiveChange", "menu", "styles", "classNames", "groupable", "className", "style"];
|
|
2
|
+
var _excluded = ["prefixCls", "rootClassName", "items", "activeKey", "defaultActiveKey", "onActiveChange", "selectable", "selectedKeys", "onSelectChange", "menu", "styles", "classNames", "groupable", "className", "style"];
|
|
3
3
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
4
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
6
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
7
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
8
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
5
9
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
10
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
7
11
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
@@ -32,6 +36,9 @@ var Conversations = function Conversations(props) {
|
|
|
32
36
|
activeKey = props.activeKey,
|
|
33
37
|
defaultActiveKey = props.defaultActiveKey,
|
|
34
38
|
onActiveChange = props.onActiveChange,
|
|
39
|
+
propsSelectable = props.selectable,
|
|
40
|
+
selectedKeys = props.selectedKeys,
|
|
41
|
+
onSelectChange = props.onSelectChange,
|
|
35
42
|
menu = props.menu,
|
|
36
43
|
_props$styles = props.styles,
|
|
37
44
|
styles = _props$styles === void 0 ? {} : _props$styles,
|
|
@@ -61,18 +68,34 @@ var Conversations = function Conversations(props) {
|
|
|
61
68
|
getPrefixCls = _useProviderContext.getPrefixCls;
|
|
62
69
|
var prefixCls = getPrefixCls('conversations');
|
|
63
70
|
var mergedCls = classnames(prefixCls, className, rootClassName, _defineProperty({}, "".concat(prefixCls, "-rtl"), direction === 'rtl'));
|
|
64
|
-
var
|
|
71
|
+
var onActiveChangeRef = React.useRef(onActiveChange);
|
|
72
|
+
onActiveChangeRef.current = onActiveChange;
|
|
73
|
+
var onConversationItemClick = React.useCallback(function (info) {
|
|
74
|
+
var _onActiveChangeRef$cu;
|
|
65
75
|
setMergedActiveKey(info.key);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
(_onActiveChangeRef$cu = onActiveChangeRef.current) === null || _onActiveChangeRef$cu === void 0 || _onActiveChangeRef$cu.call(onActiveChangeRef, info.key);
|
|
77
|
+
}, [setMergedActiveKey]);
|
|
78
|
+
var selectedKeysRef = React.useRef(selectedKeys);
|
|
79
|
+
selectedKeysRef.current = selectedKeys;
|
|
80
|
+
var onSelectChangeRef = React.useRef(onSelectChange);
|
|
81
|
+
onSelectChangeRef.current = onSelectChange;
|
|
82
|
+
var handleItemSelect = React.useCallback(function (key, selected) {
|
|
83
|
+
if (!onSelectChangeRef.current) return;
|
|
84
|
+
var keys = selectedKeysRef.current || [];
|
|
85
|
+
var next = selected ? [].concat(_toConsumableArray(keys), [key]) : keys.filter(function (k) {
|
|
86
|
+
return k !== key;
|
|
87
|
+
});
|
|
88
|
+
onSelectChangeRef.current(next);
|
|
89
|
+
}, []);
|
|
70
90
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
71
91
|
children: [/*#__PURE__*/_jsx(Style, {}), /*#__PURE__*/_jsx("ul", _objectSpread(_objectSpread({}, domProps), {}, {
|
|
72
92
|
style: style,
|
|
73
93
|
className: mergedCls,
|
|
74
94
|
children: groupList.map(function (groupInfo, groupIndex) {
|
|
75
95
|
var convItems = groupInfo.data.map(function (convInfo, convIndex) {
|
|
96
|
+
var itemSelectable = propsSelectable !== null && propsSelectable !== void 0 ? propsSelectable : convInfo.selectable;
|
|
97
|
+
var itemSelected = itemSelectable ? selectedKeys ? selectedKeys.includes(convInfo.key) : convInfo.selected : false;
|
|
98
|
+
var itemOnSelect = onSelectChange ? handleItemSelect : convInfo.onSelect;
|
|
76
99
|
return /*#__PURE__*/_jsx(ConversationsItem, {
|
|
77
100
|
info: convInfo,
|
|
78
101
|
prefixCls: prefixCls,
|
|
@@ -81,6 +104,9 @@ var Conversations = function Conversations(props) {
|
|
|
81
104
|
style: styles.item,
|
|
82
105
|
menu: menu,
|
|
83
106
|
active: mergedActiveKey === convInfo.key,
|
|
107
|
+
selectable: itemSelectable,
|
|
108
|
+
selected: itemSelected,
|
|
109
|
+
onSelect: itemOnSelect,
|
|
84
110
|
onClick: onConversationItemClick
|
|
85
111
|
}, convInfo.key || "key-".concat(convIndex));
|
|
86
112
|
});
|
package/package.json
CHANGED