@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/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
- // normallizedValue is used to save the value in two-dimensional array format
821
- let normallizedValue = [];
822
- const realValue = needUpdate('value') ? value : defaultValue; // eslint-disable-next-line max-depth
823
-
824
- if ((0, _isArray.default)(realValue)) {
825
- normallizedValue = (0, _isArray.default)(realValue[0]) ? realValue : [realValue];
826
- } else {
827
- if (realValue !== undefined) {
828
- normallizedValue = [[realValue]];
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
- return Boolean(this.context && this.context.checkboxGroup);
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() {
@@ -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,
@@ -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
- // normallizedValue is used to save the value in two-dimensional array format
762
- let normallizedValue = [];
763
- const realValue = needUpdate('value') ? value : defaultValue; // eslint-disable-next-line max-depth
764
-
765
- if (_Array$isArray(realValue)) {
766
- normallizedValue = _Array$isArray(realValue[0]) ? realValue : [realValue];
767
- } else {
768
- if (realValue !== undefined) {
769
- normallizedValue = [[realValue]];
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
- return Boolean(this.context && this.context.checkboxGroup);
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() {
@@ -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.0-beta.0",
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.0-beta.0",
19
- "@douyinfe/semi-foundation": "2.17.0-beta.0",
20
- "@douyinfe/semi-icons": "2.17.0-beta.0",
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.0-beta.0",
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": "471474bb6fe0a743bc3daba532279969cc9374a5",
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.0-beta.0",
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;
@@ -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 } from './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';