UNPKG

4.6 kBJavaScriptView Raw
1import React, { cloneElement, Children, Component } from 'react';
2import PropTypes from 'prop-types';
3import { findDOMNode } from 'react-dom';
4import classNames from 'classnames';
5import debounce from 'lodash.debounce';
6import { isFlexSupported } from './utils';
7
8const propTypes = {prefixCls: PropTypes.string,
9 className: PropTypes.string,
10 iconPrefix: PropTypes.string,
11 direction: PropTypes.string,
12 labelPlacement: PropTypes.string,
13 children: PropTypes.any,
14 status: PropTypes.string,
15 size: PropTypes.string,
16 progressDot: PropTypes.oneOfType([
17 PropTypes.bool,
18 PropTypes.func,
19 ]),
20 style: PropTypes.object,
21 initial: PropTypes.number,
22 current: PropTypes.number,
23 icons: PropTypes.shape({
24 finish: PropTypes.node,
25 error: PropTypes.node,
26 }),
27};
28
29const defaultProps = {
30 prefixCls: 'u-steps',
31 iconPrefix: 'u',
32 direction: 'horizontal',
33 labelPlacement: 'horizontal',
34 current: 0,
35 initial: 0,
36 status: 'process',
37 size: 'default',
38 progressDot: false,
39};
40
41class Steps extends React.Component {
42 constructor(props) {
43 super(props);
44 this.state = {
45 flexSupported: true,
46 lastStepOffsetWidth: 0,
47 };
48 this.calcStepOffsetWidth = debounce(this.calcStepOffsetWidth, 150);
49 }
50 componentDidMount() {
51 this.calcStepOffsetWidth();
52 if (!isFlexSupported()) {
53 this.setState({
54 flexSupported: false,
55 });
56 }
57 }
58 componentDidUpdate() {
59 this.calcStepOffsetWidth();
60 }
61 componentWillUnmount() {
62 if (this.calcTimeout) {
63 clearTimeout(this.calcTimeout);
64 }
65 if (this.calcStepOffsetWidth && this.calcStepOffsetWidth.cancel) {
66 this.calcStepOffsetWidth.cancel();
67 }
68 }
69 calcStepOffsetWidth = () => {
70 if (isFlexSupported()) {
71 return;
72 }
73 // Just for IE9
74 const domNode = findDOMNode(this);
75 if (domNode.children.length > 0) {
76 if (this.calcTimeout) {
77 clearTimeout(this.calcTimeout);
78 }
79 this.calcTimeout = setTimeout(() => {
80 // +1 for fit edge bug of digit width, like 35.4px
81 const lastStepOffsetWidth = (domNode.lastChild.offsetWidth || 0) + 1;
82 // Reduce shake bug
83 if (this.state.lastStepOffsetWidth === lastStepOffsetWidth ||
84 Math.abs(this.state.lastStepOffsetWidth - lastStepOffsetWidth) <= 3) {
85 return;
86 }
87 this.setState({ lastStepOffsetWidth });
88 });
89 }
90 }
91 render() {
92 const {
93 prefixCls, style = {}, className, children, direction,
94 labelPlacement, iconPrefix, status, size, current, progressDot, initial,
95 icons,
96 ...restProps,
97 } = this.props;
98 const { lastStepOffsetWidth, flexSupported } = this.state;
99 const filteredChildren = React.Children.toArray(children).filter(c => !!c);
100 const lastIndex = filteredChildren.length - 1;
101 const adjustedlabelPlacement = !!progressDot ? 'vertical' : labelPlacement;
102 const classString = classNames(prefixCls, `${prefixCls}-${direction}`, className, {
103 [`${prefixCls}-${size}`]: size,
104 [`${prefixCls}-label-${adjustedlabelPlacement}`]: direction === 'horizontal',
105 [`${prefixCls}-dot`]: !!progressDot,
106 });
107
108 return (
109 <div className={classString} style={style} {...restProps}>
110 {
111 Children.map(filteredChildren, (child, index) => {
112 if (!child) {
113 return null;
114 }
115 const stepNumber = initial + index;
116 const childProps = {
117 stepNumber: `${stepNumber + 1}`,
118 prefixCls,
119 iconPrefix,
120 wrapperStyle: style,
121 progressDot,
122 icons,
123 ...child.props,
124 };
125 if (!flexSupported && direction !== 'vertical' && index !== lastIndex) {
126 childProps.itemWidth = `${100 / lastIndex}%`;
127 childProps.adjustMarginRight = -Math.round(lastStepOffsetWidth / lastIndex + 1);
128 }
129 // fix tail color
130 if (status === 'error' && index === current - 1) {
131 childProps.className = `${prefixCls}-next-error`;
132 }
133 if (!child.props.status) {
134 if (stepNumber === current) {
135 childProps.status = status;
136 } else if (stepNumber < current) {
137 childProps.status = 'finish';
138 } else {
139 childProps.status = 'wait';
140 }
141 }
142 return cloneElement(child, childProps);
143 })
144 }
145 </div>
146 );
147 }
148}
149Steps.defaultProps = defaultProps;
150Steps.propTypes = propTypes;
151
152export default Steps;