@douyinfe/semi-ui 2.5.0 → 2.6.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/button/index.tsx +1 -1
  2. package/calendar/monthCalendar.tsx +14 -13
  3. package/cascader/index.tsx +21 -3
  4. package/cascader/item.tsx +25 -5
  5. package/datePicker/dateInput.tsx +8 -5
  6. package/datePicker/datePicker.tsx +6 -1
  7. package/datePicker/month.tsx +14 -7
  8. package/datePicker/monthsGrid.tsx +17 -5
  9. package/datePicker/navigation.tsx +8 -4
  10. package/datePicker/quickControl.tsx +1 -0
  11. package/datePicker/yearAndMonth.tsx +1 -1
  12. package/dist/css/semi.css +22 -8
  13. package/dist/css/semi.min.css +1 -1
  14. package/dist/umd/semi-ui.js +259 -104
  15. package/dist/umd/semi-ui.js.map +1 -1
  16. package/dist/umd/semi-ui.min.js +1 -1
  17. package/dist/umd/semi-ui.min.js.map +1 -1
  18. package/form/__test__/formApi.test.js +182 -0
  19. package/form/_story/FormApi/arrayDemo.jsx +4 -7
  20. package/form/_story/Layout/slotDemo.jsx +2 -2
  21. package/form/_story/demo.jsx +18 -1
  22. package/form/_story/form.stories.js +6 -6
  23. package/form/baseForm.tsx +2 -2
  24. package/form/hoc/withField.tsx +1 -1
  25. package/lib/cjs/_base/base.css +5 -5
  26. package/lib/cjs/button/Button.d.ts +4 -4
  27. package/lib/cjs/button/buttonGroup.d.ts +2 -2
  28. package/lib/cjs/button/index.d.ts +5 -6
  29. package/lib/cjs/calendar/monthCalendar.js +21 -5
  30. package/lib/cjs/cascader/index.d.ts +9 -2
  31. package/lib/cjs/cascader/index.js +14 -1
  32. package/lib/cjs/cascader/item.d.ts +6 -2
  33. package/lib/cjs/cascader/item.js +33 -4
  34. package/lib/cjs/datePicker/dateInput.d.ts +0 -2
  35. package/lib/cjs/datePicker/dateInput.js +17 -6
  36. package/lib/cjs/datePicker/datePicker.js +15 -12
  37. package/lib/cjs/datePicker/month.d.ts +1 -0
  38. package/lib/cjs/datePicker/month.js +18 -2
  39. package/lib/cjs/datePicker/monthsGrid.js +16 -4
  40. package/lib/cjs/datePicker/navigation.js +8 -0
  41. package/lib/cjs/datePicker/quickControl.js +1 -0
  42. package/lib/cjs/datePicker/yearAndMonth.js +1 -0
  43. package/lib/cjs/form/baseForm.js +2 -2
  44. package/lib/cjs/form/hoc/withField.js +1 -1
  45. package/lib/cjs/iconButton/index.d.ts +2 -2
  46. package/lib/cjs/navigation/Item.d.ts +2 -2
  47. package/lib/cjs/navigation/Item.js +8 -6
  48. package/lib/cjs/navigation/SubNav.js +2 -2
  49. package/lib/cjs/scrollList/scrollItem.d.ts +2 -1
  50. package/lib/cjs/scrollList/scrollItem.js +13 -3
  51. package/lib/cjs/table/Body/index.d.ts +2 -0
  52. package/lib/cjs/table/Body/index.js +13 -4
  53. package/lib/cjs/tooltip/index.js +6 -2
  54. package/lib/es/_base/base.css +5 -5
  55. package/lib/es/button/Button.d.ts +4 -4
  56. package/lib/es/button/buttonGroup.d.ts +2 -2
  57. package/lib/es/button/index.d.ts +5 -6
  58. package/lib/es/calendar/monthCalendar.js +22 -5
  59. package/lib/es/cascader/index.d.ts +9 -2
  60. package/lib/es/cascader/index.js +14 -1
  61. package/lib/es/cascader/item.d.ts +6 -2
  62. package/lib/es/cascader/item.js +31 -4
  63. package/lib/es/datePicker/dateInput.d.ts +0 -2
  64. package/lib/es/datePicker/dateInput.js +17 -6
  65. package/lib/es/datePicker/datePicker.js +15 -12
  66. package/lib/es/datePicker/month.d.ts +1 -0
  67. package/lib/es/datePicker/month.js +18 -2
  68. package/lib/es/datePicker/monthsGrid.js +16 -4
  69. package/lib/es/datePicker/navigation.js +8 -0
  70. package/lib/es/datePicker/quickControl.js +2 -0
  71. package/lib/es/datePicker/yearAndMonth.js +1 -0
  72. package/lib/es/form/baseForm.js +2 -2
  73. package/lib/es/form/hoc/withField.js +1 -1
  74. package/lib/es/iconButton/index.d.ts +2 -2
  75. package/lib/es/navigation/Item.d.ts +2 -2
  76. package/lib/es/navigation/Item.js +8 -6
  77. package/lib/es/navigation/SubNav.js +2 -2
  78. package/lib/es/scrollList/scrollItem.d.ts +2 -1
  79. package/lib/es/scrollList/scrollItem.js +13 -3
  80. package/lib/es/table/Body/index.d.ts +2 -0
  81. package/lib/es/table/Body/index.js +13 -4
  82. package/lib/es/tooltip/index.js +6 -2
  83. package/navigation/Item.tsx +15 -12
  84. package/navigation/SubNav.tsx +4 -4
  85. package/package.json +9 -9
  86. package/scrollList/_story/ScrollList/index.js +3 -0
  87. package/scrollList/_story/WheelList/index.js +3 -0
  88. package/scrollList/scrollItem.tsx +30 -9
  89. package/table/Body/index.tsx +15 -4
  90. package/table/__test__/table.test.js +18 -0
  91. package/table/_story/Perf/Virtualized/index.jsx +6 -0
  92. package/table/_story/v2/FixedExpandedRow/index.jsx +95 -0
  93. package/table/_story/v2/FixedHeaderMerge/index.jsx +1 -1
  94. package/table/_story/v2/defaultFilteredValue.tsx +0 -9
  95. package/table/_story/v2/index.js +2 -1
  96. package/tooltip/_story/tooltip.stories.js +702 -625
  97. package/tooltip/index.tsx +2 -2
package/button/index.tsx CHANGED
@@ -12,7 +12,7 @@ export { ButtonGroupProps } from './buttonGroup';
12
12
  export { SplitButtonGroupProps } from './splitButtonGroup';
13
13
 
14
14
  // eslint-disable-next-line
15
- export interface ButtonProps extends IconButtonProps, BaseButtonProps {} // TODO check
15
+ export interface ButtonProps extends IconButtonProps {} // TODO check
16
16
  class Button extends React.PureComponent<ButtonProps> {
17
17
  static propTypes = {
18
18
  ...BaseButton.propTypes,
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
1
2
  import React, { ReactInstance } from 'react';
2
3
  import ReactDOM from 'react-dom';
3
4
  import cls from 'classnames';
@@ -180,16 +181,16 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
180
181
  const { markWeekend, displayValue } = this.props;
181
182
  this.monthlyData = this.foundation.getMonthlyData(displayValue, dateFnsLocale);
182
183
  return (
183
- <div className={`${prefixCls}-header`}>
184
- <div role="gridcell" className={`${prefixCls}-grid`}>
185
- <ul className={`${prefixCls}-grid-row`}>
184
+ <div className={`${prefixCls}-header`} role="presentation">
185
+ <div role="presentation" className={`${prefixCls}-grid`}>
186
+ <ul role="row" className={`${prefixCls}-grid-row`}>
186
187
  {this.monthlyData[0].map(day => {
187
188
  const { weekday } = day;
188
189
  const listCls = cls({
189
190
  [`${cssClasses.PREFIX}-weekend`]: markWeekend && day.isWeekend,
190
191
  });
191
192
  return (
192
- <li key={`${weekday}-monthheader`} className={listCls}>
193
+ <li role="columnheader" aria-label={weekday} key={`${weekday}-monthheader`} className={listCls}>
193
194
  <span>{weekday}</span>
194
195
  </li>
195
196
  );
@@ -268,7 +269,7 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
268
269
  const pos = showCard && showCard[key] ? showCard[key][1] : 'leftTopOver';
269
270
  const text = (
270
271
  <LocaleConsumer componentName="Calendar">
271
- {(locale: Locale['Calendar']) => (
272
+ {(locale: Locale['Calendar']) => (// eslint-disable-next-line jsx-a11y/no-static-element-interactions
272
273
  <div
273
274
  className={`${cardCls}-wrapper`}
274
275
  style={{ bottom: 0 }}
@@ -330,8 +331,8 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
330
331
  const { itemLimit } = this.state;
331
332
  const { display, day } = events;
332
333
  return (
333
- <div role="gridcell" className={`${prefixCls}-weekrow`} ref={this.cellDom} key={`${index}-weekrow`}>
334
- <ul className={`${prefixCls}-skeleton`}>
334
+ <div role="presentation" className={`${prefixCls}-weekrow`} ref={this.cellDom} key={`${index}-weekrow`}>
335
+ <ul role="row" className={`${prefixCls}-skeleton`}>
335
336
  {weekDay.map(each => {
336
337
  const { date, dayString, isToday, isSameMonth, isWeekend, month, ind } = each;
337
338
  const listCls = cls({
@@ -341,7 +342,7 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
341
342
  });
342
343
  const shouldRenderCollapsed = Boolean(day && day[ind] && day[ind].length > itemLimit);
343
344
  const inner = (
344
- <li key={`${date}-weeksk`} className={listCls} onClick={e => this.handleClick(e, [date])}>
345
+ <li role="gridcell" aria-label={date.toLocaleDateString()} aria-current={isToday ? "date" : false} key={`${date}-weeksk`} className={listCls} onClick={e => this.handleClick(e, [date])}>
345
346
  {this.formatDayString(month, dayString)}
346
347
  {this.renderCusDateGrid(date)}
347
348
  </li>
@@ -362,8 +363,8 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
362
363
  renderMonthGrid = () => {
363
364
  const { parsedEvents } = this.state;
364
365
  return (
365
- <div role="gridcell" className={`${prefixCls}-week`}>
366
- <ul className={`${prefixCls}-grid-col`}>
366
+ <div role="presentation" className={`${prefixCls}-week`}>
367
+ <ul role="presentation" className={`${prefixCls}-grid-col`}>
367
368
  {Object.keys(this.monthlyData).map(weekInd =>
368
369
  this.renderWeekRow(weekInd, this.monthlyData[weekInd], parsedEvents[weekInd])
369
370
  )}
@@ -383,12 +384,12 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
383
384
  return (
384
385
  <LocaleConsumer componentName="Calendar">
385
386
  {(locale: Locale['Calendar'], localeCode: string, dateFnsLocale: Locale['dateFnsLocale']) => (
386
- <div className={monthCls} key={this.state.itemLimit} style={monthStyle}>
387
- <div className={`${prefixCls}-sticky-top`}>
387
+ <div role="grid" className={monthCls} key={this.state.itemLimit} style={monthStyle}>
388
+ <div role="presentation" className={`${prefixCls}-sticky-top`}>
388
389
  {header}
389
390
  {this.renderHeader(dateFnsLocale)}
390
391
  </div>
391
- <div className={`${prefixCls}-grid-wrapper`}>
392
+ <div role="presentation" className={`${prefixCls}-grid-wrapper`}>
392
393
  {this.renderMonthGrid()}
393
394
  </div>
394
395
  </div>
@@ -1,4 +1,4 @@
1
- import React, { Fragment, ReactNode, CSSProperties, MouseEvent } from 'react';
1
+ import React, { Fragment, ReactNode, CSSProperties, MouseEvent, KeyboardEvent } from 'react';
2
2
  import ReactDOM from 'react-dom';
3
3
  import cls from 'classnames';
4
4
  import PropTypes from 'prop-types';
@@ -54,6 +54,7 @@ export interface CascaderProps extends BasicCascaderProps {
54
54
  'aria-invalid'?: React.AriaAttributes['aria-invalid'];
55
55
  'aria-labelledby'?: React.AriaAttributes['aria-labelledby'];
56
56
  'aria-required'?: React.AriaAttributes['aria-required'];
57
+ 'aria-label'?: React.AriaAttributes['aria-label'];
57
58
  arrowIcon?: ReactNode;
58
59
  defaultValue?: Value;
59
60
  dropdownStyle?: CSSProperties;
@@ -100,6 +101,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
100
101
  'aria-errormessage': PropTypes.string,
101
102
  'aria-describedby': PropTypes.string,
102
103
  'aria-required': PropTypes.bool,
104
+ 'aria-label': PropTypes.string,
103
105
  arrowIcon: PropTypes.node,
104
106
  changeOnSelect: PropTypes.bool,
105
107
  defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
@@ -197,6 +199,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
197
199
  onDropdownVisibleChange: noop,
198
200
  onListScroll: noop,
199
201
  enableLeafClick: false,
202
+ 'aria-label': 'Cascader'
200
203
  };
201
204
 
202
205
  options: any;
@@ -584,7 +587,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
584
587
  );
585
588
  }
586
589
 
587
- handleItemClick = (e: MouseEvent, item: Entity | Data) => {
590
+ handleItemClick = (e: MouseEvent | KeyboardEvent, item: Entity | Data) => {
588
591
  this.foundation.handleItemClick(e, item);
589
592
  };
590
593
 
@@ -798,6 +801,14 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
798
801
  this.foundation.handleClear();
799
802
  };
800
803
 
804
+ /**
805
+ * A11y: simulate clear button click
806
+ */
807
+ handleClearEnterPress = (e: KeyboardEvent) => {
808
+ e && e.stopPropagation();
809
+ this.foundation.handleClearEnterPress();
810
+ };
811
+
801
812
  showClearBtn = () => {
802
813
  const { showClear, disabled, multiple } = this.props;
803
814
  const { selectedKeys, isOpen, isHovering, checkedKeys } = this.state;
@@ -811,7 +822,13 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
811
822
  const allowClear = this.showClearBtn();
812
823
  if (allowClear) {
813
824
  return (
814
- <div className={clearCls} onClick={this.handleClear} role='button' tabIndex={0}>
825
+ <div
826
+ className={clearCls}
827
+ onClick={this.handleClear}
828
+ onKeyPress={this.handleClearEnterPress}
829
+ role='button'
830
+ tabIndex={0}
831
+ >
815
832
  <IconClear />
816
833
  </div>
817
834
  );
@@ -891,6 +908,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
891
908
  style={style}
892
909
  ref={this.triggerRef}
893
910
  onClick={e => this.foundation.handleClick(e)}
911
+ onKeyPress={e => this.foundation.handleSelectionEnterPress(e)}
894
912
  aria-invalid={this.props['aria-invalid']}
895
913
  aria-errormessage={this.props['aria-errormessage']}
896
914
  aria-label={this.props['aria-label']}
package/cascader/item.tsx CHANGED
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
2
2
  import cls from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
4
  import { cssClasses, strings } from '@douyinfe/semi-foundation/cascader/constants';
5
+ import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
5
6
  import { includes } from 'lodash';
6
7
  import ConfigContext from '../configProvider/context';
7
8
  import LocaleConsumer from '../locale/localeConsumer';
@@ -43,7 +44,7 @@ export interface CascaderItemProps {
43
44
  selectedKeys: Set<string>;
44
45
  loadedKeys: Set<string>;
45
46
  loadingKeys: Set<string>;
46
- onItemClick: (e: React.MouseEvent, item: Entity | Data) => void;
47
+ onItemClick: (e: React.MouseEvent | React.KeyboardEvent, item: Entity | Data) => void;
47
48
  onItemHover: (e: React.MouseEvent, item: Entity) => void;
48
49
  showNext: ShowNextType;
49
50
  onItemCheckboxClick: (item: Entity | Data) => void;
@@ -84,7 +85,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
84
85
  empty: false,
85
86
  };
86
87
 
87
- onClick = (e: React.MouseEvent, item: Entity | Data) => {
88
+ onClick = (e: React.MouseEvent | React.KeyboardEvent, item: Entity | Data) => {
88
89
  const { onItemClick } = this.props;
89
90
  if (item.data.disabled || ('disabled' in item && item.disabled)) {
90
91
  return;
@@ -92,6 +93,15 @@ export default class Item extends PureComponent<CascaderItemProps> {
92
93
  onItemClick(e, item);
93
94
  };
94
95
 
96
+ /**
97
+ * A11y: simulate item click
98
+ */
99
+ handleItemEnterPress = (keyboardEvent: React.KeyboardEvent, item: Entity | Data) => {
100
+ if (isEnterPress(keyboardEvent)) {
101
+ this.onClick(keyboardEvent, item);
102
+ }
103
+ }
104
+
95
105
  onHover = (e: React.MouseEvent, item: Entity) => {
96
106
  const { showNext, onItemHover } = this.props;
97
107
  if (item.data.disabled) {
@@ -136,7 +146,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
136
146
  case 'loading':
137
147
  return <Spin wrapperClassName={`${prefixcls}-spin-icon`} />;
138
148
  case 'empty':
139
- return (<span className={`${prefixcls}-icon ${prefixcls}-icon-empty`} />);
149
+ return (<span aria-hidden={true} className={`${prefixcls}-icon ${prefixcls}-icon-empty`} />);
140
150
  default:
141
151
  return null;
142
152
  }
@@ -179,11 +189,13 @@ export default class Item extends PureComponent<CascaderItemProps> {
179
189
  });
180
190
  return (
181
191
  <li
192
+ role='menuitem'
182
193
  className={className}
183
194
  key={key}
184
195
  onClick={e => {
185
196
  this.onClick(e, item);
186
197
  }}
198
+ onKeyPress={e => this.handleItemEnterPress(e, item)}
187
199
  >
188
200
  <span className={`${prefixcls}-label`}>
189
201
  {!multiple && this.renderIcon('empty')}
@@ -211,9 +223,9 @@ export default class Item extends PureComponent<CascaderItemProps> {
211
223
  let showChildItem: Entity;
212
224
  const ind = content.length;
213
225
  content.push(
214
- <ul className={`${prefixcls}-list`} key={renderData[0].key} onScroll={e => this.props.onListScroll(e, ind)}>
226
+ <ul role='menu' className={`${prefixcls}-list`} key={renderData[0].key} onScroll={e => this.props.onListScroll(e, ind)}>
215
227
  {renderData.map(item => {
216
- const { data, key } = item;
228
+ const { data, key, parentKey } = item;
217
229
  const { children, label, disabled, isLeaf } = data;
218
230
  const { active, selected, loading } = this.getItemStatus(key);
219
231
  const hasChild = Boolean(children) && children.length;
@@ -226,13 +238,21 @@ export default class Item extends PureComponent<CascaderItemProps> {
226
238
  [`${prefixcls}-select`]: selected && !multiple,
227
239
  [`${prefixcls}-disabled`]: disabled
228
240
  });
241
+ const otherAriaProps = parentKey ? { ['aria-owns']: `cascaderItem-${parentKey}` } : {};
229
242
  return (
230
243
  <li
244
+ role='menuitem'
245
+ id={`cascaderItem-${key}`}
246
+ aria-expanded={active}
247
+ aria-haspopup={Boolean(showExpand)}
248
+ aria-disabled={disabled}
249
+ {...otherAriaProps}
231
250
  className={className}
232
251
  key={key}
233
252
  onClick={e => {
234
253
  this.onClick(e, item);
235
254
  }}
255
+ onKeyPress={e => this.handleItemEnterPress(e, item)}
236
256
  onMouseEnter={e => {
237
257
  this.onHover(e, item);
238
258
  }}
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions,jsx-a11y/interactive-supports-focus */
1
2
  /* eslint-disable max-lines-per-function */
2
3
  /* eslint-disable no-unused-vars */
3
4
  import React from 'react';
@@ -40,7 +41,6 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
40
41
  value: PropTypes.array,
41
42
  disabled: PropTypes.bool,
42
43
  type: PropTypes.oneOf(strings.TYPE_SET),
43
- multiple: PropTypes.bool,
44
44
  showClear: PropTypes.bool,
45
45
  format: PropTypes.string, // Attributes not used
46
46
  inputStyle: PropTypes.object,
@@ -65,7 +65,6 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
65
65
  onBlur: noop,
66
66
  onClear: noop,
67
67
  onFocus: noop,
68
- multiple: false,
69
68
  type: 'date',
70
69
  inputStyle: {},
71
70
  inputReadOnly: false,
@@ -177,9 +176,12 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
177
176
  const allowClear = (rangeStart || rangeEnd) && showClear;
178
177
  return allowClear && !disabled ? (
179
178
  <div
179
+ role="button"
180
+ tabIndex={0}
181
+ aria-label="Clear range input value"
180
182
  className={`${prefixCls}-range-input-clearbtn`}
181
183
  onMouseDown={e => !disabled && this.handleRangeInputClear(e)}>
182
- <IconClear />
184
+ <IconClear aria-hidden />
183
185
  </div>
184
186
  ) : null;
185
187
  }
@@ -293,6 +295,7 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
293
295
  validateStatus,
294
296
  block,
295
297
  prefixCls,
298
+ multiple, // Whether to allow multiple values for email and file types
296
299
  dateFnsLocale, // No need to pass to input
297
300
  onBlur,
298
301
  onClear,
@@ -310,8 +313,8 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
310
313
  rangeSeparator,
311
314
  ...rest
312
315
  } = this.props;
313
- const dateIcon = <IconCalendar />;
314
- const dateTimeIcon = <IconCalendarClock />;
316
+ const dateIcon = <IconCalendar aria-hidden />;
317
+ const dateTimeIcon = <IconCalendarClock aria-hidden />;
315
318
  const suffix = type.includes('Time') ? dateTimeIcon : dateIcon;
316
319
  let text = '';
317
320
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/interactive-supports-focus */
1
2
  /* eslint-disable max-len */
2
3
  import React from 'react';
3
4
  import classnames from 'classnames';
@@ -528,8 +529,12 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
528
529
  };
529
530
 
530
531
  return (
531
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
532
532
  <div
533
+ // tooltip will mount a11y props to children
534
+ // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
535
+ role="combobox"
536
+ aria-label={Array.isArray(value) && value.length ? "Change date" : "Choose date"}
537
+ aria-disabled={disabled}
533
538
  onClick={this.handleTriggerWrapperClick}
534
539
  className={inputCls}>
535
540
  {typeof triggerRender === 'function' ? (
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions */
1
2
  /* eslint-disable max-len */
2
3
  import React from 'react';
3
4
  import classNames from 'classnames';
@@ -40,7 +41,8 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
40
41
  startDateOffset: PropTypes.func,
41
42
  endDateOffset: PropTypes.func,
42
43
  rangeInputFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
43
- focusRecordsRef: PropTypes.object
44
+ focusRecordsRef: PropTypes.object,
45
+ multiple: PropTypes.bool,
44
46
  };
45
47
 
46
48
  static defaultProps = {
@@ -275,9 +277,9 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
275
277
  // i18n
276
278
  const weekdaysText = weekdays.map(key => locale.weeks[key]);
277
279
  return (
278
- <div className={weekdayCls}>
280
+ <div role="row" className={weekdayCls}>
279
281
  {weekdaysText.map((E, i) => (
280
- <div key={E + i} className={weekdayItemCls}>
282
+ <div role="columnheader" key={E + i} className={weekdayItemCls}>
281
283
  {E}
282
284
  </div>
283
285
  ))}
@@ -305,7 +307,7 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
305
307
  renderWeek(week: MonthDayInfo[], weekIndex: number) {
306
308
  const weekCls = cssClasses.WEEK;
307
309
  return (
308
- <div className={weekCls} key={weekIndex}>
310
+ <div role="row" className={weekCls} key={weekIndex}>
309
311
  {week.map((day, dayIndex) => this.renderDay(day, dayIndex))}
310
312
  </div>
311
313
  );
@@ -317,7 +319,7 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
317
319
  const { fullDate, dayNumber } = day;
318
320
  if (!fullDate) {
319
321
  return (
320
- <div key={(dayNumber as number) + dayIndex} className={cssClasses.DAY}>
322
+ <div role="gridcell" tabIndex={-1} key={(dayNumber as number) + dayIndex} className={cssClasses.DAY}>
321
323
  <span />
322
324
  </div>
323
325
  );
@@ -356,6 +358,11 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
356
358
 
357
359
  return (
358
360
  <div
361
+ role="gridcell"
362
+ tabIndex={dayStatus.isDisabled ? -1 : 0}
363
+ aria-disabled={dayStatus.isDisabled}
364
+ aria-selected={dayStatus.isSelected}
365
+ aria-label={fullDate}
359
366
  className={!customRender ? dayCls : cssClasses.DAY}
360
367
  title={fullDate}
361
368
  key={(dayNumber as number) + dayIndex}
@@ -373,13 +380,13 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
373
380
  }
374
381
 
375
382
  render() {
376
- const { forwardRef } = this.props;
383
+ const { forwardRef, multiple } = this.props;
377
384
  const weekday = this.renderDayOfWeek();
378
385
  const weeks = this.renderWeeks();
379
386
  const monthCls = classNames(cssClasses.MONTH);
380
387
  const ref = forwardRef || this.monthRef;
381
388
  return (
382
- <div ref={ref} className={monthCls}>
389
+ <div role="grid" aria-multiselectable={multiple} ref={ref} className={monthCls} >
383
390
  {weekday}
384
391
  {weeks}
385
392
  </div>
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/interactive-supports-focus,jsx-a11y/click-events-have-key-events */
1
2
  /* eslint-disable react/no-did-update-set-state */
2
3
  /* eslint-disable max-len */
3
4
  /* eslint-disable no-nested-ternary */
@@ -343,7 +344,7 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
343
344
 
344
345
  renderMonth(month: Date, panelType: PanelType) {
345
346
  const { selected, rangeStart, rangeEnd, hoverDay, maxWeekNum, offsetRangeStart, offsetRangeEnd } = this.state;
346
- const { weekStartsOn, disabledDate, locale, localeCode, renderDate, renderFullDate, startDateOffset, endDateOffset, density, rangeInputFocus, syncSwitchMonth } = this.props;
347
+ const { weekStartsOn, disabledDate, locale, localeCode, renderDate, renderFullDate, startDateOffset, endDateOffset, density, rangeInputFocus, syncSwitchMonth, multiple } = this.props;
347
348
  let monthText = '';
348
349
  // i18n monthText
349
350
  if (month) {
@@ -409,6 +410,7 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
409
410
  startDateOffset={startDateOffset}
410
411
  endDateOffset={endDateOffset}
411
412
  focusRecordsRef={this.props.focusRecordsRef}
413
+ multiple={multiple}
412
414
  />
413
415
  </div>
414
416
  );
@@ -580,12 +582,22 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
580
582
 
581
583
  return (
582
584
  <div className={switchCls} ref={current => this.adapter.setCache(`switch-${panelType}`, current)}>
583
- <div className={dateCls} onClick={e => this.foundation.showDatePanel(panelType)}>
584
- {showSwithIcon && <IconCalendar />}
585
+ <div
586
+ role="button"
587
+ aria-label="Switch to date panel"
588
+ className={dateCls}
589
+ onClick={e => this.foundation.showDatePanel(panelType)}
590
+ >
591
+ {showSwithIcon && <IconCalendar aria-hidden />}
585
592
  <span className={textCls}>{dateText || monthText}</span>
586
593
  </div>
587
- <div className={timeCls} onClick={e => this.foundation.showTimePicker(panelType, true)}>
588
- {showSwithIcon && <IconClock />}
594
+ <div
595
+ role="button"
596
+ aria-label="Switch to time panel"
597
+ className={timeCls}
598
+ onClick={e => this.foundation.showTimePicker(panelType, true)}
599
+ >
600
+ {showSwithIcon && <IconClock aria-hidden />}
589
601
  <span className={textCls}>{timeText}</span>
590
602
  </div>
591
603
  </div>
@@ -101,7 +101,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
101
101
  <div className={prefixCls} ref={ref}>
102
102
  <IconButton
103
103
  key="double-chevron-left"
104
- icon={<IconDoubleChevronLeft size={iconBtnSize}/>}
104
+ aria-label="Previous year"
105
+ icon={<IconDoubleChevronLeft aria-hidden size={iconBtnSize} />}
105
106
  size={buttonSize}
106
107
  theme={btnTheme}
107
108
  noHorizontalPadding={btnNoHorizontalPadding}
@@ -110,7 +111,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
110
111
  />
111
112
  <IconButton
112
113
  key="chevron-left"
113
- icon={<IconChevronLeft size={iconBtnSize} />}
114
+ aria-label="Previous month"
115
+ icon={<IconChevronLeft aria-hidden size={iconBtnSize} />}
114
116
  size={buttonSize}
115
117
  onClick={onPrevMonth}
116
118
  theme={btnTheme}
@@ -124,7 +126,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
124
126
  </div>
125
127
  <IconButton
126
128
  key="chevron-right"
127
- icon={<IconChevronRight size={iconBtnSize} />}
129
+ aria-label="Next month"
130
+ icon={<IconChevronRight aria-hidden size={iconBtnSize} />}
128
131
  size={buttonSize}
129
132
  onClick={onNextMonth}
130
133
  theme={btnTheme}
@@ -133,7 +136,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
133
136
  />
134
137
  <IconButton
135
138
  key="double-chevron-right"
136
- icon={<IconDoubleChevronRight size={iconBtnSize}/>}
139
+ aria-label="Next year"
140
+ icon={<IconDoubleChevronRight aria-hidden size={iconBtnSize} />}
137
141
  size={buttonSize}
138
142
  theme={btnTheme}
139
143
  noHorizontalPadding={btnNoHorizontalPadding}
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/no-static-element-interactions,jsx-a11y/click-events-have-key-events */
1
2
  import React, { PureComponent } from 'react';
2
3
  import classNames from 'classnames';
3
4
  import PropTypes from 'prop-types';
@@ -208,7 +208,7 @@ class YearAndMonth extends BaseComponent<YearAndMonthProps, YearAndMonthState> {
208
208
  <div className={prefix}>
209
209
  <IconButton
210
210
  noHorizontalPadding={false}
211
- icon={<IconChevronLeft size={iconSize} />}
211
+ icon={<IconChevronLeft aria-hidden size={iconSize} />}
212
212
  size={buttonSize}
213
213
  onClick={this.backToMain}
214
214
  >
package/dist/css/semi.css CHANGED
@@ -19,7 +19,7 @@ body .semi-always-light {
19
19
  --semi-blue-2: 152,205,253;
20
20
  --semi-blue-3: 101,178,252;
21
21
  --semi-blue-4: 50,149,251;
22
- --semi-blue-5: 0,119,250;
22
+ --semi-blue-5: 0,100,250;
23
23
  --semi-blue-6: 0,98,214;
24
24
  --semi-blue-7: 0,79,179;
25
25
  --semi-blue-8: 0,61,143;
@@ -410,7 +410,7 @@ body, body[theme-mode=dark] .semi-always-light {
410
410
  --semi-color-bg-4: rgba(var(--semi-white), 1);
411
411
  --semi-color-text-0: rgba(var(--semi-grey-9), 1);
412
412
  --semi-color-text-1: rgba(var(--semi-grey-9), .8);
413
- --semi-color-text-2: rgba(var(--semi-grey-9), .6);
413
+ --semi-color-text-2: rgba(var(--semi-grey-9), .62);
414
414
  --semi-color-text-3: rgba(var(--semi-grey-9), .35);
415
415
  --semi-shadow-elevated: 0 0 1px rgba(0, 0, 0, .3), 0 4px 14px rgba(0, 0, 0, .1);
416
416
  --semi-border-radius-extra-small: 3px;
@@ -487,9 +487,9 @@ body[theme-mode=dark], body .semi-always-dark {
487
487
  --semi-color-nav-bg: rgba(35, 36, 41, 1);
488
488
  --semi-shadow-elevated: inset 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 14px rgba(0, 0, 0, .25);
489
489
  --semi-color-overlay-bg: rgba(22, 22, 26, .6);
490
- --semi-color-fill-0: rgba(var(--semi-white), .05);
491
- --semi-color-fill-1: rgba(var(--semi-white), .09);
492
- --semi-color-fill-2: rgba(var(--semi-white), .13);
490
+ --semi-color-fill-0: rgba(var(--semi-white), .12);
491
+ --semi-color-fill-1: rgba(var(--semi-white), .16);
492
+ --semi-color-fill-2: rgba(var(--semi-white), .20);
493
493
  --semi-color-border: rgba(var(--semi-white), .08);
494
494
  --semi-color-shadow: rgba(var(--semi-black), .04);
495
495
  --semi-color-bg-0: rgba(22, 22, 26, 1);
@@ -1588,6 +1588,9 @@ body[theme-mode=dark], body .semi-always-dark {
1588
1588
  vertical-align: middle;
1589
1589
  white-space: nowrap;
1590
1590
  }
1591
+ .semi-button:focus {
1592
+ outline: 2px solid var(--semi-color-primary-light-active);
1593
+ }
1591
1594
  .semi-button-danger {
1592
1595
  background-color: var(--semi-color-danger);
1593
1596
  color: white;
@@ -1601,6 +1604,9 @@ body[theme-mode=dark], body .semi-always-dark {
1601
1604
  .semi-button-danger.semi-button-light, .semi-button-danger.semi-button-borderless {
1602
1605
  color: var(--semi-color-danger);
1603
1606
  }
1607
+ .semi-button-danger:not(.semi-button-borderless):not(.semi-button-light):focus {
1608
+ outline-color: var(--semi-color-danger-light-active);
1609
+ }
1604
1610
  .semi-button-warning {
1605
1611
  background-color: var(--semi-color-warning);
1606
1612
  color: white;
@@ -1614,6 +1620,9 @@ body[theme-mode=dark], body .semi-always-dark {
1614
1620
  .semi-button-warning.semi-button-light, .semi-button-warning.semi-button-borderless {
1615
1621
  color: var(--semi-color-warning);
1616
1622
  }
1623
+ .semi-button-warning:not(.semi-button-borderless):not(.semi-button-light):focus {
1624
+ outline-color: var(--semi-color-warning-light-active);
1625
+ }
1617
1626
  .semi-button-tertiary {
1618
1627
  background-color: var(--semi-color-tertiary);
1619
1628
  color: white;
@@ -2688,7 +2697,7 @@ body[theme-mode=dark], body .semi-always-dark {
2688
2697
  color: var(--semi-color-text-2);
2689
2698
  }
2690
2699
  .semi-cascader-selection-tag {
2691
- margin: 1px 2px;
2700
+ margin: 1px 2px 1px 0;
2692
2701
  }
2693
2702
  .semi-cascader-selection-tag:first-child {
2694
2703
  margin-left: 0;
@@ -4740,6 +4749,10 @@ body[theme-mode=dark], body .semi-always-dark {
4740
4749
  padding-top: 6px;
4741
4750
  padding-bottom: 6px;
4742
4751
  }
4752
+ .semi-form-field[x-label-pos=left] .semi-radioGroup-buttonRadio {
4753
+ padding-top: 0;
4754
+ padding-bottom: 0;
4755
+ }
4743
4756
  .semi-form-field[x-label-pos=left] .semi-switch,
4744
4757
  .semi-form-field[x-label-pos=left] .semi-rating {
4745
4758
  vertical-align: middle;
@@ -11448,6 +11461,7 @@ body[theme-mode=dark], body .semi-always-dark {
11448
11461
  cursor: not-allowed;
11449
11462
  color: var(--semi-color-disabled-text);
11450
11463
  background-color: var(--semi-color-disabled-fill);
11464
+ -webkit-text-fill-color: var(--semi-color-disabled-text);
11451
11465
  }
11452
11466
  .semi-input-wrapper-disabled:hover {
11453
11467
  background-color: var(--semi-color-disabled-fill);
@@ -16207,7 +16221,6 @@ body[theme-mode=dark], body .semi-always-dark {
16207
16221
  word-break: break-all;
16208
16222
  word-wrap: break-word;
16209
16223
  position: relative;
16210
- user-select: none;
16211
16224
  }
16212
16225
  .semi-table-thead > .semi-table-row > .semi-table-row-head.semi-table-cell-fixed-left, .semi-table-thead > .semi-table-row > .semi-table-row-head.semi-table-cell-fixed-right {
16213
16226
  z-index: 101;
@@ -16479,7 +16492,7 @@ body[theme-mode=dark], body .semi-always-dark {
16479
16492
  position: relative;
16480
16493
  z-index: 1;
16481
16494
  padding: 16px 12px;
16482
- color: var(--semi-color-disabled-bg);
16495
+ color: var(--semi-color-text-2);
16483
16496
  font-size: 14px;
16484
16497
  text-align: center;
16485
16498
  background: transparent;
@@ -17042,6 +17055,7 @@ body[theme-mode=dark], body .semi-always-dark {
17042
17055
  user-select: none;
17043
17056
  overflow: hidden;
17044
17057
  white-space: nowrap;
17058
+ vertical-align: bottom;
17045
17059
  }
17046
17060
  .semi-tag-default, .semi-tag-small {
17047
17061
  font-size: 12px;