meriadec
7 years ago
2 changed files with 131 additions and 0 deletions
@ -0,0 +1,81 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
import invariant from 'invariant' |
||||
|
import { translate } from 'react-i18next' |
||||
|
|
||||
|
import type { T } from 'types/common' |
||||
|
|
||||
|
import { ModalContent, ModalTitle, ModalFooter, ModalBody } from 'components/base/Modal' |
||||
|
import Breadcrumb from 'components/Breadcrumb' |
||||
|
|
||||
|
type Props = { |
||||
|
t: T, |
||||
|
title: string, |
||||
|
initialStepId: string, |
||||
|
onClose: void => void, |
||||
|
steps: Step[], |
||||
|
children: any, |
||||
|
} |
||||
|
|
||||
|
export type Step = { |
||||
|
id: string, |
||||
|
label: string, |
||||
|
component: StepProps => React$Node, |
||||
|
footer: StepProps => React$Node, |
||||
|
preventClose?: boolean, |
||||
|
onBack?: StepProps => void, |
||||
|
} |
||||
|
|
||||
|
type State = { |
||||
|
stepId: string, |
||||
|
} |
||||
|
|
||||
|
export type StepProps = { |
||||
|
t: T, |
||||
|
transitionTo: string => void, |
||||
|
} |
||||
|
|
||||
|
class Stepper extends PureComponent<Props, State> { |
||||
|
state = { |
||||
|
stepId: this.props.initialStepId, |
||||
|
} |
||||
|
|
||||
|
transitionTo = stepId => this.setState({ stepId }) |
||||
|
|
||||
|
render() { |
||||
|
const { t, steps, title, onClose, children, ...props } = this.props |
||||
|
const { stepId } = this.state |
||||
|
|
||||
|
const stepIndex = steps.findIndex(s => s.id === stepId) |
||||
|
const step = steps[stepIndex] |
||||
|
|
||||
|
invariant(step, `Stepper: step ${stepId} doesn't exists`) |
||||
|
|
||||
|
const { component: StepComponent, footer: StepFooter, onBack, preventClose } = step |
||||
|
|
||||
|
const stepProps: StepProps = { |
||||
|
t, |
||||
|
transitionTo: this.transitionTo, |
||||
|
...props, |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<ModalBody onClose={preventClose ? undefined : onClose}> |
||||
|
<ModalTitle onBack={onBack ? () => onBack(stepProps) : undefined}>{title}</ModalTitle> |
||||
|
<ModalContent> |
||||
|
<Breadcrumb mb={6} currentStep={stepIndex} items={steps} /> |
||||
|
<StepComponent {...stepProps} /> |
||||
|
{children} |
||||
|
</ModalContent> |
||||
|
{StepFooter && ( |
||||
|
<ModalFooter horizontal align="center" justify="flex-end"> |
||||
|
<StepFooter {...stepProps} /> |
||||
|
</ModalFooter> |
||||
|
)} |
||||
|
</ModalBody> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default translate()(Stepper) |
@ -0,0 +1,50 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React from 'react' |
||||
|
import { storiesOf } from '@storybook/react' |
||||
|
import { action } from '@storybook/addon-actions' |
||||
|
|
||||
|
import Stepper from 'components/base/Stepper' |
||||
|
import Button from 'components/base/Button' |
||||
|
|
||||
|
import type { StepProps, Step } from 'components/base/Stepper' |
||||
|
|
||||
|
const stories = storiesOf('Components/base', module) |
||||
|
|
||||
|
const steps: Step[] = [ |
||||
|
{ |
||||
|
id: 'first', |
||||
|
label: 'first step', |
||||
|
component: () => <div>first step</div>, |
||||
|
footer: ({ transitionTo }: StepProps) => ( |
||||
|
<div> |
||||
|
<Button primary onClick={() => transitionTo('second')}> |
||||
|
Click to go next |
||||
|
</Button> |
||||
|
</div> |
||||
|
), |
||||
|
}, |
||||
|
{ |
||||
|
id: 'second', |
||||
|
label: 'second step', |
||||
|
preventClose: true, |
||||
|
onBack: ({ transitionTo }: StepProps) => transitionTo('first'), |
||||
|
component: () => <div>second step (you cant close on this one)</div>, |
||||
|
footer: ({ transitionTo }: StepProps) => ( |
||||
|
<div> |
||||
|
<Button primary onClick={() => transitionTo('first')}> |
||||
|
Click to go prev |
||||
|
</Button> |
||||
|
</div> |
||||
|
), |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
stories.add('Stepper', () => ( |
||||
|
<Stepper |
||||
|
onClose={action('onClose')} |
||||
|
title="Stepper component" |
||||
|
steps={steps} |
||||
|
initialStepId="first" |
||||
|
/> |
||||
|
)) |
Loading…
Reference in new issue