← All proposals

Milestone

Net-new, in two parts, in their own family so "timeline" keeps one meaning (the log).

Net-new componentOpen in Storybook

proposals/Milestone/Milestone.stories.tsx87 lines · View on GitHub
import { Decorator, Meta, StoryObj } from '@storybook/react-vite';
import { ComponentProps } from 'react';

import { MilestoneList, MilestoneListSubtitlePosition } from './MilestoneList';
import { Milestone } from './Milestone';

// `subtitlePosition` is a Milestone List prop. It is a control here too, and the
// story passes it to the list it sits in, so it never reaches the Milestone.
type MilestoneStoryArgs = ComponentProps<typeof Milestone> & {
	subtitlePosition?: MilestoneListSubtitlePosition;
};

// The line and the dot belong to a MilestoneList; this stands in for one. The padding keeps the dot inside the canvas.
const withList: Decorator<MilestoneStoryArgs> = (Story, { args }) => (
	<div
		style={{
			maxWidth: `calc(${args.subtitlePosition === 'start' ? 14 : 10} * var(--pds-spacing-4xl))`,
			padding: 'var(--pds-spacing-l)',
			paddingInlineStart: 'var(--pds-spacing-2xl)',
		}}
	>
		<MilestoneList subtitlePosition={args.subtitlePosition}>
			{Story()}
		</MilestoneList>
	</div>
);

const meta: Meta<MilestoneStoryArgs> = {
	tags: ['new-pattern', 'ready-for-dev'],
	title: 'Component Proposals/Milestones/Milestone',
	component: Milestone,
	parameters: {
		docs: {
			description: {
				component:
					'**New pattern:** not in PDS v2 today. One milestone (a step in a sequence, with a heading and a body; for events that happened, use Timeline Item) in a Milestone List: a dot on the line, a title, a subtitle and a body, on a card (the default Panel) or flat.',
			},
		},
	},
	argTypes: {
		children: { control: 'text', table: { category: 'Content' } },
		className: { table: { category: 'Base attributes' } },
		subtitle: { control: 'text', table: { category: 'Content' } },
		subtitlePosition: {
			control: 'select',
			description:
				'A Milestone List prop, set on the list these stories sit in: `below` the title or `start`, left of the line.',
			options: ['below', 'start'],
			table: { category: 'Milestone List' },
		},
		headingLevel: {
			control: 'select',
			options: [2, 3, 4, 5, 6],
			table: { category: 'Component configuration' },
		},
		isActive: { control: 'boolean', table: { category: 'State' } },
		title: { control: 'text', table: { category: 'Content' } },
		variant: {
			control: 'select',
			options: ['card', 'flat'],
			table: { category: 'Component configuration' },
		},
	},
	args: {
		headingLevel: 3,
		children:
			'Before you start, you may want to make a list of all your senior year classes and extracurricular activities, so you’re ready to enter those in your application.',
		subtitle: 'Spring 2022',
		title: 'Organize your info',
		subtitlePosition: 'below',
		variant: 'card',
	},
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	render: ({ subtitlePosition: _position, ...args }) => <Milestone {...args} />,
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = { decorators: [withList] };

export const Flat: Story = {
	args: { variant: 'flat' },
	decorators: [withList],
};