import { useState } from 'react';
import { Button, FlexContainer } from '@pantheon-systems/pds-toolkit-react';
import { Meta, StoryObj } from '@storybook/react-vite';
import { SpinnerSequence } from './SpinnerSequence';
const businessSteps = [
{ label: 'Creating business account...' },
{ label: 'Creating workspace...' },
];
const meta: Meta<typeof SpinnerSequence> = {
tags: ['new-pattern', 'ready-for-dev'],
title: 'Component Proposals/Spinner Sequence',
component: SpinnerSequence,
parameters: {
docs: {
description: {
component:
'A Spinner that walks through a list of steps, each with its own text, then ends on an illustration and a final text. You set the texts, how long each shows and the illustration.',
},
},
},
argTypes: {
activeStep: { table: { category: 'Component configuration' } },
className: { table: { category: 'Base attributes' } },
defaultDuration: { table: { category: 'Component configuration' } },
finalLabel: { table: { category: 'Content' } },
illustration: { table: { category: 'Content' } },
illustrationName: {
control: 'select',
options: [
'task',
'createEnvLive',
'createEnvMultidev',
'underConstruction',
],
table: { category: 'Content' },
},
onComplete: { table: { category: 'Component configuration' } },
size: { control: 'select', table: { category: 'Component configuration' } },
steps: { table: { category: 'Content' } },
},
args: {
defaultDuration: 2000,
finalLabel: 'Taking you to your business account',
illustrationName: 'task',
size: '5xl',
steps: businessSteps,
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
parameters: {
docs: {
description: {
story:
'Two steps of 2 seconds each, then the final state, which stays. Change a control to run it again.',
},
},
},
// Remount when a control changes so the sequence starts again.
render: (args) => (
<SpinnerSequence
key={JSON.stringify([args.steps, args.defaultDuration, args.size])}
{...args}
/>
),
};
export const OwnTimingAndSteps: Story = {
parameters: {
docs: {
description: {
story:
'Any number of steps, each with its own `duration`. Steps without one use `defaultDuration`.',
},
},
},
args: {
defaultDuration: 1500,
finalLabel: 'All set',
steps: [
{ label: 'Checking your details...' },
{ duration: 3000, label: 'Setting up your account...' },
{ duration: 1000, label: 'Almost there...' },
{ label: 'Adding your team...' },
],
},
};
export const AllSizes: Story = {
parameters: {
docs: {
description: {
story:
'Every size, at the final state, so the illustration and the spinner can be compared. The illustration is drawn at the spinner size.',
},
},
},
render: (args) => (
<FlexContainer alignItems='flex-start' flexWrap='wrap' gap='2xl'>
{(['m', 'xl', '3xl', '5xl', '6xl'] as const).map((size) => (
<SpinnerSequence
{...args}
activeStep={args.steps.length}
finalLabel={size}
key={size}
size={size}
/>
))}
</FlexContainer>
),
};
export const ControlledByTheWork: Story = {
parameters: {
docs: {
description: {
story:
'`activeStep` moves the sequence when the real work does, instead of a timer. Here the buttons stand in for the work.',
},
},
},
render: function Render(args) {
const [activeStep, setActiveStep] = useState(0);
return (
<FlexContainer flexDirection='column' gap='xl'>
<SpinnerSequence {...args} activeStep={activeStep} />
<FlexContainer gap='m'>
<Button
disabled={activeStep >= args.steps.length}
label='Next step'
onClick={() => setActiveStep(activeStep + 1)}
variant='secondary'
/>
<Button
disabled={activeStep === 0}
label='Start again'
onClick={() => setActiveStep(0)}
variant='secondary'
/>
</FlexContainer>
</FlexContainer>
);
},
};
export const OtherIllustration: Story = {
parameters: {
docs: {
description: {
story:
'`illustrationName` picks another PDS illustration. `illustration` takes your own node, drawn at the spinner size.',
},
},
},
args: { illustrationName: 'underConstruction' },
render: (args) => (
<SpinnerSequence {...args} activeStep={args.steps.length} />
),
};
SpinnerSequence
A new component, SpinnerSequence, that composes the existing PDS v2 Spinner and Illustration (the Spinner is not changed).
Net-new componentOpen in Storybook