Przeglądaj źródła

Merge branch 'milestone-2.6' into release

pointhalo 3 lat temu
rodzic
commit
fad9785c79
48 zmienionych plików z 466 dodań i 268 usunięć
  1. 13 7
      content/input/button/index-en-US.md
  2. 13 7
      content/input/button/index.md
  3. 7 0
      content/input/cascader/index-en-US.md
  4. 7 0
      content/input/cascader/index.md
  5. 10 10
      content/input/checkbox/index-en-US.md
  6. 10 10
      content/input/checkbox/index.md
  7. 10 0
      content/input/datepicker/index-en-US.md
  8. 10 0
      content/input/datepicker/index.md
  9. 12 12
      content/input/radio/index-en-US.md
  10. 12 12
      content/input/radio/index.md
  11. 9 9
      content/input/upload/index-en-US.md
  12. 9 9
      content/input/upload/index.md
  13. 7 7
      content/navigation/steps/index-en-US.md
  14. 33 33
      content/show/avatar/index-en-US.md
  15. 33 33
      content/show/avatar/index.md
  16. 8 7
      content/show/dropdown/index-en-US.md
  17. 7 7
      content/show/dropdown/index.md
  18. 9 0
      content/show/scrolllist/index-en-US.md
  19. 9 0
      content/show/scrolllist/index.md
  20. 6 6
      content/show/sidesheet/index-en-US.md
  21. 6 7
      content/show/sidesheet/index.md
  22. 13 13
      content/show/table/index-en-US.md
  23. 14 13
      content/show/table/index.md
  24. 1 1
      content/show/timeline/index-en-US.md
  25. 1 1
      content/show/timeline/index.md
  26. 11 0
      packages/semi-foundation/button/button.scss
  27. 4 0
      packages/semi-foundation/button/variables.scss
  28. 19 0
      packages/semi-foundation/cascader/foundation.ts
  29. 4 4
      packages/semi-foundation/datePicker/foundation.ts
  30. 0 1
      packages/semi-foundation/datePicker/inputFoundation.ts
  31. 1 0
      packages/semi-foundation/datePicker/monthFoundation.ts
  32. 1 1
      packages/semi-foundation/table/table.scss
  33. 1 0
      packages/semi-foundation/table/variables.scss
  34. 1 1
      packages/semi-theme-default/scss/_palette.scss
  35. 4 4
      packages/semi-theme-default/scss/global.scss
  36. 14 13
      packages/semi-ui/calendar/monthCalendar.tsx
  37. 21 3
      packages/semi-ui/cascader/index.tsx
  38. 25 5
      packages/semi-ui/cascader/item.tsx
  39. 8 5
      packages/semi-ui/datePicker/dateInput.tsx
  40. 6 1
      packages/semi-ui/datePicker/datePicker.tsx
  41. 14 7
      packages/semi-ui/datePicker/month.tsx
  42. 17 5
      packages/semi-ui/datePicker/monthsGrid.tsx
  43. 8 4
      packages/semi-ui/datePicker/navigation.tsx
  44. 1 0
      packages/semi-ui/datePicker/quickControl.tsx
  45. 1 1
      packages/semi-ui/datePicker/yearAndMonth.tsx
  46. 3 0
      packages/semi-ui/scrollList/_story/ScrollList/index.js
  47. 3 0
      packages/semi-ui/scrollList/_story/WheelList/index.js
  48. 30 9
      packages/semi-ui/scrollList/scrollItem.tsx

+ 13 - 7
content/input/button/index-en-US.md

@@ -486,13 +486,6 @@ function SplitButtonDemo(){
 }
 ```
 
-## Accessibility
-
-### ARIA
-
-- `aria-label` is used to indicate the function of the button. For icon buttons, we recommend using this attribute
-- `aria-disabled` is synchronized with the disabled attribute, indicating that the button is disabled
-
 ## API Reference
 
 ### Button
@@ -534,6 +527,19 @@ function SplitButtonDemo(){
 | style     | Custom style                                  | CSSProperties   |        |
 | className     | Custom class name                                  | string   |        |
 
+## Accessibility
+
+### ARIA
+
+- `aria-label` is used to indicate the function of the button. For icon buttons, we recommend using this attribute
+- `aria-disabled` is synchronized with the disabled attribute, indicating that the button is disabled
+
+### Keyboard and Focus
+
+- `Button`'s focus management is consistent with native `button`, keyboard users can use `Tab` and `Shift + Tab` to switch focus
+- The trigger of `Button` is the same as the native `button`, when the `button` is focused, it can be activated by `Enter` or `Space` key
+- The buttons in the `ButtonGroup` are managed in the same way as the focus of a single `button`, and can be switched by `Tab` and `Shift + Tab`
+
 ## Design Tokens
 <DesignToken/>
 

+ 13 - 7
content/input/button/index.md

@@ -445,13 +445,6 @@ function SplitButtonDemo(){
 }
 ```
 
-## Accessibility
-
-### ARIA
-
-- `aria-label` 用于表示按钮的作用,对于图标按钮,我们推荐使用此属性
-- `aria-disabled` 与 disabled 属性同步,表示按钮禁用 
-
 
 ## API 参考
 
@@ -494,6 +487,19 @@ function SplitButtonDemo(){
 | style     | 自定义样式                               | CSSProperties   |         |
 | className     | 自定义类名                               | string   |         |
 
+## Accessibility
+
+### ARIA
+
+- `aria-label` 用于表示按钮的作用,对于图标按钮,我们推荐使用此属性
+- `aria-disabled` 与 disabled 属性同步,表示按钮禁用 
+
+### 键盘和焦点
+
+- Button 的焦点管理与原生 button 一致,键盘用户可以使用 Tab 及  Shift + Tab 切换焦点
+- Button 的触发与原生 button 一致,当按钮聚焦时,可以通过 Enter 或 Space 键激活
+- ButtonGroup 中的按钮与单个按钮的焦点管理方式一致,可以通过 Tab 以及 Shift + Tab 进行切换
+
 ## 设计变量
 <DesignToken/>
 

+ 7 - 0
content/input/cascader/index-en-US.md

@@ -1591,5 +1591,12 @@ function Demo() {
 | loading    | loading                        | boolean        | -       |
 | value      | Value property (required)      | string\|number | -       |
 
+## Accessibility
+
+### ARIA
+
+- Cascader supports importing `aria-label`, `aria-describedby`, `aria-errormessage`, `aria-invalid`, `aria-labelledby`, `aria-required` to indicate the relevant information of the Cascader;
+- Cascader supports selecting options, clearing options, and expanding drop-down box by pressing the Enter key
+
 ## Design Tokens
 <DesignToken/>

+ 7 - 0
content/input/cascader/index.md

@@ -1578,5 +1578,12 @@ function Demo() {
 | loading  | 正在加载                | boolean        | -     |
 | value    | 属性值(必填)           | string\|number | -     |
 
+## Accessibility
+
+### ARIA
+
+- Cascader 支持传入 `aria-label`、`aria-describedby`、`aria-errormessage`、`aria-invalid`、`aria-labelledby`、`aria-required` 来表示该 Cascader 的相关信息;
+- Cascader 支持通过按下 Enter 键来选中选项、清空选项、展开下拉框
+
 ## 设计变量
 <DesignToken/>

+ 10 - 10
content/input/checkbox/index-en-US.md

@@ -393,16 +393,6 @@ import { CheckboxGroup, Checkbox, Row, Col } from '@douyinfe/semi-ui';
 );
 ```
 
-## Accessibility
-
-### ARIA
-- The role of Checkbox is `checkbox`, the role of CheckboxGroup is `list`, and its direct child element is `listitem`
-- `aria-label`: When using the Checkbox alone, if Children have no text, it is recommended to pass in the `aria-label` prop to describe the function of the Checkbox in one sentence, which will make the screen reader read out the content of this label. If you are using Form.Checkbox, you can use the label provided by Form without passing in `aria-label`
-- `aria-labelledby` points to the `addon` node, used to explain the role of the current Checkbox
-- `aria-describedby` points to the `extra` node, which is used to supplement the explanation of the current Checkbox
-- `aria-disabled` indicates the current disabled state, which is consistent with the value of the `disabled` prop
-- `aria-checked` indicates the current checked state
-
 ## API Reference
 
 ### Checkbox
@@ -440,6 +430,16 @@ import { CheckboxGroup, Checkbox, Row, Col } from '@douyinfe/semi-ui';
 | blur()  | Remove focus |
 | focus() | Get focus    |
 
+## Accessibility
+
+### ARIA
+- The role of Checkbox is `checkbox`, the role of CheckboxGroup is `list`, and its direct child element is `listitem`
+- `aria-label`: When using the Checkbox alone, if Children have no text, it is recommended to pass in the `aria-label` prop to describe the function of the Checkbox in one sentence, which will make the screen reader read out the content of this label. If you are using Form.Checkbox, you can use the label provided by Form without passing in `aria-label`
+- `aria-labelledby` points to the `addon` node, used to explain the role of the current Checkbox
+- `aria-describedby` points to the `extra` node, which is used to supplement the explanation of the current Checkbox
+- `aria-disabled` indicates the current disabled state, which is consistent with the value of the `disabled` prop
+- `aria-checked` indicates the current checked state
+
 ## Design Tokens
 <DesignToken/>
 

+ 10 - 10
content/input/checkbox/index.md

@@ -375,16 +375,6 @@ import { Checkbox, CheckboxGroup, Row, Col } from '@douyinfe/semi-ui';
 );
 ```
 
-## Accessibility
-
-### ARIA
-- Checkbox 的 role 为 `checkbox`,CheckboxGroup 的 role 为 `list`,它的直接子元素为 `listitem`
-- `aria-label`:单独使用 Checkbox 时,如果 Children 没有文本,建议传入 `aria-label` prop,用一句话描述 Checkbox 的作用,这会让屏幕阅读器读出这个标签的内容。如果你使用的是 Form.Checkbox,可以使用 Form 提供的 label 而无需传入 `aria-label`
-- `aria-labelledby` 指向 `addon` 节点,用于解释当前 Checkbox 的作用
-- `aria-describedby` 指向 `extra` 节点,用于补充解释当前 Checkbox 的作用
-- `aria-disabled` 表示当前的禁用状态,与 `disabled` prop 的值保持一致
-- `aria-checked` 表示当前的选中状态
-
 ## API参考
 
 ### Checkbox
@@ -422,6 +412,16 @@ import { Checkbox, CheckboxGroup, Row, Col } from '@douyinfe/semi-ui';
 | blur() | 移除焦点 |
 | focus() | 获取焦点 |
 
+## Accessibility
+
+### ARIA
+- Checkbox 的 role 为 `checkbox`,CheckboxGroup 的 role 为 `list`,它的直接子元素为 `listitem`
+- `aria-label`:单独使用 Checkbox 时,如果 Children 没有文本,建议传入 `aria-label` prop,用一句话描述 Checkbox 的作用,这会让屏幕阅读器读出这个标签的内容。如果你使用的是 Form.Checkbox,可以使用 Form 提供的 label 而无需传入 `aria-label`
+- `aria-labelledby` 指向 `addon` 节点,用于解释当前 Checkbox 的作用
+- `aria-describedby` 指向 `extra` 节点,用于补充解释当前 Checkbox 的作用
+- `aria-disabled` 表示当前的禁用状态,与 `disabled` prop 的值保持一致
+- `aria-checked` 表示当前的选中状态
+
 ## 设计变量
 <DesignToken/>
 

+ 10 - 0
content/input/datepicker/index-en-US.md

@@ -791,6 +791,16 @@ function Demo() {
 | onPanelChange      | Callback when the year or date of the panel is switched|(date: DateType\|DateType[], dateStr: StringType\|StringType[])=>void|true|**1.28.0**|
 | onPresetClick      | Callback when click preset button                                                                          | (item: Object, e: Event) => void                                                                                                                                                                                 | () => {}                                               |   **1.24.0**                           |
 
+## Accessibility
+
+### ARIA
+
+- When a date is not selected, the `aria-label` of the trigger is `Choose date`, and when a date is selected, the `aria-label` of the trigger is `Change date`
+- The role of the month in the date panel is `grid`, the role of the week is set to `row`, and the date cell is set to `gridcell`
+- `aria-disabled` is true for the corresponding option when date and time are disabled
+- When multi-selected, `aria-multiselectable` of month is true, and `aria-selected` of date grid is true when selected
+- Some decorative icons in the panel, their `aria-hidden` is true
+
 ## Date and Time Format
 
 Adopted in the semi-ui component library [date-fns(v2.9.0)](https://date-fns.org/v2.9.0/docs/Getting-Started) As a date and time engine, formatting token means the following:

+ 10 - 0
content/input/datepicker/index.md

@@ -757,6 +757,16 @@ function Demo() {
 | onPanelChange | 切换面板的年份或者日期时的回调 | (date: DateType\|DateType[], dateStr: StringType\|StringType[])=>void | function | **1.28.0** |
 | onPresetClick | 点击快捷选择按钮的回调 | (item: Object, e: Event) => void | () => {} | **1.24.0** |
 
+## Accessibility
+
+### ARIA
+
+- 未选中日期时,触发器的 `aria-label` 为 `Choose date`,选中日期时,触发器的 `aria-label` 为 `Change date`
+- 日期面板中月的 role 为 `grid`,周的 role 设置为 `row`,日期格子设置为 `gridcell`
+- 日期和时间禁用时对应选项的 `aria-disabled` 为 true
+- 多选时,月的 `aria-multiselectable` 为 true,选中时日期格子的 `aria-selected` 为 true
+- 面板中一些装饰作用的 icon,它们的 `aria-hidden` 为 true
+
 ## 类型定义
 
 ```typescript

+ 12 - 12
content/input/radio/index-en-US.md

@@ -351,18 +351,6 @@ class App extends React.Component {
 }
 ```
 
-## Accessibility
-
-### Keyboard and Focus
-
-- Card type and button type Radio group can be selected by arrow switch
-
-### ARIA
-
-- `aria-label`: used to explain the role of Radio or RadioGroup
-- `aria-labelledby` points to the addon node, used to explain the content of Radio
-- `aria-describedby` points to the extra node, which is used to explain the content of Radio
-
 ## API Reference
 
 ### Radio
@@ -410,6 +398,18 @@ class App extends React.Component {
 | blur()  | Remove focus |
 | focus() | Get focus    |
 
+## Accessibility
+
+### Keyboard and Focus
+
+- Card type and button type Radio group can be selected by arrow switch
+
+### ARIA
+
+- `aria-label`: used to explain the role of Radio or RadioGroup
+- `aria-labelledby` points to the addon node, used to explain the content of Radio
+- `aria-describedby` points to the extra node, which is used to explain the content of Radio
+
 <!-- ## Related Material
 
 ```material

+ 12 - 12
content/input/radio/index.md

@@ -311,18 +311,6 @@ class App extends React.Component {
 }
 ```
 
-## Accessibility
-
-### 键盘和焦点
-
-- 卡片式、按钮式 Radio 组可以通过箭头切换选中
-
-### ARIA
-
-- `aria-label`:用于解释 Radio 或 RadioGroup 的作用
-- `aria-labelledby` 默认指向 addon 节点,用于解释 Radio 的内容
-- `aria-describedby` 默认指向 extra 节点,用于补充解释 Radio 的内容
-
 ## API 参考
 
 ### Radio
@@ -373,6 +361,18 @@ class App extends React.Component {
 | blur()  | 移除焦点 |
 | focus() | 获取焦点 |
 
+## Accessibility
+
+### 键盘和焦点
+
+- 卡片式、按钮式 Radio 组可以通过箭头切换选中
+
+### ARIA
+
+- `aria-label`:用于解释 Radio 或 RadioGroup 的作用
+- `aria-labelledby` 默认指向 addon 节点,用于解释 Radio 的内容
+- `aria-describedby` 默认指向 extra 节点,用于补充解释 Radio 的内容
+
 <!-- ## 相关物料
 ```material
 123

+ 9 - 9
content/input/upload/index-en-US.md

@@ -1196,15 +1196,6 @@ import { IconUpload } from '@douyinfe/semi-icons';
 };
 ```
 
-## Accessibility
-
-The Upload component is an interactive control that can trigger file selection when clicking or dragging. After the file is selected, the status will be displayed in the file list.
-
-### ARIA
-
-- Add `role="button"` to clickable elements
-- Add `role="list"` to the file list and describe it with `aria-label`
-
 ## API Reference
 
 ---
@@ -1272,6 +1263,15 @@ The Upload component is an interactive control that can trigger file selection w
 |validateMessage | Upload the overall error message | ReactNode | | 1.0.0 |
 |withCredentials | Whether to bring cookie information | boolean | false | |
 
+## Accessibility
+
+The Upload component is an interactive control that can trigger file selection when clicking or dragging. After the file is selected, the status will be displayed in the file list.
+
+### ARIA
+
+- Add `role="button"` to clickable elements
+- Add `role="list"` to the file list and describe it with `aria-label`
+
 ## Interfaces
 
 ### FileItem Interface

+ 9 - 9
content/input/upload/index.md

@@ -1210,15 +1210,6 @@ import { IconUpload } from '@douyinfe/semi-icons';
 };
 ```
 
-## Accessibility
-
-Upload组件是一个可交互的控件,在点击或拖拽时触发文件选择,文件选中后会在文件列表内展示状态。
-
-### ARIA
-
-- 为可点击元素添加 `role="button"`
-- 文件列表添加 `role="list"`,并用 `aria-label` 描述
-
 ## API 参考
 
 ---
@@ -1321,6 +1312,15 @@ interface FileItem {
 | insert | 上传文件,当index传入时,会插入到指定位置,不传则插入到最后 | (files: Array<File\>, index?: number) => void | 2.2.0 |
 | upload | 手动开始上传,配合uploadTrigger="custom"使用 | () => void | |
 
+## Accessibility
+
+Upload组件是一个可交互的控件,在点击或拖拽时触发文件选择,文件选中后会在文件列表内展示状态。
+
+### ARIA
+
+- 为可点击元素添加 `role="button"`
+- 文件列表添加 `role="list"`,并用 `aria-label` 描述
+
 ## 设计变量
 <DesignToken/>
 

+ 7 - 7
content/navigation/steps/index-en-US.md

@@ -311,13 +311,6 @@ class App extends React.Component {
 }
 ```
 
-## Accessibility
-
-### ARIA
-
-- Steps and Step components support passing in the `aria-label` attribute to represent the description of Steps and Steps
-- Step component has an `aria-current` `step` attribute, indicating that this is a step in the step bar
-
 ## API reference
 
 ### Steps
@@ -351,6 +344,13 @@ Step in the step bar.
 | onClick | Callback of click | function | - |  |
 | onKeyDown     | Callback ok keyDown  | function | -   |    |
 
+## Accessibility
+
+### ARIA
+
+- Steps and Step components support passing in the `aria-label` attribute to represent the description of Steps and Steps
+- Step component has an `aria-current` `step` attribute, indicating that this is a step in the step bar
+
 ## Design Tokens
 
 <DesignToken/>

+ 33 - 33
content/show/avatar/index-en-US.md

@@ -254,6 +254,39 @@ import { Avatar, AvatarGroup } from '@douyinfe/semi-ui';
 );
 ```
 
+## API Reference
+
+---
+
+### Avatar
+
+| Properties   | Instructions                                                                                                                                                                              | type           | Default  |
+| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------- |
+| alt          | Defines an alternative text description of the image.                                                                                                                                       | string         | -        |
+| className    | Class name                                                                                                                                                                                | string         | -        |
+| color        | Color of the avatar, one of `amber`, `blue`, `cyan`, `green`, `grey`, `indigo`, `light-blue`, `light-green`, `lime`, `orange`, `pink`, `rain`, `red`, `teal`, `violet`, `yellow`, `white` | string         | `grey`   |
+| hoverMask    | Avatar content overlay when hover                                                                                                                                                         | ReactNode     | -        |
+| imgAttr | Native html img attributes **>=1.5.0**| React.ImgHTMLAttributes<HTMLImageElement\> | - |
+| shape        | Shape of the avatar, one of `circle`, `square`                                                                                                                                            | string         | `circle` |
+| size         | Size of the avatar, one of `extra-extra-small`,`extra-small`, `small`, `default`, `medium`, `large`, `extra-large`                                                                                                       | string         | `medium` |
+| src          | Resource address for imgage avatars                                                                                                                                                       | string         | -        |
+| srcSet       | Set the image avatar responsive resource address                                                                                                                                          | string         | -        |
+| style        | Style name                                                                                                                                                                                | CSSProperties         | -        |
+| onClick      | Click the callback of the avatar.                                                                                                                                                         | (e: Event) => void       | -        |
+| onError      | Image load failed event, returning false closes the default fallback behavior of the component                                                                                            | (e: Event) = > boolean | -        |
+| onMouseEnter | Callback to onMouseEnter event                                                                                                                                                            | (e: Event) => void       | -        |
+| onMouseLeave | Callback to onMouseLeave event                                                                                                                                                            | (e: Event) => void       | -        |
+
+### AvatarGroup
+
+| Properties | Instructions                                                                        | type   | Default  |
+| ---------- | ----------------------------------------------------------------------------------- | ------ | -------- |
+| maxCount | Display +N when the number of avatars exceeds this value | number | - |
+| overlapFrom | Set the coverage direction of the avatars, one of `start`, `end` | string | `start` |
+| renderMore | Customize the more tag  | (restNumber: number, restAvatars: ReactNode[]) => ReactNode | - |
+| shape      | Shape of the avatar, one of `circle`, `square`                                      | string | `circle` |
+| size       | Size of the avatar, one of `extra-extra-small`, `extra-small`, `small`, `default`, `medium`, `large`, `extra-large` | string | `medium` |
+
 ## Accessibility
 
 - `alt`:When using a picture avatar, please use the `alt` attribute to explain the content of the picture
@@ -293,38 +326,5 @@ import { Avatar } from '@douyinfe/semi-ui';
 };
 ```
 
-## API Reference
-
----
-
-### Avatar
-
-| Properties   | Instructions                                                                                                                                                                              | type           | Default  |
-| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------- |
-| alt          | Defines an alternative text description of the image.                                                                                                                                       | string         | -        |
-| className    | Class name                                                                                                                                                                                | string         | -        |
-| color        | Color of the avatar, one of `amber`, `blue`, `cyan`, `green`, `grey`, `indigo`, `light-blue`, `light-green`, `lime`, `orange`, `pink`, `rain`, `red`, `teal`, `violet`, `yellow`, `white` | string         | `grey`   |
-| hoverMask    | Avatar content overlay when hover                                                                                                                                                         | ReactNode     | -        |
-| imgAttr | Native html img attributes **>=1.5.0**| React.ImgHTMLAttributes<HTMLImageElement\> | - |
-| shape        | Shape of the avatar, one of `circle`, `square`                                                                                                                                            | string         | `circle` |
-| size         | Size of the avatar, one of `extra-extra-small`,`extra-small`, `small`, `default`, `medium`, `large`, `extra-large`                                                                                                       | string         | `medium` |
-| src          | Resource address for imgage avatars                                                                                                                                                       | string         | -        |
-| srcSet       | Set the image avatar responsive resource address                                                                                                                                          | string         | -        |
-| style        | Style name                                                                                                                                                                                | CSSProperties         | -        |
-| onClick      | Click the callback of the avatar.                                                                                                                                                         | (e: Event) => void       | -        |
-| onError      | Image load failed event, returning false closes the default fallback behavior of the component                                                                                            | (e: Event) = > boolean | -        |
-| onMouseEnter | Callback to onMouseEnter event                                                                                                                                                            | (e: Event) => void       | -        |
-| onMouseLeave | Callback to onMouseLeave event                                                                                                                                                            | (e: Event) => void       | -        |
-
-### AvatarGroup
-
-| Properties | Instructions                                                                        | type   | Default  |
-| ---------- | ----------------------------------------------------------------------------------- | ------ | -------- |
-| maxCount | Display +N when the number of avatars exceeds this value | number | - |
-| overlapFrom | Set the coverage direction of the avatars, one of `start`, `end` | string | `start` |
-| renderMore | Customize the more tag  | (restNumber: number, restAvatars: ReactNode[]) => ReactNode | - |
-| shape      | Shape of the avatar, one of `circle`, `square`                                      | string | `circle` |
-| size       | Size of the avatar, one of `extra-extra-small`, `extra-small`, `small`, `default`, `medium`, `large`, `extra-large` | string | `medium` |
-
 ## Design Tokens
 <DesignToken/>

+ 33 - 33
content/show/avatar/index.md

@@ -256,6 +256,39 @@ import { AvatarGroup, Avatar } from '@douyinfe/semi-ui';
 );
 ```
 
+## API 参考
+
+---
+
+### Avatar
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| alt | 图像的替代文本描述 | string | - |
+| className | 类名 | string | - |
+| color | 指定头像的颜色,支持 `amber`、 `blue`、 `cyan`、 `green`、 `grey`、 `indigo`、 `light-blue`、 `light-green`、 `lime`、 `orange`、 `pink`、 `purple`、 `red`、 `teal`、 `violet`、 `yellow` | string | `grey` |
+| hoverMask | hover 时头像内容覆盖层 | ReactNode | - |
+| imgAttr | 原生 img 属性 **>=1.5.0** | React.ImgHTMLAttributes<HTMLImageElement\> | - |
+| shape | 指定头像的形状,支持 `circle`、`square` | string | `circle` |
+| size | 设置头像的大小,支持 `extra-extra-small`、`extra-small`、`small`、`default`、`medium`、`large`、`extra-large` | string | `medium` |
+| src | 图片类头像的资源地址 | string | - |
+| srcSet | 设置图片类头像响应式资源地址 | string | - |
+| style | 样式名 | CSSProperties | - |
+| onClick | 单击头像的回调 | (e: Event) => void | - |
+| onError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为 | (e: Event) => boolean | - |
+| onMouseEnter | MouseEnter 事件的回调 | (e: Event) => void | - |
+| onMouseLeave | MouseLeave 事件的回调 | (e: Event) => void | - |
+
+### AvatarGroup
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| maxCount | 最大数量限制,超出后显示+N | number | - |
+| overlapFrom | 设置头像覆盖方向,支持 `start`, `end` | string | `start` |
+| renderMore | 自定义渲染 more 标签 | (restNumber: number, restAvatars: ReactNode[]) => ReactNode | - |
+| shape | 指定头像的形状,支持`circle`、`square` | string | `circle` |
+| size | 设置头像的大小,支持 `extra-extra-small`, `extra-small`、`small`、`default`、`medium`、`large`、`extra-large` | string | `medium` |
+
 ## Accessibility
 
 - `alt`:使用图片头像时,请使用 `alt` 属性解释图片的内容
@@ -294,39 +327,6 @@ import { Avatar } from '@douyinfe/semi-ui';
 };
 ```
 
-## API 参考
-
----
-
-### Avatar
-
-| 属性 | 说明 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| alt | 图像的替代文本描述 | string | - |
-| className | 类名 | string | - |
-| color | 指定头像的颜色,支持 `amber`、 `blue`、 `cyan`、 `green`、 `grey`、 `indigo`、 `light-blue`、 `light-green`、 `lime`、 `orange`、 `pink`、 `purple`、 `red`、 `teal`、 `violet`、 `yellow` | string | `grey` |
-| hoverMask | hover 时头像内容覆盖层 | ReactNode | - |
-| imgAttr | 原生 img 属性 **>=1.5.0** | React.ImgHTMLAttributes<HTMLImageElement\> | - |
-| shape | 指定头像的形状,支持 `circle`、`square` | string | `circle` |
-| size | 设置头像的大小,支持 `extra-extra-small`、`extra-small`、`small`、`default`、`medium`、`large`、`extra-large` | string | `medium` |
-| src | 图片类头像的资源地址 | string | - |
-| srcSet | 设置图片类头像响应式资源地址 | string | - |
-| style | 样式名 | CSSProperties | - |
-| onClick | 单击头像的回调 | (e: Event) => void | - |
-| onError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为 | (e: Event) => boolean | - |
-| onMouseEnter | MouseEnter 事件的回调 | (e: Event) => void | - |
-| onMouseLeave | MouseLeave 事件的回调 | (e: Event) => void | - |
-
-### AvatarGroup
-
-| 属性 | 说明 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| maxCount | 最大数量限制,超出后显示+N | number | - |
-| overlapFrom | 设置头像覆盖方向,支持 `start`, `end` | string | `start` |
-| renderMore | 自定义渲染 more 标签 | (restNumber: number, restAvatars: ReactNode[]) => ReactNode | - |
-| shape | 指定头像的形状,支持`circle`、`square` | string | `circle` |
-| size | 设置头像的大小,支持 `extra-extra-small`, `extra-small`、`small`、`default`、`medium`、`large`、`extra-large` | string | `medium` |
-
 ## 设计变量
 
 <DesignToken/>

+ 8 - 7
content/show/dropdown/index-en-US.md

@@ -415,13 +415,6 @@ function DropdownEvents() {
 }
 ```
 
-## Accessibility
-
-### ARIA
-
-- Dropdown.Menu `role` is set to `menu`, `aria-orientatio` is set to `vertical`
-- Dropdown.Item `role` is set to `menuitem`
-
 ## API Reference
 
 ### Dropdown
@@ -488,6 +481,14 @@ function DropdownEvents() {
 | name                                           | menu content                        | string |
 | Other Properties refer to Title、Item、Divider |                                     |        |
 
+
+## Accessibility
+
+### ARIA
+
+- Dropdown.Menu `role` is set to `menu`, `aria-orientatio` is set to `vertical`
+- Dropdown.Item `role` is set to `menuitem`
+
 ## Design Tokens
 
 <DesignToken/>

+ 7 - 7
content/show/dropdown/index.md

@@ -412,13 +412,6 @@ function DropdownEvents() {
 }
 ```
 
-## Accessibility
-
-### ARIA
-
-- Dropdown.Menu `role` 设置为 `menu`,`aria-orientatio` 设置为 `vertical`
-- Dropdown.Item `role` 设置为 `menuitem`
-
 ## API 参考
 
 ### Dropdown
@@ -485,6 +478,13 @@ function DropdownEvents() {
 | name                                     | 菜单文本,标题或 Item 的内容               | string |        |
 | 其他属性与 Title、Item、Divider 属性对应 |                                            |        |        |
 
+## Accessibility
+
+### ARIA
+
+- Dropdown.Menu `role` 设置为 `menu`,`aria-orientatio` 设置为 `vertical`
+- Dropdown.Item `role` 设置为 `menuitem`
+
 ## 设计变量
 
 <DesignToken/>

+ 9 - 0
content/show/scrolllist/index-en-US.md

@@ -143,5 +143,14 @@ class ScrollListDemo extends React.Component {
 | transform  | When the transformation is in the selected state, the return value is displayed as a copy, and if the ScrollItem component is passed at the same time, the transform method in ItemData will be selected first. | (value: any, text: string) => string | v = > v |
 | value      | The value of each item                                                                                                                                                                                          | any       |         |
 
+
+## Accessibility
+
+### ARIA
+
+- `ScrollItem` support `aria-label`, indicates the label of current column.
+- `ScrollItem` uses `aria-disabled` to indicate whether the item is disabled
+- `ScrollItem` uses `aria-selected` to indicate whether the item is selected
+
 ## Design Tokens
 <DesignToken/>

+ 9 - 0
content/show/scrolllist/index.md

@@ -165,6 +165,15 @@ class ScrollListDemo extends React.Component {
 | transform | 该项处于选中状态时的变换,返回值会作为文案进行显示,ScrollItem 组件如果同时传入会优先选择 ItemData 中的 transform 方法 | (value: any, text: string) => string | v => v |
 | value | 每一项的值 | any |  |
 
+
+## Accessibility
+
+### ARIA
+
+- `ScrollItem` 支持传入 `aria-label`, 指定该列标签
+- `ScrollItem` 使用 `aria-disabled` 表示该项目是否被禁用
+- `ScrollItem` 使用 `aria-selected` 表示该项目是否被选中
+
 ## 设计变量
 
 <DesignToken/>

+ 6 - 6
content/show/sidesheet/index-en-US.md

@@ -298,12 +298,6 @@ class Demo extends React.Component {
 }
 ```
 
-## Accessibility
-
-### ARIA
-
-- SideSheet has a `dialog` role to indicate that it is a pop-up component, and the internal header has a `heading` role to indicate that it is a header.
-
 ## API Reference
 
 | Properties | Instructions | type | Default | Version |
@@ -332,6 +326,12 @@ class Demo extends React.Component {
 | zIndex | Z-index value for SideSheet | number | 1000 | 0.29.0 |
 | onCancel | Callback function when clicking cancel button | (e: MouseEvent) => void | - | - |
 
+## Accessibility
+
+### ARIA
+
+- SideSheet has a `dialog` role to indicate that it is a pop-up component, and the internal header has a `heading` role to indicate that it is a header.
+
 ## Design Tokens
 
 <DesignToken/>

+ 6 - 7
content/show/sidesheet/index.md

@@ -296,13 +296,6 @@ class Demo extends React.Component {
 }
 ```
 
-
-## Accessibility
-
-### ARIA
-
-- SideSheet 具有 `dialog` role 来表示它是一个弹窗组件, 内部 header 具有 `heading` role 表明是 header。
-
 ## API 参考
 
 | 属性 | 说明 | 类型 | 默认值 | 版本 |
@@ -331,6 +324,12 @@ class Demo extends React.Component {
 | zIndex | 弹层 z-index 值 | number | 1000 | 0.29.0 |
 | onCancel | 取消面板时的回调函数 | (e: MouseEvent) => void | - | - |
 
+## Accessibility
+
+### ARIA
+
+- SideSheet 具有 `dialog` role 来表示它是一个弹窗组件, 内部 header 具有 `heading` role 表明是 header。
+
 ## 设计变量
 
 <DesignToken/>

+ 13 - 13
content/show/table/index-en-US.md

@@ -4366,19 +4366,6 @@ function App() {
 render(App);
 ```
 
-## Accessibility
-
-### ARIA
-
-- The role of the table is grid, and the role of the tree table is treegrid
-- the row's role is row, and the cell's role is gridcell
-- Added aria-rowcount and aria-colcount attributes to the table to indicate the number of rows and columns
-- The row has added aria-rowindex to indicate which row it currently belongs to, and the first row is 1
-- The row of the tree table has aria-level representing the tree level of the current row, the first level is 1
-- Expandable table rows have the aria-expanded attribute, indicating whether the current row is expanded
-- The new aria-colindex of the cell indicates which column the current grid belongs to, and the first column is 1
-- Added aria-label to column filter and sort buttons, and added aria-label attribute to row select buttons
-
 ## API Reference
 
 ## Table
@@ -4662,6 +4649,19 @@ function Demo() {
 | -------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------- |
 | getCurrentPageData() | Returns the data object of the current page: { dataSource: RecordType[], groups: Map<{groupKey: string, recordKeys: Set<string\>}> } | 0.37.0 |
 
+## Accessibility
+
+### ARIA
+
+- The role of the table is grid, and the role of the tree table is treegrid
+- the row's role is row, and the cell's role is gridcell
+- Added aria-rowcount and aria-colcount attributes to the table to indicate the number of rows and columns
+- The row has added aria-rowindex to indicate which row it currently belongs to, and the first row is 1
+- The row of the tree table has aria-level representing the tree level of the current row, the first level is 1
+- Expandable table rows have the aria-expanded attribute, indicating whether the current row is expanded
+- The new aria-colindex of the cell indicates which column the current grid belongs to, and the first column is 1
+- Added aria-label to column filter and sort buttons, and added aria-label attribute to row select buttons
+
 ## Design Tokens
 <DesignToken/>
 

+ 14 - 13
content/show/table/index.md

@@ -4371,19 +4371,6 @@ function App() {
 render(App);
 ```
 
-## Accessibility
-
-### ARIA
-
-- 表格的 role 为 grid,树形表格的 role 为 treegrid
-- 行的 role 为 row,单元格的 role 为 gridcell
-- 表格新增了 aria-rowcount 和 aria-colcount 属性表示行和列的数量
-- 行新增了 aria-rowindex 表示当前属于第几行,第一行为 1
-- 树形表格的行具有 aria-level 表示当前行的树形层级,第一层为 1
-- 可展开表格行具有 aria-expanded 属性,表示当前行是否展开
-- 单元格的新增了 aria-colindex 表示当前格子属于第几列,第一列为 1
-- 列的筛选和排序按钮添加了 aria-label,行的选择按钮添加了 aria-label 属性
-
 ## API 参考
 
 ## Table
@@ -4676,6 +4663,20 @@ function Demo() {
 | -------------------- | ------------------------------------------------------------------------------------------------------------- | ------ |
 | getCurrentPageData() | 返回当前页的数据对象:{ dataSource: RecordType[], groups: Map<{groupKey: string, recordKeys: Set<string\>}> } | 0.37.0 |
 
+
+## Accessibility
+
+### ARIA
+
+- 表格的 role 为 grid,树形表格的 role 为 treegrid
+- 行的 role 为 row,单元格的 role 为 gridcell
+- 表格新增了 aria-rowcount 和 aria-colcount 属性表示行和列的数量
+- 行新增了 aria-rowindex 表示当前属于第几行,第一行为 1
+- 树形表格的行具有 aria-level 表示当前行的树形层级,第一层为 1
+- 可展开表格行具有 aria-expanded 属性,表示当前行是否展开
+- 单元格的新增了 aria-colindex 表示当前格子属于第几列,第一列为 1
+- 列的筛选和排序按钮添加了 aria-label,行的选择按钮添加了 aria-label 属性
+
 ## 设计变量
 <DesignToken/>
 

+ 1 - 1
content/show/timeline/index-en-US.md

@@ -209,7 +209,7 @@ import { IconAlertTriangle } from '@douyinfe/semi-icons';
 ### ARIA
 - The element of dot and line between dots in TimeLine have a `aria-hidden`, indicates that they do not support Accessibility API.
 - Supporting API `aria-label` to specify TimeLine's label.
-```js
+```text
 <Timeline aria-label="Accident timeline">
     <Timeline.Item time="2015-09-01">Accident started</Timeline.Item>
     <Timeline.Item time="2015-09-01">Process</Timeline.Item>

+ 1 - 1
content/show/timeline/index.md

@@ -249,7 +249,7 @@ import { IconAlertTriangle } from '@douyinfe/semi-icons';
 ### ARIA
 - 组件中时间点的连线以及时间点本身被设置了 `aria-hidden`,不会响应 Accessibility API
 - 可以通过传入 `aria-label` 设置 TimeLine 组件的标签
-```js
+```text
 <Timeline aria-label="xx事故处理过程时间线">
     <Timeline.Item time="2015-09-01">创建服务现场</Timeline.Item>
     <Timeline.Item time="2015-09-02">初步排除网络异常</Timeline.Item>

+ 11 - 0
packages/semi-foundation/button/button.scss

@@ -23,6 +23,11 @@ $module: #{$prefix}-button;
     outline: none;
     vertical-align: middle;
     white-space: nowrap;
+
+    &:focus {
+        outline: $width-button-outline solid $color-button_primary-outline-focus;
+    }
+
     &-danger {
         background-color: $color-button_danger-bg-default;
         color: $color-button_danger-text-default;
@@ -36,6 +41,9 @@ $module: #{$prefix}-button;
         &.#{$module}-borderless {
             color: $color-button_danger-bg-default;
         }
+        &:not(.#{$module}-borderless):not(.#{$module}-light):focus {
+            outline-color: $color-button_danger-outline-focus;
+        }
     }
     &-warning {
         background-color: $color-button_warning-bg-default;
@@ -50,6 +58,9 @@ $module: #{$prefix}-button;
         &.#{$module}-borderless {
             color: $color-button_warning-bg-default;
         }
+        &:not(.#{$module}-borderless):not(.#{$module}-light):focus {
+            outline-color: $color-button_warning-outline-focus;
+        }
     }
     &-tertiary {
         background-color: $color-button_tertiary-bg-default;

+ 4 - 0
packages/semi-foundation/button/variables.scss

@@ -10,6 +10,7 @@ $color-button_primary-text-hover: white; // 主要按钮文字颜色 - 悬浮
 $color-button_primary-bg-active: var(--semi-color-primary-active); // 主要按钮背景颜色 - 按下
 $color-button_primary-border-active: var(--semi-color-primary-active); // 主要按钮描边颜色 - 按下
 $color-button_primary-text-active: white; // 主要按钮文字颜色 - 按下
+$color-button_primary-outline-focus: var(--semi-color-primary-light-active); // 主要按钮轮廓 - 聚焦
 
 // secondary
 $color-button_secondary-bg-default: var(--semi-color-secondary); // 次要按钮背景颜色
@@ -36,6 +37,7 @@ $color-button_danger-text-hover: white; // 危险按钮文字颜色 - 悬浮
 $color-button_danger-bg-active: var(--semi-color-danger-active); // 危险按钮背景颜色 - 按下
 $color-button_danger-border-active: var(--semi-color-danger-active); // 危险按钮描边颜色 - 按下
 $color-button_danger-text-active: white; // 危险按钮文字颜色 - 按下
+$color-button_danger-outline-focus: var(--semi-color-danger-light-active); // 危险按钮轮廓 - 聚焦
 
 // warning
 $color-button_warning-bg-default: var(--semi-color-warning); // 警告按钮背景颜色
@@ -49,6 +51,7 @@ $color-button_warning-text-hover: white; // 警告按钮文字颜色 - 悬浮
 $color-button_warning-bg-active: var(--semi-color-warning-active); // 警告按钮背景颜色 - 按下
 $color-button_warning-border-active: var(--semi-color-warning-active); // 警告按钮描边颜色 - 按下
 $color-button_warning-text-active: white; // 警告按钮文字颜色 - 按下
+$color-button_warning-outline-focus: var(--semi-color-warning-light-active); // 警告按钮轮廓 - 聚焦
 
 // tertiary
 $color-button_tertiary-bg-default: var(--semi-color-tertiary); // 第三按钮背景颜色
@@ -134,3 +137,4 @@ $height-button_default: $height-control-default; // 按钮高度 - 默认
 $width-button-border: $border-thickness;  // 按钮描边宽度
 $radius-button: var(--semi-border-radius-small); // 按钮圆角大小
 $radius-button_group: $radius-button; // 按钮组圆角大小
+$width-button-outline: 2px; // 按钮轮廓宽度

+ 19 - 0
packages/semi-foundation/cascader/foundation.ts

@@ -18,6 +18,7 @@ import {
     calcMergeType
 } from './util';
 import { strings } from './constants';
+import isEnterPress from '../utils/isEnterPress';
 
 export interface BasicData {
     data: BasicCascaderData;
@@ -602,6 +603,15 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
         }
     }
 
+    /**
+     * A11y: simulate selection click
+     */
+    handleSelectionEnterPress(keyboardEvent: any) {
+        if (isEnterPress(keyboardEvent)) {
+            this.handleClick(keyboardEvent);
+        }
+    }
+
     toggleHoverState(bool: boolean) {
         this._adapter.toggleHovering(bool);
     }
@@ -911,6 +921,15 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
         this._adapter.rePositionDropdown();
     }
 
+    /**
+     * A11y: simulate clear button click
+     */
+    handleClearEnterPress(keyboardEvent: any) {
+        if (isEnterPress(keyboardEvent)) {
+            this.handleClear();
+        }
+    }
+
     getRenderData() {
         const { keyEntities, isSearching } = this.getStates();
         const isFilterable = this._isFilterable();

+ 4 - 4
packages/semi-foundation/datePicker/foundation.ts

@@ -163,8 +163,8 @@ export interface DatePickerFoundationState {
     panelShow: boolean;
     isRange: boolean;
     inputValue: string;
-    value: ValueType;
-    cachedSelectedValue: ValueType;
+    value: Date[];
+    cachedSelectedValue: Date[];
     prevTimeZone: string | number;
     motionEnd: boolean;
     rangeInputFocus: 'rangeStart' | 'rangeEnd' | boolean;
@@ -185,9 +185,9 @@ export interface DatePickerAdapter extends DefaultAdapter<DatePickerFoundationPr
     notifyConfirm: DatePickerFoundationProps['onConfirm'];
     notifyOpenChange: DatePickerFoundationProps['onOpenChange'];
     notifyPresetsClick: DatePickerFoundationProps['onPresetClick'];
-    updateValue: (value: ValueType) => void;
+    updateValue: (value: Date[]) => void;
     updatePrevTimezone: (prevTimeZone: string | number) => void;
-    updateCachedSelectedValue: (cachedSelectedValue: ValueType) => void;
+    updateCachedSelectedValue: (cachedSelectedValue: Date[]) => void;
     updateInputValue: (inputValue: string) => void;
     needConfirm: () => boolean;
     typeIsYearOrMonth: () => boolean;

+ 0 - 1
packages/semi-foundation/datePicker/inputFoundation.ts

@@ -32,7 +32,6 @@ export interface DateInputFoundationProps extends DateInputElementProps, DateInp
     value?: ValueType;
     disabled?: boolean;
     type?: Type;
-    multiple?: boolean;
     showClear?: boolean;
     format?: string;
     inputStyle?: React.CSSProperties;

+ 1 - 0
packages/semi-foundation/datePicker/monthFoundation.ts

@@ -28,6 +28,7 @@ export interface MonthFoundationProps {
     focusRecordsRef: any;
     locale: any;
     localeCode: string;
+    multiple: boolean;
 }
 
 export type MonthDayInfo = {

+ 1 - 1
packages/semi-foundation/table/table.scss

@@ -466,7 +466,7 @@ $module: #{$prefix}-table;
         position: relative;
         z-index: 1;
         padding: #{$spacing-table-paddingY} #{$spacing-table-paddingX};
-        color: $color-table_disabled-bg-default;
+        color: $color-table_placeholder-text-default;
         font-size: #{$font-table_base-fontSize};
         text-align: center;
         background: $color-table_pl-bg-default;

+ 1 - 0
packages/semi-foundation/table/variables.scss

@@ -73,6 +73,7 @@ $color-table_sorter-text-hover: var(--semi-color-text-2); // 表格排序按钮
 $color-table_page-text-default: var(--semi-color-text-2); // 表格翻页器文本颜色
 $color-table_resizer-bg-default: var(--semi-color-primary); // 表格拉伸标示线颜色
 $color-table_selection-bg-default: rgba(var(--semi-grey-0), 1); // 表格分组背景色
+$color-table_placeholder-text-default: var(--semi-color-text-2); // 表格空数据文本颜色
 
 // Other
 $font-table_base-fontSize: 14px; // 表格默认文本字号

+ 1 - 1
packages/semi-theme-default/scss/_palette.scss

@@ -16,7 +16,7 @@ body .semi-always-light {
     --semi-blue-2: 152,205,253;
     --semi-blue-3: 101,178,252;
     --semi-blue-4: 50,149,251;
-    --semi-blue-5: 0,119,250;
+    --semi-blue-5: 0,100,250;
     --semi-blue-6: 0,98,214;
     --semi-blue-7: 0,79,179;
     --semi-blue-8: 0,61,143;

+ 4 - 4
packages/semi-theme-default/scss/global.scss

@@ -92,7 +92,7 @@ body, body[theme-mode="dark"] .semi-always-light {
     --semi-color-bg-4: rgba(var(--semi-white), 1); // 背景色 - 最上层(特殊)
     --semi-color-text-0: rgba(var(--semi-grey-9), 1); // 文本/图标颜色 - 最主要
     --semi-color-text-1: rgba(var(--semi-grey-9), .8); // 文本/图标颜色 - 稍次要
-    --semi-color-text-2: rgba(var(--semi-grey-9), .6); // 文本/图标颜色 - 次要
+    --semi-color-text-2: rgba(var(--semi-grey-9), .62); // 文本/图标颜色 - 次要
     --semi-color-text-3: rgba(var(--semi-grey-9), .35); // 文本/图标颜色 - 最次要
     --semi-shadow-elevated: 0 0 1px rgba(0, 0, 0, .3), 0 4px 14px rgba(0, 0, 0, .1); // 用于toast, modal, popover等需要提升层级的界面元素
     --semi-border-radius-extra-small: 3px; // 超小圆角,用于 checkbox 内圆角
@@ -169,9 +169,9 @@ body[theme-mode="dark"], body .semi-always-dark {
     --semi-color-nav-bg: rgba(35, 36, 41, 1);
     --semi-shadow-elevated: inset 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 14px rgba(0, 0, 0, .25);
     --semi-color-overlay-bg: rgba(22, 22, 26, .6);
-    --semi-color-fill-0: rgba(var(--semi-white), .05);
-    --semi-color-fill-1: rgba(var(--semi-white), .09);
-    --semi-color-fill-2: rgba(var(--semi-white), .13);
+    --semi-color-fill-0: rgba(var(--semi-white), .12);
+    --semi-color-fill-1: rgba(var(--semi-white), .16);
+    --semi-color-fill-2: rgba(var(--semi-white), .20);
     --semi-color-border: rgba(var(--semi-white), .08);
     --semi-color-shadow: rgba(var(--semi-black), .04);
     --semi-color-bg-0: rgba(22, 22, 26, 1);

+ 14 - 13
packages/semi-ui/calendar/monthCalendar.tsx

@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
 import React, { ReactInstance } from 'react';
 import ReactDOM from 'react-dom';
 import cls from 'classnames';
@@ -180,16 +181,16 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
         const { markWeekend, displayValue } = this.props;
         this.monthlyData = this.foundation.getMonthlyData(displayValue, dateFnsLocale);
         return (
-            <div className={`${prefixCls}-header`}>
-                <div role="gridcell" className={`${prefixCls}-grid`}>
-                    <ul className={`${prefixCls}-grid-row`}>
+            <div className={`${prefixCls}-header`} role="presentation">
+                <div role="presentation" className={`${prefixCls}-grid`}>
+                    <ul role="row" className={`${prefixCls}-grid-row`}>
                         {this.monthlyData[0].map(day => {
                             const { weekday } = day;
                             const listCls = cls({
                                 [`${cssClasses.PREFIX}-weekend`]: markWeekend && day.isWeekend,
                             });
                             return (
-                                <li key={`${weekday}-monthheader`} className={listCls}>
+                                <li role="columnheader" aria-label={weekday} key={`${weekday}-monthheader`} className={listCls}>
                                     <span>{weekday}</span>
                                 </li>
                             );
@@ -268,7 +269,7 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
         const pos = showCard && showCard[key] ? showCard[key][1] : 'leftTopOver';
         const text = (
             <LocaleConsumer componentName="Calendar">
-                {(locale: Locale['Calendar']) => (
+                {(locale: Locale['Calendar']) => (// eslint-disable-next-line jsx-a11y/no-static-element-interactions
                     <div
                         className={`${cardCls}-wrapper`}
                         style={{ bottom: 0 }}
@@ -330,8 +331,8 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
         const { itemLimit } = this.state;
         const { display, day } = events;
         return (
-            <div role="gridcell" className={`${prefixCls}-weekrow`} ref={this.cellDom} key={`${index}-weekrow`}>
-                <ul className={`${prefixCls}-skeleton`}>
+            <div role="presentation" className={`${prefixCls}-weekrow`} ref={this.cellDom} key={`${index}-weekrow`}>
+                <ul role="row" className={`${prefixCls}-skeleton`}>
                     {weekDay.map(each => {
                         const { date, dayString, isToday, isSameMonth, isWeekend, month, ind } = each;
                         const listCls = cls({
@@ -341,7 +342,7 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
                         });
                         const shouldRenderCollapsed = Boolean(day && day[ind] && day[ind].length > itemLimit);
                         const inner = (
-                            <li key={`${date}-weeksk`} className={listCls} onClick={e => this.handleClick(e, [date])}>
+                            <li role="gridcell" aria-label={date.toLocaleDateString()} aria-current={isToday ? "date" : false} key={`${date}-weeksk`} className={listCls} onClick={e => this.handleClick(e, [date])}>
                                 {this.formatDayString(month, dayString)}
                                 {this.renderCusDateGrid(date)}
                             </li>
@@ -362,8 +363,8 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
     renderMonthGrid = () => {
         const { parsedEvents } = this.state;
         return (
-            <div role="gridcell" className={`${prefixCls}-week`}>
-                <ul className={`${prefixCls}-grid-col`}>
+            <div role="presentation" className={`${prefixCls}-week`}>
+                <ul role="presentation" className={`${prefixCls}-grid-col`}>
                     {Object.keys(this.monthlyData).map(weekInd =>
                         this.renderWeekRow(weekInd, this.monthlyData[weekInd], parsedEvents[weekInd])
                     )}
@@ -383,12 +384,12 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
         return (
             <LocaleConsumer componentName="Calendar">
                 {(locale: Locale['Calendar'], localeCode: string, dateFnsLocale: Locale['dateFnsLocale']) => (
-                    <div className={monthCls} key={this.state.itemLimit} style={monthStyle}>
-                        <div className={`${prefixCls}-sticky-top`}>
+                    <div role="grid" className={monthCls} key={this.state.itemLimit} style={monthStyle}>
+                        <div role="presentation" className={`${prefixCls}-sticky-top`}>
                             {header}
                             {this.renderHeader(dateFnsLocale)}
                         </div>
-                        <div className={`${prefixCls}-grid-wrapper`}>
+                        <div role="presentation" className={`${prefixCls}-grid-wrapper`}>
                             {this.renderMonthGrid()}
                         </div>
                     </div>

+ 21 - 3
packages/semi-ui/cascader/index.tsx

@@ -1,4 +1,4 @@
-import React, { Fragment, ReactNode, CSSProperties, MouseEvent } from 'react';
+import React, { Fragment, ReactNode, CSSProperties, MouseEvent, KeyboardEvent } from 'react';
 import ReactDOM from 'react-dom';
 import cls from 'classnames';
 import PropTypes from 'prop-types';
@@ -54,6 +54,7 @@ export interface CascaderProps extends BasicCascaderProps {
     'aria-invalid'?: React.AriaAttributes['aria-invalid'];
     'aria-labelledby'?: React.AriaAttributes['aria-labelledby'];
     'aria-required'?: React.AriaAttributes['aria-required'];
+    'aria-label'?: React.AriaAttributes['aria-label'];
     arrowIcon?: ReactNode;
     defaultValue?: Value;
     dropdownStyle?: CSSProperties;
@@ -100,6 +101,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         'aria-errormessage': PropTypes.string,
         'aria-describedby': PropTypes.string,
         'aria-required': PropTypes.bool,
+        'aria-label': PropTypes.string,
         arrowIcon: PropTypes.node,
         changeOnSelect: PropTypes.bool,
         defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
@@ -197,6 +199,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         onDropdownVisibleChange: noop,
         onListScroll: noop,
         enableLeafClick: false,
+        'aria-label': 'Cascader'
     };
 
     options: any;
@@ -584,7 +587,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         );
     }
 
-    handleItemClick = (e: MouseEvent, item: Entity | Data) => {
+    handleItemClick = (e: MouseEvent | KeyboardEvent, item: Entity | Data) => {
         this.foundation.handleItemClick(e, item);
     };
 
@@ -798,6 +801,14 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         this.foundation.handleClear();
     };
 
+    /**
+     * A11y: simulate clear button click
+     */
+    handleClearEnterPress = (e: KeyboardEvent) => {
+        e && e.stopPropagation();
+        this.foundation.handleClearEnterPress();
+    };
+
     showClearBtn = () => {
         const { showClear, disabled, multiple } = this.props;
         const { selectedKeys, isOpen, isHovering, checkedKeys } = this.state;
@@ -811,7 +822,13 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         const allowClear = this.showClearBtn();
         if (allowClear) {
             return (
-                <div className={clearCls} onClick={this.handleClear} role='button' tabIndex={0}>
+                <div 
+                    className={clearCls}
+                    onClick={this.handleClear} 
+                    onKeyPress={this.handleClearEnterPress}
+                    role='button' 
+                    tabIndex={0}
+                >
                     <IconClear />
                 </div>
             );
@@ -891,6 +908,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
                 style={style}
                 ref={this.triggerRef}
                 onClick={e => this.foundation.handleClick(e)}
+                onKeyPress={e => this.foundation.handleSelectionEnterPress(e)}
                 aria-invalid={this.props['aria-invalid']}
                 aria-errormessage={this.props['aria-errormessage']}
                 aria-label={this.props['aria-label']}

+ 25 - 5
packages/semi-ui/cascader/item.tsx

@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
 import cls from 'classnames';
 import PropTypes from 'prop-types';
 import { cssClasses, strings } from '@douyinfe/semi-foundation/cascader/constants';
+import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
 import { includes } from 'lodash';
 import ConfigContext from '../configProvider/context';
 import LocaleConsumer from '../locale/localeConsumer';
@@ -43,7 +44,7 @@ export interface CascaderItemProps {
     selectedKeys: Set<string>;
     loadedKeys: Set<string>;
     loadingKeys: Set<string>;
-    onItemClick: (e: React.MouseEvent, item: Entity | Data) => void;
+    onItemClick: (e: React.MouseEvent | React.KeyboardEvent, item: Entity | Data) => void;
     onItemHover: (e: React.MouseEvent, item: Entity) => void;
     showNext: ShowNextType;
     onItemCheckboxClick: (item: Entity | Data) => void;
@@ -84,7 +85,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
         empty: false,
     };
 
-    onClick = (e: React.MouseEvent, item: Entity | Data) => {
+    onClick = (e: React.MouseEvent | React.KeyboardEvent, item: Entity | Data) => {
         const { onItemClick } = this.props;
         if (item.data.disabled || ('disabled' in item && item.disabled)) {
             return;
@@ -92,6 +93,15 @@ export default class Item extends PureComponent<CascaderItemProps> {
         onItemClick(e, item);
     };
 
+    /**
+     * A11y: simulate item click
+     */
+    handleItemEnterPress = (keyboardEvent: React.KeyboardEvent, item: Entity | Data) => {
+        if (isEnterPress(keyboardEvent)) {
+            this.onClick(keyboardEvent, item);
+        }
+    }
+
     onHover = (e: React.MouseEvent, item: Entity) => {
         const { showNext, onItemHover } = this.props;
         if (item.data.disabled) {
@@ -136,7 +146,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
             case 'loading':
                 return <Spin wrapperClassName={`${prefixcls}-spin-icon`} />;
             case 'empty':
-                return (<span className={`${prefixcls}-icon ${prefixcls}-icon-empty`} />);
+                return (<span aria-hidden={true} className={`${prefixcls}-icon ${prefixcls}-icon-empty`} />);
             default:
                 return null;
         }
@@ -179,11 +189,13 @@ export default class Item extends PureComponent<CascaderItemProps> {
                     });
                     return (
                         <li
+                            role='menuitem'
                             className={className}
                             key={key}
                             onClick={e => {
                                 this.onClick(e, item);
                             }}
+                            onKeyPress={e => this.handleItemEnterPress(e, item)}
                         >
                             <span className={`${prefixcls}-label`}>
                                 {!multiple && this.renderIcon('empty')}
@@ -211,9 +223,9 @@ export default class Item extends PureComponent<CascaderItemProps> {
         let showChildItem: Entity;
         const ind = content.length;
         content.push(
-            <ul className={`${prefixcls}-list`} key={renderData[0].key} onScroll={e => this.props.onListScroll(e, ind)}>
+            <ul role='menu' className={`${prefixcls}-list`} key={renderData[0].key} onScroll={e => this.props.onListScroll(e, ind)}>
                 {renderData.map(item => {
-                    const { data, key } = item;
+                    const { data, key, parentKey } = item;
                     const { children, label, disabled, isLeaf } = data;
                     const { active, selected, loading } = this.getItemStatus(key);
                     const hasChild = Boolean(children) && children.length;
@@ -226,13 +238,21 @@ export default class Item extends PureComponent<CascaderItemProps> {
                         [`${prefixcls}-select`]: selected && !multiple,
                         [`${prefixcls}-disabled`]: disabled
                     });
+                    const otherAriaProps = parentKey ? { ['aria-owns']: `cascaderItem-${parentKey}` } : {};
                     return (
                         <li
+                            role='menuitem'
+                            id={`cascaderItem-${key}`}
+                            aria-expanded={active}
+                            aria-haspopup={Boolean(showExpand)}
+                            aria-disabled={disabled}
+                            {...otherAriaProps}
                             className={className}
                             key={key}
                             onClick={e => {
                                 this.onClick(e, item);
                             }}
+                            onKeyPress={e => this.handleItemEnterPress(e, item)}
                             onMouseEnter={e => {
                                 this.onHover(e, item);
                             }}

+ 8 - 5
packages/semi-ui/datePicker/dateInput.tsx

@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions,jsx-a11y/interactive-supports-focus */
 /* eslint-disable max-lines-per-function */
 /* eslint-disable no-unused-vars */
 import React from 'react';
@@ -40,7 +41,6 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
         value: PropTypes.array,
         disabled: PropTypes.bool,
         type: PropTypes.oneOf(strings.TYPE_SET),
-        multiple: PropTypes.bool,
         showClear: PropTypes.bool,
         format: PropTypes.string, // Attributes not used
         inputStyle: PropTypes.object,
@@ -65,7 +65,6 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
         onBlur: noop,
         onClear: noop,
         onFocus: noop,
-        multiple: false,
         type: 'date',
         inputStyle: {},
         inputReadOnly: false,
@@ -177,9 +176,12 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
         const allowClear = (rangeStart || rangeEnd) && showClear;
         return allowClear && !disabled ? (
             <div
+                role="button"
+                tabIndex={0}
+                aria-label="Clear range input value"
                 className={`${prefixCls}-range-input-clearbtn`}
                 onMouseDown={e => !disabled && this.handleRangeInputClear(e)}>
-                <IconClear />
+                <IconClear aria-hidden />
             </div>
         ) : null;
     }
@@ -293,6 +295,7 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
             validateStatus,
             block,
             prefixCls,
+            multiple, // Whether to allow multiple values for email and file types
             dateFnsLocale, // No need to pass to input
             onBlur,
             onClear,
@@ -310,8 +313,8 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
             rangeSeparator,
             ...rest
         } = this.props;
-        const dateIcon = <IconCalendar />;
-        const dateTimeIcon = <IconCalendarClock />;
+        const dateIcon = <IconCalendar aria-hidden />;
+        const dateTimeIcon = <IconCalendarClock aria-hidden />;
         const suffix = type.includes('Time') ? dateTimeIcon : dateIcon;
         let text = '';
 

+ 6 - 1
packages/semi-ui/datePicker/datePicker.tsx

@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/interactive-supports-focus */
 /* eslint-disable max-len */
 import React from 'react';
 import classnames from 'classnames';
@@ -528,8 +529,12 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
         };
 
         return (
-            // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
             <div
+                // tooltip will mount a11y props to children
+                // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
+                role="combobox"
+                aria-label={Array.isArray(value) && value.length ? "Change date" : "Choose date"}
+                aria-disabled={disabled}
                 onClick={this.handleTriggerWrapperClick}
                 className={inputCls}>
                 {typeof triggerRender === 'function' ? (

+ 14 - 7
packages/semi-ui/datePicker/month.tsx

@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions */
 /* eslint-disable max-len */
 import React from 'react';
 import classNames from 'classnames';
@@ -40,7 +41,8 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
         startDateOffset: PropTypes.func,
         endDateOffset: PropTypes.func,
         rangeInputFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
-        focusRecordsRef: PropTypes.object
+        focusRecordsRef: PropTypes.object,
+        multiple: PropTypes.bool,
     };
 
     static defaultProps = {
@@ -275,9 +277,9 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
         // i18n
         const weekdaysText = weekdays.map(key => locale.weeks[key]);
         return (
-            <div className={weekdayCls}>
+            <div role="row" className={weekdayCls}>
                 {weekdaysText.map((E, i) => (
-                    <div key={E + i} className={weekdayItemCls}>
+                    <div role="columnheader" key={E + i} className={weekdayItemCls}>
                         {E}
                     </div>
                 ))}
@@ -305,7 +307,7 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
     renderWeek(week: MonthDayInfo[], weekIndex: number) {
         const weekCls = cssClasses.WEEK;
         return (
-            <div className={weekCls} key={weekIndex}>
+            <div role="row" className={weekCls} key={weekIndex}>
                 {week.map((day, dayIndex) => this.renderDay(day, dayIndex))}
             </div>
         );
@@ -317,7 +319,7 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
         const { fullDate, dayNumber } = day;
         if (!fullDate) {
             return (
-                <div key={(dayNumber as number) + dayIndex} className={cssClasses.DAY}>
+                <div role="gridcell" tabIndex={-1} key={(dayNumber as number) + dayIndex} className={cssClasses.DAY}>
                     <span />
                 </div>
             );
@@ -356,6 +358,11 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
 
         return (
             <div
+                role="gridcell"
+                tabIndex={dayStatus.isDisabled ? -1 : 0}
+                aria-disabled={dayStatus.isDisabled}
+                aria-selected={dayStatus.isSelected}
+                aria-label={fullDate}
                 className={!customRender ? dayCls : cssClasses.DAY}
                 title={fullDate}
                 key={(dayNumber as number) + dayIndex}
@@ -373,13 +380,13 @@ export default class Month extends BaseComponent<MonthProps, MonthState> {
     }
 
     render() {
-        const { forwardRef } = this.props;
+        const { forwardRef, multiple } = this.props;
         const weekday = this.renderDayOfWeek();
         const weeks = this.renderWeeks();
         const monthCls = classNames(cssClasses.MONTH);
         const ref = forwardRef || this.monthRef;
         return (
-            <div ref={ref} className={monthCls}>
+            <div role="grid" aria-multiselectable={multiple} ref={ref} className={monthCls} >
                 {weekday}
                 {weeks}
             </div>

+ 17 - 5
packages/semi-ui/datePicker/monthsGrid.tsx

@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/interactive-supports-focus,jsx-a11y/click-events-have-key-events */
 /* eslint-disable react/no-did-update-set-state */
 /* eslint-disable max-len */
 /* eslint-disable no-nested-ternary */
@@ -343,7 +344,7 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
 
     renderMonth(month: Date, panelType: PanelType) {
         const { selected, rangeStart, rangeEnd, hoverDay, maxWeekNum, offsetRangeStart, offsetRangeEnd } = this.state;
-        const { weekStartsOn, disabledDate, locale, localeCode, renderDate, renderFullDate, startDateOffset, endDateOffset, density, rangeInputFocus, syncSwitchMonth } = this.props;
+        const { weekStartsOn, disabledDate, locale, localeCode, renderDate, renderFullDate, startDateOffset, endDateOffset, density, rangeInputFocus, syncSwitchMonth, multiple } = this.props;
         let monthText = '';
         // i18n monthText
         if (month) {
@@ -409,6 +410,7 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
                     startDateOffset={startDateOffset}
                     endDateOffset={endDateOffset}
                     focusRecordsRef={this.props.focusRecordsRef}
+                    multiple={multiple}
                 />
             </div>
         );
@@ -580,12 +582,22 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
 
         return (
             <div className={switchCls} ref={current => this.adapter.setCache(`switch-${panelType}`, current)}>
-                <div className={dateCls} onClick={e => this.foundation.showDatePanel(panelType)}>
-                    {showSwithIcon && <IconCalendar />}
+                <div
+                    role="button"
+                    aria-label="Switch to date panel"
+                    className={dateCls}
+                    onClick={e => this.foundation.showDatePanel(panelType)}
+                >
+                    {showSwithIcon && <IconCalendar aria-hidden />}
                     <span className={textCls}>{dateText || monthText}</span>
                 </div>
-                <div className={timeCls} onClick={e => this.foundation.showTimePicker(panelType, true)}>
-                    {showSwithIcon && <IconClock />}
+                <div
+                    role="button"
+                    aria-label="Switch to time panel"
+                    className={timeCls}
+                    onClick={e => this.foundation.showTimePicker(panelType, true)}
+                >
+                    {showSwithIcon && <IconClock aria-hidden />}
                     <span className={textCls}>{timeText}</span>
                 </div>
             </div>

+ 8 - 4
packages/semi-ui/datePicker/navigation.tsx

@@ -101,7 +101,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
             <div className={prefixCls} ref={ref}>
                 <IconButton
                     key="double-chevron-left"
-                    icon={<IconDoubleChevronLeft size={iconBtnSize}/>} 
+                    aria-label="Previous year"
+                    icon={<IconDoubleChevronLeft aria-hidden size={iconBtnSize} />}
                     size={buttonSize}
                     theme={btnTheme}
                     noHorizontalPadding={btnNoHorizontalPadding}
@@ -110,7 +111,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
                 />
                 <IconButton
                     key="chevron-left"
-                    icon={<IconChevronLeft size={iconBtnSize} />}
+                    aria-label="Previous month"
+                    icon={<IconChevronLeft aria-hidden size={iconBtnSize} />}
                     size={buttonSize}
                     onClick={onPrevMonth}
                     theme={btnTheme}
@@ -124,7 +126,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
                 </div>
                 <IconButton
                     key="chevron-right"
-                    icon={<IconChevronRight size={iconBtnSize} />}
+                    aria-label="Next month"
+                    icon={<IconChevronRight aria-hidden size={iconBtnSize} />}
                     size={buttonSize}
                     onClick={onNextMonth}
                     theme={btnTheme}
@@ -133,7 +136,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
                 />
                 <IconButton
                     key="double-chevron-right"
-                    icon={<IconDoubleChevronRight size={iconBtnSize}/>} 
+                    aria-label="Next year"
+                    icon={<IconDoubleChevronRight aria-hidden size={iconBtnSize} />}
                     size={buttonSize}
                     theme={btnTheme}
                     noHorizontalPadding={btnNoHorizontalPadding}

+ 1 - 0
packages/semi-ui/datePicker/quickControl.tsx

@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/no-static-element-interactions,jsx-a11y/click-events-have-key-events */
 import React, { PureComponent } from 'react';
 import classNames from 'classnames';
 import PropTypes from 'prop-types';

+ 1 - 1
packages/semi-ui/datePicker/yearAndMonth.tsx

@@ -208,7 +208,7 @@ class YearAndMonth extends BaseComponent<YearAndMonthProps, YearAndMonthState> {
                     <div className={prefix}>
                         <IconButton
                             noHorizontalPadding={false}
-                            icon={<IconChevronLeft size={iconSize} />}
+                            icon={<IconChevronLeft aria-hidden size={iconSize} />}
                             size={buttonSize}
                             onClick={this.backToMain}
                         >

+ 3 - 0
packages/semi-ui/scrollList/_story/ScrollList/index.js

@@ -43,6 +43,7 @@ class ScrollListDemo extends React.Component {
                     type={1}
                     selectedIndex={this.state.selectIndex1}
                     onSelect={this.onSelect}
+                    aria-label="1"
                 />
                 <ScrollItem
                     mode="normal"
@@ -50,6 +51,7 @@ class ScrollListDemo extends React.Component {
                     type={2}
                     selectedIndex={this.state.selectIndex2}
                     onSelect={this.onSelect}
+                    aria-label="2"
                 />
                 <ScrollItem
                     mode="normal"
@@ -57,6 +59,7 @@ class ScrollListDemo extends React.Component {
                     type={3}
                     selectedIndex={this.state.selectIndex3}
                     onSelect={this.onSelect}
+                    aria-label="3"
                 />
             </ScrollList>
         );

+ 3 - 0
packages/semi-ui/scrollList/_story/WheelList/index.js

@@ -92,6 +92,7 @@ class ScrollListDemo extends React.Component {
                         type={1}
                         selectedIndex={this.state.selectIndex1}
                         onSelect={this.onSelectAP}
+                        aria-label="时段"
                     />
                     <ScrollItem
                         {...commonProps}
@@ -99,6 +100,7 @@ class ScrollListDemo extends React.Component {
                         type={2}
                         selectedIndex={this.state.selectIndex2}
                         onSelect={this.onSelectHour}
+                        aria-label="小时"
                     />
                     <ScrollItem
                         {...commonProps}
@@ -106,6 +108,7 @@ class ScrollListDemo extends React.Component {
                         type={3}
                         selectedIndex={this.state.selectIndex3}
                         onSelect={this.onSelectMinute}
+                        aria-label="分钟"
                     />
                 </ScrollList>
             </div>

+ 30 - 9
packages/semi-ui/scrollList/scrollItem.tsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { AriaAttributes } from 'react';
 import BaseComponent from '../_base/baseComponent';
 import PropTypes from 'prop-types';
 import classnames from 'classnames';
@@ -28,6 +28,7 @@ export interface ScrollItemProps<T extends Item> {
     motion?: Motion;
     style?: React.CSSProperties;
     type?: string | number; // used to identify the scrollItem, used internally by the semi component, and does not need to be exposed to the user
+    'aria-label'?: AriaAttributes['aria-label'];
 }
 
 export interface ScrollItemState {
@@ -413,15 +414,15 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
             const { transform: itemTrans } = item;
 
             const transform = typeof itemTrans === 'function' ? itemTrans : commonTrans;
-
+            const selected = selectedIndex === index;
             const cls = classnames({
-                [`${cssClasses.PREFIX}-item-sel`]: selectedIndex === index && mode !== wheelMode,
+                [`${cssClasses.PREFIX}-item-sel`]: selected && mode !== wheelMode,
                 [`${cssClasses.PREFIX}-item-disabled`]: Boolean(item.disabled),
             });
 
             let text = '';
 
-            if (selectedIndex === index) {
+            if (selected) {
                 if (typeof transform === 'function') {
                     text = transform(item.value, item.text);
                 } else {
@@ -441,7 +442,14 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
 
             return (
                 // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
-                <li key={prefixKey + index} {...events} className={cls}>
+                <li
+                    key={prefixKey + index}
+                    {...events}
+                    className={cls}
+                    role="option"
+                    aria-selected={selected}
+                    aria-disabled={item.disabled}
+                >
                     {text}
                 </li>
             );
@@ -457,7 +465,14 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
 
         return (
             <div style={style} className={wrapperCls} ref={this._cacheWrapperNode}>
-                <ul ref={this._cacheListNode}>{inner}</ul>
+                <ul
+                    role="listbox"
+                    aria-multiselectable={false}
+                    aria-label={this.props['aria-label']}
+                    ref={this._cacheListNode}
+                >
+                    {inner}
+                </ul>
             </div>
         );
     };
@@ -470,13 +485,13 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
         const { prependCount, appendCount } = this.state;
 
         const prependList = times(prependCount).reduce((arr, num) => {
-            const items = this.renderItemList(`pre_${ num }_`);
+            const items = this.renderItemList(`pre_${num}_`);
             arr.unshift(...items);
 
             return arr;
         }, []);
         const appendList = times(appendCount).reduce((arr, num) => {
-            const items = this.renderItemList(`app_${ num }_`);
+            const items = this.renderItemList(`app_${num}_`);
             arr.push(...items);
             return arr;
         }, []);
@@ -500,7 +515,13 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
                 <div className={selectorCls} ref={this._cacheSelectorNode} />
                 <div className={postShadeCls} />
                 <div className={listWrapperCls} ref={this._cacheWrapperNode} onScroll={this.scrollToSelectItem}>
-                    <ul ref={this._cacheListNode} onClick={this.clickToSelectItem}>
+                    <ul
+                        role="listbox"
+                        aria-label={this.props['aria-label']}
+                        aria-multiselectable={false}
+                        ref={this._cacheListNode}
+                        onClick={this.clickToSelectItem}
+                    >
                         {prependList}
                         {inner}
                         {appendList}