Skip to content

Commit

Permalink
feat(ProgressIndicator): add experimental progress indicator (carbon-…
Browse files Browse the repository at this point in the history
…design-system#1726)

* feat(ProgressIndicator): update SVG icons and match experimental markup

* feat(ProgressIndicator): support experimental overflow tooltip

* fix(ProgressIndicator): avoid passing style prop to nested tooltips

* fix(ProgressIndicator): allow assignment of tooltip ID for each step

* refactor(ProgressIndicator): use render prop for overflow tooltip

* refactor(ProgressIndicator): set default progress step label

* refactor(ProgressIndicator): remove else-returns
  • Loading branch information
emyarod authored and asudoh committed Feb 9, 2019
1 parent 01a510c commit 3b6f028
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 38 deletions.
48 changes: 39 additions & 9 deletions src/components/ProgressIndicator/ProgressIndicator-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,67 @@

import React from 'react';
import { storiesOf } from '@storybook/react';

import { withKnobs, number } from '@storybook/addon-knobs';
import { ProgressIndicator, ProgressStep } from '../ProgressIndicator';
import ProgressIndicatorSkeleton from '../ProgressIndicator/ProgressIndicator.Skeleton';
import Tooltip from '../Tooltip';
import { componentsX } from '../../internal/FeatureFlags';

storiesOf('Progress Indicator', module)
.addDecorator(withKnobs)
.add(
'Default',
() => (
<ProgressIndicator
currentIndex={number('Current progress (currentIndex)', 3)}>
currentIndex={number('Current progress (currentIndex)', 1)}>
<ProgressStep
label="First step"
description="Step 1: Getting Started with Node.js"
description="Step 1: Getting started with Carbon Design System"
secondaryLabel="Optional label"
/>
<ProgressStep
label="Second step"
description="Step 2: Getting Started with Node.js"
label={componentsX ? null : 'Second step with tooltip'}
description="Step 2: Getting started with Carbon Design System"
renderLabel={() => (
<Tooltip
direction="bottom"
showIcon={false}
triggerClassName="bx--progress-label"
triggerText={'Second step with tooltip'}
tooltipId="tooltipId-0">
<p>Overflow tooltip content.</p>
</Tooltip>
)}
/>
<ProgressStep
label="Third step"
description="Step 3: Getting Started with Node.js"
label={componentsX ? null : 'Third step with tooltip'}
description="Step 3: Getting started with Carbon Design System"
renderLabel={() => (
<Tooltip
direction="bottom"
showIcon={false}
triggerClassName="bx--progress-label"
triggerText={'Third step with tooltip'}
tooltipId="tooltipId-1">
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Animi
consequuntur hic ratione aliquid cupiditate, nesciunt saepe iste
blanditiis cumque maxime tenetur veniam est illo deserunt sint
quae pariatur. Laboriosam, consequatur.
</p>
</Tooltip>
)}
/>
<ProgressStep
label="Fourth step"
description="Step 4: Getting Started with Node.js"
description="Step 4: Getting started with Carbon Design System"
invalid
secondaryLabel="Example invalid step"
/>
<ProgressStep
label="Fifth step"
description="Step 5: Getting Started with Node.js"
description="Step 5: Getting started with Carbon Design System"
disabled
/>
</ProgressIndicator>
),
Expand Down
142 changes: 113 additions & 29 deletions src/components/ProgressIndicator/ProgressIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,96 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import classnames from 'classnames';
import { settings } from 'carbon-components';
// TODO: import { CheckmarkOutline16 } from '@carbon/icons-react';
import CheckmarkOutline16 from '@carbon/icons-react/lib/checkmark--outline/16';
// TODO: import { Warning16 } from '@carbon/icons-react';
import Warning16 from '@carbon/icons-react/lib/warning/16';
import { componentsX } from '../../internal/FeatureFlags';

const { prefix } = settings;

const defaultRenderLabel = props => <p {...props} />;
export const ProgressStep = ({ ...props }) => {
const { label, description, className, current, complete } = props;
const {
label,
description,
className,
current,
complete,
invalid,
secondaryLabel,
disabled,
renderLabel: ProgressStepLabel,
} = props;

const classes = classnames({
[`${prefix}--progress-step`]: true,
[`${prefix}--progress-step--current`]: current,
[`${prefix}--progress-step--complete`]: complete,
[`${prefix}--progress-step--incomplete`]: !complete && !current,
[`${prefix}--progress-step--disabled`]: disabled,
[className]: className,
});

const currentSvg = current && (
<svg>
<circle cx="12" cy="12" r="12" />
<circle cx="12" cy="12" r="6" />
<title>{description}</title>
</svg>
);

const completeSvg = complete && (
<svg width="16" height="16" viewBox="0 0 16 16">
<title>{description}</title>
<g fillRule="nonzero">
<path d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z" />
<path d="M11.646 5.146l.708.708-5.604 5.603-3.104-3.103.708-.708 2.396 2.397z" />
</g>
</svg>
);

const incompleteSvg = !complete && (
<svg>
<title>{description}</title>
<circle cx="12" cy="12" r="12" />
</svg>
);
const currentSvg =
current &&
(componentsX ? (
<svg>
<path d="M 7, 7 m -7, 0 a 7,7 0 1,0 14,0 a 7,7 0 1,0 -14,0" />
</svg>
) : (
<svg>
<circle cx="12" cy="12" r="12" />
<circle cx="12" cy="12" r="6" />
<title>{description}</title>
</svg>
));

const completeSvg =
complete &&
(componentsX ? (
<CheckmarkOutline16 aria-label={description} role="img" />
) : (
<svg width="16" height="16" viewBox="0 0 16 16">
<title>{description}</title>
<g fillRule="nonzero">
<path d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z" />
<path d="M11.646 5.146l.708.708-5.604 5.603-3.104-3.103.708-.708 2.396 2.397z" />
</g>
</svg>
));
const incompleteSvg = (() => {
if (complete) {
return null;
}
if (componentsX) {
if (invalid) {
return <Warning16 className={`${prefix}--progress__warning`} />;
}
return (
<svg>
<path d="M8 1C4.1 1 1 4.1 1 8s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 13c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6z" />
</svg>
);
}
return (
<svg>
<title>{description}</title>
<circle cx="12" cy="12" r="12" />
</svg>
);
})();

return (
<li className={classes}>
{currentSvg || completeSvg || incompleteSvg}
<p className={`${prefix}--progress-label`}>{label}</p>
<ProgressStepLabel className={`${prefix}--progress-label`}>
{label}
</ProgressStepLabel>
{componentsX &&
secondaryLabel !== null &&
secondaryLabel !== undefined ? (
<p className={`${prefix}--progress-optional`}>{secondaryLabel}</p>
) : null}
<span className={`${prefix}--progress-line`} />
</li>
);
Expand Down Expand Up @@ -82,6 +129,41 @@ ProgressStep.propTypes = {
* Provide a description for the <ProgressStep>
*/
description: PropTypes.string,

/**
* Specify whether the step is invalid
*/
invalid: PropTypes.bool,

/**
* Provide an optional secondary label
*/
secondaryLabel: PropTypes.string,

/*
* An optional parameter to allow for overflow content to be rendered in a
* tooltip.
*/
renderLabel: PropTypes.function,

/**
* Provide the props that describe a progress step tooltip
*/
overflowTooltipProps: PropTypes.object,

/**
* Specify whether the step is disabled
*/
disabled: PropTypes.bool,

/**
* The ID of the tooltip content.
*/
tooltipId: PropTypes.string,
};

ProgressStep.defaultProps = {
renderLabel: defaultRenderLabel,
};

export class ProgressIndicator extends Component {
Expand Down Expand Up @@ -125,11 +207,13 @@ export class ProgressIndicator extends Component {
return React.cloneElement(child, {
current: true,
});
} else if (index < this.state.currentIndex) {
}
if (index < this.state.currentIndex) {
return React.cloneElement(child, {
complete: true,
});
} else if (index > this.state.currentIndex) {
}
if (index > this.state.currentIndex) {
return React.cloneElement(child, {
complete: false,
});
Expand Down

0 comments on commit 3b6f028

Please sign in to comment.