@douyinfe/semi-ui 2.3.0-beta.0 → 2.4.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.
Files changed (97) hide show
  1. package/_base/_story/a11y.scss +0 -1
  2. package/_base/_story/index.scss +2 -5
  3. package/avatar/avatarGroup.tsx +1 -1
  4. package/avatar/index.tsx +0 -4
  5. package/button/__test__/button.test.js +1 -1
  6. package/checkbox/_story/checkbox.stories.js +2 -2
  7. package/collapse/index.tsx +1 -1
  8. package/collapse/item.tsx +1 -3
  9. package/datePicker/_story/RenderDate/index.js +13 -3
  10. package/datePicker/_story/RenderFullDate/index.js +36 -14
  11. package/datePicker/_story/RenderFullDate/index.scss +1 -1
  12. package/datePicker/_story/datePicker.stories.js +19 -11
  13. package/datePicker/_story/v2/PanelOpen.jsx +39 -0
  14. package/datePicker/_story/v2/index.js +2 -1
  15. package/dist/css/semi.css +33 -9
  16. package/dist/css/semi.min.css +1 -1
  17. package/dist/umd/semi-ui.js +96 -57
  18. package/dist/umd/semi-ui.js.map +1 -1
  19. package/dist/umd/semi-ui.min.js +1 -1
  20. package/dist/umd/semi-ui.min.js.map +1 -1
  21. package/dropdown/index.tsx +11 -3
  22. package/empty/index.tsx +1 -1
  23. package/input/textarea.tsx +5 -3
  24. package/inputNumber/__test__/inputNumber.test.js +36 -8
  25. package/inputNumber/index.tsx +2 -1
  26. package/lib/cjs/avatar/avatarGroup.js +1 -2
  27. package/lib/cjs/avatar/index.js +1 -6
  28. package/lib/cjs/collapse/index.js +1 -2
  29. package/lib/cjs/collapse/item.js +1 -5
  30. package/lib/cjs/dropdown/index.d.ts +10 -3
  31. package/lib/cjs/empty/index.js +1 -2
  32. package/lib/cjs/input/textarea.js +4 -2
  33. package/lib/cjs/inputNumber/index.js +3 -2
  34. package/lib/cjs/list/index.d.ts +4 -4
  35. package/lib/cjs/navigation/Item.js +1 -1
  36. package/lib/cjs/navigation/SubNav.js +1 -1
  37. package/lib/cjs/scrollList/scrollItem.d.ts +5 -1
  38. package/lib/cjs/scrollList/scrollItem.js +7 -0
  39. package/lib/cjs/select/index.js +1 -1
  40. package/lib/cjs/sideSheet/SideSheetContent.js +5 -9
  41. package/lib/cjs/spin/icon.js +2 -1
  42. package/lib/cjs/table/Table.js +9 -5
  43. package/lib/cjs/timePicker/TimePicker.d.ts +2 -0
  44. package/lib/cjs/timePicker/TimePicker.js +2 -3
  45. package/lib/cjs/timePicker/index.d.ts +1 -0
  46. package/lib/cjs/tooltip/index.js +1 -1
  47. package/lib/cjs/tree/treeNode.js +10 -1
  48. package/lib/cjs/treeSelect/index.js +11 -3
  49. package/lib/cjs/typography/util.js +0 -1
  50. package/lib/cjs/upload/fileCard.js +3 -3
  51. package/lib/es/avatar/avatarGroup.js +1 -2
  52. package/lib/es/avatar/index.js +1 -6
  53. package/lib/es/collapse/index.js +1 -2
  54. package/lib/es/collapse/item.js +1 -5
  55. package/lib/es/dropdown/index.d.ts +10 -3
  56. package/lib/es/empty/index.js +1 -2
  57. package/lib/es/input/textarea.js +4 -2
  58. package/lib/es/inputNumber/index.js +3 -2
  59. package/lib/es/list/index.d.ts +4 -4
  60. package/lib/es/navigation/Item.js +1 -1
  61. package/lib/es/navigation/SubNav.js +1 -1
  62. package/lib/es/scrollList/scrollItem.d.ts +5 -1
  63. package/lib/es/scrollList/scrollItem.js +7 -0
  64. package/lib/es/select/index.js +1 -1
  65. package/lib/es/sideSheet/SideSheetContent.js +5 -9
  66. package/lib/es/spin/icon.js +2 -1
  67. package/lib/es/table/Table.js +9 -5
  68. package/lib/es/timePicker/TimePicker.d.ts +2 -0
  69. package/lib/es/timePicker/TimePicker.js +2 -3
  70. package/lib/es/timePicker/index.d.ts +1 -0
  71. package/lib/es/tooltip/index.js +2 -2
  72. package/lib/es/tree/treeNode.js +9 -1
  73. package/lib/es/treeSelect/index.js +12 -4
  74. package/lib/es/typography/util.js +0 -1
  75. package/lib/es/upload/fileCard.js +3 -3
  76. package/list/index.tsx +5 -5
  77. package/navigation/Item.tsx +1 -1
  78. package/navigation/SubNav.tsx +1 -1
  79. package/package.json +8 -8
  80. package/scrollList/scrollItem.tsx +10 -3
  81. package/select/index.tsx +6 -1
  82. package/sideSheet/SideSheetContent.tsx +6 -8
  83. package/spin/icon.tsx +2 -1
  84. package/table/Table.tsx +9 -6
  85. package/table/_story/table.stories.js +2 -0
  86. package/table/_story/v2/FixedColumnsChange/index.jsx +104 -0
  87. package/table/_story/v2/FixedZIndex/index.jsx +87 -0
  88. package/timePicker/TimePicker.tsx +3 -1
  89. package/timePicker/__test__/timePicker.test.js +42 -3
  90. package/timePicker/_story/timepicker.stories.js +18 -0
  91. package/tooltip/index.tsx +3 -2
  92. package/tree/treeNode.tsx +9 -2
  93. package/treeSelect/__test__/treeSelect.test.js +157 -0
  94. package/treeSelect/index.tsx +21 -12
  95. package/typography/_story/typography.stories.js +8 -0
  96. package/typography/util.tsx +0 -1
  97. package/upload/fileCard.tsx +2 -2
@@ -87,7 +87,7 @@ export default class SideSheetContent extends React.PureComponent<SideSheetConte
87
87
  let header, closer;
88
88
  if (title) {
89
89
  header = (
90
- <div className={`${prefixCls}-title`} aria-label={'Sidesheet title'}>
90
+ <div className={`${prefixCls}-title`}>
91
91
  {this.props.title}
92
92
  </div>
93
93
  );
@@ -106,7 +106,7 @@ export default class SideSheetContent extends React.PureComponent<SideSheetConte
106
106
  );
107
107
  }
108
108
  return (
109
- <div className={`${prefixCls}-header`} role={'heading'} style={{ ...headerStyle }}>
109
+ <div className={`${prefixCls}-header`} role={'heading'} aria-level={1} style={{ ...headerStyle }}>
110
110
  {header}
111
111
  {closer}
112
112
  </div>
@@ -137,13 +137,13 @@ export default class SideSheetContent extends React.PureComponent<SideSheetConte
137
137
  style={{ ...props.style, ...style }}
138
138
  // id={this.dialogId}
139
139
  >
140
- <div className={`${prefixCls}-content`} aria-label={`Sidesheet content`}>
140
+ <div className={`${prefixCls}-content`}>
141
141
  {header}
142
- <div className={`${prefixCls}-body`} aria-label={`Sidesheet body`} style={props.bodyStyle}>
142
+ <div className={`${prefixCls}-body`} style={props.bodyStyle}>
143
143
  {props.children}
144
144
  </div>
145
145
  {props.footer ? (
146
- <div className={`${prefixCls}-footer`} aria-label={`Sidesheet footer`}>
146
+ <div className={`${prefixCls}-footer`}>
147
147
  {props.footer}
148
148
  </div>
149
149
  ) : null}
@@ -167,9 +167,7 @@ export default class SideSheetContent extends React.PureComponent<SideSheetConte
167
167
  wrapperStyle.width = width;
168
168
  }
169
169
  return (
170
- <div className={wrapperCls}
171
- style={wrapperStyle}
172
- aria-label={this.props['aria-label']}>
170
+ <div className={wrapperCls} style={wrapperStyle}>
173
171
  {this.getMaskElement()}
174
172
  {this.getDialogElement()}
175
173
  </div>
package/spin/icon.tsx CHANGED
@@ -29,7 +29,8 @@ function Icon(props: IconProps = {}) {
29
29
  viewBox="0 0 36 36"
30
30
  version="1.1"
31
31
  xmlns="http://www.w3.org/2000/svg"
32
- aria-label="spin"
32
+ aria-hidden
33
+ data-icon="spin"
33
34
  >
34
35
  <defs>
35
36
  <linearGradient x1="0%" y1="100%" x2="100%" y2="100%" id={id}>
package/table/Table.tsx CHANGED
@@ -534,7 +534,6 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
534
534
  this.foundation.initExpandedRowKeys({ groups: stateGroups });
535
535
  }
536
536
 
537
-
538
537
  /**
539
538
  * After dataSource is updated || (cachedColumns || cachedChildren updated)
540
539
  * 1. Cache filtered sorted data and a collection of data rows, stored in this
@@ -547,17 +546,20 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
547
546
  const filteredSortedDataSource = this.foundation.getFilteredSortedDataSource(_dataSource, stateQueries);
548
547
  this.foundation.setCachedFilteredSortedDataSource(filteredSortedDataSource);
549
548
  states.dataSource = filteredSortedDataSource;
550
- // when dataSource has change, should reset currentPage
551
- states.pagination = isObject(statePagination) ? {
552
- ...statePagination,
553
- currentPage: isObject(propsPagination) && propsPagination.currentPage ? propsPagination.currentPage : 1,
554
- } : statePagination;
555
549
 
556
550
  if (this.props.groupBy) {
557
551
  states.groups = null;
558
552
  }
559
553
  }
560
554
 
555
+ // when dataSource has change, should reset currentPage
556
+ if (dataSource !== prevProps.dataSource) {
557
+ states.pagination = isObject(statePagination) ? {
558
+ ...statePagination,
559
+ currentPage: isObject(propsPagination) && propsPagination.currentPage ? propsPagination.currentPage : 1,
560
+ } : statePagination;
561
+ }
562
+
561
563
  if (Object.keys(states).length) {
562
564
  const {
563
565
  // eslint-disable-next-line @typescript-eslint/no-shadow
@@ -1372,6 +1374,7 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
1372
1374
  <div
1373
1375
  ref={this.rootWrapRef}
1374
1376
  className={classnames(className, `${prefixCls}-wrapper`)}
1377
+ data-column-fixed={anyColumnFixed}
1375
1378
  style={wrapStyle}
1376
1379
  id={id}
1377
1380
  >
@@ -76,6 +76,8 @@ export { default as ScrollBar } from './ScrollBar';
76
76
  export { default as TableSpan } from './TableSpan';
77
77
  export { default as FixRenderReturnProps } from './FixRenderReturnProps';
78
78
  export { default as WarnColumnWithoutDataIndex } from './WarnColumnWithoutDataIndex';
79
+ export { default as FixedColumnsChange } from './v2/FixedColumnsChange';
80
+ export { default as FixedZIndex } from './v2/FixedZIndex';
79
81
 
80
82
  // empty table
81
83
 
@@ -0,0 +1,104 @@
1
+ import React, { useState, useMemo } from 'react';
2
+ import { Table, Avatar } from '@douyinfe/semi-ui';
3
+ import * as dateFns from 'date-fns';
4
+
5
+ const DAY = 24 * 60 * 60 * 1000;
6
+ const figmaIconUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/figma-icon.png';
7
+
8
+ const getData = () => {
9
+ const data = [];
10
+ for (let i = 0; i < 46; i++) {
11
+ const isSemiDesign = i % 2 === 0;
12
+ const randomNumber = (i * 1000) % 199;
13
+ data.push({
14
+ key: '' + i,
15
+ name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi Pro 设计稿${i}.fig`,
16
+ owner: isSemiDesign ? '姜鹏志' : '郝宣',
17
+ size: randomNumber,
18
+ updateTime: new Date('2022-01-01').valueOf() + randomNumber * DAY,
19
+ avatarBg: isSemiDesign ? 'grey' : 'red'
20
+ });
21
+ }
22
+ return data;
23
+ };
24
+
25
+ const data = getData();
26
+
27
+ /**
28
+ * fix https://github.com/DouyinFE/semi-design/issues/381
29
+ */
30
+ App.storyName = 'fixed columns change';
31
+ function App() {
32
+ const [dataSource, setData] = useState(data);
33
+ const [rowKeys, setRowKeys] = useState([]);
34
+
35
+ const columns = [
36
+ {
37
+ title: '标题',
38
+ dataIndex: 'name',
39
+ width: 400,
40
+ render: (text, record, index) => {
41
+ return (
42
+ <div>
43
+ <Avatar size="small" shape="square" src={figmaIconUrl} style={{ marginRight: 12 }}></Avatar>
44
+ {text}
45
+ </div>
46
+ );
47
+ },
48
+ filters: [
49
+ {
50
+ text: 'Semi Design 设计稿',
51
+ value: 'Semi Design 设计稿',
52
+ },
53
+ {
54
+ text: 'Semi Pro 设计稿',
55
+ value: 'Semi Pro 设计稿',
56
+ },
57
+ ],
58
+ onFilter: (value, record) => record.name.includes(value),
59
+ },
60
+ {
61
+ title: '大小',
62
+ dataIndex: 'size',
63
+ sorter: (a, b) => a.size - b.size > 0 ? 1 : -1,
64
+ render: (text) => `${text} KB`
65
+ },
66
+ {
67
+ title: '所有者',
68
+ dataIndex: 'owner',
69
+ render: (text, record, index) => {
70
+ return (
71
+ <div>
72
+ <Avatar size="small" color={record.avatarBg} style={{ marginRight: 4 }}>{typeof text === 'string' && text.slice(0, 1)}</Avatar>
73
+ {text}
74
+ </div>
75
+ );
76
+ }
77
+ },
78
+ {
79
+ title: '更新日期',
80
+ dataIndex: 'updateTime',
81
+ sorter: (a, b) => a.updateTime - b.updateTime > 0 ? 1 : -1,
82
+ render: (value) => {
83
+ return dateFns.format(new Date(value), 'yyyy-MM-dd');
84
+ }
85
+ }
86
+ ];
87
+
88
+ return (
89
+ <Table
90
+ columns={columns}
91
+ dataSource={dataSource}
92
+ pagination={{
93
+ pageSize: 5,
94
+ }}
95
+ rowSelection={{
96
+ onChange: rowKeys => setRowKeys(rowKeys),
97
+ selectedRowKeys: rowKeys,
98
+ }}
99
+ scroll={{ y: 300 }}
100
+ />
101
+ );
102
+ }
103
+
104
+ export default App;
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { Table, Tooltip, Tag } from '@douyinfe/semi-ui';
3
+
4
+ App.storyName = 'fixed z-index bug';
5
+ export default function App() {
6
+ const columns = [
7
+ {
8
+ title: 'Name',
9
+ dataIndex: 'name',
10
+ width: 150,
11
+ fixed: true,
12
+ filters: [
13
+ {
14
+ text: 'King 3',
15
+ value: 'King 3',
16
+ },
17
+ {
18
+ text: 'King 4',
19
+ value: 'King 4',
20
+ },
21
+ ],
22
+ onFilter: (value, record) => record.name.includes(value),
23
+ },
24
+ {
25
+ title: 'Age',
26
+ dataIndex: 'age',
27
+ width: 150,
28
+ sorter: (a, b) => (a.age - b.age > 0 ? 1 : -1),
29
+ },
30
+ {
31
+ title: 'Address',
32
+ width: 200,
33
+ dataIndex: 'address',
34
+ },
35
+ {
36
+ title: 'Description',
37
+ // width: 400,
38
+ dataIndex: 'description',
39
+ },
40
+ {
41
+ fixed: 'right',
42
+ width: 250,
43
+ render: (text, record) => <Tooltip content={record.description}><Tag color="green">Show Info</Tag></Tooltip>
44
+ }
45
+ ];
46
+
47
+ let data = [];
48
+
49
+ const rowSelection = {
50
+ onChange: (selectedRowKeys, selectedRows) => {
51
+ // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
52
+ },
53
+ getCheckboxProps: record => ({
54
+ disabled: record.name === 'Michael James', // Column configuration not to be checked
55
+ name: record.name,
56
+ }),
57
+ // fixed: true,
58
+ };
59
+
60
+ for (let i = 0; i < 46; i++) {
61
+ let age = (i * 1000) % 149;
62
+ let name = `Edward King ${i}`;
63
+ data.push({
64
+ key: `${ i}`,
65
+ name,
66
+ age,
67
+ address: `London, Park Lane no. ${i}`,
68
+ description: `My name is ${name}, I am ${age} years old, living in New York No. ${i + 1} Lake Park.`,
69
+ });
70
+ }
71
+
72
+ const scroll = { y: 300, x: 1500 };
73
+
74
+ return (
75
+ <div style={{ position: 'relative', height: '100vh' }}>
76
+ <div style={{ height: 60, background: 'red', position: 'absolute', top: 0, left: 0, right: 0, zIndex: 2 }}>
77
+ Fixed Header
78
+ </div>
79
+ <Table
80
+ columns={columns}
81
+ dataSource={data}
82
+ scroll={scroll}
83
+ rowSelection={rowSelection}
84
+ />
85
+ </div>
86
+ );
87
+ }
@@ -90,6 +90,7 @@ export type TimePickerProps = {
90
90
  zIndex?: number | string;
91
91
  onBlur?: React.FocusEventHandler<HTMLInputElement>;
92
92
  onChange?: TimePickerAdapter['notifyChange'];
93
+ onChangeWithDateFirst?: boolean;
93
94
  onFocus?: React.FocusEventHandler<HTMLInputElement>;
94
95
  onOpenChange?: (open: boolean) => void;
95
96
  };
@@ -187,6 +188,7 @@ export default class TimePicker extends BaseComponent<TimePickerProps, TimePicke
187
188
  onFocus: noop,
188
189
  onBlur: noop,
189
190
  onChange: noop,
191
+ onChangeWithDateFirst: true,
190
192
  use12Hours: false,
191
193
  focusOnOpen: false,
192
194
  onKeyDown: noop,
@@ -257,7 +259,7 @@ export default class TimePicker extends BaseComponent<TimePickerProps, TimePicke
257
259
  }
258
260
  },
259
261
  notifyOpenChange: (...args) => this.props.onOpenChange(...args),
260
- notifyChange: (...args) => this.props.onChange && this.props.onChange(...args),
262
+ notifyChange: (agr1, arg2) => this.props.onChange && this.props.onChange(agr1, arg2),
261
263
  notifyFocus: (...args) => this.props.onFocus && this.props.onFocus(...args),
262
264
  notifyBlur: (...args) => this.props.onBlur && this.props.onBlur(...args),
263
265
  isRangePicker: () => this.props.type === strings.TYPE_TIME_RANGE_PICKER,
@@ -22,11 +22,13 @@ describe(`TimePicker`, () => {
22
22
  const defaultMinute = 24;
23
23
  const defaultSeconds = 18;
24
24
 
25
- const onFoucs = sinon.spy();
25
+ const onFocus = sinon.spy();
26
+ const onChange = sinon.spy();
26
27
 
27
28
  const elem = mount(
28
29
  <TimePicker
29
- onFocus={onFoucs}
30
+ onChange={onChange}
31
+ onFocus={onFocus}
30
32
  panelHeader={<strong>Select Time</strong>}
31
33
  locale={Locale.TimePicker}
32
34
  localeCode={Locale.code}
@@ -59,7 +61,7 @@ describe(`TimePicker`, () => {
59
61
  // focus
60
62
  elem.find(`input`).simulate('focus');
61
63
  await sleep(200);
62
- expect(onFoucs.calledOnce).toBeTruthy();
64
+ expect(onFocus.calledOnce).toBeTruthy();
63
65
 
64
66
  // input value
65
67
  const newInputHour = 10;
@@ -82,6 +84,12 @@ describe(`TimePicker`, () => {
82
84
 
83
85
  await sleep(200);
84
86
  expect(elem.state('open')).toBe(false);
87
+
88
+ expect(onChange.called).toBeTruthy();
89
+ const args = onChange.getCall(0).args;
90
+ expect(args[0] instanceof Date).toBe(true);
91
+ expect(typeof args[1]).toBe('string');
92
+ elem.unmount();
85
93
  });
86
94
 
87
95
  it(`test controlled value`, async () => {
@@ -113,6 +121,7 @@ describe(`TimePicker`, () => {
113
121
  let currentDate0 = elem0.state('value')[0];
114
122
 
115
123
  expect(currentDate0.getMinutes()).toBe(defaultMinute);
124
+ elem0.unmount();
116
125
  });
117
126
 
118
127
  it(`test controlled value with onchange`, async () => {
@@ -149,6 +158,7 @@ describe(`TimePicker`, () => {
149
158
 
150
159
  let currentDate1 = elem1.state('value')[0];
151
160
  expect(currentDate1.getMinutes()).toBe(newInputMinute);
161
+ elem1.unmount();
152
162
  });
153
163
 
154
164
  it(`test controlled open`, async () => {
@@ -227,6 +237,7 @@ describe(`TimePicker`, () => {
227
237
  nextSelectedLi.simulate('click');
228
238
  await sleep(200);
229
239
  expect(elem.state('value')[0].getHours()).toBe(newHour);
240
+ elem.unmount();
230
241
  });
231
242
 
232
243
  it('test isTimeFormatLike function', () => {
@@ -279,5 +290,33 @@ describe(`TimePicker`, () => {
279
290
  const args = onChange.getCall(0).args;
280
291
  expect(args[0]).toBe(undefined);
281
292
  expect(args[1]).toBe('');
293
+ elem.unmount();
294
+ });
295
+
296
+ it('test onChangeWithDateFirst=false', async () => {
297
+ const onChange = sinon.spy();
298
+ let props = {
299
+ defaultValue: "10:23:15",
300
+ onChange,
301
+ defaultOpen: true,
302
+ onChangeWithDateFirst: false,
303
+ autofocus: true,
304
+ locale: Locale.TimePicker,
305
+ localeCode: Locale.code,
306
+ scrollItemProps: { cycled: false }
307
+ };
308
+ const elem = mount(<TimePicker {...props} />);
309
+ // click minute
310
+ const minuteUl = elem.find(`.${BASE_CLASS_PREFIX}-timepicker-panel-list-minute .${BASE_CLASS_PREFIX}-scrolllist-list-outer ul`);
311
+ const minuteLis = minuteUl.find(`li`);
312
+
313
+ minuteUl.simulate('click', { target: minuteLis.at(0).getDOMNode(), nativeEvent: null });
314
+ await sleep(200);
315
+
316
+ expect(onChange.called).toBeTruthy();
317
+ const args = onChange.getCall(0).args;
318
+ expect(typeof args[0]).toBe('string');
319
+ expect(args[1] instanceof Date).toBe(true);
320
+ elem.unmount();
282
321
  });
283
322
  });
@@ -262,3 +262,21 @@ export const ShowClear = () => (
262
262
  />
263
263
  </>
264
264
  );
265
+
266
+
267
+ export const TimePickerWithOnChangeWithDateFirst = () => {
268
+ return (
269
+ <div>
270
+ onChangeWithDateFirst=true (default)
271
+ <TimePicker onChange={(...val) => console.log(...val)} />
272
+ <br />
273
+ onChangeWithDateFirst=false
274
+ <TimePicker onChangeWithDateFirst={false} onChange={(...val) => console.log(...val)} />
275
+
276
+ </div>
277
+ );
278
+ };
279
+
280
+ TimePickerWithOnChangeWithDateFirst.story = {
281
+ name: 'OnChangeWithDateFirst',
282
+ };
package/tooltip/index.tsx CHANGED
@@ -12,7 +12,7 @@ import { ArrayElement } from '@douyinfe/semi-foundation/utils/type';
12
12
  import { convertDOMRectToObject, DOMRectLikeType } from '@douyinfe/semi-foundation/utils/dom';
13
13
  import TooltipFoundation, { TooltipAdapter, Position, PopupContainerDOMRect } from '@douyinfe/semi-foundation/tooltip/foundation';
14
14
  import { strings, cssClasses, numbers } from '@douyinfe/semi-foundation/tooltip/constants';
15
- import { getUuidv4 } from '@douyinfe/semi-foundation/utils/uuid';
15
+ import { getUuidShort } from '@douyinfe/semi-foundation/utils/uuid';
16
16
  import '@douyinfe/semi-foundation/tooltip/tooltip.scss';
17
17
 
18
18
  import BaseComponent, { BaseProps } from '../_base/baseComponent';
@@ -174,7 +174,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
174
174
  placement: props.position || 'top',
175
175
  transitionStyle: {},
176
176
  isPositionUpdated: false,
177
- id: getUuidv4(), // auto generate id, will be used by children.aria-descriptionby & content.id, improve a11y
177
+ id: getUuidShort(), // auto generate id, will be used by children.aria-describedby & content.id, improve a11y
178
178
  };
179
179
  this.foundation = new TooltipFoundation(this.adapter);
180
180
  this.eventManager = new Event();
@@ -540,6 +540,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
540
540
 
541
541
  return (
542
542
  <Portal getPopupContainer={this.props.getPopupContainer} style={{ zIndex }}>
543
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
543
544
  <div
544
545
  className={`${BASE_CLASS_PREFIX}-portal-inner`}
545
546
  style={portalInnerStyle}
package/tree/treeNode.tsx CHANGED
@@ -3,7 +3,7 @@ import cls from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
4
  import { cssClasses } from '@douyinfe/semi-foundation/tree/constants';
5
5
  import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
6
- import { debounce, isFunction, isString, get } from 'lodash';
6
+ import { debounce, isFunction, isString, get, isEmpty } from 'lodash';
7
7
  import { IconTreeTriangleDown, IconFile, IconFolder, IconFolderOpen } from '@douyinfe/semi-icons';
8
8
  import { Checkbox } from '../checkbox';
9
9
  import TreeContext from './treeContext';
@@ -392,7 +392,14 @@ export default class TreeNode extends PureComponent<TreeNodeProps, TreeNodeState
392
392
  ...dragProps
393
393
  });
394
394
  } else {
395
- return customLabel;
395
+ if (isEmpty(style)) {
396
+ return customLabel;
397
+ } else {
398
+ // In virtualization, props.style will contain location information
399
+ return React.cloneElement(customLabel, {
400
+ style: { ...get(customLabel, ['props', 'style']), ...style }
401
+ });
402
+ }
396
403
  }
397
404
  }
398
405
  const labelCls = cls(`${prefixcls}-label`, {
@@ -97,6 +97,26 @@ const treeData2 = [
97
97
  }
98
98
  ];
99
99
 
100
+ const treeData3 = [
101
+ {
102
+ label: '亚洲',
103
+ value: 'Asia',
104
+ key: '0',
105
+ children: [
106
+ {
107
+ label: '中国',
108
+ value: 'China',
109
+ key: '0-0',
110
+ },
111
+ ],
112
+ },
113
+ {
114
+ label: '北美洲',
115
+ value: 'North America',
116
+ key: '1',
117
+ }
118
+ ];
119
+
100
120
  let commonProps = {
101
121
  motion: false,
102
122
  motionExpand: false,
@@ -780,4 +800,141 @@ describe('TreeSelect', () => {
780
800
  done();
781
801
  }, 100);
782
802
  });
803
+
804
+ it('treeData is updated should not clear value when uncontrolled mode and single selection', () => {
805
+ const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
806
+ const treeSelect = getTreeSelect({
807
+ defaultExpandAll: true
808
+ });
809
+ treeSelect
810
+ .find(`.${BASE_CLASS_PREFIX}-tree-option-list .${BASE_CLASS_PREFIX}-tree-option`)
811
+ .at(2)
812
+ .simulate('click', nativeEvent);
813
+ expect(
814
+ treeSelect
815
+ .find(`.${BASE_CLASS_PREFIX}-tree-select .${BASE_CLASS_PREFIX}-tree-select-selection span`)
816
+ .getDOMNode()
817
+ .textContent
818
+ ).toEqual('北京');
819
+ treeSelect.setProps({ treeData: treeChildren});
820
+ treeSelect.update();
821
+ expect(
822
+ treeSelect
823
+ .find(`.${BASE_CLASS_PREFIX}-tree-select .${BASE_CLASS_PREFIX}-tree-select-selection span`)
824
+ .getDOMNode()
825
+ .textContent
826
+ ).toEqual('北京');
827
+ treeSelect.setProps({ treeData: treeData2});
828
+ treeSelect.update();
829
+ expect(
830
+ treeSelect
831
+ .find(`.${BASE_CLASS_PREFIX}-tree-select .${BASE_CLASS_PREFIX}-tree-select-selection span`)
832
+ .getDOMNode()
833
+ .textContent
834
+ ).toEqual('');
835
+ });
836
+
837
+ it('treeData is updated should not clear value when uncontrolled mode and multiple selection', () => {
838
+ const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
839
+ const treeSelect = getTreeSelect({
840
+ defaultExpandAll: true,
841
+ multiple: true,
842
+ });
843
+ treeSelect
844
+ .find(`.${BASE_CLASS_PREFIX}-tree-option-list .${BASE_CLASS_PREFIX}-tree-option`)
845
+ .at(2)
846
+ .simulate('click', nativeEvent);
847
+ expect(
848
+ treeSelect
849
+ .find(`.${BASE_CLASS_PREFIX}-tree-select-selection .${BASE_CLASS_PREFIX}-tag-group .${BASE_CLASS_PREFIX}-tag`)
850
+ .at(0)
851
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
852
+ .getDOMNode()
853
+ .textContent
854
+ ).toEqual('北京');
855
+ treeSelect.setProps({ treeData: treeChildren});
856
+ treeSelect.update();
857
+ expect(
858
+ treeSelect
859
+ .find(`.${BASE_CLASS_PREFIX}-tree-select-selection .${BASE_CLASS_PREFIX}-tag-group .${BASE_CLASS_PREFIX}-tag`)
860
+ .at(0)
861
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
862
+ .getDOMNode()
863
+ .textContent
864
+ ).toEqual('北京');
865
+ treeSelect.setProps({ treeData: treeData2});
866
+ treeSelect.update();
867
+ expect(
868
+ treeSelect
869
+ .find(`.${BASE_CLASS_PREFIX}-tree-select-selection .${BASE_CLASS_PREFIX}-tag-group .${BASE_CLASS_PREFIX}-tag`)
870
+ .at(0)
871
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
872
+ .length
873
+ ).toEqual(0);
874
+ });
875
+
876
+ it('treeData is updated should not clear value when controlled mode and single selection', () => {
877
+ const treeSelect = getTreeSelect({
878
+ defaultExpandAll: true,
879
+ value: 'Beijing'
880
+ });
881
+ expect(
882
+ treeSelect
883
+ .find(`.${BASE_CLASS_PREFIX}-tree-select .${BASE_CLASS_PREFIX}-tree-select-selection span`)
884
+ .getDOMNode()
885
+ .textContent
886
+ ).toEqual('北京');
887
+ treeSelect.setProps({ treeData: treeChildren});
888
+ treeSelect.update();
889
+ expect(
890
+ treeSelect
891
+ .find(`.${BASE_CLASS_PREFIX}-tree-select .${BASE_CLASS_PREFIX}-tree-select-selection span`)
892
+ .getDOMNode()
893
+ .textContent
894
+ ).toEqual('北京');
895
+ treeSelect.setProps({ treeData: treeData3});
896
+ treeSelect.update();
897
+ expect(
898
+ treeSelect
899
+ .find(`.${BASE_CLASS_PREFIX}-tree-select .${BASE_CLASS_PREFIX}-tree-select-selection span`)
900
+ .getDOMNode()
901
+ .textContent
902
+ ).toEqual('');
903
+ });
904
+
905
+ it('treeData is updated should not clear value when controlled mode and multiple selection', () => {
906
+ const treeSelect = getTreeSelect({
907
+ defaultExpandAll: true,
908
+ multiple: true,
909
+ value: 'Beijing'
910
+ });
911
+ expect(
912
+ treeSelect
913
+ .find(`.${BASE_CLASS_PREFIX}-tree-select-selection .${BASE_CLASS_PREFIX}-tag-group .${BASE_CLASS_PREFIX}-tag`)
914
+ .at(0)
915
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
916
+ .getDOMNode()
917
+ .textContent
918
+ ).toEqual('北京');
919
+ treeSelect.setProps({ treeData: treeChildren});
920
+ treeSelect.update();
921
+ expect(
922
+ treeSelect
923
+ .find(`.${BASE_CLASS_PREFIX}-tree-select-selection .${BASE_CLASS_PREFIX}-tag-group .${BASE_CLASS_PREFIX}-tag`)
924
+ .at(0)
925
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
926
+ .getDOMNode()
927
+ .textContent
928
+ ).toEqual('北京');
929
+ treeSelect.setProps({ treeData: treeData3});
930
+ treeSelect.update();
931
+ expect(
932
+ treeSelect
933
+ .find(`.${BASE_CLASS_PREFIX}-tree-select-selection .${BASE_CLASS_PREFIX}-tag-group .${BASE_CLASS_PREFIX}-tag`)
934
+ .at(0)
935
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
936
+ .length
937
+ ).toEqual(0);
938
+ });
939
+
783
940
  })