@douyinfe/semi-ui 2.17.0-beta.0 → 2.17.1
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/autoComplete/index.tsx +2 -0
- package/cascader/_story/cascader.stories.js +91 -1
- package/cascader/index.tsx +35 -26
- package/checkbox/checkbox.tsx +4 -1
- package/dist/css/semi.css +1 -1
- package/dist/css/semi.min.css +1 -1
- package/dist/umd/semi-ui.js +68 -50
- 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/empty/index.tsx +3 -3
- package/lib/cjs/autoComplete/index.js +5 -2
- package/lib/cjs/cascader/index.js +36 -25
- package/lib/cjs/checkbox/checkbox.js +4 -1
- package/lib/cjs/empty/index.js +1 -1
- package/lib/es/autoComplete/index.js +5 -2
- package/lib/es/cascader/index.js +40 -29
- package/lib/es/checkbox/checkbox.js +4 -1
- package/lib/es/empty/index.js +1 -1
- package/package.json +7 -7
- 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/empty/index.tsx
CHANGED
|
@@ -79,17 +79,17 @@ export default class Empty extends BaseComponent<EmptyProps, EmptyState> {
|
|
|
79
79
|
const { className, image, description, style, title, imageStyle, children, layout, darkModeImage } = this.props;
|
|
80
80
|
|
|
81
81
|
const alt = typeof description === 'string' ? description : 'empty';
|
|
82
|
-
const imgSrc = this.state.mode && darkModeImage ? darkModeImage : image;
|
|
82
|
+
const imgSrc = ((this.state.mode === 'dark') && darkModeImage) ? darkModeImage : image;
|
|
83
83
|
let imageNode = null;
|
|
84
84
|
if (typeof imgSrc === 'string') {
|
|
85
|
-
imageNode = <img alt={alt} src={imgSrc}
|
|
85
|
+
imageNode = <img alt={alt} src={imgSrc}/>;
|
|
86
86
|
} else if (imgSrc && 'id' in (imgSrc as any)) {
|
|
87
87
|
imageNode = (
|
|
88
88
|
<svg
|
|
89
89
|
// className={iconCls}
|
|
90
90
|
aria-hidden="true"
|
|
91
91
|
>
|
|
92
|
-
<use xlinkHref={`#${(imgSrc as any).id}`}
|
|
92
|
+
<use xlinkHref={`#${(imgSrc as any).id}`}/>
|
|
93
93
|
</svg>
|
|
94
94
|
);
|
|
95
95
|
} else {
|
|
@@ -227,7 +227,7 @@ class AutoComplete extends _baseComponent.default {
|
|
|
227
227
|
selection
|
|
228
228
|
} = this.state;
|
|
229
229
|
const useCustomTrigger = typeof triggerRender === 'function';
|
|
230
|
-
const outerProps = (0, _assign.default)({
|
|
230
|
+
const outerProps = (0, _assign.default)((0, _assign.default)({
|
|
231
231
|
style,
|
|
232
232
|
className: useCustomTrigger ? (0, _classnames.default)(className) : (0, _classnames.default)({
|
|
233
233
|
[prefixCls]: true,
|
|
@@ -236,7 +236,10 @@ class AutoComplete extends _baseComponent.default {
|
|
|
236
236
|
onClick: this.handleInputClick,
|
|
237
237
|
ref: this.triggerRef,
|
|
238
238
|
id
|
|
239
|
-
}, keyboardEventSet)
|
|
239
|
+
}, keyboardEventSet), {
|
|
240
|
+
// tooltip give tabindex 0 to children by default, autoComplete just need the input get focus, so outer div's tabindex set to -1
|
|
241
|
+
tabIndex: -1
|
|
242
|
+
});
|
|
240
243
|
const innerProps = {
|
|
241
244
|
disabled,
|
|
242
245
|
placeholder,
|
|
@@ -801,6 +801,33 @@ class Cascader extends _baseComponent.default {
|
|
|
801
801
|
return firstInProps || treeDataHasChange;
|
|
802
802
|
};
|
|
803
803
|
|
|
804
|
+
const getRealKeys = (realValue, keyEntities) => {
|
|
805
|
+
// normallizedValue is used to save the value in two-dimensional array format
|
|
806
|
+
let normallizedValue = [];
|
|
807
|
+
|
|
808
|
+
if ((0, _isArray.default)(realValue)) {
|
|
809
|
+
normallizedValue = (0, _isArray.default)(realValue[0]) ? realValue : [realValue];
|
|
810
|
+
} else {
|
|
811
|
+
if (realValue !== undefined) {
|
|
812
|
+
normallizedValue = [[realValue]];
|
|
813
|
+
}
|
|
814
|
+
} // formatValuePath is used to save value of valuePath
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
const formatValuePath = [];
|
|
818
|
+
(0, _forEach.default)(normallizedValue).call(normallizedValue, valueItem => {
|
|
819
|
+
const formatItem = onChangeWithObject ? (0, _map.default)(valueItem).call(valueItem, i => i === null || i === void 0 ? void 0 : i.value) : valueItem;
|
|
820
|
+
formatValuePath.push(formatItem);
|
|
821
|
+
}); // formatKeys is used to save key of value
|
|
822
|
+
|
|
823
|
+
const formatKeys = [];
|
|
824
|
+
(0, _forEach.default)(formatValuePath).call(formatValuePath, v => {
|
|
825
|
+
const formatKeyItem = (0, _util.findKeysForValues)(v, keyEntities);
|
|
826
|
+
!(0, _isEmpty2.default)(formatKeyItem) && formatKeys.push(formatKeyItem);
|
|
827
|
+
});
|
|
828
|
+
return formatKeys;
|
|
829
|
+
};
|
|
830
|
+
|
|
804
831
|
const needUpdateTreeData = needUpdate('treeData') || needUpdateData();
|
|
805
832
|
const needUpdateValue = needUpdate('value') || (0, _isEmpty2.default)(prevProps) && defaultValue;
|
|
806
833
|
|
|
@@ -817,31 +844,15 @@ class Cascader extends _baseComponent.default {
|
|
|
817
844
|
let realKeys = prevState.checkedKeys; // when data was updated
|
|
818
845
|
|
|
819
846
|
if (needUpdateValue) {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
}
|
|
830
|
-
} // formatValuePath is used to save value of valuePath
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
const formatValuePath = [];
|
|
834
|
-
(0, _forEach.default)(normallizedValue).call(normallizedValue, valueItem => {
|
|
835
|
-
const formatItem = onChangeWithObject ? (0, _map.default)(valueItem).call(valueItem, i => i === null || i === void 0 ? void 0 : i.value) : valueItem;
|
|
836
|
-
formatValuePath.push(formatItem);
|
|
837
|
-
}); // formatKeys is used to save key of value
|
|
838
|
-
|
|
839
|
-
const formatKeys = [];
|
|
840
|
-
(0, _forEach.default)(formatValuePath).call(formatValuePath, v => {
|
|
841
|
-
const formatKeyItem = (0, _util.findKeysForValues)(v, keyEntities);
|
|
842
|
-
!(0, _isEmpty2.default)(formatKeyItem) && formatKeys.push(formatKeyItem);
|
|
843
|
-
});
|
|
844
|
-
realKeys = formatKeys;
|
|
847
|
+
const realValue = needUpdate('value') ? value : defaultValue;
|
|
848
|
+
realKeys = getRealKeys(realValue, keyEntities);
|
|
849
|
+
} else {
|
|
850
|
+
// needUpdateValue is false
|
|
851
|
+
// if treeData is updated & Cascader is controlled, realKeys should be recalculated
|
|
852
|
+
if (needUpdateTreeData && 'value' in props) {
|
|
853
|
+
const realValue = value;
|
|
854
|
+
realKeys = getRealKeys(realValue, keyEntities);
|
|
855
|
+
}
|
|
845
856
|
}
|
|
846
857
|
|
|
847
858
|
if ((0, _isSet2.default)(realKeys)) {
|
|
@@ -123,7 +123,10 @@ class Checkbox extends _baseComponent.default {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
isInGroup() {
|
|
126
|
-
|
|
126
|
+
// Why do we need to determine whether there is a value in props?
|
|
127
|
+
// If there is no value in the props of the checkbox in the context of the checkboxGroup,
|
|
128
|
+
// it will be considered not to belong to the checkboxGroup。
|
|
129
|
+
return Boolean(this.context && this.context.checkboxGroup && 'value' in this.props);
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
focus() {
|
package/lib/cjs/empty/index.js
CHANGED
|
@@ -88,7 +88,7 @@ class Empty extends _baseComponent.default {
|
|
|
88
88
|
darkModeImage
|
|
89
89
|
} = this.props;
|
|
90
90
|
const alt = typeof description === 'string' ? description : 'empty';
|
|
91
|
-
const imgSrc = this.state.mode && darkModeImage ? darkModeImage : image;
|
|
91
|
+
const imgSrc = this.state.mode === 'dark' && darkModeImage ? darkModeImage : image;
|
|
92
92
|
let imageNode = null;
|
|
93
93
|
|
|
94
94
|
if (typeof imgSrc === 'string') {
|
|
@@ -195,7 +195,7 @@ class AutoComplete extends BaseComponent {
|
|
|
195
195
|
} = this.state;
|
|
196
196
|
const useCustomTrigger = typeof triggerRender === 'function';
|
|
197
197
|
|
|
198
|
-
const outerProps = _Object$assign({
|
|
198
|
+
const outerProps = _Object$assign(_Object$assign({
|
|
199
199
|
style,
|
|
200
200
|
className: useCustomTrigger ? cls(className) : cls({
|
|
201
201
|
[prefixCls]: true,
|
|
@@ -204,7 +204,10 @@ class AutoComplete extends BaseComponent {
|
|
|
204
204
|
onClick: this.handleInputClick,
|
|
205
205
|
ref: this.triggerRef,
|
|
206
206
|
id
|
|
207
|
-
}, keyboardEventSet)
|
|
207
|
+
}, keyboardEventSet), {
|
|
208
|
+
// tooltip give tabindex 0 to children by default, autoComplete just need the input get focus, so outer div's tabindex set to -1
|
|
209
|
+
tabIndex: -1
|
|
210
|
+
});
|
|
208
211
|
|
|
209
212
|
const innerProps = {
|
|
210
213
|
disabled,
|
package/lib/es/cascader/index.js
CHANGED
|
@@ -742,6 +742,37 @@ class Cascader extends BaseComponent {
|
|
|
742
742
|
return firstInProps || treeDataHasChange;
|
|
743
743
|
};
|
|
744
744
|
|
|
745
|
+
const getRealKeys = (realValue, keyEntities) => {
|
|
746
|
+
// normallizedValue is used to save the value in two-dimensional array format
|
|
747
|
+
let normallizedValue = [];
|
|
748
|
+
|
|
749
|
+
if (_Array$isArray(realValue)) {
|
|
750
|
+
normallizedValue = _Array$isArray(realValue[0]) ? realValue : [realValue];
|
|
751
|
+
} else {
|
|
752
|
+
if (realValue !== undefined) {
|
|
753
|
+
normallizedValue = [[realValue]];
|
|
754
|
+
}
|
|
755
|
+
} // formatValuePath is used to save value of valuePath
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
const formatValuePath = [];
|
|
759
|
+
|
|
760
|
+
_forEachInstanceProperty(normallizedValue).call(normallizedValue, valueItem => {
|
|
761
|
+
const formatItem = onChangeWithObject ? _mapInstanceProperty(valueItem).call(valueItem, i => i === null || i === void 0 ? void 0 : i.value) : valueItem;
|
|
762
|
+
formatValuePath.push(formatItem);
|
|
763
|
+
}); // formatKeys is used to save key of value
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
const formatKeys = [];
|
|
767
|
+
|
|
768
|
+
_forEachInstanceProperty(formatValuePath).call(formatValuePath, v => {
|
|
769
|
+
const formatKeyItem = findKeysForValues(v, keyEntities);
|
|
770
|
+
!_isEmpty(formatKeyItem) && formatKeys.push(formatKeyItem);
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
return formatKeys;
|
|
774
|
+
};
|
|
775
|
+
|
|
745
776
|
const needUpdateTreeData = needUpdate('treeData') || needUpdateData();
|
|
746
777
|
const needUpdateValue = needUpdate('value') || _isEmpty(prevProps) && defaultValue;
|
|
747
778
|
|
|
@@ -758,35 +789,15 @@ class Cascader extends BaseComponent {
|
|
|
758
789
|
let realKeys = prevState.checkedKeys; // when data was updated
|
|
759
790
|
|
|
760
791
|
if (needUpdateValue) {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
}
|
|
771
|
-
} // formatValuePath is used to save value of valuePath
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
const formatValuePath = [];
|
|
775
|
-
|
|
776
|
-
_forEachInstanceProperty(normallizedValue).call(normallizedValue, valueItem => {
|
|
777
|
-
const formatItem = onChangeWithObject ? _mapInstanceProperty(valueItem).call(valueItem, i => i === null || i === void 0 ? void 0 : i.value) : valueItem;
|
|
778
|
-
formatValuePath.push(formatItem);
|
|
779
|
-
}); // formatKeys is used to save key of value
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
const formatKeys = [];
|
|
783
|
-
|
|
784
|
-
_forEachInstanceProperty(formatValuePath).call(formatValuePath, v => {
|
|
785
|
-
const formatKeyItem = findKeysForValues(v, keyEntities);
|
|
786
|
-
!_isEmpty(formatKeyItem) && formatKeys.push(formatKeyItem);
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
realKeys = formatKeys;
|
|
792
|
+
const realValue = needUpdate('value') ? value : defaultValue;
|
|
793
|
+
realKeys = getRealKeys(realValue, keyEntities);
|
|
794
|
+
} else {
|
|
795
|
+
// needUpdateValue is false
|
|
796
|
+
// if treeData is updated & Cascader is controlled, realKeys should be recalculated
|
|
797
|
+
if (needUpdateTreeData && 'value' in props) {
|
|
798
|
+
const realValue = value;
|
|
799
|
+
realKeys = getRealKeys(realValue, keyEntities);
|
|
800
|
+
}
|
|
790
801
|
}
|
|
791
802
|
|
|
792
803
|
if (_isSet(realKeys)) {
|
|
@@ -98,7 +98,10 @@ class Checkbox extends BaseComponent {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
isInGroup() {
|
|
101
|
-
|
|
101
|
+
// Why do we need to determine whether there is a value in props?
|
|
102
|
+
// If there is no value in the props of the checkbox in the context of the checkboxGroup,
|
|
103
|
+
// it will be considered not to belong to the checkboxGroup。
|
|
104
|
+
return Boolean(this.context && this.context.checkboxGroup && 'value' in this.props);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
focus() {
|
package/lib/es/empty/index.js
CHANGED
|
@@ -67,7 +67,7 @@ export default class Empty extends BaseComponent {
|
|
|
67
67
|
darkModeImage
|
|
68
68
|
} = this.props;
|
|
69
69
|
const alt = typeof description === 'string' ? description : 'empty';
|
|
70
|
-
const imgSrc = this.state.mode && darkModeImage ? darkModeImage : image;
|
|
70
|
+
const imgSrc = this.state.mode === 'dark' && darkModeImage ? darkModeImage : image;
|
|
71
71
|
let imageNode = null;
|
|
72
72
|
|
|
73
73
|
if (typeof imgSrc === 'string') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@douyinfe/semi-ui",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/es/index.js",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@babel/runtime-corejs3": "^7.15.4",
|
|
17
17
|
"@douyinfe/semi-animation": "2.12.0",
|
|
18
|
-
"@douyinfe/semi-animation-react": "2.17.
|
|
19
|
-
"@douyinfe/semi-foundation": "2.17.
|
|
20
|
-
"@douyinfe/semi-icons": "2.17.
|
|
18
|
+
"@douyinfe/semi-animation-react": "2.17.1",
|
|
19
|
+
"@douyinfe/semi-foundation": "2.17.1",
|
|
20
|
+
"@douyinfe/semi-icons": "2.17.1",
|
|
21
21
|
"@douyinfe/semi-illustrations": "2.15.0",
|
|
22
|
-
"@douyinfe/semi-theme-default": "2.17.
|
|
22
|
+
"@douyinfe/semi-theme-default": "2.17.1",
|
|
23
23
|
"async-validator": "^3.5.0",
|
|
24
24
|
"classnames": "^2.2.6",
|
|
25
25
|
"copy-text-to-clipboard": "^2.1.1",
|
|
@@ -66,13 +66,13 @@
|
|
|
66
66
|
],
|
|
67
67
|
"author": "",
|
|
68
68
|
"license": "MIT",
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "e2dfadcc7f24b9af6cab08b64ac0ead052219961",
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@babel/plugin-proposal-decorators": "^7.15.8",
|
|
72
72
|
"@babel/plugin-transform-runtime": "^7.15.8",
|
|
73
73
|
"@babel/preset-env": "^7.15.8",
|
|
74
74
|
"@babel/preset-react": "^7.14.5",
|
|
75
|
-
"@douyinfe/semi-scss-compile": "2.17.
|
|
75
|
+
"@douyinfe/semi-scss-compile": "2.17.1",
|
|
76
76
|
"@storybook/addon-knobs": "^6.3.1",
|
|
77
77
|
"@types/lodash": "^4.14.176",
|
|
78
78
|
"@types/react": ">=16.0.0",
|
|
@@ -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';
|