@douyinfe/semi-ui 2.3.1 → 2.5.0-beta.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 (119) hide show
  1. package/cascader/__test__/cascader.test.js +24 -0
  2. package/cascader/_story/cascader.stories.js +73 -0
  3. package/cascader/index.tsx +5 -2
  4. package/datePicker/_story/RenderDate/index.js +13 -3
  5. package/datePicker/_story/RenderFullDate/index.js +36 -14
  6. package/datePicker/_story/RenderFullDate/index.scss +1 -1
  7. package/datePicker/_story/datePicker.stories.js +19 -11
  8. package/datePicker/_story/v2/PanelOpen.jsx +39 -0
  9. package/datePicker/_story/v2/index.js +2 -1
  10. package/datePicker/datePicker.tsx +1 -0
  11. package/dist/css/semi.css +84 -36
  12. package/dist/css/semi.min.css +1 -1
  13. package/dist/umd/semi-ui.js +487 -170
  14. package/dist/umd/semi-ui.js.map +1 -1
  15. package/dist/umd/semi-ui.min.js +1 -1
  16. package/dist/umd/semi-ui.min.js.map +1 -1
  17. package/form/_story/demo.jsx +1 -0
  18. package/input/index.tsx +1 -0
  19. package/input/textarea.tsx +6 -4
  20. package/inputNumber/__test__/inputNumber.test.js +36 -8
  21. package/lib/cjs/autoComplete/index.d.ts +1 -1
  22. package/lib/cjs/cascader/index.js +6 -0
  23. package/lib/cjs/datePicker/datePicker.js +12 -8
  24. package/lib/cjs/dropdown/index.d.ts +1 -1
  25. package/lib/cjs/form/baseForm.d.ts +1 -1
  26. package/lib/cjs/form/field.d.ts +1 -1
  27. package/lib/cjs/input/index.js +2 -1
  28. package/lib/cjs/input/textarea.js +5 -3
  29. package/lib/cjs/navigation/Item.js +1 -1
  30. package/lib/cjs/navigation/SubNav.js +1 -1
  31. package/lib/cjs/scrollList/scrollItem.d.ts +5 -1
  32. package/lib/cjs/scrollList/scrollItem.js +7 -0
  33. package/lib/cjs/select/index.d.ts +1 -1
  34. package/lib/cjs/select/index.js +1 -1
  35. package/lib/cjs/select/option.js +2 -2
  36. package/lib/cjs/table/Table.d.ts +1 -1
  37. package/lib/cjs/table/Table.js +17 -7
  38. package/lib/cjs/table/interface.d.ts +1 -0
  39. package/lib/cjs/tabs/interface.d.ts +1 -1
  40. package/lib/cjs/timePicker/TimePicker.d.ts +2 -0
  41. package/lib/cjs/timePicker/TimePicker.js +4 -4
  42. package/lib/cjs/timePicker/index.d.ts +1 -0
  43. package/lib/cjs/tooltip/index.d.ts +1 -1
  44. package/lib/cjs/tree/index.d.ts +2 -0
  45. package/lib/cjs/tree/index.js +15 -8
  46. package/lib/cjs/tree/treeNode.js +10 -1
  47. package/lib/cjs/treeSelect/index.d.ts +2 -0
  48. package/lib/cjs/treeSelect/index.js +75 -30
  49. package/lib/cjs/typography/util.js +0 -1
  50. package/lib/cjs/upload/fileCard.js +31 -22
  51. package/lib/cjs/upload/index.d.ts +6 -0
  52. package/lib/cjs/upload/index.js +15 -8
  53. package/lib/cjs/upload/interface.d.ts +8 -6
  54. package/lib/es/autoComplete/index.d.ts +1 -1
  55. package/lib/es/cascader/index.js +5 -0
  56. package/lib/es/datePicker/datePicker.js +12 -8
  57. package/lib/es/dropdown/index.d.ts +1 -1
  58. package/lib/es/form/baseForm.d.ts +1 -1
  59. package/lib/es/form/field.d.ts +1 -1
  60. package/lib/es/input/index.js +2 -1
  61. package/lib/es/input/textarea.js +5 -3
  62. package/lib/es/navigation/Item.js +1 -1
  63. package/lib/es/navigation/SubNav.js +1 -1
  64. package/lib/es/scrollList/scrollItem.d.ts +5 -1
  65. package/lib/es/scrollList/scrollItem.js +7 -0
  66. package/lib/es/select/index.d.ts +1 -1
  67. package/lib/es/select/index.js +1 -1
  68. package/lib/es/select/option.js +2 -2
  69. package/lib/es/table/Table.d.ts +1 -1
  70. package/lib/es/table/Table.js +19 -7
  71. package/lib/es/table/interface.d.ts +1 -0
  72. package/lib/es/tabs/interface.d.ts +1 -1
  73. package/lib/es/timePicker/TimePicker.d.ts +2 -0
  74. package/lib/es/timePicker/TimePicker.js +4 -4
  75. package/lib/es/timePicker/index.d.ts +1 -0
  76. package/lib/es/tooltip/index.d.ts +1 -1
  77. package/lib/es/tree/index.d.ts +2 -0
  78. package/lib/es/tree/index.js +15 -8
  79. package/lib/es/tree/treeNode.js +9 -1
  80. package/lib/es/treeSelect/index.d.ts +2 -0
  81. package/lib/es/treeSelect/index.js +76 -31
  82. package/lib/es/typography/util.js +0 -1
  83. package/lib/es/upload/fileCard.js +31 -24
  84. package/lib/es/upload/index.d.ts +6 -0
  85. package/lib/es/upload/index.js +14 -8
  86. package/lib/es/upload/interface.d.ts +8 -6
  87. package/navigation/Item.tsx +1 -1
  88. package/navigation/SubNav.tsx +1 -1
  89. package/package.json +9 -8
  90. package/scrollList/scrollItem.tsx +10 -3
  91. package/select/index.tsx +6 -1
  92. package/select/option.tsx +2 -2
  93. package/table/Table.tsx +16 -8
  94. package/table/_story/table.stories.js +1 -0
  95. package/table/_story/v2/FixedColumnsChange/index.jsx +104 -0
  96. package/table/_story/v2/FixedHeaderMerge/index.jsx +98 -0
  97. package/table/_story/v2/FixedZIndex/index.jsx +87 -0
  98. package/table/_story/v2/defaultFilteredValue.tsx +123 -0
  99. package/table/_story/v2/index.js +4 -0
  100. package/table/interface.ts +1 -0
  101. package/tabs/interface.ts +1 -1
  102. package/timePicker/TimePicker.tsx +4 -1
  103. package/timePicker/__test__/timePicker.test.js +42 -3
  104. package/timePicker/_story/timepicker.stories.js +18 -0
  105. package/tooltip/_story/tooltip.stories.js +83 -1
  106. package/tree/__test__/treeMultiple.test.js +94 -0
  107. package/tree/_story/tree.stories.js +169 -0
  108. package/tree/index.tsx +12 -5
  109. package/tree/treeNode.tsx +9 -2
  110. package/treeSelect/__test__/treeMultiple.test.js +94 -0
  111. package/treeSelect/__test__/treeSelect.test.js +157 -0
  112. package/treeSelect/_story/treeSelect.stories.js +242 -0
  113. package/treeSelect/index.tsx +93 -52
  114. package/typography/_story/typography.stories.js +8 -0
  115. package/typography/util.tsx +0 -1
  116. package/upload/_story/upload.stories.js +22 -6
  117. package/upload/fileCard.tsx +23 -23
  118. package/upload/index.tsx +15 -6
  119. package/upload/interface.ts +7 -5
@@ -0,0 +1,98 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Table, Button } from '@douyinfe/semi-ui';
3
+
4
+ Demo.storyName = "fixed jsx column nested bug";
5
+
6
+
7
+ /**
8
+ * fixed https://github.com/DouyinFE/semi-design/issues/619
9
+ *
10
+ * Test with Cypress
11
+ */
12
+ export default function Demo() {
13
+ const columns = [
14
+ {
15
+ title: 'Base Information',
16
+ fixed: 'left',
17
+ children: [
18
+ {
19
+ title: 'Name',
20
+ dataIndex: 'name',
21
+ width: 200,
22
+ },
23
+ {
24
+ title: 'Age',
25
+ dataIndex: 'age',
26
+ width: 100,
27
+ },
28
+ ],
29
+ },
30
+ {
31
+ title: 'Company Information',
32
+ children: [
33
+ {
34
+ title: 'Company Name',
35
+ dataIndex: 'company.name',
36
+ },
37
+ {
38
+ title: 'Company Address',
39
+ dataIndex: 'company.address',
40
+ },
41
+ ],
42
+ }
43
+ ];
44
+
45
+ const data = useMemo(() => {
46
+ const data = [];
47
+ for (let i = 0; i < 100; i++) {
48
+ let age = 40 + (Math.random() > 0.5 ? 1 : -1) * (i % 9);
49
+ let name = `Edward King ${i}`;
50
+ data.push({
51
+ key: '' + i,
52
+ company: {
53
+ name: 'ByteDance',
54
+ address: 'No. 48, Zhichun Road',
55
+ },
56
+ name,
57
+ age,
58
+ address: `No ${i + 1}, Zhongguancun Street`,
59
+ description: `My name is ${name}, I am ${age} years old, living in No ${i + 1}, Zhongguancun Street`,
60
+ });
61
+ }
62
+ return data;
63
+ }, []);
64
+
65
+ const [flag, setFlag] = React.useState(true);
66
+
67
+ return (
68
+ <>
69
+ <Button data-cy="button" onClick={()=> setFlag(!flag)}>reRender</Button>
70
+ <Table dataSource={data} pagination={true} size="small">
71
+ {columns.map((item, titleIndex) =>
72
+ (
73
+ <Table.Column
74
+ key={titleIndex}
75
+ title={item.title}
76
+ >
77
+ {item.children.map(
78
+ (childItem, columnIndex) =>
79
+ (
80
+ <Table.Column
81
+ title={childItem.title}
82
+ dataIndex={childItem.dataIndex}
83
+ key={titleIndex.toString() + columnIndex.toString()}
84
+ />
85
+ )
86
+ )}
87
+ </Table.Column>
88
+ )
89
+ )}
90
+ <Table.Column
91
+ title=""
92
+ key="lastColumn"
93
+ render={() => 123}
94
+ />
95
+ </Table>
96
+ </>
97
+ );
98
+ }
@@ -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
+ }
@@ -0,0 +1,123 @@
1
+ import React, { useState, useEffect, useMemo } from 'react';
2
+ import { Table, Avatar, Button } from '@douyinfe/semi-ui';
3
+ import * as dateFns from 'date-fns';
4
+ import { ColumnProps, ChangeInfoFilter } from '@douyinfe/semi-ui/table';
5
+
6
+ const DAY = 24 * 60 * 60 * 1000;
7
+ const figmaIconUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/figma-icon.png';
8
+
9
+ function App() {
10
+ const [dataSource, setData] = useState([]);
11
+ const [filteredValue, setFilteredValue] = useState(['Semi Pro 设计稿']);
12
+
13
+ const scroll = useMemo(() => ({ y: 300 }), []);
14
+
15
+ const columns: ColumnProps[] = [
16
+ {
17
+ title: '标题',
18
+ dataIndex: 'name',
19
+ width: 400,
20
+ render: (text, record, index) => {
21
+ return (
22
+ <div>
23
+ <Avatar size="small" shape="square" src={figmaIconUrl} style={{ marginRight: 12 }}></Avatar>
24
+ {text}
25
+ </div>
26
+ );
27
+ },
28
+ filters: [
29
+ {
30
+ text: 'Semi Design 设计稿',
31
+ value: 'Semi Design 设计稿',
32
+ },
33
+ {
34
+ text: 'Semi Pro 设计稿',
35
+ value: 'Semi Pro 设计稿',
36
+ },
37
+ ],
38
+ onFilter: (value, record) => record.name.includes(value),
39
+ sorter: (a, b) => a.name.length - b.name.length > 0 ? 1 : -1,
40
+ // filterMultiple: false,
41
+ // filteredValue: filteredValue,
42
+ defaultFilteredValue: filteredValue,
43
+ },
44
+ {
45
+ title: '大小',
46
+ dataIndex: 'size',
47
+ sorter: (a, b) => a.size - b.size > 0 ? 1 : -1,
48
+ render: (text) => `${text} KB`
49
+ },
50
+ {
51
+ title: '所有者',
52
+ dataIndex: 'owner',
53
+ render: (text, record, index) => {
54
+ return (
55
+ <div>
56
+ <Avatar size="small" color={record.avatarBg} style={{ marginRight: 4 }}>{typeof text === 'string' && text.slice(0, 1)}</Avatar>
57
+ {text}
58
+ </div>
59
+ );
60
+ }
61
+
62
+ },
63
+ {
64
+ title: '更新日期',
65
+ dataIndex: 'updateTime',
66
+ sorter: (a, b) => a.updateTime - b.updateTime > 0 ? 1 : -1,
67
+ render: (value) => {
68
+ return dateFns.format(new Date(value), 'yyyy-MM-dd');
69
+ }
70
+ }
71
+ ];
72
+
73
+ const getData = (total) => {
74
+ const data = [];
75
+ for (let i = 0; i < total; i++) {
76
+ const isSemiDesign = i % 2 === 0;
77
+ const randomNumber = (i * 1000) % 199;
78
+ data.push({
79
+ key: '' + i,
80
+ name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi Pro 设计稿${i}.fig`,
81
+ owner: isSemiDesign ? '姜鹏志' : '郝宣',
82
+ size: randomNumber,
83
+ updateTime: new Date().valueOf() + randomNumber * DAY,
84
+ avatarBg: isSemiDesign ? 'grey' : 'red'
85
+ });
86
+ }
87
+ return data;
88
+ };
89
+
90
+ const handleFilterChange = (filters: ChangeInfoFilter<any>[]) => {
91
+ console.log('filters', filters);
92
+ if (Array.isArray(filters) && filters.length) {
93
+ const { filteredValue } = filters.find(filter => filter.dataIndex === 'name');
94
+ setFilteredValue(filteredValue);
95
+ }
96
+ };
97
+
98
+ const handleChange = (options) => {
99
+ const { filters } = options;
100
+ handleFilterChange(filters);
101
+ };
102
+
103
+ const toggleChangeData = () => {
104
+ const length = dataSource.length;
105
+ const newData = getData(length === 46 ? 25 : 46);
106
+ setData(newData);
107
+ };
108
+
109
+ useEffect(() => {
110
+ const data = getData(46);
111
+ setData(data);
112
+ }, []);
113
+
114
+ return (
115
+ <div>
116
+ <Button onClick={toggleChangeData}>toggle change dataSource (46/25)</Button>
117
+ <Table columns={columns} dataSource={dataSource} scroll={scroll} onChange={handleChange} />
118
+ </div>
119
+ );
120
+ }
121
+
122
+ App.storyName = 'defaultFilteredValue';
123
+ export default App;
@@ -0,0 +1,4 @@
1
+ export { default as DefaultFilteredValue } from './defaultFilteredValue';
2
+ export { default as FixedColumnsChange } from './FixedColumnsChange';
3
+ export { default as FixedZIndex } from './FixedZIndex';
4
+ export { default as FixedHeaderMerge } from './FixedHeaderMerge';
@@ -79,6 +79,7 @@ export interface ColumnProps<RecordType extends Record<string, any> = any> {
79
79
  className?: string;
80
80
  colSpan?: number;
81
81
  dataIndex?: string;
82
+ defaultFilteredValue?: any[];
82
83
  defaultSortOrder?: SortOrder;
83
84
  filterChildrenRecord?: boolean;
84
85
  filterDropdown?: React.ReactNode;
package/tabs/interface.ts CHANGED
@@ -58,7 +58,7 @@ export interface TabBarProps {
58
58
  export interface TabPaneProps {
59
59
  className?: string;
60
60
  disabled?: boolean;
61
- icon?: string;
61
+ icon?: ReactNode;
62
62
  itemKey?: string;
63
63
  style?: CSSProperties;
64
64
  tab?: ReactNode;
@@ -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,
@@ -447,6 +449,7 @@ export default class TimePicker extends BaseComponent<TimePickerProps, TimePicke
447
449
  panelFooter,
448
450
  rangeSeparator,
449
451
  onOpenChange,
452
+ onChangeWithDateFirst,
450
453
  popupClassName: propPopupClassName,
451
454
  hideDisabledOptions,
452
455
  use12Hours,
@@ -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
+ };
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useMemo } from 'react';
2
2
  import Tooltip from '../index';
3
3
  import './story.scss';
4
- import { Tag, Icon, IconButton, Switch, Checkbox, Radio, Button, Select, InputNumber } from '@douyinfe/semi-ui';
4
+ import { Tag, Icon, IconButton, Switch, Checkbox, Radio, Button, Select, InputNumber, Space } from '@douyinfe/semi-ui';
5
5
 
6
6
  import InTableDemo from './InTable';
7
7
  import EdgeDemo from './Edge';
@@ -736,3 +736,85 @@ export const AutoAdjustWithSpacing = () => {
736
736
  AutoAdjustWithSpacing.story = {
737
737
  name: 'AutoAdjustWithSpacing',
738
738
  };
739
+
740
+ /**
741
+ * Chromatic UI test
742
+ */
743
+ export const leftTopOverDemo = () => {
744
+ const [visible, setVisible] = useState(true);
745
+ const content = (
746
+ <div style={{ height: 200, width: 200 }}>
747
+ Semi Design
748
+ </div>
749
+ );
750
+
751
+ const commonProps = {
752
+ content,
753
+ trigger: 'click',
754
+ showArrow: false,
755
+ visible,
756
+ trigger: 'custom',
757
+ motion: false,
758
+ };
759
+ const buttonStyle = {
760
+ width: 200,
761
+ };
762
+
763
+ return (
764
+ <div data-cy='wrapper'>
765
+ <Button onClick={() => setVisible(!visible)}>toggle visible</Button>
766
+ <div style={{ paddingTop: 200 }}>
767
+ <Space spacing={80}>
768
+ <Tooltip {...commonProps} position='leftTopOver' >
769
+ <Button data-cy='leftTopOver' style={buttonStyle}>leftTopOver</Button>
770
+ </Tooltip>
771
+ <Tooltip {...commonProps} position='leftBottomOver'>
772
+ <Button data-cy='leftBottomOver' style={buttonStyle}>leftBottomOver</Button>
773
+ </Tooltip>
774
+ <Tooltip {...commonProps} position='rightTopOver'>
775
+ <Button data-cy='rightTopOver' style={buttonStyle}>rightTopOver</Button>
776
+ </Tooltip>
777
+ <Tooltip {...commonProps} position='rightBottomOver'>
778
+ <Button data-cy='rightBottomOver' style={buttonStyle}>rightBottomOver</Button>
779
+ </Tooltip>
780
+ </Space>
781
+ </div>
782
+ </div>
783
+ )
784
+ };
785
+ leftTopOverDemo.storyName = `leftTopOver visible`;
786
+ leftTopOverDemo.parameters = {
787
+ chromatic: {
788
+ disableSnapshot: false,
789
+ delay: 3000,
790
+ viewports: [1200]
791
+ }
792
+ };
793
+
794
+ /**
795
+ * Cypress test
796
+ */
797
+ export const leftTopOverAutoAdjustOverflow = () => {
798
+ const content = (
799
+ <div style={{ height: 200, width: 200 }}>
800
+ Semi Design
801
+ </div>
802
+ );
803
+
804
+ const commonProps = {
805
+ content,
806
+ trigger: 'click',
807
+ showArrow: false,
808
+ };
809
+
810
+ return (
811
+ <div data-cy='wrapper' style={{ width: '200vw', height: '200vw', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
812
+ <div>
813
+ <Tooltip {...commonProps} position='leftTopOver' >
814
+ <Button data-cy='leftTopOver' style={{ width: 200 }}>leftTopOver</Button>
815
+ </Tooltip>
816
+ </div>
817
+ </div>
818
+ )
819
+ };
820
+ leftTopOverAutoAdjustOverflow.storyName = `leftTopOver autoAdjustOverflow`;
@@ -357,6 +357,100 @@ describe('Tree', () => {
357
357
  ).toEqual(true);
358
358
  });
359
359
 
360
+ it('unRelated', () => {
361
+ const spyOnChange = sinon.spy(() => { });
362
+ const tree = getTree({
363
+ defaultExpandAll: true,
364
+ onChange: spyOnChange,
365
+ checkRelation: 'unRelated',
366
+ });
367
+ const nodelevel2 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`);
368
+ const selectedNode = nodelevel2.at(0);
369
+ selectedNode.simulate('click');
370
+ expect(spyOnChange.calledOnce).toBe(true);
371
+ expect(spyOnChange.calledWithMatch(['Zhongguo'])).toEqual(true);
372
+ // Note: selectedNode cannot be used directly here. selectedNode is the original node in the unselected state
373
+ expect(
374
+ tree
375
+ .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
376
+ .at(0)
377
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-checked`)
378
+ ).toEqual(true);
379
+ const nodelevel3 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`);
380
+ expect(
381
+ nodelevel3
382
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-unChecked` )
383
+ ).toEqual(true);
384
+ expect(
385
+ nodelevel3
386
+ .at(1)
387
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-unChecked` )
388
+ ).toEqual(true);
389
+ });
390
+
391
+ it('unRelated + value', () => {
392
+ const tree = getTree({
393
+ defaultExpandAll: true,
394
+ checkRelation: 'unRelated',
395
+ value: 'Zhongguo'
396
+ });
397
+ expect(
398
+ tree
399
+ .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
400
+ .at(0)
401
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-checked`)
402
+ ).toEqual(true);
403
+ const nodelevel3 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`);
404
+ expect(
405
+ nodelevel3
406
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-unChecked` )
407
+ ).toEqual(true);
408
+ expect(
409
+ nodelevel3
410
+ .at(1)
411
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-unChecked` )
412
+ ).toEqual(true);
413
+ });
414
+
415
+ it('unRelated + defaultValue', () => {
416
+ const tree = getTree({
417
+ defaultExpandAll: true,
418
+ checkRelation: 'unRelated',
419
+ defaultValue: 'Zhongguo'
420
+ });
421
+ expect(
422
+ tree
423
+ .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
424
+ .at(0)
425
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-checked`)
426
+ ).toEqual(true);
427
+ const nodelevel3 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`);
428
+ expect(
429
+ nodelevel3
430
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-unChecked` )
431
+ ).toEqual(true);
432
+ expect(
433
+ nodelevel3
434
+ .at(1)
435
+ .exists(`.${BASE_CLASS_PREFIX}-checkbox-unChecked` )
436
+ ).toEqual(true);
437
+ });
438
+
439
+ it('unRelated + onSelect', () => {
440
+ const spyOnSelect = sinon.spy(() => { });
441
+ const tree = getTree({
442
+ defaultExpandAll: true,
443
+ onSelect: spyOnSelect,
444
+ checkRelation: 'unRelated',
445
+ });
446
+ const nodelevel2 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`);
447
+ const selectedNode = nodelevel2.at(0);
448
+ selectedNode.simulate('click');
449
+ expect(spyOnSelect.calledOnce).toBe(true);
450
+ // onSelect first args is key, not value
451
+ expect(spyOnSelect.calledWithMatch('zhongguo')).toEqual(true);
452
+ });
453
+
360
454
  it('controlled: leaf values show correct', () => {
361
455
  let tree = getTree({
362
456
  value: 'Beijing'