Skip to content

Commit 204d0ac

Browse files
committed
feat(Stepper): Add Stepper component
1 parent 72edae8 commit 204d0ac

File tree

9 files changed

+534
-3
lines changed

9 files changed

+534
-3
lines changed

.storybook/config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import 'react-mdl/extra/material.css'
66
import './storybook.scss'
77

88
function loadStories () {
9+
require('../stories/AutoComplete.story');
910
require('../stories/Menu.story');
10-
require('../stories/SelectField.story');
1111
require('../stories/MultiSelectField.story');
12-
require('../stories/AutoComplete.story');
12+
require('../stories/SelectField.story');
13+
require('../stories/Stepper.story');
1314
}
1415

1516
configure(loadStories, module);

src/SelectField/SelectField.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ export default class SelectField extends Component {
1111

1212
static propTypes = {
1313
align: PropTypes.string,
14-
children: PropTypes.arrayOf(PropTypes.element),
14+
children: PropTypes.oneOfType([
15+
PropTypes.arrayOf(PropTypes.element),
16+
PropTypes.element,
17+
]),
1518
className: PropTypes.string,
1619
disabled: PropTypes.bool,
1720
error: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),

src/Stepper/Step.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React, { Children, PropTypes } from 'react' // eslint-disable-line no-unused-vars
2+
3+
const Step = props => {
4+
return Children.only(props.children)
5+
}
6+
7+
Step.propTypes = {
8+
children: PropTypes.any.isRequired,
9+
onTitleClick: PropTypes.func,
10+
title: PropTypes.string,
11+
}
12+
13+
export default Step

src/Stepper/Stepper.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React, { Children, PropTypes } from 'react'
2+
import classnames from 'classnames'
3+
4+
import { Icon } from 'react-mdl'
5+
6+
import './Stepper.scss'
7+
8+
const Stepper = props => {
9+
const { activeStep, horizontal, hideLastTitle, onStepTitleClick } = props
10+
const children = Children.toArray(props.children)
11+
const last = hideLastTitle && children.pop()
12+
const stepperClass = classnames('mdl-stepper', {
13+
'mdl-stepper--horizontal': horizontal,
14+
'mdl-stepper--vertical': !horizontal,
15+
})
16+
return (
17+
<div className={stepperClass}>
18+
<ul className={'mdl-stepper__steps'}>
19+
{children.map((child, index) => {
20+
const stepClass = classnames('mdl-stepper__step', {
21+
'mdl-stepper__step--active': index === activeStep,
22+
'mdl-stepper__step--completed': index < activeStep,
23+
})
24+
const wrapStyle = { cursor: onStepTitleClick ? 'pointer' : 'default' }
25+
return (
26+
<li className={stepClass} key={`${child.props.title}${index}`}>
27+
<div className={'mdl-stepper__title'} onClick={() => onStepTitleClick(index)}>
28+
<span className={'mdl-stepper__title-wrap'} style={wrapStyle}>
29+
<span className={'mdl-stepper__title-text'}>
30+
{child.props.title}
31+
</span>
32+
<span className={'mdl-stepper__title-icon'}>
33+
{activeStep > index ? <Icon name={'check'}/> : (index+1)}
34+
</span>
35+
</span>
36+
</div>
37+
<div className={'mdl-stepper__content'}>
38+
{child.props.children}
39+
</div>
40+
</li>
41+
)
42+
})}
43+
</ul>
44+
{hideLastTitle && activeStep === children.length &&
45+
<div className={'mdl-stepper__last'}>
46+
{last.props.children}
47+
</div>}
48+
</div>
49+
)
50+
}
51+
52+
Stepper.propTypes = {
53+
activeStep: PropTypes.number.isRequired,
54+
children: PropTypes.any.isRequired,
55+
hideLastTitle: PropTypes.bool,
56+
horizontal: PropTypes.bool,
57+
onStepTitleClick: PropTypes.func,
58+
}
59+
60+
export default Stepper

src/Stepper/Stepper.scss

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
.mdl-stepper {
2+
position: relative;
3+
max-width: 800px;
4+
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
5+
0 3px 1px -2px rgba(0, 0, 0, 0.2),
6+
0 1px 5px 0 rgba(0, 0, 0, 0.12);
7+
8+
.mdl-stepper__steps {
9+
list-style: none;
10+
width: 100%;
11+
margin: 0;
12+
padding: 0;
13+
14+
.mdl-stepper__step {
15+
position: relative;
16+
17+
.mdl-stepper__title {
18+
19+
.mdl-stepper__title-wrap {
20+
position: relative;
21+
z-index: 2;
22+
display: flex;
23+
flex-direction: row-reverse;
24+
justify-content: flex-end;
25+
align-items: center;
26+
padding: 10px;
27+
background: #fff;
28+
}
29+
30+
.mdl-stepper__title-text {
31+
margin-left: 10px;
32+
white-space: nowrap;
33+
overflow: hidden;
34+
text-overflow: ellipsis;
35+
}
36+
37+
.mdl-stepper__title-icon {
38+
display: flex;
39+
align-items: center;
40+
justify-content: center;
41+
width: 28px;
42+
height: 28px;
43+
font-size: 14px;
44+
font-weight: 400;
45+
border-radius: 50%;
46+
background: #a6a6a6;
47+
color: #fff;
48+
.material-icons {
49+
font-size: 15px;
50+
}
51+
}
52+
53+
}
54+
55+
.mdl-stepper__content {
56+
display: none;
57+
}
58+
59+
&--active {
60+
.mdl-stepper__title {
61+
.mdl-stepper__title-text {
62+
font-weight: bold;
63+
}
64+
.mdl-stepper__title-icon {
65+
background: #0288d1;
66+
}
67+
}
68+
.mdl-stepper__content {
69+
display: flex;
70+
}
71+
}
72+
73+
&--completed {
74+
.mdl-stepper__title {
75+
.mdl-stepper__title-icon {
76+
background: #0288d1;
77+
}
78+
}
79+
}
80+
81+
}
82+
83+
@media (max-width: 799px) {
84+
padding: 20px 14px;
85+
86+
.mdl-stepper__step {
87+
margin-bottom: 20px;
88+
89+
&:not(:last-child) {
90+
&:after {
91+
content: '';
92+
position: absolute;
93+
top: 10px;
94+
left: 24px;
95+
width: 1px;
96+
bottom: -20px;
97+
background-color: rgba(0,0,0,0.1);
98+
}
99+
}
100+
101+
.mdl-stepper__title {
102+
height: 64px;
103+
align-items: flex-start;
104+
}
105+
106+
.mdl-stepper__content {
107+
margin: 0 10px 0 50px;
108+
}
109+
110+
}
111+
112+
}
113+
114+
@media (max-width: 480px) {
115+
padding: 20px 4px;
116+
}
117+
118+
}
119+
120+
}
121+
122+
.mdl-stepper--vertical {
123+
display: flex;
124+
flex-direction: column;
125+
126+
.mdl-stepper__steps {
127+
padding: 20px 14px;
128+
129+
.mdl-stepper__step {
130+
margin-bottom: 20px;
131+
132+
&:not(:last-child) {
133+
&:after {
134+
content: '';
135+
position: absolute;
136+
top: 10px;
137+
left: 24px;
138+
width: 1px;
139+
bottom: -20px;
140+
background-color: rgba(0,0,0,0.1);
141+
}
142+
}
143+
144+
.mdl-stepper__title {
145+
display: flex;
146+
align-items: flex-start;
147+
height: 64px;
148+
}
149+
150+
.mdl-stepper__content {
151+
margin: 0 10px 0 50px;
152+
}
153+
154+
}
155+
156+
@media (max-width: 480px) {
157+
padding: 20px 4px;
158+
}
159+
}
160+
161+
.mdl-stepper__last {
162+
position: relative;
163+
margin: -40px 24px 40px 64px;
164+
}
165+
166+
}
167+
168+
.mdl-stepper--horizontal {
169+
display: flex;
170+
flex-direction: column;
171+
min-height: 400px;
172+
173+
@media (max-width: 799px) {
174+
.mdl-stepper__last {
175+
position: relative;
176+
margin: -40px 24px 40px 64px;
177+
}
178+
}
179+
180+
@media (min-width: 800px) {
181+
182+
.mdl-stepper__steps {
183+
position: relative;
184+
display: flex;
185+
flex: 1;
186+
flex-direction: row;
187+
justify-content: space-between;
188+
padding: 0 24px 0 14px;
189+
190+
&:after {
191+
content: '';
192+
position: absolute;
193+
z-index: 1;
194+
top: 44px;
195+
left: 14px;
196+
right: 24px;
197+
height: 1px;
198+
background-color: rgba(0,0,0,0.1);
199+
}
200+
201+
&:before {
202+
content: '';
203+
position: absolute;
204+
top: 0;
205+
left: 0;
206+
right: 0;
207+
height: 88px;
208+
pointer-events: none;
209+
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2),
210+
0px 1px 1px 0px rgba(0,0,0,0.14),
211+
0px 1px 3px 0px rgba(0,0,0,0.12);
212+
}
213+
214+
.mdl-stepper__step {
215+
position: static;
216+
margin: 0;
217+
padding: 0;
218+
margin-top: 20px;
219+
220+
.mdl-stepper__title {
221+
.mdl-stepper__title-text {
222+
max-width: 124px;
223+
}
224+
}
225+
226+
&--active {
227+
.mdl-stepper__content {
228+
position: absolute;
229+
top: 88px;
230+
left: 0;
231+
right: 0;
232+
bottom: 0;
233+
padding: 24px;
234+
}
235+
}
236+
237+
}
238+
239+
}
240+
241+
.mdl-stepper__last {
242+
position: absolute;
243+
display: flex;
244+
flex: 1;
245+
top: 88px;
246+
left: 0;
247+
right: 0;
248+
bottom: 0;
249+
padding: 24px;
250+
}
251+
252+
}
253+
254+
}

src/Stepper/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default from './Stepper'

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ export SelectField from './SelectField'
55
export AutoComplete from './AutoComplete'
66
export MultiSelectField from './MultiSelectField'
77
export Option from './SelectField/Option'
8+
export Stepper from './Stepper'
9+
export Step from './Stepper/Step'

0 commit comments

Comments
 (0)