Skip to content

Commit d34bdc2

Browse files
committed
fix(TreeSelect): supoort a11y, add aria attrs
1 parent 8ed65cc commit d34bdc2

File tree

3 files changed

+48
-13
lines changed

3 files changed

+48
-13
lines changed

src/tree/view/tree-node.jsx

+36-11
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import TreeNodeInput from './tree-node-input';
1010

1111
const { Expand } = Animate;
1212
const { bindCtx } = func;
13-
const { isPromise, pickOthers } = obj;
13+
const { isPromise, pickOthers, pickAttrsWith } = obj;
1414
const isRoot = pos => /^0-(\d)+$/.test(pos);
1515

1616
/**
@@ -70,6 +70,7 @@ export default class TreeNode extends Component {
7070
dragOverGapBottom: PropTypes.bool,
7171
parentNode: PropTypes.object,
7272
onKeyDown: PropTypes.func,
73+
size: PropTypes.number,
7374
};
7475

7576
static defaultProps = {
@@ -78,6 +79,7 @@ export default class TreeNode extends Component {
7879
disabled: false,
7980
checkboxDisabled: false,
8081
isLeaf: false,
82+
size: 1,
8183
};
8284

8385
constructor(props) {
@@ -378,6 +380,7 @@ export default class TreeNode extends Component {
378380
<Checkbox
379381
aria-label={typeof label === 'string' ? label : null}
380382
checked={checked}
383+
tabIndex={-1}
381384
indeterminate={indeterminate}
382385
disabled={disabled || checkboxDisabled}
383386
onChange={this.handleCheck}
@@ -460,12 +463,14 @@ export default class TreeNode extends Component {
460463
root,
461464
pos,
462465
selected,
466+
checked,
463467
disabled,
464468
expanded,
465469
dragOver,
466470
dragOverGapTop,
467471
dragOverGapBottom,
468472
_key,
473+
size,
469474
} = this.props;
470475
const {
471476
loadData,
@@ -474,9 +479,22 @@ export default class TreeNode extends Component {
474479
draggable: rootDraggable,
475480
filterTreeNode,
476481
} = root.props;
482+
const { label } = this.state;
483+
477484
this.showLine = !isNodeBlock && showLine;
485+
const indexArr = pos.split('-');
486+
487+
const ARIA_PREFIX = 'aria-';
488+
const ariaProps = pickAttrsWith(this.props, ARIA_PREFIX);
478489
const others = pickOthers(Object.keys(TreeNode.propTypes), this.props);
479490

491+
// remove aria keys
492+
Object.keys(others).forEach(key => {
493+
if (key.match(ARIA_PREFIX)) {
494+
delete others[key];
495+
}
496+
});
497+
480498
if (rootDraggable) {
481499
others.onDragEnter = this.handleDragEnter;
482500
others.onDragOver = this.handleDragOver;
@@ -507,16 +525,18 @@ export default class TreeNode extends Component {
507525
typeof isNodeBlock === 'object'
508526
? parseInt(isNodeBlock.indent || 24)
509527
: 24;
510-
const level = pos.split('-').length - 2;
528+
const level = indexArr.length - 2;
511529
const paddingLeftProp = rtl ? 'paddingRight' : 'paddingLeft';
512530

513531
const innerStyle = isNodeBlock
514532
? { [paddingLeftProp]: `${indent * level + defaultPaddingLeft}px` }
515533
: null;
534+
516535
const innerProps = {
517536
className: innerClassName,
518537
style: innerStyle,
519538
onKeyDown: this.handleKeyDown,
539+
...ariaProps,
520540
};
521541
if (isNodeBlock) {
522542
this.addCallbacks(innerProps);
@@ -537,15 +557,20 @@ export default class TreeNode extends Component {
537557
}
538558

539559
return (
540-
<li
541-
role="treeitem"
542-
aria-selected={selected}
543-
aria-disabled={disabled}
544-
aria-expanded={expanded && !!hasChildTree}
545-
className={newClassName}
546-
{...others}
547-
>
548-
<div ref="node" {...innerProps}>
560+
<li role="presentation" className={newClassName} {...others}>
561+
<div
562+
ref="node"
563+
role="treeitem"
564+
aria-selected={selected}
565+
aria-disabled={disabled}
566+
aria-checked={checked}
567+
aria-expanded={expanded && !!hasChildTree}
568+
aria-label={typeof label === 'string' ? label : null}
569+
aria-level={level + 1}
570+
aria-posinset={Number(indexArr[indexArr.length - 1]) + 1}
571+
aria-setsize={size}
572+
{...innerProps}
573+
>
549574
{canExpand
550575
? this.renderSwitcher()
551576
: this.renderNoopSwitcher()}

src/tree/view/tree.jsx

+11-1
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,14 @@ export default class Tree extends Component {
962962
if (children && children.length) {
963963
props.children = loop(children, pos);
964964
}
965-
const node = <TreeNode rtl={rtl} key={key} {...props} />;
965+
const node = (
966+
<TreeNode
967+
rtl={rtl}
968+
key={key}
969+
size={data.length}
970+
{...props}
971+
/>
972+
);
966973
this._k2n[key].node = node;
967974
return node;
968975
});
@@ -987,6 +994,7 @@ export default class Tree extends Component {
987994

988995
props._key = key;
989996
props.rtl = rtl;
997+
props.size = Children.count(children);
990998

991999
const node = cloneElement(child, props);
9921000
this._k2n[key].node = node;
@@ -1006,6 +1014,7 @@ export default class Tree extends Component {
10061014
showLine,
10071015
isNodeBlock,
10081016
isLabelBlock,
1017+
multiple,
10091018
} = this.props;
10101019
const others = pickOthers(Object.keys(Tree.propTypes), this.props);
10111020

@@ -1025,6 +1034,7 @@ export default class Tree extends Component {
10251034
return (
10261035
<ul
10271036
role="tree"
1037+
aria-multiselectable={multiple}
10281038
onBlur={this.handleBlur}
10291039
className={newClassName}
10301040
{...others}

test/tree/index-spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ describe('Tree', () => {
260260
<TreeNode key="1" label="Component">
261261
<TreeNode key="2" label="Form" selectable={false}>
262262
<TreeNode key="4" label="Input" />
263-
<TreeNode key="5" label="Select" disabled />
263+
<TreeNode aria-label="select one" key="5" label="Select" disabled />
264264
</TreeNode>
265265
<TreeNode key="3" label="Display">
266266
<TreeNode key="6" label="Table" />

0 commit comments

Comments
 (0)