Add Stepper component (https://github.com/woocommerce/woocommerce-admin/pull/2246)
* Add Stepper component * Add Muriel colors as variables * Add changelog entry for Stepper component
This commit is contained in:
parent
5e07474d16
commit
8f528ee824
|
@ -22,6 +22,7 @@
|
||||||
{ "component": "Section" },
|
{ "component": "Section" },
|
||||||
{ "component": "SegmentedSelection" },
|
{ "component": "SegmentedSelection" },
|
||||||
{ "component": "SplitButton" },
|
{ "component": "SplitButton" },
|
||||||
|
{ "component": "Stepper" },
|
||||||
{ "component": "Summary", "render": "MySummaryList" },
|
{ "component": "Summary", "render": "MySummaryList" },
|
||||||
{ "component": "Table" },
|
{ "component": "Table" },
|
||||||
{ "component": "Tag" },
|
{ "component": "Tag" },
|
||||||
|
|
|
@ -57,3 +57,7 @@ $core-orange: #ca4a1f;
|
||||||
|
|
||||||
$button: #f0f2f4;
|
$button: #f0f2f4;
|
||||||
$button-border: darken($button, 20%);
|
$button-border: darken($button, 20%);
|
||||||
|
|
||||||
|
// Muriel
|
||||||
|
$muriel-gray-dark-300: #969ca1;
|
||||||
|
$muriel-active: #bb4f10;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
- Tweaks to SummaryListPlaceholder height in order to better match SummaryNumber.
|
- Tweaks to SummaryListPlaceholder height in order to better match SummaryNumber.
|
||||||
- EllipsisMenu component (breaking change): Remove `children` prop in favor of a render prop `renderContent` so that function arguments `isOpen`, `onToggle`, and `onClose` can be passed down.
|
- EllipsisMenu component (breaking change): Remove `children` prop in favor of a render prop `renderContent` so that function arguments `isOpen`, `onToggle`, and `onClose` can be passed down.
|
||||||
- Chart has a new prop named `yBelow1Format` which overrides the `yFormat` for values between -1 and 1 (not included).
|
- Chart has a new prop named `yBelow1Format` which overrides the `yFormat` for values between -1 and 1 (not included).
|
||||||
|
- Add new component `<Stepper />` for showing a list of steps and progress.
|
||||||
|
|
||||||
# 2.0.0
|
# 2.0.0
|
||||||
- Chart legend component now uses withInstanceId HOC so the ids used in several HTML elements are unique.
|
- Chart legend component now uses withInstanceId HOC so the ids used in several HTML elements are unique.
|
||||||
|
|
|
@ -40,6 +40,7 @@ export { default as SearchListItem } from './search-list-control/item';
|
||||||
export { default as SectionHeader } from './section-header';
|
export { default as SectionHeader } from './section-header';
|
||||||
export { default as SegmentedSelection } from './segmented-selection';
|
export { default as SegmentedSelection } from './segmented-selection';
|
||||||
export { default as SplitButton } from './split-button';
|
export { default as SplitButton } from './split-button';
|
||||||
|
export { default as Stepper } from './stepper';
|
||||||
export { default as SummaryList } from './summary';
|
export { default as SummaryList } from './summary';
|
||||||
export { default as SummaryListPlaceholder } from './summary/placeholder';
|
export { default as SummaryListPlaceholder } from './summary/placeholder';
|
||||||
export { default as SummaryNumber } from './summary/number';
|
export { default as SummaryNumber } from './summary/number';
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/** @format */
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
aria-hidden="true"
|
||||||
|
focusable="false"
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="3" width="14" height="12">
|
||||||
|
<path d="M6.59631 11.9062L3.46881 8.77875L2.40381 9.83625L6.59631 14.0287L15.5963
|
||||||
|
5.02875L14.5388 3.97125L6.59631 11.9062Z" fill="white" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0)">
|
||||||
|
<rect width="18" height="18" fill="white" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
|
@ -0,0 +1,68 @@
|
||||||
|
```jsx
|
||||||
|
import { Stepper } from '@woocommerce/components';
|
||||||
|
|
||||||
|
const MyStepper = withState( {
|
||||||
|
currentStep: 'first',
|
||||||
|
isComplete: false,
|
||||||
|
} )( ( { currentStep, isComplete, setState } ) => {
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
label: 'First',
|
||||||
|
key: 'first',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Second',
|
||||||
|
key: 'second',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Third',
|
||||||
|
key: 'third',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fourth',
|
||||||
|
key: 'fourth',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const currentIndex = steps.findIndex( s => currentStep === s.key );
|
||||||
|
|
||||||
|
if ( isComplete ) {
|
||||||
|
steps.forEach( s => s.isComplete = true );
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ isComplete ? (
|
||||||
|
<button onClick={ () => setState( { currentStep: 'first', isComplete: false } ) } >
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={ () => setState( { currentStep: steps[ currentIndex - 1 ]['key'] } ) }
|
||||||
|
disabled={ currentIndex < 1 }
|
||||||
|
>
|
||||||
|
Previous step
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={ () => setState( { currentStep: steps[ currentIndex + 1 ]['key'] } ) }
|
||||||
|
disabled={ currentIndex >= steps.length - 1 }
|
||||||
|
>
|
||||||
|
Next step
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={ () => setState( { isComplete: true } ) }
|
||||||
|
disabled={ currentIndex !== steps.length - 1 }
|
||||||
|
>
|
||||||
|
Complete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
|
||||||
|
<Stepper
|
||||||
|
steps={ steps }
|
||||||
|
currentStep={ currentStep }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
```
|
|
@ -0,0 +1,84 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { Component, Fragment } from '@wordpress/element';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import CheckIcon from './check-icon';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stepper component to indicate progress in a set number of steps.
|
||||||
|
*/
|
||||||
|
class Stepper extends Component {
|
||||||
|
render() {
|
||||||
|
const { className, currentStep, steps } = this.props;
|
||||||
|
const currentIndex = steps.findIndex( s => currentStep === s.key );
|
||||||
|
const stepperClassName = classnames( 'woocommerce-stepper', className );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ stepperClassName }>
|
||||||
|
{ steps.map( ( step, i ) => {
|
||||||
|
const { key, label, isComplete } = step;
|
||||||
|
const stepClassName = classnames( 'woocommerce-stepper__step', {
|
||||||
|
'is-active': key === currentStep,
|
||||||
|
'is-complete': 'undefined' !== typeof isComplete ? isComplete : currentIndex > i,
|
||||||
|
} );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment key={ key } >
|
||||||
|
<div
|
||||||
|
className={ stepClassName }
|
||||||
|
>
|
||||||
|
<div className="woocommerce-stepper__step-icon">
|
||||||
|
<span className="woocommerce-stepper__step-number">{ i + 1 }</span>
|
||||||
|
<CheckIcon />
|
||||||
|
</div>
|
||||||
|
<span className="woocommerce-stepper_step-label">
|
||||||
|
{ label }
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="woocommerce-stepper__step-divider" />
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
} ) }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stepper.propTypes = {
|
||||||
|
/**
|
||||||
|
* Additional class name to style the component.
|
||||||
|
*/
|
||||||
|
className: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* The current step's key.
|
||||||
|
*/
|
||||||
|
currentStep: PropTypes.string.isRequired,
|
||||||
|
/**
|
||||||
|
* An array of steps used.
|
||||||
|
*/
|
||||||
|
steps: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape( {
|
||||||
|
/**
|
||||||
|
* Key used to identify step.
|
||||||
|
*/
|
||||||
|
key: PropTypes.string.isRequired,
|
||||||
|
/**
|
||||||
|
* Label displayed in stepper.
|
||||||
|
*/
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
/**
|
||||||
|
* Optionally mark a step complete regardless of step index.
|
||||||
|
*/
|
||||||
|
isComplete: PropTypes.bool,
|
||||||
|
} )
|
||||||
|
).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Stepper;
|
|
@ -0,0 +1,72 @@
|
||||||
|
.woocommerce-stepper {
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2),
|
||||||
|
0 2px 2px rgba(0, 0, 0, 0.12),
|
||||||
|
0 0 2px rgba(0, 0, 0, 0.14);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: $gap-large;
|
||||||
|
padding-left: $gap;
|
||||||
|
padding-right: $gap;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
.woocommerce-stepper__step {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: $gap-small;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active,
|
||||||
|
&.is-complete {
|
||||||
|
color: $muriel-active;
|
||||||
|
|
||||||
|
.woocommerce-stepper__step-icon {
|
||||||
|
background: $muriel-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-complete {
|
||||||
|
.woocommerce-stepper__step-number {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-stepper__step-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin-right: $gap-small;
|
||||||
|
background: $muriel-gray-dark-300;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-stepper__step-divider {
|
||||||
|
flex-grow: 1;
|
||||||
|
border-bottom: 1px solid $muriel-gray-dark-300;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include breakpoint( '<782px' ) {
|
||||||
|
.woocommerce-stepper_step-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.woocommerce-stepper__step-icon {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
@import 'section-header/style.scss';
|
@import 'section-header/style.scss';
|
||||||
@import 'segmented-selection/style.scss';
|
@import 'segmented-selection/style.scss';
|
||||||
@import 'split-button/style.scss';
|
@import 'split-button/style.scss';
|
||||||
|
@import 'stepper/style.scss';
|
||||||
@import 'summary/style.scss';
|
@import 'summary/style.scss';
|
||||||
@import 'table/style.scss';
|
@import 'table/style.scss';
|
||||||
@import 'tag/style.scss';
|
@import 'tag/style.scss';
|
||||||
|
|
Loading…
Reference in New Issue