@douyinfe/semi-ui 2.14.0-beta.2 → 2.15.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 (185) hide show
  1. package/autoComplete/index.tsx +0 -1
  2. package/cascader/__test__/cascader.test.js +13 -10
  3. package/cascader/_story/cascader.stories.js +22 -0
  4. package/cascader/index.tsx +53 -35
  5. package/checkbox/checkbox.tsx +1 -0
  6. package/checkbox/checkboxInner.tsx +4 -1
  7. package/datePicker/__test__/datePicker.test.js +1 -0
  8. package/datePicker/_story/v2/FixTriggerRender.tsx +36 -0
  9. package/datePicker/_story/v2/index.js +1 -0
  10. package/datePicker/datePicker.tsx +7 -5
  11. package/dist/css/semi.css +39 -11
  12. package/dist/css/semi.min.css +1 -1
  13. package/dist/umd/semi-ui.js +1151 -347
  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/dropdown/context.ts +2 -0
  18. package/dropdown/dropdownItem.tsx +2 -1
  19. package/dropdown/dropdownMenu.tsx +24 -1
  20. package/dropdown/index.tsx +10 -2
  21. package/form/_story/form.stories.tsx +23 -15
  22. package/form/hoc/withField.tsx +1 -1
  23. package/form/interface.ts +1 -1
  24. package/input/__test__/input.test.js +31 -0
  25. package/input/_story/input.stories.js +24 -1
  26. package/input/index.tsx +5 -2
  27. package/input/inputGroup.tsx +7 -6
  28. package/inputNumber/index.tsx +5 -3
  29. package/lib/cjs/autoComplete/index.d.ts +0 -1
  30. package/lib/cjs/autoComplete/index.js +0 -1
  31. package/lib/cjs/cascader/index.d.ts +1 -1
  32. package/lib/cjs/cascader/index.js +36 -9
  33. package/lib/cjs/checkbox/checkbox.d.ts +1 -0
  34. package/lib/cjs/checkbox/checkbox.js +2 -1
  35. package/lib/cjs/checkbox/checkboxInner.d.ts +2 -0
  36. package/lib/cjs/checkbox/checkboxInner.js +8 -2
  37. package/lib/cjs/datePicker/datePicker.d.ts +1 -1
  38. package/lib/cjs/datePicker/datePicker.js +21 -6
  39. package/lib/cjs/dropdown/context.d.ts +2 -0
  40. package/lib/cjs/dropdown/dropdownItem.js +3 -1
  41. package/lib/cjs/dropdown/dropdownMenu.d.ts +18 -1
  42. package/lib/cjs/dropdown/dropdownMenu.js +23 -2
  43. package/lib/cjs/dropdown/index.d.ts +4 -0
  44. package/lib/cjs/dropdown/index.js +13 -5
  45. package/lib/cjs/form/baseForm.d.ts +16 -15
  46. package/lib/cjs/form/field.d.ts +16 -15
  47. package/lib/cjs/form/hoc/withField.d.ts +1 -1
  48. package/lib/cjs/form/interface.d.ts +1 -1
  49. package/lib/cjs/input/index.d.ts +2 -1
  50. package/lib/cjs/input/index.js +11 -5
  51. package/lib/cjs/input/inputGroup.js +16 -9
  52. package/lib/cjs/inputNumber/index.d.ts +1 -0
  53. package/lib/cjs/inputNumber/index.js +8 -3
  54. package/lib/cjs/locale/source/de.d.ts +3 -0
  55. package/lib/cjs/locale/source/de.js +165 -0
  56. package/lib/cjs/locale/source/fr.d.ts +3 -0
  57. package/lib/cjs/locale/source/fr.js +165 -0
  58. package/lib/cjs/locale/source/it.d.ts +3 -0
  59. package/lib/cjs/locale/source/it.js +165 -0
  60. package/lib/cjs/modal/ModalContent.d.ts +1 -0
  61. package/lib/cjs/modal/ModalContent.js +17 -4
  62. package/lib/cjs/modal/confirm.d.ts +5 -0
  63. package/lib/cjs/radio/radio.d.ts +2 -0
  64. package/lib/cjs/radio/radio.js +2 -1
  65. package/lib/cjs/radio/radioInner.d.ts +2 -0
  66. package/lib/cjs/radio/radioInner.js +8 -2
  67. package/lib/cjs/rating/index.d.ts +7 -0
  68. package/lib/cjs/rating/index.js +135 -68
  69. package/lib/cjs/rating/item.d.ts +27 -3
  70. package/lib/cjs/rating/item.js +145 -38
  71. package/lib/cjs/select/index.d.ts +2 -0
  72. package/lib/cjs/select/index.js +15 -3
  73. package/lib/cjs/spin/icon.js +1 -1
  74. package/lib/cjs/table/Body/index.js +1 -1
  75. package/lib/cjs/tabs/index.d.ts +1 -0
  76. package/lib/cjs/tabs/index.js +2 -1
  77. package/lib/cjs/tabs/interface.d.ts +1 -0
  78. package/lib/cjs/tag/index.js +4 -5
  79. package/lib/cjs/tag/interface.d.ts +1 -0
  80. package/lib/cjs/tagInput/index.d.ts +2 -0
  81. package/lib/cjs/tagInput/index.js +19 -5
  82. package/lib/cjs/timePicker/TimeInput.d.ts +2 -1
  83. package/lib/cjs/timePicker/TimeInput.js +7 -3
  84. package/lib/cjs/timePicker/TimePicker.d.ts +2 -0
  85. package/lib/cjs/timePicker/TimePicker.js +2 -1
  86. package/lib/cjs/timePicker/index.d.ts +1 -0
  87. package/lib/cjs/tooltip/index.d.ts +2 -0
  88. package/lib/cjs/tooltip/index.js +12 -4
  89. package/lib/cjs/tree/index.d.ts +1 -0
  90. package/lib/cjs/tree/index.js +21 -5
  91. package/lib/cjs/tree/treeNode.js +15 -19
  92. package/lib/cjs/treeSelect/index.js +20 -4
  93. package/lib/es/autoComplete/index.d.ts +0 -1
  94. package/lib/es/autoComplete/index.js +0 -1
  95. package/lib/es/cascader/index.d.ts +1 -1
  96. package/lib/es/cascader/index.js +36 -9
  97. package/lib/es/checkbox/checkbox.d.ts +1 -0
  98. package/lib/es/checkbox/checkbox.js +2 -1
  99. package/lib/es/checkbox/checkboxInner.d.ts +2 -0
  100. package/lib/es/checkbox/checkboxInner.js +8 -2
  101. package/lib/es/datePicker/datePicker.d.ts +1 -1
  102. package/lib/es/datePicker/datePicker.js +21 -6
  103. package/lib/es/dropdown/context.d.ts +2 -0
  104. package/lib/es/dropdown/dropdownItem.js +3 -1
  105. package/lib/es/dropdown/dropdownMenu.d.ts +18 -1
  106. package/lib/es/dropdown/dropdownMenu.js +21 -2
  107. package/lib/es/dropdown/index.d.ts +4 -0
  108. package/lib/es/dropdown/index.js +13 -5
  109. package/lib/es/form/baseForm.d.ts +16 -15
  110. package/lib/es/form/field.d.ts +16 -15
  111. package/lib/es/form/hoc/withField.d.ts +1 -1
  112. package/lib/es/form/interface.d.ts +1 -1
  113. package/lib/es/input/index.d.ts +2 -1
  114. package/lib/es/input/index.js +11 -5
  115. package/lib/es/input/inputGroup.js +15 -9
  116. package/lib/es/inputNumber/index.d.ts +1 -0
  117. package/lib/es/inputNumber/index.js +8 -3
  118. package/lib/es/locale/source/de.d.ts +3 -0
  119. package/lib/es/locale/source/de.js +153 -0
  120. package/lib/es/locale/source/fr.d.ts +3 -0
  121. package/lib/es/locale/source/fr.js +153 -0
  122. package/lib/es/locale/source/it.d.ts +3 -0
  123. package/lib/es/locale/source/it.js +153 -0
  124. package/lib/es/modal/ModalContent.d.ts +1 -0
  125. package/lib/es/modal/ModalContent.js +17 -4
  126. package/lib/es/modal/confirm.d.ts +5 -0
  127. package/lib/es/radio/radio.d.ts +2 -0
  128. package/lib/es/radio/radio.js +2 -1
  129. package/lib/es/radio/radioInner.d.ts +2 -0
  130. package/lib/es/radio/radioInner.js +8 -2
  131. package/lib/es/rating/index.d.ts +7 -0
  132. package/lib/es/rating/index.js +133 -65
  133. package/lib/es/rating/item.d.ts +27 -3
  134. package/lib/es/rating/item.js +145 -32
  135. package/lib/es/select/index.d.ts +2 -0
  136. package/lib/es/select/index.js +15 -3
  137. package/lib/es/spin/icon.js +1 -1
  138. package/lib/es/table/Body/index.js +1 -1
  139. package/lib/es/tabs/index.d.ts +1 -0
  140. package/lib/es/tabs/index.js +2 -1
  141. package/lib/es/tabs/interface.d.ts +1 -0
  142. package/lib/es/tag/index.js +4 -5
  143. package/lib/es/tag/interface.d.ts +1 -0
  144. package/lib/es/tagInput/index.d.ts +2 -0
  145. package/lib/es/tagInput/index.js +19 -5
  146. package/lib/es/timePicker/TimeInput.d.ts +2 -1
  147. package/lib/es/timePicker/TimeInput.js +7 -3
  148. package/lib/es/timePicker/TimePicker.d.ts +2 -0
  149. package/lib/es/timePicker/TimePicker.js +2 -1
  150. package/lib/es/timePicker/index.d.ts +1 -0
  151. package/lib/es/tooltip/index.d.ts +2 -0
  152. package/lib/es/tooltip/index.js +13 -4
  153. package/lib/es/tree/index.d.ts +1 -0
  154. package/lib/es/tree/index.js +19 -5
  155. package/lib/es/tree/treeNode.js +14 -20
  156. package/lib/es/treeSelect/index.js +18 -4
  157. package/locale/source/de.ts +156 -0
  158. package/locale/source/fr.ts +156 -0
  159. package/locale/source/it.ts +156 -0
  160. package/modal/ModalContent.tsx +7 -4
  161. package/package.json +8 -8
  162. package/radio/radio.tsx +2 -0
  163. package/radio/radioInner.tsx +4 -1
  164. package/rating/__test__/rating.test.js +13 -31
  165. package/rating/_story/rating.stories.js +13 -2
  166. package/rating/index.tsx +63 -18
  167. package/rating/item.tsx +141 -26
  168. package/select/index.tsx +6 -2
  169. package/spin/icon.tsx +1 -1
  170. package/table/Body/index.tsx +1 -1
  171. package/table/_story/v2/FixedVirtualizedEmpty.tsx +76 -0
  172. package/table/_story/v2/index.js +2 -1
  173. package/tabs/index.tsx +1 -0
  174. package/tabs/interface.ts +1 -0
  175. package/tag/index.tsx +2 -3
  176. package/tag/interface.ts +1 -0
  177. package/tagInput/index.tsx +8 -4
  178. package/timePicker/TimeInput.tsx +5 -3
  179. package/timePicker/TimePicker.tsx +2 -0
  180. package/tooltip/index.tsx +7 -2
  181. package/tree/index.tsx +13 -2
  182. package/tree/treeNode.tsx +11 -13
  183. package/treeSelect/_story/treeSelect.stories.js +38 -1
  184. package/treeSelect/index.tsx +13 -3
  185. package/upload/_story/upload.stories.tsx +9 -6
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import Rating from '../index';
3
+ import Button from '../../button'
3
4
  import { IconLikeHeart } from '@douyinfe/semi-icons';
4
5
 
5
6
  export default {
@@ -25,7 +26,7 @@ export const _Rating = () => (
25
26
  <Rating allowClear={false} />
26
27
  <br />
27
28
  <h5>character</h5>
28
- <Rating character={<IconLikeHeart />} />
29
+ <Rating size="small" character={<IconLikeHeart />} />
29
30
  <br />
30
31
  <Rating character={'好'} defaultValue={2} disabled />
31
32
  </div>
@@ -72,7 +73,7 @@ class Demo extends React.Component {
72
73
  const desc = ['terrible', 'bad', 'normal', 'good', 'wonderful'];
73
74
  return (
74
75
  <div>
75
- <span>How was the help you received: {value ? <span>{desc[value - 1]}</span> : ''}</span>
76
+ <span>How was the help you received: {value ? <span id='rating-result'>{desc[value - 1]}</span> : ''}</span>
76
77
  <br />
77
78
  <Rating tooltips={desc} onChange={this.handleChange} value={value} />
78
79
  </div>
@@ -95,3 +96,13 @@ export const Keydown = () => <KeyDownDemo />;
95
96
  Keydown.story = {
96
97
  name: 'keydown',
97
98
  };
99
+
100
+ const AutoFocusDemo = () => {
101
+ return <Rating defaultValue={2} autoFocus />;
102
+ }
103
+
104
+ export const AutoFocus = () => <AutoFocusDemo />;
105
+
106
+ AutoFocus.story = {
107
+ name: 'autofocus',
108
+ };
package/rating/index.tsx CHANGED
@@ -41,6 +41,7 @@ export interface RatingProps {
41
41
  size?: 'small' | 'default' | number;
42
42
  tooltips?: string[];
43
43
  id?: string;
44
+ preventScroll?: boolean;
44
45
  }
45
46
 
46
47
  export interface RatingState {
@@ -48,6 +49,7 @@ export interface RatingState {
48
49
  hoverValue: number;
49
50
  focused: boolean;
50
51
  clearedValue: number;
52
+ emptyStarFocusVisible: boolean;
51
53
  }
52
54
 
53
55
  export default class Rating extends BaseComponent<RatingProps, RatingState> {
@@ -79,6 +81,7 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
79
81
  size: PropTypes.oneOfType([PropTypes.oneOf(strings.SIZE_SET), PropTypes.number]),
80
82
  tooltips: PropTypes.arrayOf(PropTypes.string),
81
83
  id: PropTypes.string,
84
+ preventScroll: PropTypes.bool,
82
85
  };
83
86
 
84
87
  static defaultProps = {
@@ -90,7 +93,7 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
90
93
  prefixCls: cssClasses.PREFIX,
91
94
  onChange: noop,
92
95
  onHoverChange: noop,
93
- tabIndex: 0,
96
+ tabIndex: -1,
94
97
  size: 'default' as const,
95
98
  };
96
99
 
@@ -108,6 +111,7 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
108
111
  focused: false,
109
112
  hoverValue: undefined,
110
113
  clearedValue: null,
114
+ emptyStarFocusVisible: false,
111
115
  };
112
116
 
113
117
  this.foundation = new RatingFoundation(this.adapter);
@@ -127,9 +131,11 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
127
131
  return {
128
132
  ...super.adapter,
129
133
  focus: () => {
130
- const { disabled } = this.props;
134
+ const { disabled, count } = this.props;
135
+ const { value } = this.state;
131
136
  if (!disabled) {
132
- this.rate.focus();
137
+ const index = Math.ceil(value) - 1;
138
+ this.stars[index < 0 ? count : index].starFocus();
133
139
  }
134
140
  },
135
141
  getStarDOM: (index: number) => {
@@ -180,6 +186,11 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
180
186
  });
181
187
  onKeyDown && onKeyDown(e);
182
188
  },
189
+ setEmptyStarFocusVisible: (focusVisible: boolean): void => {
190
+ this.setState({
191
+ emptyStarFocusVisible: focusVisible,
192
+ });
193
+ },
183
194
  };
184
195
  }
185
196
 
@@ -217,9 +228,9 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
217
228
  };
218
229
 
219
230
  focus = () => {
220
- const { disabled } = this.props;
231
+ const { disabled, preventScroll } = this.props;
221
232
  if (!disabled) {
222
- this.rate.focus();
233
+ this.rate.focus({ preventScroll });
223
234
  }
224
235
  };
225
236
 
@@ -238,11 +249,31 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
238
249
  this.rate = node;
239
250
  };
240
251
 
241
- render() {
242
- const { count, allowHalf, style, prefixCls, disabled, className, character, tabIndex, size, tooltips, id } =
243
- this.props;
252
+ handleStarFocusVisible = (event: React.FocusEvent) => {
253
+ this.foundation.handleStarFocusVisible(event);
254
+ }
255
+
256
+ handleStarBlur = (event: React.FocusEvent) => {
257
+ this.foundation.handleStarBlur(event);
258
+ }
259
+
260
+ getAriaLabelPrefix = () => {
261
+ if (this.props['aria-label']) {
262
+ return this.props['aria-label'];
263
+ }
264
+ let prefix = 'star';
265
+ const { character } = this.props;
266
+ if (typeof character === 'string') {
267
+ prefix = character;
268
+ }
269
+ return prefix;
270
+ }
271
+
272
+ getItemList = (ariaLabelPrefix: string) => {
273
+ const { count, allowHalf, prefixCls, disabled, character, size, tooltips } =this.props;
244
274
  const { value, hoverValue, focused } = this.state;
245
- const itemList = [...Array(count).keys()].map(ind => {
275
+ // index == count is for Empty rating
276
+ const itemList = [...Array(count + 1).keys()].map(ind => {
246
277
  const content = (
247
278
  <Item
248
279
  ref={this.saveRef(ind)}
@@ -251,13 +282,16 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
251
282
  prefixCls={`${prefixCls}-star`}
252
283
  allowHalf={allowHalf}
253
284
  value={hoverValue === undefined ? value : hoverValue}
254
- onClick={this.onClick}
255
- onHover={this.onHover}
285
+ onClick={disabled ? noop : this.onClick}
286
+ onHover={disabled ? noop : this.onHover}
256
287
  key={ind}
257
288
  disabled={disabled}
258
289
  character={character}
259
290
  focused={focused}
260
- size={size}
291
+ size={ind === count ? 0 : size}
292
+ ariaLabelPrefix={ariaLabelPrefix}
293
+ onFocus={disabled || count !== ind ? noop : this.handleStarFocusVisible}
294
+ onBlur={disabled || count !== ind ? noop : this.handleStarBlur}
261
295
  />
262
296
  );
263
297
  if (tooltips) {
@@ -271,25 +305,36 @@ export default class Rating extends BaseComponent<RatingProps, RatingState> {
271
305
  }
272
306
  return content;
273
307
  });
308
+ return itemList;
309
+ }
310
+
311
+ render() {
312
+ const { style, prefixCls, disabled, className, id, count, tabIndex } = this.props;
313
+ const { value, emptyStarFocusVisible } = this.state;
314
+ const ariaLabelPrefix = this.getAriaLabelPrefix();
315
+ const ariaLabel = `Rating: ${value} of ${count} ${ariaLabelPrefix}${value === 1 ? '' : 's'},`;
316
+ const itemList = this.getItemList(ariaLabelPrefix);
274
317
  const listCls = cls(
275
318
  prefixCls,
276
319
  {
277
320
  [`${prefixCls}-disabled`]: disabled,
321
+ [`${prefixCls}-focus`]: emptyStarFocusVisible,
278
322
  },
279
323
  className
280
324
  );
281
325
  return (
282
- <ul
283
- aria-label={this.props['aria-label']}
326
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
327
+ <ul
328
+ aria-label={ariaLabel}
284
329
  aria-labelledby={this.props['aria-labelledby']}
285
330
  aria-describedby={this.props['aria-describedby']}
286
331
  className={listCls}
287
332
  style={style}
288
- onMouseLeave={disabled ? null : this.onMouseLeave}
333
+ onMouseLeave={disabled ? noop : this.onMouseLeave}
289
334
  tabIndex={disabled ? -1 : tabIndex}
290
- onFocus={disabled ? null : this.onFocus}
291
- onBlur={disabled ? null : this.onBlur}
292
- onKeyDown={disabled ? null : this.onKeyDown}
335
+ onFocus={disabled ? noop : this.onFocus}
336
+ onBlur={disabled ? noop : this.onBlur}
337
+ onKeyDown={disabled ? noop : this.onKeyDown}
293
338
  ref={this.saveRate as any}
294
339
  id={id}
295
340
  >
package/rating/item.tsx CHANGED
@@ -1,14 +1,17 @@
1
1
  import React, { PureComponent } from 'react';
2
2
  import cls from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
- import { strings } from '@douyinfe/semi-foundation/rating/constants';
4
+ import { cssClasses, strings } from '@douyinfe/semi-foundation/rating/constants';
5
5
  import '@douyinfe/semi-foundation/rating/rating.scss';
6
6
  import { IconStar } from '@douyinfe/semi-icons';
7
+ import { RatingItemFoundation, RatingItemAdapter } from '@douyinfe/semi-foundation/rating/foundation';
8
+ import BaseComponent, { BaseProps } from '../_base/baseComponent';
9
+
7
10
 
8
11
  type ArrayElement<ArrayType extends readonly unknown[]> =
9
12
  ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
10
13
 
11
- export interface RatingItemProps {
14
+ export interface RatingItemProps extends BaseProps {
12
15
  value: number;
13
16
  index: number;
14
17
  prefixCls: string;
@@ -19,11 +22,20 @@ export interface RatingItemProps {
19
22
  focused: boolean;
20
23
  disabled: boolean;
21
24
  count: number;
25
+ ariaLabelPrefix: string;
22
26
  size: number | ArrayElement<typeof strings.SIZE_SET>;
23
27
  'aria-describedby'?: React.AriaAttributes['aria-describedby'];
28
+ onFocus?: (e: React.FocusEvent) => void;
29
+ onBlur?: (e: React.FocusEvent) => void;
30
+ preventScroll?: boolean;
31
+ }
32
+
33
+ export interface RatingItemState {
34
+ firstStarFocus: boolean,
35
+ secondStarFocus: boolean,
24
36
  }
25
37
 
26
- export default class Item extends PureComponent<RatingItemProps> {
38
+ export default class Item extends BaseComponent<RatingItemProps, RatingItemState> {
27
39
  static propTypes = {
28
40
  value: PropTypes.number,
29
41
  index: PropTypes.number,
@@ -35,13 +47,47 @@ export default class Item extends PureComponent<RatingItemProps> {
35
47
  focused: PropTypes.bool,
36
48
  disabled: PropTypes.bool,
37
49
  count: PropTypes.number,
50
+ ariaLabelPrefix: PropTypes.string,
38
51
  size: PropTypes.oneOfType([
39
52
  PropTypes.oneOf(strings.SIZE_SET),
40
53
  PropTypes.number,
41
54
  ]),
42
55
  'aria-describedby': PropTypes.string,
56
+ onFocus: PropTypes.func,
57
+ onBlur: PropTypes.func,
58
+ preventScroll: PropTypes.bool,
43
59
  };
44
60
 
61
+ foundation: RatingItemFoundation;
62
+
63
+ constructor(props: RatingItemProps) {
64
+ super(props);
65
+ this.state = {
66
+ firstStarFocus: false,
67
+ secondStarFocus: false,
68
+ };
69
+ this.foundation = new RatingItemFoundation(this.adapter);
70
+ }
71
+
72
+ get adapter(): RatingItemAdapter<RatingItemProps, RatingItemState> {
73
+ return {
74
+ ...super.adapter,
75
+ setFirstStarFocus: (value) => {
76
+ this.setState({
77
+ firstStarFocus: value,
78
+ });
79
+ },
80
+ setSecondStarFocus: (value) => {
81
+ this.setState({
82
+ secondStarFocus: value,
83
+ });
84
+ }
85
+ };
86
+ }
87
+
88
+ firstStar: HTMLDivElement = null;
89
+ secondStar: HTMLDivElement = null;
90
+
45
91
  onHover: React.MouseEventHandler = e => {
46
92
  const { onHover, index } = this.props;
47
93
  onHover(e, index);
@@ -52,6 +98,19 @@ export default class Item extends PureComponent<RatingItemProps> {
52
98
  onClick(e, index);
53
99
  };
54
100
 
101
+ onFocus = (e, star) => {
102
+ const { onFocus } = this.props;
103
+ onFocus && onFocus(e);
104
+ this.foundation.handleFocusVisible(e, star);
105
+ }
106
+
107
+ onBlur = (e, star) => {
108
+ const { onBlur } = this.props;
109
+ onBlur && onBlur(e);
110
+ this.foundation.handleBlur(e, star);
111
+ }
112
+
113
+
55
114
  onKeyDown: React.KeyboardEventHandler = e => {
56
115
  const { onClick, index } = this.props;
57
116
  if (e.keyCode === 13) {
@@ -59,6 +118,23 @@ export default class Item extends PureComponent<RatingItemProps> {
59
118
  }
60
119
  };
61
120
 
121
+ starFocus = () => {
122
+ const { value, index, preventScroll } = this.props;
123
+ if (value - index === 0.5) {
124
+ this.firstStar.focus({ preventScroll });
125
+ } else {
126
+ this.secondStar.focus({ preventScroll });
127
+ }
128
+ }
129
+
130
+ saveFirstStar = (node: HTMLDivElement) => {
131
+ this.firstStar = node;
132
+ };
133
+
134
+ saveSecondStar = (node: HTMLDivElement) => {
135
+ this.secondStar = node;
136
+ };
137
+
62
138
  render() {
63
139
  const {
64
140
  index,
@@ -69,18 +145,18 @@ export default class Item extends PureComponent<RatingItemProps> {
69
145
  disabled,
70
146
  allowHalf,
71
147
  focused,
72
- size
148
+ size,
149
+ ariaLabelPrefix,
73
150
  } = this.props;
151
+ const { firstStarFocus, secondStarFocus } = this.state;
74
152
  const starValue = index + 1;
75
153
  const diff = starValue - value;
76
- const isFocused = value === 0 && index === 0 && focused;
77
154
  // const isHalf = allowHalf && value + 0.5 === starValue;
78
155
  const isHalf = allowHalf && diff < 1 && diff > 0;
79
- const firstWidth = isHalf ? 1 - diff : 0.5;
156
+ const firstWidth = 1 - diff;
80
157
  const isFull = starValue <= value;
81
158
  const isCustomSize = typeof size === 'number';
82
159
  const starCls = cls(prefixCls, {
83
- [`${prefixCls}-focused`]: isFocused,
84
160
  [`${prefixCls}-half`]: isHalf,
85
161
  [`${prefixCls}-full`]: isFull,
86
162
  [`${prefixCls}-${size}`]: !isCustomSize,
@@ -91,26 +167,65 @@ export default class Item extends PureComponent<RatingItemProps> {
91
167
  fontSize: size
92
168
  } : {};
93
169
  const iconSize = isCustomSize ? 'inherit' : (size === 'small' ? 'default' : 'extra-large');
94
- const content = character ? character : <IconStar size={iconSize} />;
170
+ const content = character ? character : <IconStar size={iconSize} style={{ display: 'block' }}/>;
171
+ const isEmpty = index === count;
172
+ const starWrapCls = cls(`${prefixCls}-wrapper`,{
173
+ [`${prefixCls}-disabled`]: disabled,
174
+ [`${cssClasses.PREFIX}-focus`]: (firstStarFocus || secondStarFocus) && value !== 0,
175
+ });
176
+ const starWrapProps = {
177
+ onClick: disabled ? null : this.onClick ,
178
+ onKeyDown: disabled ? null : this.onKeyDown,
179
+ onMouseMove: disabled ? null : this.onHover,
180
+ className: starWrapCls,
181
+ };
182
+ const AriaSetSize = allowHalf ? count * 2 + 1 : count + 1;
183
+ const firstStarProps = {
184
+ ref: this.saveFirstStar as any,
185
+ role:"radio",
186
+ 'aria-checked': value === index + 0.5,
187
+ 'aria-posinset': 2 * index + 1,
188
+ 'aria-setsize': AriaSetSize,
189
+ 'aria-disabled': disabled,
190
+ 'aria-label': `${index + 0.5} ${ariaLabelPrefix}s`,
191
+ 'aria-labelledby': this.props['aria-describedby'],
192
+ 'aria-describedby': this.props['aria-describedby'],
193
+ className: cls(`${prefixCls}-first`,`${cssClasses.PREFIX}-no-focus`),
194
+ tabIndex: !disabled && value === index + 0.5 ? 0 : -1,
195
+ onFocus: (e) => {
196
+ this.onFocus(e, 'first');
197
+ },
198
+ onBlur:(e) => {
199
+ this.onBlur(e, 'first');
200
+ },
201
+ };
202
+
203
+ const secondStarTabIndex = !disabled && ((value === index + 1) || (isEmpty && value === 0)) ? 0 : -1;
204
+ const secondStarProps = {
205
+ ref: this.saveSecondStar as any,
206
+ role:"radio",
207
+ 'aria-checked': isEmpty ? value === 0 : value === index + 1,
208
+ 'aria-posinset': allowHalf ? 2 * (index + 1) : index + 1,
209
+ 'aria-setsize': AriaSetSize,
210
+ 'aria-disabled': disabled,
211
+ 'aria-label': `${isEmpty ? 0 : index + 1} ${ariaLabelPrefix}${index === 0 ? '' : 's'}`,
212
+ 'aria-labelledby': this.props['aria-describedby'],
213
+ 'aria-describedby': this.props['aria-describedby'],
214
+ className: cls(`${prefixCls}-second`,`${cssClasses.PREFIX}-no-focus`),
215
+ tabIndex: secondStarTabIndex,
216
+ onFocus: (e) => {
217
+ this.onFocus(e, 'second');
218
+ },
219
+ onBlur:(e) => {
220
+ this.onBlur(e, 'second');
221
+ },
222
+ };
223
+
95
224
  return (
96
- <li className={starCls} style={{ ...sizeStyle }}>
97
- <div
98
- onClick={disabled ? null : this.onClick}
99
- onKeyDown={disabled ? null : this.onKeyDown}
100
- onMouseMove={disabled ? null : this.onHover}
101
- role="radio"
102
- aria-checked={value > index ? 'true' : 'false'}
103
- aria-posinset={index + 1}
104
- aria-setsize={count}
105
- aria-disabled={disabled}
106
- aria-label={`Rating ${index + (isHalf ? 0.5 : 1)}`}
107
- aria-labelledby={this.props['aria-describedby']} // screen reader will read labelledby instead of describedby
108
- aria-describedby={this.props['aria-describedby']}
109
- tabIndex={0}
110
- className={`${prefixCls}-wrapper`}
111
- >
112
- <div className={`${prefixCls}-first`} style={{ width: `${firstWidth * 100}%` }}>{content}</div>
113
- <div className={`${prefixCls}-second`} x-semi-prop="character">{content}</div>
225
+ <li className={starCls} style={{ ...sizeStyle }} key={index} >
226
+ <div {...(starWrapProps as any)}>
227
+ {allowHalf && !isEmpty && <div {...firstStarProps} style={{ width: `${firstWidth * 100}%` }}>{content}</div>}
228
+ <div {...secondStarProps} x-semi-prop="character">{content}</div>
114
229
  </div>
115
230
  </li>
116
231
  );
package/select/index.tsx CHANGED
@@ -152,6 +152,7 @@ export type SelectProps = {
152
152
  onBlur?: (e: React.FocusEvent) => void;
153
153
  onListScroll?: (e: React.UIEvent<HTMLDivElement>) => void;
154
154
  children?: React.ReactNode;
155
+ preventScroll?: boolean;
155
156
  } & Pick<
156
157
  TooltipProps,
157
158
  | 'spacing'
@@ -271,6 +272,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
271
272
  renderOptionItem: PropTypes.func,
272
273
  onListScroll: PropTypes.func,
273
274
  arrowIcon: PropTypes.node,
275
+ preventScroll: PropTypes.bool,
274
276
  // open: PropTypes.bool,
275
277
  // tagClosable: PropTypes.bool,
276
278
  };
@@ -396,8 +398,9 @@ class Select extends BaseComponent<SelectProps, SelectState> {
396
398
  });
397
399
  },
398
400
  focusInput: () => {
401
+ const { preventScroll } = this.props;
399
402
  if (this.inputRef && this.inputRef.current) {
400
- this.inputRef.current.focus();
403
+ this.inputRef.current.focus({ preventScroll });
401
404
  }
402
405
  },
403
406
  };
@@ -526,8 +529,9 @@ class Select extends BaseComponent<SelectProps, SelectState> {
526
529
  },
527
530
  focusTrigger: () => {
528
531
  try {
532
+ const { preventScroll } = this.props;
529
533
  const el = (this.triggerRef.current) as any;
530
- el.focus();
534
+ el.focus({ preventScroll });
531
535
  } catch (error) {
532
536
 
533
537
  }
package/spin/icon.tsx CHANGED
@@ -40,7 +40,7 @@ function Icon(props: IconProps = {}) {
40
40
  </linearGradient>
41
41
  </defs>
42
42
  <g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
43
- <rect fillOpacity="0.01" fill="#FFFFFF" x="0" y="0" width="36" height="36" />
43
+ <rect fillOpacity="0.01" fill="none" x="0" y="0" width="36" height="36" />
44
44
  <path
45
45
  d="M34,18 C34,9.163444 26.836556,2 18,2 C11.6597233,2 6.18078805,5.68784135 3.59122325,11.0354951"
46
46
  stroke={`url(#${id})`}
@@ -423,7 +423,7 @@ class Body extends BaseComponent<BodyProps, BodyState> {
423
423
 
424
424
  const listStyle = {
425
425
  width: '100%',
426
- height: y,
426
+ height: virtualizedData?.length ? y : 0,
427
427
  overflowX: 'auto',
428
428
  overflowY: 'auto',
429
429
  } as const;
@@ -0,0 +1,76 @@
1
+ import React, { useState } from 'react';
2
+ import { Table, Tag, Tooltip, Button } from '../../../index';
3
+
4
+ export default function App() {
5
+ const [data, setData] = useState([]);
6
+
7
+ const loadData = () => {
8
+ if (Array.isArray(data) && data.length > 0) {
9
+ setData([]);
10
+ return;
11
+ }
12
+
13
+ const newData = [];
14
+ for (let i = 0; i < 10000; i++) {
15
+ const age = (i * 1000) % 149;
16
+ const name = `Edward King ${i}`;
17
+ newData.push({
18
+ key: '' + i,
19
+ name,
20
+ age,
21
+ address: `London, Park Lane no. ${i}`,
22
+ description: `My name is ${name}, I am ${age} years old, living in New York No. ${i + 1} Lake Park.`,
23
+ });
24
+ }
25
+
26
+ setData(newData);
27
+ };
28
+
29
+ const scroll = { y: 600, x: 1600 };
30
+ const style = { width: 800 };
31
+ const columns = [
32
+ {
33
+ title: 'Name',
34
+ dataIndex: 'name',
35
+ width: 150,
36
+ fixed: true,
37
+ filters: [
38
+ {
39
+ text: 'Code 45',
40
+ value: '45',
41
+ },
42
+ {
43
+ text: 'King 4',
44
+ value: 'King 4',
45
+ },
46
+ ],
47
+ onFilter: (value, record) => record.name.includes(value),
48
+ },
49
+ {
50
+ title: 'Age',
51
+ dataIndex: 'age',
52
+ width: 150,
53
+ sorter: (a, b) => (a.age - b.age > 0 ? 1 : -1),
54
+ },
55
+ {
56
+ title: 'Address',
57
+ // width: 200,
58
+ dataIndex: 'address',
59
+ },
60
+ {
61
+ fixed: 'right' as const,
62
+ width: 250,
63
+ render: (text, record) => (
64
+ <Tooltip content={record.description}>
65
+ <Tag color="green">Show Info</Tag>
66
+ </Tooltip>
67
+ ),
68
+ },
69
+ ];
70
+ return (
71
+ <div>
72
+ <Button onClick={loadData}>load data</Button>
73
+ <Table pagination={false} columns={columns} dataSource={data} scroll={scroll} style={style} virtualized />
74
+ </div>
75
+ );
76
+ }
@@ -6,4 +6,5 @@ export { default as FixedResizable } from './FixedResizable';
6
6
  export { default as FixedExpandedRow } from './FixedExpandedRow';
7
7
  export { default as FixedMemoryLeak } from './FixedMemoryLeak';
8
8
  export { default as FixedOnHeaderRow } from './FixedOnHeaderRow';
9
- export { default as RadioRowSelection } from './radioRowSelection';
9
+ export { default as RadioRowSelection } from './radioRowSelection';
10
+ export { default as FixedVirtualizedEmpty } from './FixedVirtualizedEmpty';
package/tabs/index.tsx CHANGED
@@ -48,6 +48,7 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
48
48
  tabPosition: PropTypes.oneOf(strings.POSITION_MAP),
49
49
  type: PropTypes.oneOf(strings.TYPE_MAP),
50
50
  onTabClose: PropTypes.func,
51
+ preventScroll: PropTypes.bool,
51
52
  };
52
53
 
53
54
  static defaultProps: TabsProps = {
package/tabs/interface.ts CHANGED
@@ -36,6 +36,7 @@ export interface TabsProps {
36
36
  tabPosition?: TabPosition;
37
37
  type?: TabType;
38
38
  onTabClose?: (tabKey: string) => void;
39
+ preventScroll?: boolean;
39
40
  }
40
41
 
41
42
  export interface TabBarProps {
package/tag/index.tsx CHANGED
@@ -1,6 +1,4 @@
1
1
  /* eslint-disable jsx-a11y/no-static-element-interactions */
2
- /* eslint-disable no-unused-vars */
3
- /* eslint-disable max-len */
4
2
  import React, { Component } from 'react';
5
3
  import classNames from 'classnames';
6
4
  import PropTypes from 'prop-types';
@@ -94,7 +92,7 @@ export default class Tag extends Component<TagProps, TagState> {
94
92
  }
95
93
 
96
94
  handleKeyDown(event: any) {
97
- const { closable, onClick } = this.props;
95
+ const { closable, onClick, onKeyDown } = this.props;
98
96
  switch (event.key) {
99
97
  case "Backspace":
100
98
  case "Delete":
@@ -111,6 +109,7 @@ export default class Tag extends Component<TagProps, TagState> {
111
109
  default:
112
110
  break;
113
111
  }
112
+ onKeyDown && onKeyDown(event);
114
113
  }
115
114
 
116
115
  renderAvatar() {
package/tag/interface.ts CHANGED
@@ -33,6 +33,7 @@ export interface TagProps {
33
33
  className?: string;
34
34
  avatarSrc?: string;
35
35
  avatarShape?: AvatarShape;
36
+ onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
36
37
  'aria-label'?: React.AriaAttributes['aria-label'];
37
38
  }
38
39