Przeglądaj źródła

feat: [TagInput] support ally aria-* (#472)

feat: [TagInput] support ally aria

feat: [TagInput] support ally aria

feat: [TagInput] support ally aria

Co-authored-by: chenyuling <[email protected]>
boomboomchen 3 lat temu
rodzic
commit
bbf132067d

+ 9 - 0
content/input/taginput/index-en-US.md

@@ -384,6 +384,7 @@ class CustomRender extends React.Component {
                 style={{display: 'flex', alignItems: 'center', fontSize: 14, marginRight: 10}}
             >
                 <Avatar 
+                    alt='avatar'
                     src={data?data.avatar:'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/avatarDemo.jpeg'} 
                     size="extra-small" 
                 />
@@ -452,6 +453,14 @@ class CustomRender extends React.Component {
 |blur() |Remove focus|1.19.0|
 |focus()|Get focus   |1.19.0|
 
+## Accessibility
+
+### Aria
+
+- TagInput supports the input of `aria-label` to indicate the function of the TagInput;
+- TagInput will set `aria-disabled` and `aria-invalid` according to disabled and validateStatus props;
+- Both the input box and the clear button of TagInput have `aria-label` to indicate the function of the element.
+
 ## Design Tokens
 <DesignToken/>
 

+ 9 - 0
content/input/taginput/index.md

@@ -384,6 +384,7 @@ class CustomRender extends React.Component {
                 style={{display: 'flex', alignItems: 'center', fontSize: 14, marginRight: 10}}
             >
                 <Avatar 
+                    alt='avatar'
                     src={data?data.avatar:'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/avatarDemo.jpeg'} 
                     size="extra-small" 
                 />
@@ -451,6 +452,14 @@ class CustomRender extends React.Component {
 |blur() |移出焦点|1.19.0|
 |focus()|获取焦点|1.19.0|
 
+## Accessibility
+
+### Aria
+
+- TagInput 支持传入 `aria-label` 来表示该 TagInput 作用;
+- TagInput 会依据 disabled 及 validateStatus props 来分别设置 `aria-disabled`、`aria-invalid`;
+- TagInput 的输入框和清空按钮均具有 `aria-label` 来表明元素作用。
+
 ## 设计变量
 <DesignToken/>
 

+ 10 - 0
packages/semi-foundation/tagInput/foundation.ts

@@ -7,6 +7,7 @@ import {
     isUndefined
 } from 'lodash';
 import getSplitedArray from './utils/getSplitedArray';
+import isEnterPress from '../utils/isEnterPress';
 
 export type TagInputChangeEvent = any;
 export type TagInputCursorEvent = any;
@@ -143,6 +144,15 @@ class TagInputFoundation extends BaseFoundation<TagInputAdapter> {
         this._adapter.notifyFocus(e);
     }
 
+    /**
+     * A11y: simulate clear button click
+     */
+    handleClearEnterPress(e: TagInputKeyboardEvent) {
+        if (isEnterPress(e)) {
+            this.handleClearBtn(e);
+        }
+    }
+
     handleClearBtn(e: TagInputMouseEvent) {
         const { inputValue, tagsArray } = this._adapter.getStates();
         if (tagsArray.length > 0) {

+ 2 - 2
packages/semi-ui/tagInput/_story/tagInput.stories.js

@@ -13,7 +13,7 @@ export default {
 
 export const Default = () => (
   <>
-    <TagInput defaultValue={['抖音', '火山', '西瓜视频']} placeholder="请输入..." style={style} />
+    <TagInput aria-label='input tag' defaultValue={['抖音', '火山', '西瓜视频']} placeholder="请输入..." style={style} />
     <TagInput
       maxTagCount={2}
       showRestTagsPopover={true}
@@ -348,7 +348,7 @@ class CustomRender extends React.Component {
           marginRight: 10,
         }}
       >
-        <Avatar src={node.avatar} size="extra-small">
+        <Avatar alt="avatar" src={node.avatar} size="extra-small">
           {node.abbr}
         </Avatar>
         <span

+ 19 - 2
packages/semi-ui/tagInput/index.tsx

@@ -57,6 +57,7 @@ export interface TagInputProps {
     validateStatus?: ValidateStatus;
     value?: string[];
     autoFocus?: boolean;
+    'aria-label'?: string;
 }
 
 export interface TagInputState {
@@ -102,7 +103,8 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         size: PropTypes.oneOf(strings.SIZE_SET),
         validateStatus: PropTypes.oneOf(strings.STATUS),
         prefix: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
-        suffix: PropTypes.oneOfType([PropTypes.string, PropTypes.node])
+        suffix: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+        'aria-label': PropTypes.string,
     };
 
     static defaultProps = {
@@ -216,6 +218,10 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         this.foundation.handleClearBtn(e);
     };
 
+    handleClearEnterPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
+        this.foundation.handleClearEnterPress(e);
+    };
+
     handleTagClose = (idx: number) => {
         this.foundation.handleTagClose(idx);
     };
@@ -236,7 +242,14 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         });
         if (showClear) {
             return (
-                <div className={clearCls} onClick={e => this.handleClearBtn(e)}>
+                <div 
+                    role="button"
+                    tabIndex={0} 
+                    aria-label="Clear TagInput value" 
+                    className={clearCls} 
+                    onClick={e => this.handleClearBtn(e)}
+                    onKeyPress={e => this.handleClearEnterPress(e)}
+                >
                     <IconClear />
                 </div>
             );
@@ -398,6 +411,9 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
             <div
                 style={style}
                 className={tagInputCls}
+                aria-disabled={disabled}
+                aria-label={this.props['aria-label']}
+                aria-invalid={validateStatus === 'error'}
                 onMouseEnter={e => {
                     this.handleInputMouseEnter(e);
                 }}
@@ -409,6 +425,7 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
                 <div className={wrapperCls}>
                     {this.renderTags()}
                     <Input
+                        aria-label='input value'
                         ref={this.inputRef as any}
                         className={inputCls}
                         disabled={disabled}