diff --git a/docs/step/demo/basic.md b/docs/step/demo/basic.md index 310f087f0a..14968f977f 100644 --- a/docs/step/demo/basic.md +++ b/docs/step/demo/basic.md @@ -6,8 +6,6 @@ `circle`类型可通过`labelPlacement`设置文本排列方向。 -在当前的step item上添加aria-label标签来支持无障碍识别当前step进度 - :::lang=en-us # Basic @@ -17,8 +15,6 @@ In the simplest case, Step has three types that can be toggled through the `shap The `circle` type can be used to set the orientation of the text through `labelPlacement`. -Add the `aria-label` tag to the current step item to support the current step progress for accessibility recognition - ::: --- @@ -26,7 +22,7 @@ Add the `aria-label` tag to the current step item to support the current step pr ````jsx import { Step } from '@alifd/next'; -const steps = [['Step 1', 'Open the refrigerator door'], ['Step 2', 'Put the elephant in the refrigerator'], ['Step 3', 'Close the refrigerator door']].map((item, index) => ); +const steps = [['Step 1', 'Open the refrigerator door'], ['Step 2', 'Put the elephant in the refrigerator'], ['Step 3', 'Close the refrigerator door']].map((item, index) => ); ReactDOM.render(

Arrow

diff --git a/docs/step/demo/controlled.md b/docs/step/demo/controlled.md index 43434088c0..b1e08f04a3 100644 --- a/docs/step/demo/controlled.md +++ b/docs/step/demo/controlled.md @@ -30,7 +30,7 @@ class Component extends React.Component { currentStep: 3, stepType: 'circle', stepAnimation: true, - labelPlacement: 'vertical' + labelPlacement: 'ver' }; this.onClick = this.onClick.bind(this); @@ -77,9 +77,9 @@ class Component extends React.Component { } - { - ['horizontal', 'vertical'].map(item => {item}) + ['hoz', 'ver'].map(item => {item}) } diff --git a/docs/step/demo/direction.md b/docs/step/demo/direction.md index 2dd4f61210..efc18666a9 100644 --- a/docs/step/demo/direction.md +++ b/docs/step/demo/direction.md @@ -24,14 +24,14 @@ import { Step } from '@alifd/next'; ReactDOM.render(
- +

- +
, mountNode); diff --git a/docs/step/demo/disable.md b/docs/step/demo/disable.md index ed9a71c392..b57a96b6a0 100644 --- a/docs/step/demo/disable.md +++ b/docs/step/demo/disable.md @@ -23,7 +23,7 @@ import { Step } from '@alifd/next'; ReactDOM.render(
- + @@ -31,7 +31,7 @@ ReactDOM.render(

- + @@ -39,7 +39,7 @@ ReactDOM.render(

- + diff --git a/docs/step/demo/percent.md b/docs/step/demo/percent.md index 538be6f6f9..0389bb9606 100644 --- a/docs/step/demo/percent.md +++ b/docs/step/demo/percent.md @@ -23,14 +23,14 @@ import { Step } from '@alifd/next'; ReactDOM.render(
- +

- +
, mountNode); diff --git a/docs/step/theme/index.jsx b/docs/step/theme/index.jsx index 7a79cf8130..5085fa4432 100644 --- a/docs/step/theme/index.jsx +++ b/docs/step/theme/index.jsx @@ -73,8 +73,8 @@ class FunctionDemo extends React.Component { }, contentPos: { label: '内容位置', - value: 'vertical', - enum: [{ value: 'vertical', label: '节点下方' }, { value: 'horizontal', label: '节点右侧' }], + value: 'ver', + enum: [{ value: 'ver', label: '节点下方' }, { value: 'hoz', label: '节点右侧' }], } }, dotDemoFunction: { @@ -162,14 +162,14 @@ class FunctionDemo extends React.Component { - + { itemData.horizontal.map((v, index) => this.itemRender({ flag, index, ...v })) } - + { itemData.disabled.map((v, index) => this.itemRender({ flag, index, ...v })) } @@ -204,21 +204,21 @@ class FunctionDemo extends React.Component { - + { itemData.horizontal.map((v, index) => this.itemRender({ flag, index, ...v })) } - + { itemData.percent.map((v, index) => this.itemRender({ flag, index, ...v })) } - + { itemData.disabled.map((v, index) => this.itemRender({ flag, index, ...v })) } diff --git a/src/step/scss/basic.scss b/src/step/scss/basic.scss index 998fda679f..b9fdacf169 100644 --- a/src/step/scss/basic.scss +++ b/src/step/scss/basic.scss @@ -9,6 +9,11 @@ position: relative; vertical-align: middle; outline: 0; + height: 100%; + + &-body { + outline: 0; + } &-node { transition: all .2s ease; diff --git a/src/step/view/step-item.jsx b/src/step/view/step-item.jsx index 3ef186b5d0..aa205bc687 100644 --- a/src/step/view/step-item.jsx +++ b/src/step/view/step-item.jsx @@ -224,6 +224,7 @@ class StepItem extends Component { status, title, content, + shape, } = this.props; const { others, stepCls, overlayCls } = args; const nodeElement = this._getNode(); @@ -260,11 +261,13 @@ class StepItem extends Component {
); } + if (shape !== 'arrow') { + delete others.tabIndex; + delete others['aria-current']; + } return ( -
-
+ ); } @@ -409,9 +414,7 @@ class StepItem extends Component { const overlayCls = status === 'finish' ? { width: '100%' } : null; const arrowElement = ( -
{title}
-
+ ); const otherElement = this.getNode({ others, stepCls, overlayCls }); diff --git a/src/step/view/step.jsx b/src/step/view/step.jsx index a599983da8..c420d803a3 100644 --- a/src/step/view/step.jsx +++ b/src/step/view/step.jsx @@ -2,8 +2,9 @@ import React, { Component, Children } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { support, events, dom } from '../../util'; +import { support, events, dom, KEYCODE, func } from '../../util'; +const { makeChain } = func; const getHeight = el => dom.getStyle(el, 'height'); const setHeight = (el, height) => dom.setStyle(el, 'height', height); @@ -68,6 +69,7 @@ export default class Step extends Component { this.state = { parentWidth: 'auto', parentHeight: 'auto', + currentfocus: 0, }; this.resize = this.resize.bind(this); } @@ -108,6 +110,8 @@ export default class Step extends Component { (labelPlacement === 'vertical' || labelPlacement === 'ver') ) { const step = ReactDOM.findDOMNode(this.step); + // just resize when init + if (step.style.height) return; const height = Array.prototype.slice .call(step.getElementsByClassName(`${prefix}step-item`)) .reduce((ret, re) => { @@ -133,6 +137,40 @@ export default class Step extends Component { } } + // set dir key for aria handle + handleKeyDown = e => { + const { shape, children } = this.props; + const { length: max } = children; + let { currentfocus } = this.state; + const initPosition = currentfocus; + switch (e.keyCode) { + case KEYCODE.RIGHT: + case KEYCODE.DOWN: + currentfocus++; + break; + case KEYCODE.LEFT: + case KEYCODE.UP: + currentfocus--; + break; + default: + break; + } + currentfocus = + currentfocus >= max ? 0 : currentfocus < 0 ? max - 1 : currentfocus; + this.setState({ currentfocus }, () => { + const child = this.step.children[currentfocus]; + if (!child) return; + const focusItem = + shape === 'arrow' + ? child + : child.querySelector('.next-step-item-body'); + focusItem && focusItem.focus(); + }); + if (initPosition !== currentfocus) { + e.preventDefault(); + } + }; + _getValidChildren(children) { const result = []; React.Children.forEach(children, child => { @@ -149,26 +187,23 @@ export default class Step extends Component { render() { // eslint-disable-next-line - let { - prefix, - locale, + const { className, current, - direction, labelPlacement, shape, - children, readOnly, animation, itemRender, rtl, ...others } = this.props; + let { prefix, direction, children } = this.props; prefix = this.context.prefix || prefix; const { parentWidth, parentHeight } = this.state; // type不同对应的direction不同 - direction = shape === 'arrow' ? 'horizontal' : direction; + direction = shape === 'arrow' ? 'hoz' : direction; // children去除null children = this._getValidChildren(children); @@ -195,6 +230,8 @@ export default class Step extends Component { parentHeight, readOnly, animation, + tabIndex: this.state.currentfocus === index ? '0' : '-1', + 'aria-current': status === 'process' ? 'step' : null, itemRender: child.props.itemRender ? child.props.itemRender : itemRender, // 优先使用Item的itemRender @@ -221,10 +258,12 @@ export default class Step extends Component { others.dir = 'rtl'; } + others.onKeyDown = makeChain(this.handleKeyDown, others.onKeyDown); + return ( -
+
    {cloneChildren} -
+ ); } } diff --git a/test/step/index-spec.js b/test/step/index-spec.js index 7af1f60207..97edf4a5f5 100644 --- a/test/step/index-spec.js +++ b/test/step/index-spec.js @@ -81,21 +81,21 @@ describe('Step', () => { it('should render with diffrent directions', () => { const wrapper = mount( - + ); const wrapper2 = mount( - + ); const wrapper3 = mount( - + @@ -109,14 +109,14 @@ describe('Step', () => { it('should render with labelPlacement', () => { const wrapper = mount( - + ); const wrapper2 = mount( - + @@ -252,7 +252,7 @@ describe('Step', () => { it('should change current step', () => { const wrapper = mount( - + @@ -273,7 +273,7 @@ describe('Step', () => { ); assert(wrapper.find('.next-step-label-vertical').length === 1); - wrapper.setProps({ labelPlacement: 'horizontal' }, () => { + wrapper.setProps({ labelPlacement: 'hoz' }, () => { assert(wrapper.find('.next-step-label-horizontal').length === 1); // 横向模式下会调整 next-step-item-tail 的宽度值 const $tail = wrapper.find('.next-step-item-tail'); @@ -313,7 +313,7 @@ describe('Step', () => { let ret_2 = -1; const wrapper2 = mount( - + (ret_2 = index)} @@ -329,5 +329,37 @@ describe('Step', () => { .simulate('click'); assert(ret_2 === 0); }); + + it('should trigger keyboard event', () => { + const wrapper = mount( + + + + + + ); + + wrapper + .find('.next-step-item-first') + .simulate('keydown', {keyCode: 40}); + + assert(wrapper.find('.next-step-item-body').at(1).instance().getAttribute('tabindex')==='0'); + + wrapper + .find('.next-step-item-first') + .simulate('keydown', {keyCode: 38}); + assert(wrapper.find('.next-step-item-body').at(0).instance().getAttribute('tabindex')==='0'); + + wrapper + .find('.next-step-item-first') + .simulate('keydown', {keyCode: 39}); + assert(wrapper.find('.next-step-item-body').at(1).instance().getAttribute('tabindex')==='0'); + + wrapper + .find('.next-step-item-first') + .simulate('keydown', {keyCode: 37}); + assert(wrapper.find('.next-step-item-body').at(0).instance().getAttribute('tabindex')==='0'); + + }); }); });