Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(docs): add CSS-only stepper docs #3092

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pretty-bugs-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-styles': patch
---

Updated the stepper styles: changed the colors and font-weights, as well as the current step label position on smaller screens.
5 changes: 5 additions & 0 deletions .changeset/shaggy-weeks-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-documentation': minor
---

Added documentation for the CSS-only stepper and deprecated the stepper based on ng-bootstrap progress bar.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
describe('Stepper', () => {
it('default', () => {
cy.visit('/iframe.html?id=snapshots--stepper');
cy.get('.stepper', { timeout: 30000 }).should('be.visible');
cy.percySnapshot('Steppers', { widths: [320, 1440] });
});
});

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,56 +1,47 @@
import { Meta, Source } from '@storybook/blocks';
import { PostTabHeader, PostTabPanel, PostTabs } from '@swisspost/design-system-components-react';
import StylesPackageImport from '@/shared/styles-package-import.mdx';
import { Canvas, Controls, Meta } from '@storybook/blocks';
import PostComponentDemoLink from '@/shared/post-component-demo-link.mdx';
import NgbComponentImport from '@/shared/nb-bootstrap/ngb-component-import.mdx';
import * as stepperStories from './stepper.stories';
import stepperTemplate from './stepper-template.sample.html?raw';
import stepperComponent from './stepper-component.sample?raw';
import StylesPackageImport from '@/shared/styles-package-import.mdx';
import * as StepperStories from './stepper.stories';

<Meta of={stepperStories} />
<Meta of={StepperStories} />

<div className="docs-title">
# Stepper

<nav>
<link-design of={JSON.stringify(stepperStories)}></link-design>
<PostComponentDemoLink component="stepper" />
<link-design of={JSON.stringify(StepperStories)}></link-design>
</nav>
</div>

<p className="lead">Conveys progress through numbered steps.</p>
<p className="lead">The stepped progression component provides an interactive visual overview a process. It shows at a glance the amount of steps a user is required to go trough, and serves as a guide for each step, indicating its status.</p>

alizedebray marked this conversation as resolved.
Show resolved Hide resolved
<div className="alert alert-warning mb-bigger-big">
<p className="alert-heading">The stepper previously used ng-bootstrap's progressbar component, this has been deprecated in favor of the CSS-only stepper documented below.</p>
<div className="d-flex justify-content-end"><PostComponentDemoLink component="stepper" /></div>
</div>

<div className="alert alert-info mb-bigger-big">
<p className="alert-heading">The stepper uses ng-bootstrap's progressbar component.</p>
<Canvas sourceState="shown" of={StepperStories.Default} />
<div className="hide-col-default">
<Controls of={StepperStories.Default} />
</div>

<ul>
<li>
<a href="#component-import" target="_self">Component Import</a>
</li>
<li>
<a href="#style-imports" target="_self">Style Imports</a>
</li>
<li>
<a href="#example" target="_self">Example</a>
</li>
</ul>
<StylesPackageImport components={['stepper']} />

## Examples

### Navigational Stepper

<NgbComponentImport module="NgbProgressbarModule" />
You can use a stepper to allow users to navigate to specific steps.
To do so, use `a` elements for the `.stepper-link` of the steps you want to be navigable, and use `span` for the step you want not to be navigable.
Then, wrap the stepper inside a `<nav>`.
alizedebray marked this conversation as resolved.
Show resolved Hide resolved

<StylesPackageImport components={["progress", "stepper"]} />
However, it is better not to use an `a` for the current step since the user is already on the page.

## Example
<Canvas of={StepperStories.NavigationalStepper} />

<PostTabs>
<PostTabHeader slot="tabs" panel="template">template.html</PostTabHeader>
<PostTabPanel name="template">
<Source code={stepperTemplate} language="html"/>
</PostTabPanel>
### Informational Stepper

<PostTabHeader slot="tabs" panel="component">component.ts</PostTabHeader>
<PostTabPanel name="component">
<Source code={stepperComponent} language="typescript"/>
</PostTabPanel>
</PostTabs>
If you wish to display the stepper for informational purposes only, you can use `<span>` elements for the `.stepper-link` on all the steps.
In this case, there's no need to wrap the stepper inside a `<nav>`.

<Canvas of={StepperStories.InformationalStepper} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Args, StoryContext, StoryObj } from '@storybook/web-components';
import meta from './stepper.stories';
import { html } from 'lit';
import { bombArgs } from '@/utils';

const { id, ...metaWithoutId } = meta;

export default {
...metaWithoutId,
title: 'Snapshots',
};

type Story = StoryObj;

export const Stepper: Story = {
render: (_args: Args, context: StoryContext) => {
return html`
<div class="d-flex flex-column gap-1">
${['bg-white', 'bg-dark'].map(
bg => html`
<div class="${bg} d-flex flex-column gap-regular p-regular">
${bombArgs({
currentStepNumber: meta.argTypes?.currentStepNumber?.options,
}).map((args: Args) => meta.render?.({ ...context.args, ...args }, context))}
</div>
`,
)}
</div>
`;
},
};
Original file line number Diff line number Diff line change
@@ -1,22 +1,134 @@
import type { StoryObj } from '@storybook/web-components';
import { Args, StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import { MetaComponent } from '@root/types';
import { ifDefined } from 'lit/directives/if-defined.js';
import { useArgs } from '@storybook/preview-api';

const steps = ['Sender', 'Product', 'Other details', 'Order summary'];

const meta: MetaComponent = {
id: '7dc546d9-e248-4d06-befe-3ad62fcd310f',
title: 'Components/Stepper',
tags: ['package:Angular'],
render: renderStepper,
parameters: {
badges: [],
design: {
type: 'figma',
url: 'https://www.figma.com/file/xZ0IW0MJO0vnFicmrHiKaY/Components-Post?type=design&node-id=20952-29106&mode=design&t=38qLaYwWdirTcHdb-4',
},
},
args: {
currentStepNumber: 3,
navigableSteps: 'all',
processName: 'Registration Form',
},
argTypes: {
navigableSteps: {
name: 'Navigable Steps',
description: 'Defines which steps in the current process the user can navigate to.',
control: {
type: 'radio',
labels: {
all: 'All steps',
completedOnly: 'Completed Steps only',
none: 'None',
},
},
options: ['all', 'completedOnly', 'none'],
table: {
category: 'General',
},
},
currentStepNumber: {
name: 'Current Step Number',
description: 'The number of the step the user is currently at in the process.',
control: {
type: 'select',
},
options: Object.keys(steps).map(key => parseInt(key, 10) + 1),
table: {
category: 'General',
},
},
processName: {
name: 'Process Name',
description:
'A straightforward, self-explanatory name for the current process, used for assistive technologies.',
control: {
type: 'text',
},
table: {
category: 'General',
},
},
},
};

export default meta;

export const Default: StoryObj = {
render: () => html``,
// RENDERER
function getStepperItem(args: Args, step: string, index: number) {
const currentStepIndex = args.currentStepNumber - 1;
const isCompletedStep = index < currentStepIndex;
const isCurrentStep = index === currentStepIndex;
const isNextStep = index > currentStepIndex;
const isLink =
(isCompletedStep && args.navigableSteps !== 'none') ||
(isNextStep && args.navigableSteps === 'all');

let status = 'Current';
if (isCompletedStep) status = 'Completed';
if (isNextStep) status = 'Next';

const text = html`<span class="visually-hidden">${status} step:</span> ${step}`;

return html`
<li aria-current=${ifDefined(isCurrentStep ? 'step' : undefined)} class="stepper-item">
${isLink
? html` <a class="stepper-link" href="../step-${index + 1}"> ${text} </a> `
: html`<span class="stepper-link">${text}</span>`}
</li>
`;
}

function renderStepper(args: Args) {
const [_, updateArgs] = useArgs();

setTimeout(() => {
const stepperLinks = document.querySelectorAll('.stepper-link');
stepperLinks.forEach((link, index) => {
if (link.tagName === 'SPAN') return;

link.addEventListener('click', e => {
e.preventDefault();
updateArgs({ currentStepNumber: index + 1 });
});
});
});

const isNav = args.navigableSteps !== 'none';
const stepper = html`<ol
class="stepper"
aria-label=${ifDefined(isNav ? undefined : args.processName + ' Progress')}
>
${steps.map((step, index) => getStepperItem(args, step, index))}
</ol>`;

return args.navigableSteps === 'none'
? stepper
: html` <nav aria-label="${args.processName}">${stepper}</nav> `;
}

export const Default: StoryObj = {};

export const NavigationalStepper: StoryObj = {
args: {
navigableSteps: 'completedOnly',
},
};

export const InformationalStepper: StoryObj = {
args: {
navigableSteps: 'none',
},
};
Loading
Loading