Last active
September 11, 2017 06:57
-
-
Save vigosan/e4aea5a38891dee027d6e839c7d61e09 to your computer and use it in GitHub Desktop.
Declarative react wizard component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react' | |
import PropTypes from 'react-proptypes' | |
import styles from './App.css' | |
class Wizard extends Component { | |
static childContextTypes = { | |
activeIndex: PropTypes.number.isRequired, | |
totalSteps: PropTypes.number.isRequired, | |
goToNextStep: PropTypes.func.isRequired, | |
goToPrevStep: PropTypes.func.isRequired | |
} | |
constructor(props) { | |
super(props) | |
let totalSteps = 0 | |
React.Children.forEach(this.props.children, child => { | |
if (child.type.name === 'Steps') { | |
totalSteps = React.Children.count(child.props.children) | |
} | |
}) | |
this.state = { | |
activeIndex: 0, | |
totalSteps | |
} | |
} | |
goToPrevStep = () => { | |
this.setState({ activeIndex: this.state.activeIndex - 1 }) | |
} | |
goToNextStep = () => { | |
this.setState({ activeIndex: this.state.activeIndex + 1 }) | |
} | |
getChildContext() { | |
const { activeIndex, totalSteps } = this.state | |
return { | |
activeIndex: activeIndex, | |
totalSteps: totalSteps, | |
goToPrevStep: this.goToPrevStep, | |
goToNextStep: this.goToNextStep | |
} | |
} | |
render() { | |
return <div className="Wizard">{this.props.children}</div> | |
} | |
} | |
class Steps extends Component { | |
render() { | |
const { children } = this.props; | |
const { activeIndex } = this.context; | |
const currentStep = React.Children.toArray(children)[activeIndex]; | |
return <div className="Wizard-Steps">{currentStep}</div>; | |
} | |
} | |
class Step extends Component { | |
render() { | |
return <div>{this.props.children}</div> | |
} | |
} | |
class Contents extends Component { | |
static contextTypes = { | |
activeIndex: PropTypes.number.isRequired | |
} | |
render() { | |
const { children } = this.props | |
const { activeIndex } = this.context | |
return <div className="Wizard-step">{children[activeIndex]}</div> | |
} | |
} | |
class Content extends Component { | |
render() { | |
return <div>{this.props.children}</div> | |
} | |
} | |
class Buttons extends Component { | |
render() { | |
return <div>{this.props.children}</div> | |
} | |
} | |
class PreviousStepButton extends Component { | |
static contextTypes = { | |
activeIndex: PropTypes.number.isRequired, | |
goToPrevStep: PropTypes.func.isRequired | |
} | |
render() { | |
const { activeIndex, goToPrevStep } = this.context | |
const { children } = this.props | |
const isDisabled = activeIndex === 0 | |
return ( | |
<button disabled={isDisabled} onClick={goToPrevStep}> | |
{children || 'Prev'} | |
</button> | |
) | |
} | |
} | |
class NextStepButton extends Component { | |
static contextTypes = { | |
activeIndex: PropTypes.number.isRequired, | |
totalSteps: PropTypes.number.isRequired, | |
goToNextStep: PropTypes.func.isRequired | |
} | |
render() { | |
const { activeIndex, totalSteps, goToNextStep } = this.context | |
const isDisabled = activeIndex === totalSteps - 1 | |
return ( | |
<button disabled={isDisabled} onClick={goToNextStep}> | |
{this.props.children || 'Next'} | |
</button> | |
) | |
} | |
} | |
class ProgressBar extends Component { | |
static contextTypes = { | |
activeIndex: PropTypes.number.isRequired, | |
totalSteps: PropTypes.number.isRequired | |
} | |
render() { | |
const { activeIndex, totalSteps } = this.context | |
return <progress value={activeIndex + 1} max={totalSteps} /> | |
} | |
} | |
const App = () => ( | |
<Wizard> | |
<ProgressBar /> | |
<Steps> | |
<Step>First</Step> | |
<Step>Second</Step> | |
</Steps> | |
<Contents> | |
<Content>This is the first step</Content> | |
<Content>This is the second step</Content> | |
</Contents> | |
<Buttons> | |
<PreviousStepButton /> | |
<NextStepButton /> | |
</Buttons> | |
</Wizard> | |
) | |
export default App |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment