Skip to content

Commit

Permalink
feat(StepIndicator): Add Step Indicator and Step (#199)
Browse files Browse the repository at this point in the history
Add the `StepIndicator` and associated `Step` components from Rivet
  • Loading branch information
burnumd authored Jul 1, 2019
1 parent 9238fb0 commit 35db62b
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/components/List/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Use the *ordered* `variant` to create an ordered list.
<li>List Item Four</li>
</List>
```

### Plain List

Use the *plain* `variant` to create a plain list with no decoration.
Expand Down
1 change: 1 addition & 0 deletions src/components/StepIndicator/Step.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`Step` contains the individual steps in a step indicator. See the examples in [StepIndicator](/#/Page%20Content?id=StepIndicator)
50 changes: 50 additions & 0 deletions src/components/StepIndicator/Step.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright (C) 2019 The Trustees of Indiana University
SPDX-License-Identifier: BSD-3-Clause
*/
import { mount } from 'enzyme';
import * as React from 'react';

import Step from './Step'

describe('<Step />', () => {
describe('Rendering and styling', () =>{
it('should render without throwing an error', () => {
const cut = mount(<Step indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} />);
expect(cut.find('li')).toHaveLength(1);
});
it('should pass attributes through', () => {
const cut = mount(<Step id="the_id" indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} />);
expect(cut.find('li').prop('id')).toEqual('the_id');
});
it('should apply custom classes', () => {
const cut = mount(<Step className="foo" indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} />);
expect(cut.find('li').hasClass('foo')).toBe(true);
});

it('should set aria-current when current is set', () => {
const cut = mount(<Step current indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} />);
expect(cut.find('span[aria-current]')).toHaveLength(1);
});

it('should set aria-current when current is set in an href', () => {
const cut = mount(<Step current href="https://foo.com" indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} />);
expect(cut.find('[aria-current="step"]')).toHaveLength(1);
});

it('should not set aria-current when current is not set', () => {
const cut = mount(<Step indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} />);
expect(cut.find('span[aria-current]')).toHaveLength(0);
});

it('should provide a link when href is set', () => {
const cut = mount(<Step indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} href="https://foo.com" />);
expect(cut.find('a')).toHaveLength(1);
});

it('should set a variant if the variant property is set', () => {
const cut = mount(<Step indicator={<span>1</span>} screenReaderIndicator="1" label={<span>Step</span>} variant="warning"/>);
expect(cut.find('span .rvt-steps__indicator--warning')).toHaveLength(1)
});
});
});
76 changes: 76 additions & 0 deletions src/components/StepIndicator/Step.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright (C) 2019 The Trustees of Indiana University
SPDX-License-Identifier: BSD-3-Clause
*/
import * as classNames from 'classnames';
import * as React from 'react'


export interface StepProps {
/**
* Defines whether the indicated step is the current step
*/
current?: boolean;

/**
* An optional URL that can be used to create a link from this step to another location
*/
href?: string;

/**
* A visual indicator to identify this step
*/
indicator: JSX.Element;

/**
* A label for this step
*/
label: JSX.Element;

/**
* An textual indicator to be used by screenreaders since the visual indicator may not include text
*/
screenReaderIndicator: string

/**
* An optional variant to be applied to the indicator
*/
variant?: 'success' | 'warning' | 'danger';
}

const indicatorClass = 'rvt-steps__indicator';

const variantClass = (variant) => variant && `${indicatorClass}--${variant}`;

const Step : React.SFC <StepProps & React.HTMLAttributes<HTMLLIElement>> =
({ current, href, indicator, label, screenReaderIndicator, variant, ...attrs}) => {
const content = (
<>
<span className="rvt-steps__label">{label}</span>
<span className={classNames(indicatorClass, variantClass(variant))}>
<span className="rvt-sr-only">{screenReaderIndicator}</span> {indicator}
</span>
</>
);
let wrapper = (
<span className="rvt-steps__item-content" aria-current={current && 'step'}>
{content}
</span>
);
if (href) {
wrapper = (
<a href={href} className="rvt-steps__item-content" aria-current={current && 'step'}>
{content}
</a>
);
}

return (
<li className="rvt-steps__item" {...attrs}>
{wrapper}
</li>
)
};
Step.displayName = 'Step';

export default Step;
24 changes: 24 additions & 0 deletions src/components/StepIndicator/StepIndicator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Use the step indicator component to help users keep track of their progress in a multi-step process, such as an application form.

View the [Rivet documentation for Step Indicator](https://rivet.iu.edu/components/page-content/step-indicator/)

### Basic step indicator

```jsx
<StepIndicator>
<Step href="#" label="Personal Information" indicator="1" screenReaderIndicator="Step"/>
<Step label="Records & transcripts" indicator="2" screenReaderIndicator="Step" current />
<Step label="Confirmation" indicator="3" screenReaderIndicator="Step" variant="success" />
</StepIndicator>
```

### Vertical Step Indicator

```jsx
<StepIndicator vertical>
<Step href="#" label="Personal Information" indicator="1" screenReaderIndicator="Step"/>
<Step label="Records & transcripts" indicator="2" screenReaderIndicator="Step" current />
<Step label="Confirmation" indicator="3" screenReaderIndicator="Step" variant="success" />
</StepIndicator>

```
35 changes: 35 additions & 0 deletions src/components/StepIndicator/StepIndicator.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Copyright (C) 2019 The Trustees of Indiana University
SPDX-License-Identifier: BSD-3-Clause
*/
import { mount } from 'enzyme';
import * as React from 'react';

import StepIndicator from './StepIndicator'

describe('<StepIndicator />', () => {
describe('Rendering and styling', () =>{
it('should render without throwing an error', () => {
const cut = mount(<StepIndicator />);
expect(cut.find('ol')).toHaveLength(1);
});
it('should pass attributes through', () => {
const cut = mount(<StepIndicator id="the_id" />);
expect(cut.find('ol').prop('id')).toEqual('the_id');
});
it('should apply custom classes', () => {
const cut = mount(<StepIndicator className="foo" />);
expect(cut.find('ol').hasClass('foo')).toBe(true);
});

it('should apply vertical styling if the vertical property is set', () => {
const cut = mount(<StepIndicator vertical />);
expect(cut.find('ol').hasClass('rvt-steps--vertical')).toBe(true);
});

it('should not apply vertical styling if the vertical property is set', () => {
const cut = mount(<StepIndicator />);
expect(cut.find('ol').hasClass('rvt-steps--vertical')).toBe(false);
});
});
});
26 changes: 26 additions & 0 deletions src/components/StepIndicator/StepIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Copyright (C) 2019 The Trustees of Indiana University
SPDX-License-Identifier: BSD-3-Clause
*/
import * as classNames from 'classnames';
import * as React from 'react';
import * as Rivet from '../util/Rivet';

export interface StepIndicatorProps {
/**
* Defines whether the step indicator should use the alternate vertical styling
*/
vertical?: boolean
}

const componentClass = 'rvt-steps';

export const StepIndicator: React.SFC<StepIndicatorProps & React.HTMLAttributes<HTMLOListElement>> =
({ className, children, vertical, id = Rivet.shortuid(), ...attrs }) => (
<ol id={id} className={classNames(componentClass, { 'rvt-steps--vertical': vertical}, className)} {...attrs}>
{children}
</ol>
);
StepIndicator.displayName = 'StepIndicator';

export default Rivet.rivetize(StepIndicator);
6 changes: 6 additions & 0 deletions src/components/StepIndicator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
Copyright (C) 2019 The Trustees of Indiana University
SPDX-License-Identifier: BSD-3-Clause
*/
export { default as Step } from './Step';
export { default as StepIndicator } from './StepIndicator';
1 change: 1 addition & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ export * from './Pagination';
export * from './Panel';
export * from './RadioButton';
export * from './Section';
export * from './StepIndicator';
export * from './Table';
export * from './Tabs';
1 change: 1 addition & 0 deletions styleguide.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = {
components: () => [
'src/components/Badge/*.tsx',
'src/components/List/*.tsx',
'src/components/StepIndicator/*.tsx',
'src/components/Table/*.tsx',
'src/components/Tabs/*.tsx',
],
Expand Down
38 changes: 13 additions & 25 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -171,19 +171,12 @@
"@types/node" "*"
"@types/react" "*"

"@types/react@*":
"@types/react@*", "@types/react@16.4.1":
version "16.4.1"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.1.tgz#c53bbfb4a78933db587da085ac60dbf5fcf73f8f"
dependencies:
csstype "^2.2.0"

"@types/react@16.4.7":
version "16.4.7"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.7.tgz#f33f6d759a7e1833befa15224d68942d178a5a3f"
integrity sha512-tHpSs7HMyjnpyfzka1G0pYh7rBNdpwGgcIDT4vfV6jUaR69yOHo/vNH2H+d9iYHo9xnX4qDe7UalPe9HiGRkLw==
dependencies:
csstype "^2.2.0"

"@vxna/mini-html-webpack-template@^0.1.7":
version "0.1.7"
resolved "https://registry.yarnpkg.com/@vxna/mini-html-webpack-template/-/mini-html-webpack-template-0.1.7.tgz#2a8270e513ee14f395cc17c2ce22ced383c45d22"
Expand Down Expand Up @@ -8604,25 +8597,20 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.0.0"
inherits "^2.0.1"

rivet-collapsible@0.1.1-alpha:
version "0.1.1-alpha"
resolved "https://registry.yarnpkg.com/rivet-collapsible/-/rivet-collapsible-0.1.1-alpha.tgz#27c211891a8510e2c592f1caf305d14fb5337ffb"
dependencies:
rivet-uits "^1.0.0"

rivet-switch@0.1.1-alpha:
version "0.1.1-alpha"
resolved "https://registry.yarnpkg.com/rivet-switch/-/rivet-switch-0.1.1-alpha.tgz#a49ee1e291d223010caeff54351a69703ad61b10"
dependencies:
rivet-uits "^1.0.0"
rivet-collapsible@0.2.10:
version "0.2.10"
resolved "https://registry.npmjs.org/rivet-collapsible/-/rivet-collapsible-0.2.10.tgz#6ef38eadc032021b57495c8e17337cd92fbb1a4f"
integrity sha512-JWtF3nmysDb8yhT3wbpaiOIBC7SxJAQvnhnI2dmZxXlDub06RLxXQwFiPSpV+LObmgrI8huVNPVtkAgXzR/3ow==

rivet-uits@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/rivet-uits/-/rivet-uits-1.1.0.tgz#bd50edae3fd222cd1f8d67416e6513eecf9a4c23"
rivet-switch@0.3.1:
version "0.3.1"
resolved "https://registry.npmjs.org/rivet-switch/-/rivet-switch-0.3.1.tgz#1a58086aad8f00760adbd4bcbdc26a0d0ae314b1"
integrity sha512-JWA/3/jN6qqb4+RadxHeukLNPf2EgRMMgzO9fypvY2kRw5W1HOaW2bJIwTC85j/SVvn+VciZjucYcmnQjYhlHQ==

rivet-uits@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/rivet-uits/-/rivet-uits-1.0.0.tgz#73f8d011be56cdb3637245d0b9f8af9038a2478a"
rivet-uits@1.6.0:
version "1.6.0"
resolved "https://registry.npmjs.org/rivet-uits/-/rivet-uits-1.6.0.tgz#d58d57183afb55d501bfa841d597634d1e6dcaaf"
integrity sha512-SEpELSU4c5swRSIpWqVD+z/e71gdpaJNTZ19V5gqGwEZO16xlKxENPA+FSSuKkCVaoZ0OHUwmJdLZhUp4bZdUw==

rst-selector-parser@^2.2.3:
version "2.2.3"
Expand Down

0 comments on commit 35db62b

Please sign in to comment.