@douyinfe/semi-ui 2.4.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 (35) hide show
  1. package/datePicker/_story/RenderDate/index.js +13 -3
  2. package/datePicker/_story/RenderFullDate/index.js +36 -14
  3. package/datePicker/_story/RenderFullDate/index.scss +1 -1
  4. package/datePicker/_story/datePicker.stories.js +19 -11
  5. package/datePicker/_story/v2/PanelOpen.jsx +39 -0
  6. package/datePicker/_story/v2/index.js +2 -1
  7. package/dist/css/semi.css +18 -0
  8. package/dist/css/semi.min.css +1 -1
  9. package/dist/umd/semi-ui.js +20 -6
  10. package/dist/umd/semi-ui.js.map +1 -1
  11. package/dist/umd/semi-ui.min.js +1 -1
  12. package/dist/umd/semi-ui.min.js.map +1 -1
  13. package/lib/cjs/navigation/Item.js +1 -1
  14. package/lib/cjs/navigation/SubNav.js +1 -1
  15. package/lib/cjs/scrollList/scrollItem.d.ts +5 -1
  16. package/lib/cjs/scrollList/scrollItem.js +7 -0
  17. package/lib/cjs/treeSelect/index.js +11 -3
  18. package/lib/cjs/typography/util.js +0 -1
  19. package/lib/es/navigation/Item.js +1 -1
  20. package/lib/es/navigation/SubNav.js +1 -1
  21. package/lib/es/scrollList/scrollItem.d.ts +5 -1
  22. package/lib/es/scrollList/scrollItem.js +7 -0
  23. package/lib/es/treeSelect/index.js +12 -4
  24. package/lib/es/typography/util.js +0 -1
  25. package/navigation/Item.tsx +1 -1
  26. package/navigation/SubNav.tsx +1 -1
  27. package/package.json +8 -8
  28. package/scrollList/scrollItem.tsx +10 -3
  29. package/table/_story/v2/FixedColumnsChange/index.jsx +1 -1
  30. package/table/_story/v2/FixedZIndex/index.jsx +1 -1
  31. package/timePicker/__test__/timePicker.test.js +9 -1
  32. package/treeSelect/__test__/treeSelect.test.js +157 -0
  33. package/treeSelect/index.tsx +21 -12
  34. package/typography/_story/typography.stories.js +8 -0
  35. package/typography/util.tsx +0 -1
@@ -204,7 +204,7 @@ class NavItem extends _baseComponent.default {
204
204
  } else {
205
205
  let placeholderIcons = null;
206
206
 
207
- if (mode === _constants.strings.MODE_VERTICAL && !limitIndent) {
207
+ if (mode === _constants.strings.MODE_VERTICAL && !limitIndent && !isCollapsed) {
208
208
  const iconAmount = icon && !indent ? level : level - 1;
209
209
  placeholderIcons = (0, _times2.default)(iconAmount, () => this.renderIcon(null, _constants.strings.ICON_POS_RIGHT, false));
210
210
  }
@@ -230,7 +230,7 @@ class SubNav extends _baseComponent.default {
230
230
 
231
231
  let placeholderIcons = null;
232
232
 
233
- if (mode === _constants.strings.MODE_VERTICAL && !limitIndent) {
233
+ if (mode === _constants.strings.MODE_VERTICAL && !limitIndent && !isCollapsed) {
234
234
  /* Different icons' amount means different indents.*/
235
235
  const iconAmount = icon && !indent ? level : level - 1;
236
236
  placeholderIcons = (0, _times2.default)(iconAmount, index => this.renderIcon(null, _constants.strings.ICON_POS_RIGHT, false, undefined, index));
@@ -3,7 +3,10 @@ import BaseComponent from '../_base/baseComponent';
3
3
  import PropTypes from 'prop-types';
4
4
  import { Item, ScrollItemAdapter } from '@douyinfe/semi-foundation/lib/cjs/scrollList/itemFoundation';
5
5
  import { Motion } from '../_base/base';
6
- declare type DebounceSelectFn = (e: React.UIEvent, newSelectedNode: HTMLElement) => void;
6
+ interface DebounceSelectFn {
7
+ (e: React.UIEvent, newSelectedNode: HTMLElement): void;
8
+ cancel(): void;
9
+ }
7
10
  export interface ScrollItemProps<T extends Item> {
8
11
  mode?: string;
9
12
  cycled?: boolean;
@@ -52,6 +55,7 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
52
55
  debouncedSelect: DebounceSelectFn;
53
56
  constructor(props?: {});
54
57
  get adapter(): ScrollItemAdapter<ScrollItemProps<T>, ScrollItemState, T>;
58
+ componentWillUnmount(): void;
55
59
  componentDidMount(): void;
56
60
  componentDidUpdate(prevProps: ScrollItemProps<T>): void;
57
61
  _cacheNode: (name: string, node: Element) => Element;
@@ -451,6 +451,13 @@ class ScrollItem extends _baseComponent.default {
451
451
  });
452
452
  }
453
453
 
454
+ componentWillUnmount() {
455
+ if (this.props.cycled) {
456
+ this.throttledAdjustList.cancel();
457
+ this.debouncedSelect.cancel();
458
+ }
459
+ }
460
+
454
461
  componentDidMount() {
455
462
  this.foundation.init();
456
463
  const {
@@ -950,7 +950,7 @@ class TreeSelect extends _baseComponent.default {
950
950
  } // if treeData keys changes, we won't show animation
951
951
 
952
952
 
953
- if (treeData && props.motion && !(0, _isEqual2.default)(new _set.default((0, _keys.default)(newState.keyEntities)), new _set.default((0, _keys.default)(prevState.keyEntities)))) {
953
+ if (treeData && props.motion && !(0, _isEqual2.default)((0, _keys.default)(newState.keyEntities), (0, _keys.default)(prevState.keyEntities))) {
954
954
  if (prevProps && props.motion) {
955
955
  newState.motionKeys = new _set.default([]);
956
956
  newState.motionType = null;
@@ -996,7 +996,11 @@ class TreeSelect extends _baseComponent.default {
996
996
  newState.selectedKeys = (0, _treeUtil.findKeysForValues)((0, _treeUtil.normalizeValue)(props.defaultValue, withObject), valueEntities, isMultiple);
997
997
  } else if (treeData) {
998
998
  // If `treeData` changed, we also need check it
999
- newState.selectedKeys = (0, _treeUtil.findKeysForValues)((0, _treeUtil.normalizeValue)(props.value, withObject) || '', valueEntities, isMultiple);
999
+ if (props.value) {
1000
+ newState.selectedKeys = (0, _treeUtil.findKeysForValues)((0, _treeUtil.normalizeValue)(props.value, withObject) || '', valueEntities, isMultiple);
1001
+ } else {
1002
+ newState.selectedKeys = (0, _treeUtil.updateKeys)(prevState.selectedKeys, keyEntities);
1003
+ }
1000
1004
  }
1001
1005
  } else {
1002
1006
  // checkedKeys: multiple mode controlled || data changed
@@ -1008,7 +1012,11 @@ class TreeSelect extends _baseComponent.default {
1008
1012
  checkedKeyValues = (0, _treeUtil.findKeysForValues)((0, _treeUtil.normalizeValue)(props.defaultValue, withObject), valueEntities, isMultiple);
1009
1013
  } else if (treeData) {
1010
1014
  // If `treeData` changed, we also need check it
1011
- checkedKeyValues = (0, _treeUtil.findKeysForValues)((0, _treeUtil.normalizeValue)(props.value, withObject) || [], valueEntities, isMultiple);
1015
+ if (props.value) {
1016
+ checkedKeyValues = (0, _treeUtil.findKeysForValues)((0, _treeUtil.normalizeValue)(props.value, withObject) || [], valueEntities, isMultiple);
1017
+ } else {
1018
+ checkedKeyValues = (0, _treeUtil.updateKeys)(prevState.checkedKeys, keyEntities);
1019
+ }
1012
1020
  }
1013
1021
 
1014
1022
  if (checkedKeyValues) {
@@ -77,7 +77,6 @@ const getRenderText = function (originEle, rows) {
77
77
  ellipsisContainer.style.zIndex = '-1000'; // clean up css overflow
78
78
 
79
79
  ellipsisContainer.style.textOverflow = 'clip';
80
- ellipsisContainer.style.whiteSpace = 'normal';
81
80
  ellipsisContainer.style.webkitLineClamp = 'none'; // Render fake container
82
81
 
83
82
  _reactDom.default.render( /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), ellipsisContainer); // Check if ellipsis in measure div is height enough for content
@@ -176,7 +176,7 @@ export default class NavItem extends BaseComponent {
176
176
  } else {
177
177
  let placeholderIcons = null;
178
178
 
179
- if (mode === strings.MODE_VERTICAL && !limitIndent) {
179
+ if (mode === strings.MODE_VERTICAL && !limitIndent && !isCollapsed) {
180
180
  const iconAmount = icon && !indent ? level : level - 1;
181
181
  placeholderIcons = _times(iconAmount, () => this.renderIcon(null, strings.ICON_POS_RIGHT, false));
182
182
  }
@@ -200,7 +200,7 @@ export default class SubNav extends BaseComponent {
200
200
 
201
201
  let placeholderIcons = null;
202
202
 
203
- if (mode === strings.MODE_VERTICAL && !limitIndent) {
203
+ if (mode === strings.MODE_VERTICAL && !limitIndent && !isCollapsed) {
204
204
  /* Different icons' amount means different indents.*/
205
205
  const iconAmount = icon && !indent ? level : level - 1;
206
206
  placeholderIcons = _times(iconAmount, index => this.renderIcon(null, strings.ICON_POS_RIGHT, false, undefined, index));
@@ -3,7 +3,10 @@ import BaseComponent from '../_base/baseComponent';
3
3
  import PropTypes from 'prop-types';
4
4
  import { Item, ScrollItemAdapter } from '@douyinfe/semi-foundation/lib/es/scrollList/itemFoundation';
5
5
  import { Motion } from '../_base/base';
6
- declare type DebounceSelectFn = (e: React.UIEvent, newSelectedNode: HTMLElement) => void;
6
+ interface DebounceSelectFn {
7
+ (e: React.UIEvent, newSelectedNode: HTMLElement): void;
8
+ cancel(): void;
9
+ }
7
10
  export interface ScrollItemProps<T extends Item> {
8
11
  mode?: string;
9
12
  cycled?: boolean;
@@ -52,6 +55,7 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
52
55
  debouncedSelect: DebounceSelectFn;
53
56
  constructor(props?: {});
54
57
  get adapter(): ScrollItemAdapter<ScrollItemProps<T>, ScrollItemState, T>;
58
+ componentWillUnmount(): void;
55
59
  componentDidMount(): void;
56
60
  componentDidUpdate(prevProps: ScrollItemProps<T>): void;
57
61
  _cacheNode: (name: string, node: Element) => Element;
@@ -429,6 +429,13 @@ export default class ScrollItem extends BaseComponent {
429
429
  });
430
430
  }
431
431
 
432
+ componentWillUnmount() {
433
+ if (this.props.cycled) {
434
+ this.throttledAdjustList.cancel();
435
+ this.debouncedSelect.cancel();
436
+ }
437
+ }
438
+
432
439
  componentDidMount() {
433
440
  this.foundation.init();
434
441
  const {
@@ -17,7 +17,7 @@ import ReactDOM from 'react-dom';
17
17
  import cls from 'classnames';
18
18
  import PropTypes from 'prop-types';
19
19
  import TreeSelectFoundation from '@douyinfe/semi-foundation/lib/es/treeSelect/foundation';
20
- import { convertDataToEntities, flattenTreeData, calcExpandedKeysForValues, calcMotionKeys, findKeysForValues, calcCheckedKeys, calcExpandedKeys, getValueOrKey, normalizeKeyList, calcDisabledKeys, normalizeValue } from '@douyinfe/semi-foundation/lib/es/tree/treeUtil';
20
+ import { convertDataToEntities, flattenTreeData, calcExpandedKeysForValues, calcMotionKeys, findKeysForValues, calcCheckedKeys, calcExpandedKeys, getValueOrKey, normalizeKeyList, calcDisabledKeys, normalizeValue, updateKeys } from '@douyinfe/semi-foundation/lib/es/tree/treeUtil';
21
21
  import { cssClasses, strings } from '@douyinfe/semi-foundation/lib/es/treeSelect/constants';
22
22
  import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/lib/es/popover/constants';
23
23
  import { FixedSizeList as VirtualList } from 'react-window';
@@ -896,7 +896,7 @@ class TreeSelect extends BaseComponent {
896
896
  } // if treeData keys changes, we won't show animation
897
897
 
898
898
 
899
- if (treeData && props.motion && !_isEqual(new _Set(_Object$keys(newState.keyEntities)), new _Set(_Object$keys(prevState.keyEntities)))) {
899
+ if (treeData && props.motion && !_isEqual(_Object$keys(newState.keyEntities), _Object$keys(prevState.keyEntities))) {
900
900
  if (prevProps && props.motion) {
901
901
  newState.motionKeys = new _Set([]);
902
902
  newState.motionType = null;
@@ -942,7 +942,11 @@ class TreeSelect extends BaseComponent {
942
942
  newState.selectedKeys = findKeysForValues(normalizeValue(props.defaultValue, withObject), valueEntities, isMultiple);
943
943
  } else if (treeData) {
944
944
  // If `treeData` changed, we also need check it
945
- newState.selectedKeys = findKeysForValues(normalizeValue(props.value, withObject) || '', valueEntities, isMultiple);
945
+ if (props.value) {
946
+ newState.selectedKeys = findKeysForValues(normalizeValue(props.value, withObject) || '', valueEntities, isMultiple);
947
+ } else {
948
+ newState.selectedKeys = updateKeys(prevState.selectedKeys, keyEntities);
949
+ }
946
950
  }
947
951
  } else {
948
952
  // checkedKeys: multiple mode controlled || data changed
@@ -954,7 +958,11 @@ class TreeSelect extends BaseComponent {
954
958
  checkedKeyValues = findKeysForValues(normalizeValue(props.defaultValue, withObject), valueEntities, isMultiple);
955
959
  } else if (treeData) {
956
960
  // If `treeData` changed, we also need check it
957
- checkedKeyValues = findKeysForValues(normalizeValue(props.value, withObject) || [], valueEntities, isMultiple);
961
+ if (props.value) {
962
+ checkedKeyValues = findKeysForValues(normalizeValue(props.value, withObject) || [], valueEntities, isMultiple);
963
+ } else {
964
+ checkedKeyValues = updateKeys(prevState.checkedKeys, keyEntities);
965
+ }
958
966
  }
959
967
 
960
968
  if (checkedKeyValues) {
@@ -62,7 +62,6 @@ const getRenderText = function (originEle, rows) {
62
62
  ellipsisContainer.style.zIndex = '-1000'; // clean up css overflow
63
63
 
64
64
  ellipsisContainer.style.textOverflow = 'clip';
65
- ellipsisContainer.style.whiteSpace = 'normal';
66
65
  ellipsisContainer.style.webkitLineClamp = 'none'; // Render fake container
67
66
 
68
67
  ReactDOM.render( /*#__PURE__*/React.createElement(React.Fragment, null), ellipsisContainer); // Check if ellipsis in measure div is height enough for content
@@ -195,7 +195,7 @@ export default class NavItem extends BaseComponent<NavItemProps, NavItemState> {
195
195
  itemChildren = children;
196
196
  } else {
197
197
  let placeholderIcons = null;
198
- if (mode === strings.MODE_VERTICAL && !limitIndent) {
198
+ if (mode === strings.MODE_VERTICAL && !limitIndent && !isCollapsed) {
199
199
  const iconAmount = (icon && !indent) ? level : level - 1;
200
200
  placeholderIcons = times(iconAmount, () => this.renderIcon(null, strings.ICON_POS_RIGHT, false));
201
201
  }
@@ -237,7 +237,7 @@ export default class SubNav extends BaseComponent<SubNavProps, SubNavState> {
237
237
  }
238
238
 
239
239
  let placeholderIcons = null;
240
- if (mode === strings.MODE_VERTICAL && !limitIndent) {
240
+ if (mode === strings.MODE_VERTICAL && !limitIndent && !isCollapsed) {
241
241
  /* Different icons' amount means different indents.*/
242
242
  const iconAmount = (icon && !indent) ? level : level - 1;
243
243
  placeholderIcons = times(iconAmount, index => this.renderIcon(null, strings.ICON_POS_RIGHT, false, undefined, index));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@douyinfe/semi-ui",
3
- "version": "2.4.0-beta.0",
3
+ "version": "2.4.0",
4
4
  "description": "",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/es/index.js",
@@ -14,11 +14,11 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@babel/runtime-corejs3": "^7.15.4",
17
- "@douyinfe/semi-animation-react": "2.4.0-beta.0",
18
- "@douyinfe/semi-foundation": "2.4.0-beta.0",
19
- "@douyinfe/semi-icons": "2.4.0-beta.0",
20
- "@douyinfe/semi-illustrations": "2.4.0-beta.0",
21
- "@douyinfe/semi-theme-default": "2.4.0-beta.0",
17
+ "@douyinfe/semi-animation-react": "2.4.0",
18
+ "@douyinfe/semi-foundation": "2.4.0",
19
+ "@douyinfe/semi-icons": "2.4.0",
20
+ "@douyinfe/semi-illustrations": "2.4.0",
21
+ "@douyinfe/semi-theme-default": "2.4.0",
22
22
  "@types/react-window": "^1.8.2",
23
23
  "async-validator": "^3.5.0",
24
24
  "classnames": "^2.2.6",
@@ -68,13 +68,13 @@
68
68
  ],
69
69
  "author": "",
70
70
  "license": "MIT",
71
- "gitHead": "ebf8a78f5152f9733af771cd567f042eccb8c4b9",
71
+ "gitHead": "d902a6f731475dea585d63907aee06ebe1153419",
72
72
  "devDependencies": {
73
73
  "@babel/plugin-proposal-decorators": "^7.15.8",
74
74
  "@babel/plugin-transform-runtime": "^7.15.8",
75
75
  "@babel/preset-env": "^7.15.8",
76
76
  "@babel/preset-react": "^7.14.5",
77
- "@douyinfe/semi-scss-compile": "2.4.0-beta.0",
77
+ "@douyinfe/semi-scss-compile": "2.4.0",
78
78
  "@storybook/addon-knobs": "^6.3.1",
79
79
  "@types/lodash": "^4.14.176",
80
80
  "babel-loader": "^8.2.2",
@@ -13,8 +13,10 @@ import { Motion } from '../_base/base';
13
13
  const msPerFrame = 1000 / 60;
14
14
  const blankReg = /^\s*$/;
15
15
  const wheelMode = 'wheel';
16
-
17
- type DebounceSelectFn = (e: React.UIEvent, newSelectedNode: HTMLElement) => void;
16
+ interface DebounceSelectFn {
17
+ (e: React.UIEvent, newSelectedNode: HTMLElement): void;
18
+ cancel(): void
19
+ }
18
20
  export interface ScrollItemProps<T extends Item> {
19
21
  mode?: string;
20
22
  cycled?: boolean;
@@ -110,7 +112,12 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
110
112
  scrollToCenter: this.scrollToCenter,
111
113
  };
112
114
  }
113
-
115
+ componentWillUnmount(){
116
+ if (this.props.cycled) {
117
+ this.throttledAdjustList.cancel();
118
+ this.debouncedSelect.cancel();
119
+ }
120
+ }
114
121
  componentDidMount() {
115
122
  this.foundation.init();
116
123
 
@@ -15,7 +15,7 @@ const getData = () => {
15
15
  name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi Pro 设计稿${i}.fig`,
16
16
  owner: isSemiDesign ? '姜鹏志' : '郝宣',
17
17
  size: randomNumber,
18
- updateTime: new Date().valueOf() + randomNumber * DAY,
18
+ updateTime: new Date('2022-01-01').valueOf() + randomNumber * DAY,
19
19
  avatarBg: isSemiDesign ? 'grey' : 'red'
20
20
  });
21
21
  }
@@ -58,7 +58,7 @@ export default function App() {
58
58
  };
59
59
 
60
60
  for (let i = 0; i < 46; i++) {
61
- let age = 40 + (Math.random() > 0.5 ? 1 : -1) * Math.ceil(i / 3);
61
+ let age = (i * 1000) % 149;
62
62
  let name = `Edward King ${i}`;
63
63
  data.push({
64
64
  key: `${ i}`,
@@ -89,6 +89,7 @@ describe(`TimePicker`, () => {
89
89
  const args = onChange.getCall(0).args;
90
90
  expect(args[0] instanceof Date).toBe(true);
91
91
  expect(typeof args[1]).toBe('string');
92
+ elem.unmount();
92
93
  });
93
94
 
94
95
  it(`test controlled value`, async () => {
@@ -120,6 +121,7 @@ describe(`TimePicker`, () => {
120
121
  let currentDate0 = elem0.state('value')[0];
121
122
 
122
123
  expect(currentDate0.getMinutes()).toBe(defaultMinute);
124
+ elem0.unmount();
123
125
  });
124
126
 
125
127
  it(`test controlled value with onchange`, async () => {
@@ -156,6 +158,7 @@ describe(`TimePicker`, () => {
156
158
 
157
159
  let currentDate1 = elem1.state('value')[0];
158
160
  expect(currentDate1.getMinutes()).toBe(newInputMinute);
161
+ elem1.unmount();
159
162
  });
160
163
 
161
164
  it(`test controlled open`, async () => {
@@ -234,6 +237,7 @@ describe(`TimePicker`, () => {
234
237
  nextSelectedLi.simulate('click');
235
238
  await sleep(200);
236
239
  expect(elem.state('value')[0].getHours()).toBe(newHour);
240
+ elem.unmount();
237
241
  });
238
242
 
239
243
  it('test isTimeFormatLike function', () => {
@@ -286,6 +290,7 @@ describe(`TimePicker`, () => {
286
290
  const args = onChange.getCall(0).args;
287
291
  expect(args[0]).toBe(undefined);
288
292
  expect(args[1]).toBe('');
293
+ elem.unmount();
289
294
  });
290
295
 
291
296
  it('test onChangeWithDateFirst=false', async () => {
@@ -297,7 +302,8 @@ describe(`TimePicker`, () => {
297
302
  onChangeWithDateFirst: false,
298
303
  autofocus: true,
299
304
  locale: Locale.TimePicker,
300
- localeCode: Locale.code
305
+ localeCode: Locale.code,
306
+ scrollItemProps: { cycled: false }
301
307
  };
302
308
  const elem = mount(<TimePicker {...props} />);
303
309
  // click minute
@@ -305,10 +311,12 @@ describe(`TimePicker`, () => {
305
311
  const minuteLis = minuteUl.find(`li`);
306
312
 
307
313
  minuteUl.simulate('click', { target: minuteLis.at(0).getDOMNode(), nativeEvent: null });
314
+ await sleep(200);
308
315
 
309
316
  expect(onChange.called).toBeTruthy();
310
317
  const args = onChange.getCall(0).args;
311
318
  expect(typeof args[0]).toBe('string');
312
319
  expect(args[1] instanceof Date).toBe(true);
320
+ elem.unmount();
313
321
  });
314
322
  });
@@ -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
  })
@@ -23,7 +23,8 @@ import {
23
23
  getValueOrKey,
24
24
  normalizeKeyList,
25
25
  calcDisabledKeys,
26
- normalizeValue
26
+ normalizeValue,
27
+ updateKeys,
27
28
  } from '@douyinfe/semi-foundation/tree/treeUtil';
28
29
  import { cssClasses, strings } from '@douyinfe/semi-foundation/treeSelect/constants';
29
30
  import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
@@ -362,7 +363,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
362
363
  if (
363
364
  treeData &&
364
365
  props.motion &&
365
- !isEqual(new Set(Object.keys(newState.keyEntities)), new Set(Object.keys(prevState.keyEntities)))
366
+ !isEqual(Object.keys(newState.keyEntities), Object.keys(prevState.keyEntities))
366
367
  ) {
367
368
  if (prevProps && props.motion) {
368
369
  newState.motionKeys = new Set([]);
@@ -432,11 +433,15 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
432
433
  );
433
434
  } else if (treeData) {
434
435
  // If `treeData` changed, we also need check it
435
- newState.selectedKeys = findKeysForValues(
436
- normalizeValue(props.value, withObject) || '',
437
- valueEntities,
438
- isMultiple
439
- );
436
+ if (props.value) {
437
+ newState.selectedKeys = findKeysForValues(
438
+ normalizeValue(props.value, withObject) || '',
439
+ valueEntities,
440
+ isMultiple
441
+ );
442
+ } else {
443
+ newState.selectedKeys = updateKeys(prevState.selectedKeys, keyEntities);
444
+ }
440
445
  }
441
446
  } else {
442
447
  // checkedKeys: multiple mode controlled || data changed
@@ -456,11 +461,15 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
456
461
  );
457
462
  } else if (treeData) {
458
463
  // If `treeData` changed, we also need check it
459
- checkedKeyValues = findKeysForValues(
460
- normalizeValue(props.value, withObject) || [],
461
- valueEntities,
462
- isMultiple
463
- );
464
+ if (props.value) {
465
+ checkedKeyValues = findKeysForValues(
466
+ normalizeValue(props.value, withObject) || [],
467
+ valueEntities,
468
+ isMultiple
469
+ );
470
+ } else {
471
+ checkedKeyValues = updateKeys(prevState.checkedKeys, keyEntities);
472
+ }
464
473
  }
465
474
 
466
475
  if (checkedKeyValues) {
@@ -309,6 +309,14 @@ export const EllipsisMultiple = () => (
309
309
  Web 应用。 区别于其他的设计系统而言,Semi Design
310
310
  以用户中心、内容优先、设计人性化为设计理念,具有四大优势。
311
311
  </Paragraph>
312
+ <br />
313
+ <Paragraph ellipsis={{ rows: 3, expandable: true }} style={{ width: 300, whiteSpace: 'pre-line' }}>
314
+ {'这是一个多行截断的\n例子: Semi Design 是由互娱社区\n前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。 区别于其他的设计系统而言,Semi Design 以用户中心、内容优先、设计人性化为设计理念,具有四大优势。'}
315
+ </Paragraph>
316
+ <br />
317
+ <Paragraph ellipsis={{ rows: 3, expandable: true }} style={{ width: 300, whiteSpace: 'pre-wrap' }}>
318
+ {'这是一个多行截断的\n例子: Semi Des ign 是由互 娱社区\n前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。 区别于其他的设计系统而言,Semi Design 以用户中心、内容优先、设计人性化为设计理念,具有四大优势。'}
319
+ </Paragraph>
312
320
  </div>
313
321
  );
314
322
 
@@ -63,7 +63,6 @@ const getRenderText = (
63
63
 
64
64
  // clean up css overflow
65
65
  ellipsisContainer.style.textOverflow = 'clip';
66
- ellipsisContainer.style.whiteSpace = 'normal';
67
66
  ellipsisContainer.style.webkitLineClamp = 'none';
68
67
 
69
68
  // Render fake container