UNPKG

3.56 kBJavaScriptView Raw
1import React, { PropTypes } from 'react';
2import ReactDOM from 'react-dom';
3import classNames from 'classnames';
4
5const propTypes = {
6 prefixCls: PropTypes.string,
7 iconPrefix: PropTypes.string,
8 direction: PropTypes.string,
9 labelPlacement: PropTypes.string,
10 children: PropTypes.any,
11 current: PropTypes.number,
12 status: PropTypes.oneOf(['wait', 'process', 'finish', 'error']),
13 direction: PropTypes.oneOf(['horizontal', 'vertical']),
14 size: PropTypes.oneOf(['default', 'small'])
15};
16
17const defaultProps = {
18 prefixCls: 'u-steps',
19 iconPrefix: 'u',
20 direction: 'horizontal',
21 labelPlacement: 'horizontal',
22 current: 0,
23 status: 'process',
24 size: 'default',
25};
26
27class Steps extends React.Component {
28 constructor(props) {
29 super(props);
30 this.state = {
31 lastStepOffsetWidth: 0,
32 };
33 }
34 componentDidMount() {
35 this.calcLastStepOffsetWidth();
36 }
37 componentDidUpdate() {
38 this.calcLastStepOffsetWidth();
39 }
40 componentWillUnmount() {
41 if (this.calcTimeout) {
42 clearTimeout(this.calcTimeout);
43 }
44 }
45 calcLastStepOffsetWidth = () => {
46 const domNode = ReactDOM.findDOMNode(this);
47 if (domNode.children.length > 0) {
48 if (this.calcTimeout) {
49 clearTimeout(this.calcTimeout);
50 }
51 this.calcTimeout = setTimeout(() => {
52 // +1 for fit edge bug of digit width, like 35.4px
53 const lastStepOffsetWidth = (domNode.lastChild.offsetWidth || 0) + 1;
54 if (this.state.lastStepOffsetWidth === lastStepOffsetWidth) {
55 return;
56 }
57 this.setState({ lastStepOffsetWidth });
58 });
59 }
60 }
61 render() {
62 const props = this.props;
63 const { prefixCls, style = {}, className, children, direction,
64 labelPlacement, iconPrefix, status, size, current, ...restProps } = props;
65 const lastIndex = children.length - 1;
66 const reLayouted = this.state.lastStepOffsetWidth > 0;
67 const classString = classNames({
68 [prefixCls]: true,
69 [`${prefixCls}-${size}`]: size,
70 [`${prefixCls}-${direction}`]: true,
71 [`${prefixCls}-label-${labelPlacement}`]: direction === 'horizontal',
72 [`${prefixCls}-hidden`]: !reLayouted,
73 [className]: className,
74 });
75
76 return (
77 <div className={classString} style={style} {...restProps}>
78 {
79 React.Children.map(children, (ele, idx) => {
80 const tailWidth = (direction === 'vertical' || idx === lastIndex || !reLayouted)
81 ? null : `${100 / lastIndex}%`;
82 const adjustMarginRight = (direction === 'vertical' || idx === lastIndex)
83 ? null : -Math.round(this.state.lastStepOffsetWidth / lastIndex + 1);
84 const np = {
85 stepNumber: (idx + 1).toString(),
86 stepLast: idx === lastIndex,
87 tailWidth,
88 adjustMarginRight,
89 prefixCls,
90 iconPrefix,
91 wrapperStyle: style,
92 };
93
94 // fix tail color
95 if (status === 'error' && idx === current - 1) {
96 np.className = `${props.prefixCls}-next-error`;
97 }
98
99 if (!ele.props.status) {
100 if (idx === current) {
101 np.status = status;
102 } else if (idx < current) {
103 np.status = 'finish';
104 } else {
105 np.status = 'wait';
106 }
107 }
108 return React.cloneElement(ele, np);
109 }, this)
110 }
111 </div>
112 );
113 }
114}
115Steps.defaultProps = defaultProps;
116Steps.propTypes = propTypes;
117
118export default Steps;