Skip to content

Commit

Permalink
feat(Step): support keyborad direction and use semantic label
Browse files Browse the repository at this point in the history
  • Loading branch information
jianyi.zh committed Mar 25, 2019
1 parent e343718 commit 7225e8b
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 47 deletions.
6 changes: 1 addition & 5 deletions docs/step/demo/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

`circle`类型可通过`labelPlacement`设置文本排列方向。

在当前的step item上添加aria-label标签来支持无障碍识别当前step进度

:::lang=en-us
# Basic

Expand All @@ -17,16 +15,14 @@ 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

:::

---

````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) => <Step.Item aria-current={index === 1 ? 'step' : null} aria-label={index === 1 ? `Current Step, ${item[0]}, ${item[1]}` : null} key={index} title={item[0]} content={item[1]}/>);
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) => <Step.Item aria-current={index === 1 ? 'step' : null} key={index} title={item[0]} content={item[1]}/>);

ReactDOM.render(<div>
<h3>Arrow</h3>
Expand Down
6 changes: 3 additions & 3 deletions docs/step/demo/controlled.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -77,9 +77,9 @@ class Component extends React.Component {
}
</Select>

<Select placeholder="Label placement" onChange={this.onLabelPlacementChange.bind(this)} className="custom-select" defaultValue="vertical">
<Select placeholder="Label placement" onChange={this.onLabelPlacementChange.bind(this)} className="custom-select" defaultValue="ver">
{
['horizontal', 'vertical'].map(item => <Select.Option value={item} key={item}>{item}</Select.Option>)
['hoz', 'ver'].map(item => <Select.Option value={item} key={item}>{item}</Select.Option>)
}
</Select>

Expand Down
4 changes: 2 additions & 2 deletions docs/step/demo/direction.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ import { Step } from '@alifd/next';
ReactDOM.render(<div>
<Step current={1} direction="ver" animation={false}>
<Step.Item title="Step 1" content="Open the refrigerator door" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2, Put the elephant in the refrigerator" content="Put the elephant in the refrigerator" />
<Step.Item title="Step 2" content="Put the elephant in the refrigerator" />
<Step.Item title="Step 3" content="Close the refrigerator door" />
</Step>

<br /><br />
<Step current={1} direction="ver" shape="dot" animation={false}>
<Step.Item title="Step 1" content="Open the refrigerator door" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2, Put the elephant in the refrigerator" content="Put the elephant in the refrigerator" />
<Step.Item title="Step 2" content="Put the elephant in the refrigerator" />
<Step.Item title="Step 3" content="Close the refrigerator door" />
</Step>
</div>, mountNode);
Expand Down
6 changes: 3 additions & 3 deletions docs/step/demo/disable.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ import { Step } from '@alifd/next';
ReactDOM.render(<div>
<Step current={1} shape="arrow">
<Step.Item title="Step 1" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2" />
<Step.Item title="Step 2" />
<Step.Item title="Step 3" disabled />
<Step.Item title="Step 4" />
</Step>
<br />
<br />
<Step current={1} shape="dot">
<Step.Item title="Step 1" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2" />
<Step.Item title="Step 2" />
<Step.Item title="Step 3" disabled />
<Step.Item title="Step 4" />
</Step>
<br />
<br />
<Step current={1} shape="circle">
<Step.Item title="Step 1" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2" />
<Step.Item title="Step 2" />
<Step.Item title="Step 3" disabled />
<Step.Item title="Step 4" />
</Step>
Expand Down
4 changes: 2 additions & 2 deletions docs/step/demo/percent.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import { Step } from '@alifd/next';
ReactDOM.render(<div>
<Step current={1} animation={false} shape="dot">
<Step.Item title="Step 1" content="Open the refrigerator door" icon="calendar" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2, Put the elephant in the refrigerator" content="Put the elephant in the refrigerator" percent={40}/>
<Step.Item title="Step 2" content="Put the elephant in the refrigerator" percent={40}/>
<Step.Item title="Step 3" content="Close the refrigerator door" icon="smile" />
</Step>
<br />
<br />
<Step current={1} animation={false}>
<Step.Item title="Step 1" content="Open the refrigerator door" icon="calendar" />
<Step.Item title="Step 2" aria-label="Current Step, Step 2, Put the elephant in the refrigerator" content="Put the elephant in the refrigerator" percent={40}/>
<Step.Item title="Step 2" content="Put the elephant in the refrigerator" percent={40}/>
<Step.Item title="Step 3" content="Close the refrigerator door" icon="smile" />
</Step>
</div>, mountNode);
Expand Down
14 changes: 7 additions & 7 deletions docs/step/theme/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -162,14 +162,14 @@ class FunctionDemo extends React.Component {
</Demo>
<Demo title={i18n.verticalGroup} block>
<DemoGroup label={i18n.horizontal}>
<Step current={1} shape={shape} direction="vertical" >
<Step current={1} shape={shape} direction="ver" >
{
itemData.horizontal.map((v, index) => this.itemRender({ flag, index, ...v }))
}
</Step>
</DemoGroup>
<DemoGroup label={i18n.disabled}>
<Step current={2} shape={shape} direction="vertical" >
<Step current={2} shape={shape} direction="ver" >
{
itemData.disabled.map((v, index) => this.itemRender({ flag, index, ...v }))
}
Expand Down Expand Up @@ -204,21 +204,21 @@ class FunctionDemo extends React.Component {
</Demo>
<Demo title={i18n.verticalGroup} block>
<DemoGroup label={i18n.horizontal}>
<Step current={1} shape={shape} direction="vertical" >
<Step current={1} shape={shape} direction="ver" >
{
itemData.horizontal.map((v, index) => this.itemRender({ flag, index, ...v }))
}
</Step>
</DemoGroup>
<DemoGroup label={i18n.percent}>
<Step current={2} shape={shape} direction="vertical" >
<Step current={2} shape={shape} direction="ver" >
{
itemData.percent.map((v, index) => this.itemRender({ flag, index, ...v }))
}
</Step>
</DemoGroup>
<DemoGroup label={i18n.disabled}>
<Step current={2} shape={shape} direction="vertical" >
<Step current={2} shape={shape} direction="ver" >
{
itemData.disabled.map((v, index) => this.itemRender({ flag, index, ...v }))
}
Expand Down
5 changes: 5 additions & 0 deletions src/step/scss/basic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
position: relative;
vertical-align: middle;
outline: 0;
height: 100%;

&-body {
outline: 0;
}

&-node {
transition: all .2s ease;
Expand Down
19 changes: 11 additions & 8 deletions src/step/view/step-item.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ class StepItem extends Component {
status,
title,
content,
shape,
} = this.props;
const { others, stepCls, overlayCls } = args;
const nodeElement = this._getNode();
Expand Down Expand Up @@ -260,11 +261,13 @@ class StepItem extends Component {
</div>
);
}
if (shape !== 'arrow') {
delete others.tabIndex;
delete others['aria-current'];
}

return (
<div
tabIndex="0"
aria-current={status === 'process' ? 'step' : null}
<li
{...others}
style={this.getStyle()}
className={stepCls}
Expand All @@ -274,6 +277,8 @@ class StepItem extends Component {
<div
className={`${prefix}step-item-body`}
ref={this._refHandlerCreator('body')}
tabIndex={this.props.tabIndex}
aria-current={this.props['aria-current']}
>
<div
className={`${prefix}step-item-title`}
Expand All @@ -296,7 +301,7 @@ class StepItem extends Component {
/>
</div>
</div>
</div>
</li>
);
}

Expand Down Expand Up @@ -409,9 +414,7 @@ class StepItem extends Component {

const overlayCls = status === 'finish' ? { width: '100%' } : null;
const arrowElement = (
<div
tabIndex="0"
aria-current={status === 'process' ? 'step' : null}
<li
{...others}
style={this.getStyle()}
className={stepCls}
Expand All @@ -420,7 +423,7 @@ class StepItem extends Component {
<div className={`${prefix}step-item-container`}>
<div className={`${prefix}step-item-title`}>{title}</div>
</div>
</div>
</li>
);
const otherElement = this.getNode({ others, stepCls, overlayCls });

Expand Down
57 changes: 48 additions & 9 deletions src/step/view/step.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -68,6 +69,7 @@ export default class Step extends Component {
this.state = {
parentWidth: 'auto',
parentHeight: 'auto',
currentfocus: 0,
};
this.resize = this.resize.bind(this);
}
Expand Down Expand Up @@ -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) => {
Expand All @@ -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 => {
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -221,10 +258,12 @@ export default class Step extends Component {
others.dir = 'rtl';
}

others.onKeyDown = makeChain(this.handleKeyDown, others.onKeyDown);

return (
<div {...others} className={stepCls} ref={this._stepRefHandler}>
<ol {...others} className={stepCls} ref={this._stepRefHandler}>
{cloneChildren}
</div>
</ol>
);
}
}
Loading

0 comments on commit 7225e8b

Please sign in to comment.