@douyinfe/semi-ui 2.17.0 → 2.19.0-alpha.0
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/anchor/index.tsx +1 -1
- package/anchor/link.tsx +3 -4
- package/autoComplete/__test__/autoComplete.test.js +6 -6
- package/autoComplete/index.tsx +3 -1
- package/autoComplete/option.tsx +164 -0
- package/calendar/__test__/calendar.test.js +21 -2
- package/calendar/_story/calendar.stories.js +31 -0
- package/calendar/index.tsx +3 -1
- package/calendar/interface.ts +2 -1
- package/carousel/index.tsx +5 -5
- package/checkbox/checkbox.tsx +10 -2
- package/dist/css/semi.css +174 -29
- package/dist/css/semi.min.css +1 -1
- package/dist/umd/semi-ui.js +4190 -5430
- package/dist/umd/semi-ui.js.map +1 -1
- package/dist/umd/semi-ui.min.js +1 -1
- package/dist/umd/semi-ui.min.js.map +1 -1
- package/form/_story/FieldProps/labelOptional.jsx +30 -0
- package/form/_story/form.stories.js +7 -0
- package/form/hoc/withField.tsx +1 -0
- package/form/label.tsx +21 -7
- package/gulpfile.js +3 -1
- package/lib/cjs/_base/base.css +35 -0
- package/lib/cjs/anchor/index.js +2 -1
- package/lib/cjs/anchor/link.d.ts +1 -1
- package/lib/cjs/anchor/link.js +9 -5
- package/lib/cjs/autoComplete/index.d.ts +1 -1
- package/lib/cjs/autoComplete/index.js +6 -3
- package/lib/cjs/autoComplete/option.d.ts +50 -0
- package/lib/cjs/autoComplete/option.js +218 -0
- package/lib/cjs/calendar/index.d.ts +2 -0
- package/lib/cjs/calendar/index.js +3 -1
- package/lib/cjs/calendar/interface.d.ts +2 -1
- package/lib/cjs/carousel/index.js +2 -2
- package/lib/cjs/checkbox/checkbox.d.ts +4 -0
- package/lib/cjs/checkbox/checkbox.js +9 -3
- package/lib/cjs/form/hoc/withField.js +2 -1
- package/lib/cjs/form/label.d.ts +8 -5
- package/lib/cjs/form/label.js +15 -4
- package/lib/cjs/locale/interface.d.ts +3 -0
- package/lib/cjs/locale/source/ar.js +3 -0
- package/lib/cjs/locale/source/de.js +3 -0
- package/lib/cjs/locale/source/en_GB.js +3 -0
- package/lib/cjs/locale/source/en_US.js +3 -0
- package/lib/cjs/locale/source/es.js +3 -0
- package/lib/cjs/locale/source/fr.js +3 -0
- package/lib/cjs/locale/source/id_ID.js +3 -0
- package/lib/cjs/locale/source/it.js +3 -0
- package/lib/cjs/locale/source/ja_JP.js +3 -0
- package/lib/cjs/locale/source/ko_KR.js +3 -0
- package/lib/cjs/locale/source/ms_MY.js +3 -0
- package/lib/cjs/locale/source/pt_BR.js +3 -0
- package/lib/cjs/locale/source/ru_RU.js +3 -0
- package/lib/cjs/locale/source/th_TH.js +3 -0
- package/lib/cjs/locale/source/tr_TR.js +3 -0
- package/lib/cjs/locale/source/vi_VN.js +3 -0
- package/lib/cjs/locale/source/zh_CN.js +3 -0
- package/lib/cjs/locale/source/zh_TW.js +3 -0
- package/lib/cjs/modal/Modal.js +0 -8
- package/lib/cjs/modal/ModalContent.js +4 -1
- package/lib/cjs/radio/radio.d.ts +2 -0
- package/lib/cjs/radio/radio.js +33 -8
- package/lib/cjs/table/ColumnFilter.js +4 -2
- package/lib/cjs/table/ColumnSorter.d.ts +1 -0
- package/lib/cjs/table/ColumnSorter.js +9 -6
- package/lib/cjs/table/Table.js +11 -4
- package/lib/cjs/tag/group.d.ts +3 -0
- package/lib/cjs/tag/group.js +24 -6
- package/lib/cjs/tag/index.d.ts +2 -1
- package/lib/cjs/tag/index.js +7 -5
- package/lib/cjs/tag/interface.d.ts +2 -1
- package/lib/cjs/tree/index.d.ts +3 -1
- package/lib/cjs/tree/index.js +23 -0
- package/lib/cjs/tree/interface.d.ts +4 -0
- package/lib/cjs/tree/treeNode.d.ts +4 -1
- package/lib/cjs/tree/treeNode.js +13 -4
- package/lib/es/_base/base.css +35 -0
- package/lib/es/anchor/index.js +2 -1
- package/lib/es/anchor/link.d.ts +1 -1
- package/lib/es/anchor/link.js +9 -5
- package/lib/es/autoComplete/index.d.ts +1 -1
- package/lib/es/autoComplete/index.js +6 -3
- package/lib/es/autoComplete/option.d.ts +50 -0
- package/lib/es/autoComplete/option.js +188 -0
- package/lib/es/calendar/index.d.ts +2 -0
- package/lib/es/calendar/index.js +3 -1
- package/lib/es/calendar/interface.d.ts +2 -1
- package/lib/es/carousel/index.js +2 -2
- package/lib/es/checkbox/checkbox.d.ts +4 -0
- package/lib/es/checkbox/checkbox.js +10 -4
- package/lib/es/form/hoc/withField.js +2 -1
- package/lib/es/form/label.d.ts +8 -5
- package/lib/es/form/label.js +13 -4
- package/lib/es/locale/interface.d.ts +3 -0
- package/lib/es/locale/source/ar.js +3 -0
- package/lib/es/locale/source/de.js +3 -0
- package/lib/es/locale/source/en_GB.js +3 -0
- package/lib/es/locale/source/en_US.js +3 -0
- package/lib/es/locale/source/es.js +3 -0
- package/lib/es/locale/source/fr.js +3 -0
- package/lib/es/locale/source/id_ID.js +3 -0
- package/lib/es/locale/source/it.js +3 -0
- package/lib/es/locale/source/ja_JP.js +3 -0
- package/lib/es/locale/source/ko_KR.js +3 -0
- package/lib/es/locale/source/ms_MY.js +3 -0
- package/lib/es/locale/source/pt_BR.js +3 -0
- package/lib/es/locale/source/ru_RU.js +3 -0
- package/lib/es/locale/source/th_TH.js +3 -0
- package/lib/es/locale/source/tr_TR.js +3 -0
- package/lib/es/locale/source/vi_VN.js +3 -0
- package/lib/es/locale/source/zh_CN.js +3 -0
- package/lib/es/locale/source/zh_TW.js +3 -0
- package/lib/es/modal/Modal.js +0 -8
- package/lib/es/modal/ModalContent.js +4 -1
- package/lib/es/radio/radio.d.ts +2 -0
- package/lib/es/radio/radio.js +31 -8
- package/lib/es/table/ColumnFilter.js +4 -2
- package/lib/es/table/ColumnSorter.d.ts +1 -0
- package/lib/es/table/ColumnSorter.js +9 -6
- package/lib/es/table/Table.js +10 -4
- package/lib/es/tag/group.d.ts +3 -0
- package/lib/es/tag/group.js +24 -6
- package/lib/es/tag/index.d.ts +2 -1
- package/lib/es/tag/index.js +7 -5
- package/lib/es/tag/interface.d.ts +2 -1
- package/lib/es/tree/index.d.ts +3 -1
- package/lib/es/tree/index.js +22 -0
- package/lib/es/tree/interface.d.ts +4 -0
- package/lib/es/tree/treeNode.d.ts +4 -1
- package/lib/es/tree/treeNode.js +13 -4
- package/locale/interface.ts +3 -0
- package/locale/source/ar.ts +3 -0
- package/locale/source/de.ts +3 -0
- package/locale/source/en_GB.ts +3 -0
- package/locale/source/en_US.ts +3 -0
- package/locale/source/es.ts +3 -0
- package/locale/source/fr.ts +3 -0
- package/locale/source/id_ID.ts +3 -0
- package/locale/source/it.ts +3 -0
- package/locale/source/ja_JP.ts +3 -0
- package/locale/source/ko_KR.ts +3 -0
- package/locale/source/ms_MY.ts +3 -0
- package/locale/source/pt_BR.ts +3 -0
- package/locale/source/ru_RU.ts +3 -0
- package/locale/source/th_TH.ts +3 -0
- package/locale/source/tr_TR.ts +4 -1
- package/locale/source/vi_VN.ts +3 -0
- package/locale/source/zh_CN.ts +3 -0
- package/locale/source/zh_TW.ts +3 -0
- package/modal/Modal.tsx +0 -6
- package/modal/ModalContent.tsx +4 -1
- package/modal/__test__/modal.test.js +1 -1
- package/modal/_story/__snapshots__/modal.stories.tsx.snap +203 -0
- package/package.json +7 -7
- package/radio/_story/radio.stories.js +2 -2
- package/radio/radio.tsx +27 -5
- package/rating/__test__/rating.test.js +1 -1
- package/select/__test__/select.test.js +11 -17
- package/select/_story/select.stories.js +6 -6
- package/steps/_story/steps.stories.js +3 -3
- package/switch/_story/switch.stories.js +4 -4
- package/switch/_story/switch.stories.tsx +4 -4
- package/table/ColumnFilter.tsx +2 -1
- package/table/ColumnSorter.tsx +16 -10
- package/table/Table.tsx +7 -4
- package/table/_story/v2/FixedFilter/index.tsx +106 -0
- package/table/_story/v2/FixedSorter/index.tsx +102 -0
- package/table/_story/v2/index.js +4 -2
- package/tag/_story/tag.stories.js +57 -1
- package/tag/group.tsx +20 -3
- package/tag/index.tsx +6 -5
- package/tag/interface.ts +2 -1
- package/transfer/_story/transfer.stories.js +2 -2
- package/tree/_story/tree.stories.js +152 -3
- package/tree/index.tsx +16 -1
- package/tree/interface.ts +6 -0
- package/tree/treeNode.tsx +11 -5
- package/upload/_story/upload.stories.js +2 -2
- package/webpack.config.js +13 -3
package/table/Table.tsx
CHANGED
|
@@ -933,16 +933,22 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
|
|
|
933
933
|
const stateSortOrder = get(curQuery, 'sortOrder');
|
|
934
934
|
const defaultSortOrder = get(curQuery, 'defaultSortOrder', false);
|
|
935
935
|
const sortOrder = this.foundation.isSortOrderValid(stateSortOrder) ? stateSortOrder : defaultSortOrder;
|
|
936
|
+
const TitleNode = typeof rawTitle !== 'function' && <React.Fragment key={strings.DEFAULT_KEY_COLUMN_TITLE}>{rawTitle as React.ReactNode}</React.Fragment>;
|
|
936
937
|
if (typeof column.sorter === 'function' || column.sorter === true) {
|
|
938
|
+
// In order to increase the click hot area of sorting, when sorting is required & useFullRender is false,
|
|
939
|
+
// both the title and sorting areas are used as the click hot area for sorting。
|
|
937
940
|
const sorter = (
|
|
938
941
|
<ColumnSorter
|
|
939
942
|
key={strings.DEFAULT_KEY_COLUMN_SORTER}
|
|
940
943
|
sortOrder={sortOrder}
|
|
941
944
|
onClick={e => this.foundation.handleSort(column, e)}
|
|
945
|
+
title={TitleNode}
|
|
942
946
|
/>
|
|
943
947
|
);
|
|
944
948
|
useFullRender && (titleMap.sorter = sorter);
|
|
945
949
|
titleArr.push(sorter);
|
|
950
|
+
} else {
|
|
951
|
+
titleArr.push(TitleNode);
|
|
946
952
|
}
|
|
947
953
|
|
|
948
954
|
const stateFilteredValue = get(curQuery, 'filteredValue');
|
|
@@ -964,10 +970,7 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
|
|
|
964
970
|
|
|
965
971
|
const newTitle =
|
|
966
972
|
typeof rawTitle === 'function' ?
|
|
967
|
-
() => rawTitle(titleMap) :
|
|
968
|
-
titleArr.unshift(
|
|
969
|
-
<React.Fragment key={strings.DEFAULT_KEY_COLUMN_TITLE}>{rawTitle}</React.Fragment>
|
|
970
|
-
) && titleArr;
|
|
973
|
+
() => rawTitle(titleMap) : titleArr;
|
|
971
974
|
|
|
972
975
|
column = { ...column, title: newTitle };
|
|
973
976
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { useState, useMemo, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line semi-design/no-import
|
|
4
|
+
import { Table, Avatar } from '@douyinfe/semi-ui';
|
|
5
|
+
import * as dateFns from 'date-fns';
|
|
6
|
+
|
|
7
|
+
const DAY = 24 * 60 * 60 * 1000;
|
|
8
|
+
const figmaIconUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/figma-icon.png';
|
|
9
|
+
|
|
10
|
+
const columns = [
|
|
11
|
+
{
|
|
12
|
+
title: '标题',
|
|
13
|
+
dataIndex: 'name',
|
|
14
|
+
width: 400,
|
|
15
|
+
render: (text, record, index) => {
|
|
16
|
+
return (
|
|
17
|
+
<div>
|
|
18
|
+
<Avatar size="small" shape="square" src={figmaIconUrl} style={{ marginRight: 12 }}></Avatar>
|
|
19
|
+
{text}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
},
|
|
23
|
+
filters: [
|
|
24
|
+
{
|
|
25
|
+
text: 'Semi Design 设计稿',
|
|
26
|
+
value: 'Semi Design 设计稿',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
text: 'Semi Pro 设计稿',
|
|
30
|
+
value: 'Semi Pro 设计稿',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
onFilter: (value, record) => record.name.includes(value),
|
|
34
|
+
sorter: (a, b) => a.name.length - b.name.length > 0 ? 1 : -1,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: '大小',
|
|
38
|
+
dataIndex: 'size',
|
|
39
|
+
sorter: (a, b) => a.size - b.size > 0 ? 1 : -1,
|
|
40
|
+
render: (text) => `${text} KB`
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
title: '所有者',
|
|
44
|
+
dataIndex: 'owner',
|
|
45
|
+
render: (text, record, index) => {
|
|
46
|
+
return (
|
|
47
|
+
<div>
|
|
48
|
+
<Avatar size="small" color={record.avatarBg} style={{ marginRight: 4 }}>{typeof text === 'string' && text.slice(0, 1)}</Avatar>
|
|
49
|
+
{text}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
title: '更新日期',
|
|
57
|
+
dataIndex: 'updateTime',
|
|
58
|
+
sorter: (a, b) => a.updateTime - b.updateTime > 0 ? 1 : -1,
|
|
59
|
+
render: (value) => {
|
|
60
|
+
return dateFns.format(new Date(value), 'yyyy-MM-dd');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
App.storyName = 'Fixed filter issue 1036';
|
|
66
|
+
/**
|
|
67
|
+
* test with cypress, please don't modify this story
|
|
68
|
+
*/
|
|
69
|
+
export default function App() {
|
|
70
|
+
const [dataSource, setData] = useState([]);
|
|
71
|
+
|
|
72
|
+
const rowSelection = useMemo(() => ({
|
|
73
|
+
onChange: (selectedRowKeys, selectedRows) => {
|
|
74
|
+
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
|
75
|
+
},
|
|
76
|
+
getCheckboxProps: record => ({
|
|
77
|
+
disabled: record.name === 'Michael James', // Column configuration not to be checked
|
|
78
|
+
name: record.name,
|
|
79
|
+
}),
|
|
80
|
+
}), []);
|
|
81
|
+
const scroll = useMemo(() => ({ y: 300 }), []);
|
|
82
|
+
|
|
83
|
+
const getData = () => {
|
|
84
|
+
const data = [];
|
|
85
|
+
for (let i = 0; i < 46; i++) {
|
|
86
|
+
const isSemiDesign = i % 2 === 0;
|
|
87
|
+
const randomNumber = (i * 1000) % 199;
|
|
88
|
+
data.push({
|
|
89
|
+
key: '' + i,
|
|
90
|
+
name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi Pro 设计稿${i}.fig`,
|
|
91
|
+
owner: isSemiDesign ? '姜鹏志' : '郝宣',
|
|
92
|
+
size: randomNumber,
|
|
93
|
+
updateTime: new Date('2022-08-11').valueOf() + randomNumber * DAY,
|
|
94
|
+
avatarBg: isSemiDesign ? 'grey' : 'red'
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return data;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
const data = getData();
|
|
102
|
+
setData(data);
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
return <Table columns={columns} dataSource={dataSource} rowSelection={rowSelection} scroll={scroll} />;
|
|
106
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
// eslint-disable-next-line semi-design/no-import
|
|
3
|
+
import { Table } from '@douyinfe/semi-ui';
|
|
4
|
+
// eslint-disable-next-line semi-design/no-import
|
|
5
|
+
import { ChangeInfo } from '@douyinfe/semi-ui/table';
|
|
6
|
+
|
|
7
|
+
const data = [
|
|
8
|
+
{
|
|
9
|
+
key: 'a',
|
|
10
|
+
group: 'yes',
|
|
11
|
+
count: 3,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: 'b',
|
|
15
|
+
group: 'no',
|
|
16
|
+
count: 3,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
key: 'c',
|
|
20
|
+
group: 'no',
|
|
21
|
+
count: 1,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
key: 'd',
|
|
25
|
+
group: 'yes',
|
|
26
|
+
count: 1,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: 'e',
|
|
30
|
+
group: 'no',
|
|
31
|
+
count: 2,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: 'f',
|
|
35
|
+
group: 'yes',
|
|
36
|
+
count: 2,
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
Demo.storyName = 'fixed sorter';
|
|
41
|
+
/**
|
|
42
|
+
* 保持分组顺序不变的排序方式
|
|
43
|
+
*/
|
|
44
|
+
function Demo() {
|
|
45
|
+
const [filtered, setFiltered] = useState([...data]);
|
|
46
|
+
console.log(filtered);
|
|
47
|
+
const columns = [
|
|
48
|
+
{
|
|
49
|
+
title: 'ID',
|
|
50
|
+
dataIndex: 'key',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: 'group',
|
|
54
|
+
dataIndex: 'Group',
|
|
55
|
+
sorter: (a, b) => a.group === 'yes' ? -1 : 1,
|
|
56
|
+
// sortOrder: 'ascend'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Count',
|
|
60
|
+
dataIndex: 'count',
|
|
61
|
+
// sorter: true
|
|
62
|
+
sorter: (a, b) => a.count - b.count > 0 ? 1 : -1,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
const onTableChange = ({ sorter }: ChangeInfo<any>) => {
|
|
67
|
+
if (sorter) {
|
|
68
|
+
const { dataIndex, sortOrder } = sorter;
|
|
69
|
+
setFiltered(prev => [...prev].sort((a, b) => {
|
|
70
|
+
if (a.group !== b.group) {
|
|
71
|
+
return a.group === 'yes' ? -1 : 1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let ascendValue = -1;
|
|
75
|
+
if (dataIndex === 'count') {
|
|
76
|
+
ascendValue = a.count - b.count > 0 ? 1 : -1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return sortOrder === 'ascend' ? ascendValue : -ascendValue;
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div style={{ padding: '20px 0px' }}>
|
|
87
|
+
<Table
|
|
88
|
+
dataSource={filtered}
|
|
89
|
+
onChange={onTableChange}
|
|
90
|
+
rowKey="key"
|
|
91
|
+
groupBy="group"
|
|
92
|
+
columns={columns}
|
|
93
|
+
renderGroupSection={groupKey => <strong>分组 {groupKey}</strong>}
|
|
94
|
+
expandAllGroupRows
|
|
95
|
+
scroll={{ y: 480 }}
|
|
96
|
+
pagination={{ pageSize: 4 }}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default Demo;
|
package/table/_story/v2/index.js
CHANGED
|
@@ -4,7 +4,9 @@ export { default as FixedZIndex } from './FixedZIndex';
|
|
|
4
4
|
export { default as FixedHeaderMerge } from './FixedHeaderMerge';
|
|
5
5
|
export { default as FixedResizable } from './FixedResizable';
|
|
6
6
|
export { default as FixedExpandedRow } from './FixedExpandedRow';
|
|
7
|
-
export { default as FixedMemoryLeak
|
|
7
|
+
export { default as FixedMemoryLeak } from './FixedMemoryLeak';
|
|
8
8
|
export { default as FixedOnHeaderRow } from './FixedOnHeaderRow';
|
|
9
9
|
export { default as RadioRowSelection } from './radioRowSelection';
|
|
10
|
-
export { default as FixedVirtualizedEmpty } from './FixedVirtualizedEmpty';
|
|
10
|
+
export { default as FixedVirtualizedEmpty } from './FixedVirtualizedEmpty';
|
|
11
|
+
export { default as FixedFilter } from './FixedFilter';
|
|
12
|
+
export { default as FixedSorter } from './FixedSorter';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* argus-disable unPkgSensitiveInfo */
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useCallback, useState } from 'react';
|
|
3
3
|
import withPropsCombinations from 'react-storybook-addon-props-combinations';
|
|
4
4
|
import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
|
|
5
5
|
|
|
@@ -232,3 +232,59 @@ export const AvatarTagGroup = () => <AvatarTagGroupDemo />;
|
|
|
232
232
|
AvatarTagGroup.story = {
|
|
233
233
|
name: 'avatar tagGroup',
|
|
234
234
|
};
|
|
235
|
+
|
|
236
|
+
class TagGroupCloseableDemo extends React.Component {
|
|
237
|
+
constructor(props){
|
|
238
|
+
super(props);
|
|
239
|
+
this.state = {
|
|
240
|
+
tagList: [
|
|
241
|
+
{ tagKey: '1', color: 'white', children: '抖音', closable: true,},
|
|
242
|
+
{ tagKey: '2',color: 'white', children: '火山小视频', closable: true,},
|
|
243
|
+
{ tagKey: '3',color: 'white', children: '剪映', closable: true,},
|
|
244
|
+
{ tagKey: '4',color: 'white', children: '皮皮虾', closable: true,},
|
|
245
|
+
]
|
|
246
|
+
};
|
|
247
|
+
this.tagListClick = this.tagListClick.bind(this);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
tagListClick(value, e, tagKey){
|
|
251
|
+
const newTagList = [...this.state.tagList];
|
|
252
|
+
const closeTagIndex = newTagList.findIndex(t => t.tagKey === tagKey);
|
|
253
|
+
newTagList.splice(closeTagIndex, 1);
|
|
254
|
+
this.setState({
|
|
255
|
+
tagList: newTagList,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
render() {
|
|
260
|
+
return (
|
|
261
|
+
<div style={ {
|
|
262
|
+
backgroundColor: 'var(--semi-color-fill-0)',
|
|
263
|
+
height: 35,
|
|
264
|
+
width: 300,
|
|
265
|
+
display: 'flex',
|
|
266
|
+
alignItems: 'center',
|
|
267
|
+
padding: '0 10px',
|
|
268
|
+
marginBottom: 30,
|
|
269
|
+
}}>
|
|
270
|
+
<TagGroup
|
|
271
|
+
maxTagCount={3}
|
|
272
|
+
style={ {
|
|
273
|
+
display: 'flex',
|
|
274
|
+
alignItems: 'center',
|
|
275
|
+
width: 350,
|
|
276
|
+
}}
|
|
277
|
+
tagList={this.state.tagList}
|
|
278
|
+
size='large'
|
|
279
|
+
onTagClose={this.tagListClick}
|
|
280
|
+
/>
|
|
281
|
+
</div>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export const TagGroupCloseable = () => <TagGroupCloseableDemo />;
|
|
287
|
+
|
|
288
|
+
TagGroupCloseable.story = {
|
|
289
|
+
name: 'tagGroup closable',
|
|
290
|
+
}
|
package/tag/group.tsx
CHANGED
|
@@ -21,6 +21,7 @@ export interface TagGroupProps<T> {
|
|
|
21
21
|
popoverProps?: PopoverProps;
|
|
22
22
|
avatarShape?: AvatarShape;
|
|
23
23
|
mode?: string;
|
|
24
|
+
onTagClose: (tagChildren: React.ReactNode, event: React.MouseEvent<HTMLElement>, tagKey: string | number) => void;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export default class TagGroup<T> extends PureComponent<TagGroupProps<T>> {
|
|
@@ -29,6 +30,7 @@ export default class TagGroup<T> extends PureComponent<TagGroupProps<T>> {
|
|
|
29
30
|
className: '',
|
|
30
31
|
size: tagSize[0],
|
|
31
32
|
avatarShape: 'square',
|
|
33
|
+
onTagClose: () => undefined,
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
static propTypes = {
|
|
@@ -40,6 +42,7 @@ export default class TagGroup<T> extends PureComponent<TagGroupProps<T>> {
|
|
|
40
42
|
tagList: PropTypes.array,
|
|
41
43
|
size: PropTypes.oneOf(tagSize),
|
|
42
44
|
mode: PropTypes.string,
|
|
45
|
+
onTagClose: PropTypes.func,
|
|
43
46
|
showPopover: PropTypes.bool,
|
|
44
47
|
popoverProps: PropTypes.object,
|
|
45
48
|
avatarShape: PropTypes.oneOf(avatarShapeSet),
|
|
@@ -95,18 +98,32 @@ export default class TagGroup<T> extends PureComponent<TagGroupProps<T>> {
|
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
renderAllTags() {
|
|
98
|
-
const { tagList, size, mode, avatarShape } = this.props;
|
|
99
|
-
const renderTags = tagList.map((tag
|
|
101
|
+
const { tagList, size, mode, avatarShape, onTagClose } = this.props;
|
|
102
|
+
const renderTags = tagList.map((tag): (Tag | React.ReactNode) => {
|
|
100
103
|
if (mode === 'custom') {
|
|
101
104
|
return tag as React.ReactNode;
|
|
102
105
|
}
|
|
103
106
|
if (!(tag as TagProps).size) {
|
|
104
107
|
(tag as TagProps).size = size;
|
|
105
108
|
}
|
|
109
|
+
|
|
106
110
|
if (!(tag as TagProps).avatarShape) {
|
|
107
111
|
(tag as TagProps).avatarShape = avatarShape;
|
|
108
112
|
}
|
|
109
|
-
|
|
113
|
+
|
|
114
|
+
if (!(tag as TagProps).tagKey) {
|
|
115
|
+
if (typeof (tag as TagProps).children === 'string' || typeof (tag as TagProps).children === 'number') {
|
|
116
|
+
(tag as TagProps).tagKey = (tag as TagProps).children as string | number;
|
|
117
|
+
} else {
|
|
118
|
+
(tag as TagProps).tagKey = Math.random();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return <Tag {...(tag as TagProps)} key={(tag as TagProps).tagKey} onClose={(tagChildren, e, tagKey) => {
|
|
122
|
+
if ((tag as TagProps).onClose) {
|
|
123
|
+
(tag as TagProps).onClose(tagChildren, e, tagKey);
|
|
124
|
+
}
|
|
125
|
+
onTagClose && onTagClose(tagChildren, e, tagKey);
|
|
126
|
+
}} />;
|
|
110
127
|
});
|
|
111
128
|
return renderTags;
|
|
112
129
|
}
|
package/tag/index.tsx
CHANGED
|
@@ -40,6 +40,7 @@ export default class Tag extends Component<TagProps, TagState> {
|
|
|
40
40
|
|
|
41
41
|
static propTypes = {
|
|
42
42
|
children: PropTypes.node,
|
|
43
|
+
tagKey: PropTypes.oneOf([PropTypes.string, PropTypes.number]),
|
|
43
44
|
size: PropTypes.oneOf(tagSize),
|
|
44
45
|
color: PropTypes.oneOf(tagColors),
|
|
45
46
|
type: PropTypes.oneOf(tagType),
|
|
@@ -79,11 +80,11 @@ export default class Tag extends Component<TagProps, TagState> {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
close(e: React.MouseEvent<HTMLElement>, value: React.ReactNode) {
|
|
83
|
+
close(e: React.MouseEvent<HTMLElement>, value: React.ReactNode, tagKey: string | number) {
|
|
83
84
|
const { onClose } = this.props;
|
|
84
85
|
e.stopPropagation();
|
|
85
86
|
e.nativeEvent.stopImmediatePropagation();
|
|
86
|
-
onClose && onClose(value, e);
|
|
87
|
+
onClose && onClose(value, e, tagKey);
|
|
87
88
|
// when user call e.preventDefault() in onClick callback, tag will not hidden
|
|
88
89
|
if (e.defaultPrevented) {
|
|
89
90
|
return;
|
|
@@ -96,7 +97,7 @@ export default class Tag extends Component<TagProps, TagState> {
|
|
|
96
97
|
switch (event.key) {
|
|
97
98
|
case "Backspace":
|
|
98
99
|
case "Delete":
|
|
99
|
-
closable && this.close(event, this.props.children);
|
|
100
|
+
closable && this.close(event, this.props.children, this.props.tagKey);
|
|
100
101
|
handlePrevent(event);
|
|
101
102
|
break;
|
|
102
103
|
case "Enter":
|
|
@@ -119,7 +120,7 @@ export default class Tag extends Component<TagProps, TagState> {
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
render() {
|
|
122
|
-
const { children, size, color, closable, visible, onClose, onClick, className, type, avatarSrc, avatarShape, tabIndex, ...attr } = this.props;
|
|
123
|
+
const { tagKey, children, size, color, closable, visible, onClose, onClick, className, type, avatarSrc, avatarShape, tabIndex, ...attr } = this.props;
|
|
123
124
|
const { visible: isVisible } = this.state;
|
|
124
125
|
const clickable = onClick !== Tag.defaultProps.onClick || closable;
|
|
125
126
|
// only when the Tag is clickable or closable, the value of tabIndex is allowed to be passed in.
|
|
@@ -145,7 +146,7 @@ export default class Tag extends Component<TagProps, TagState> {
|
|
|
145
146
|
const wrapProps = clickable ? ({ ...baseProps, ...a11yProps }) : baseProps;
|
|
146
147
|
const closeIcon = closable ? (
|
|
147
148
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
|
|
148
|
-
<div className={`${prefixCls}-close`} onClick={e => this.close(e, children)}>
|
|
149
|
+
<div className={`${prefixCls}-close`} onClick={e => this.close(e, children, tagKey)}>
|
|
149
150
|
<IconClose size="small" />
|
|
150
151
|
</div>
|
|
151
152
|
) : null;
|
package/tag/interface.ts
CHANGED
|
@@ -22,12 +22,13 @@ export type AvatarShape = 'circle' | 'square';
|
|
|
22
22
|
|
|
23
23
|
export interface TagProps {
|
|
24
24
|
children?: React.ReactNode;
|
|
25
|
+
tagKey?: string | number;
|
|
25
26
|
size?: TagSize;
|
|
26
27
|
color?: TagColor;
|
|
27
28
|
type?: TagType;
|
|
28
29
|
closable?: boolean;
|
|
29
30
|
visible?: boolean;
|
|
30
|
-
onClose?: (tagChildren: React.ReactNode, event: React.MouseEvent<HTMLElement
|
|
31
|
+
onClose?: (tagChildren: React.ReactNode, event: React.MouseEvent<HTMLElement>, tagKey: string | number) => void;
|
|
31
32
|
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
|
32
33
|
style?: React.CSSProperties;
|
|
33
34
|
className?: string;
|
|
@@ -195,7 +195,7 @@ TransferDraggableAndDisabled.story = {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
|
|
198
|
-
const
|
|
198
|
+
const ControlledTransfer = () => {
|
|
199
199
|
const [value, setValue] = useState([2, 3]);
|
|
200
200
|
|
|
201
201
|
const handleChange = value => {
|
|
@@ -209,7 +209,7 @@ const ControledTransfer = () => {
|
|
|
209
209
|
);
|
|
210
210
|
};
|
|
211
211
|
|
|
212
|
-
export const ControlledTransfer = () => <
|
|
212
|
+
export const ControlledTransfer = () => <ControlledTransfer />;
|
|
213
213
|
|
|
214
214
|
ControlledTransfer.story = {
|
|
215
215
|
name: '受控Transfer',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React, { useRef, useState } from 'react';
|
|
1
|
+
import React, { useRef, useState, useCallback } from 'react';
|
|
2
2
|
import { cloneDeep, difference, isEqual } from 'lodash';
|
|
3
3
|
import { IconEdit, IconMapPin, IconMore } from '@douyinfe/semi-icons';
|
|
4
4
|
import Tree from '../index';
|
|
5
5
|
import AutoSizer from '../autoSizer';
|
|
6
|
-
import { Button, ButtonGroup, Input, Popover, Toast, Space } from '../../index';
|
|
6
|
+
import { Button, ButtonGroup, Input, Popover, Toast, Space, Select, Switch } from '../../index';
|
|
7
7
|
import BigTree from './BigData';
|
|
8
8
|
import testData from './data';
|
|
9
9
|
const TreeNode = Tree.TreeNode;
|
|
@@ -2398,4 +2398,153 @@ export const ValueImpactExpansionWithDynamicTreeData = () => {
|
|
|
2398
2398
|
</Space>
|
|
2399
2399
|
</>
|
|
2400
2400
|
)
|
|
2401
|
-
}
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
class DemoV extends React.Component {
|
|
2404
|
+
constructor() {
|
|
2405
|
+
super();
|
|
2406
|
+
this.state = {
|
|
2407
|
+
gData: [],
|
|
2408
|
+
total: 0,
|
|
2409
|
+
align: 'center',
|
|
2410
|
+
scrollKey: '',
|
|
2411
|
+
expandAll: false,
|
|
2412
|
+
};
|
|
2413
|
+
this.onGen = this.onGen.bind(this);
|
|
2414
|
+
this.onScroll = this.onScroll.bind(this);
|
|
2415
|
+
this.onInputChange = this.onInputChange.bind(this);
|
|
2416
|
+
this.onInputBlur = this.onInputBlur.bind(this);
|
|
2417
|
+
this.onSelectChange = this.onSelectChange.bind(this);
|
|
2418
|
+
this.treeRef = React.createRef();
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
generateData(x = 5, y = 4, z = 3, gData = []) {
|
|
2422
|
+
// x:每一级下的节点总数。y:每级节点里有y个节点、存在子节点。z:树的level层级数(0表示一级)
|
|
2423
|
+
function _loop(_level, _preKey, _tns) {
|
|
2424
|
+
const preKey = _preKey || '0';
|
|
2425
|
+
const tns = _tns || gData;
|
|
2426
|
+
|
|
2427
|
+
const children = [];
|
|
2428
|
+
for (let i = 0; i < x; i++) {
|
|
2429
|
+
const key = `${preKey}-${i}`;
|
|
2430
|
+
tns.push({ label: `${key}-标签`, key: `${key}-key`, value: `${key}-value` });
|
|
2431
|
+
if (i < y) {
|
|
2432
|
+
children.push(key);
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
if (_level < 0) {
|
|
2436
|
+
return tns;
|
|
2437
|
+
}
|
|
2438
|
+
const __level = _level - 1;
|
|
2439
|
+
children.forEach((key, index) => {
|
|
2440
|
+
tns[index].children = [];
|
|
2441
|
+
return _loop(__level, key, tns[index].children);
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
return null;
|
|
2445
|
+
}
|
|
2446
|
+
_loop(z);
|
|
2447
|
+
|
|
2448
|
+
function calcTotal(x, y, z) {
|
|
2449
|
+
const rec = n => (n >= 0 ? x * y ** n-- + rec(n) : 0);
|
|
2450
|
+
return rec(z + 1);
|
|
2451
|
+
}
|
|
2452
|
+
return { gData, total: calcTotal(x, y, z) };
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
onGen() {
|
|
2456
|
+
const { gData, total } = this.generateData();
|
|
2457
|
+
this.setState({
|
|
2458
|
+
gData,
|
|
2459
|
+
total
|
|
2460
|
+
});
|
|
2461
|
+
};
|
|
2462
|
+
|
|
2463
|
+
onScroll(scrollKey, align) {
|
|
2464
|
+
this.treeRef?.current.scrollTo({ key: scrollKey, align});
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
onInputChange(value) {
|
|
2468
|
+
this.setState({
|
|
2469
|
+
scrollKey: value,
|
|
2470
|
+
})
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
onInputBlur(e) {
|
|
2474
|
+
const { value } = e.target;
|
|
2475
|
+
this.onScroll(value, this.state.align);
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
onSelectChange(align){
|
|
2479
|
+
this.setState({
|
|
2480
|
+
align: align,
|
|
2481
|
+
})
|
|
2482
|
+
this.onScroll(this.state.scrollKey, align);
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
render() {
|
|
2486
|
+
const style = {
|
|
2487
|
+
width: 260,
|
|
2488
|
+
border: '1px solid var(--semi-color-border)'
|
|
2489
|
+
};
|
|
2490
|
+
return (
|
|
2491
|
+
<div style={{ padding: '0 20px' }}>
|
|
2492
|
+
<Button onClick={this.onGen}>生成数据: </Button>
|
|
2493
|
+
<span>共 {this.state.total} 个节点</span>
|
|
2494
|
+
<br/>
|
|
2495
|
+
<br/>
|
|
2496
|
+
<div style={{ display: 'flex', alignItems: 'center', }}>
|
|
2497
|
+
<span>defaultExpandAll</span>
|
|
2498
|
+
<Switch onChange={(value) => {
|
|
2499
|
+
this.setState({
|
|
2500
|
+
expandAll: value,
|
|
2501
|
+
})
|
|
2502
|
+
}}/>
|
|
2503
|
+
</div>
|
|
2504
|
+
<br/>
|
|
2505
|
+
<span>跳转的key:</span>
|
|
2506
|
+
<Input
|
|
2507
|
+
placeholder={'格式:x-x-key'}
|
|
2508
|
+
style={{ width: 180, marginRight: 20 }}
|
|
2509
|
+
onChange={this.onInputChange}
|
|
2510
|
+
onBlur={this.onInputBlur}
|
|
2511
|
+
></Input>
|
|
2512
|
+
<span>scroll align:</span>
|
|
2513
|
+
<Select
|
|
2514
|
+
defaultValue='center'
|
|
2515
|
+
style={{ width: 180 }}
|
|
2516
|
+
optionList={['center', 'start', 'end', 'smart', 'auto'].map(item => ({
|
|
2517
|
+
value: item,
|
|
2518
|
+
label: item,
|
|
2519
|
+
}))}
|
|
2520
|
+
onChange={this.onSelectChange}
|
|
2521
|
+
>
|
|
2522
|
+
</Select>
|
|
2523
|
+
<br />
|
|
2524
|
+
<br />
|
|
2525
|
+
{this.state.gData.length ? (
|
|
2526
|
+
<Tree
|
|
2527
|
+
key={`key-${this.state.expandAll}`}
|
|
2528
|
+
ref={this.treeRef}
|
|
2529
|
+
defaultExpandAll={this.state.expandAll}
|
|
2530
|
+
treeData={this.state.gData}
|
|
2531
|
+
filterTreeNode
|
|
2532
|
+
showFilteredOnly
|
|
2533
|
+
style={style}
|
|
2534
|
+
virtualize={{
|
|
2535
|
+
// if set height for tree, it will fill 100%
|
|
2536
|
+
height: 300,
|
|
2537
|
+
itemSize: 28,
|
|
2538
|
+
}}
|
|
2539
|
+
/>
|
|
2540
|
+
) : null}
|
|
2541
|
+
</div>
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
export const virtualizeTree = () => <DemoV />;
|
|
2547
|
+
|
|
2548
|
+
virtualizeTree.story = {
|
|
2549
|
+
name: 'virtualize tree',
|
|
2550
|
+
};
|
package/tree/index.tsx
CHANGED
|
@@ -39,7 +39,8 @@ import {
|
|
|
39
39
|
TreeNodeData,
|
|
40
40
|
FlattenNode,
|
|
41
41
|
KeyEntity,
|
|
42
|
-
OptionProps
|
|
42
|
+
OptionProps,
|
|
43
|
+
ScrollData,
|
|
43
44
|
} from './interface';
|
|
44
45
|
import CheckboxGroup from '../checkbox/checkboxGroup';
|
|
45
46
|
|
|
@@ -146,6 +147,7 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
|
|
|
146
147
|
onNodeClick: any;
|
|
147
148
|
onMotionEnd: any;
|
|
148
149
|
context: ContextValue;
|
|
150
|
+
virtualizedListRef: React.RefObject<any>;
|
|
149
151
|
|
|
150
152
|
constructor(props: TreeProps) {
|
|
151
153
|
super(props);
|
|
@@ -179,6 +181,7 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
|
|
|
179
181
|
this.optionsRef = React.createRef();
|
|
180
182
|
this.foundation = new TreeFoundation(this.adapter);
|
|
181
183
|
this.dragNode = null;
|
|
184
|
+
this.virtualizedListRef = React.createRef();
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
/**
|
|
@@ -493,6 +496,17 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
|
|
|
493
496
|
this.foundation.handleInputChange(value);
|
|
494
497
|
};
|
|
495
498
|
|
|
499
|
+
scrollTo = (scrollData: ScrollData) => {
|
|
500
|
+
const { key, align = 'center' } = scrollData;
|
|
501
|
+
const { flattenNodes } = this.state;
|
|
502
|
+
if (key) {
|
|
503
|
+
const index = flattenNodes?.findIndex((node) => {
|
|
504
|
+
return node.key === key;
|
|
505
|
+
});
|
|
506
|
+
index >= 0 && (this.virtualizedListRef.current as any)?.scrollToItem(index, align);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
496
510
|
renderInput() {
|
|
497
511
|
const {
|
|
498
512
|
searchClassName,
|
|
@@ -664,6 +678,7 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
|
|
|
664
678
|
<AutoSizer defaultHeight={virtualize.height} defaultWidth={virtualize.width}>
|
|
665
679
|
{({ height, width }: { width: string | number; height: string | number }) => (
|
|
666
680
|
<VirtualList
|
|
681
|
+
ref={this.virtualizedListRef}
|
|
667
682
|
itemCount={flattenNodes.length}
|
|
668
683
|
itemSize={virtualize.itemSize}
|
|
669
684
|
height={height}
|