146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
import type { Meta, StoryObj } from '@storybook/react';
|
|
import { PlusIcon } from '@heroicons/react/24/solid';
|
|
import { Button } from './Button';
|
|
|
|
const meta = {
|
|
title: 'Components/Button',
|
|
component: Button,
|
|
tags: ['autodocs'],
|
|
parameters: {
|
|
docs: {
|
|
description: {
|
|
component:
|
|
'Polymorphic button component: renders a native `<button>` or a React Router `<Link>` when `to` is provided.',
|
|
},
|
|
},
|
|
},
|
|
argTypes: {
|
|
label: {
|
|
description: 'Visible button label text.',
|
|
control: 'text',
|
|
table: { type: { summary: 'string' } },
|
|
},
|
|
type: {
|
|
description: 'Base visual style.',
|
|
options: ['solid', 'outlined', 'noborder'],
|
|
control: 'inline-radio',
|
|
table: { type: { summary: "'solid' | 'outlined' | 'noborder'" } },
|
|
},
|
|
variant: {
|
|
description:
|
|
'Color variant. If omitted: `primary` for `solid`, `secondary` for the other types.',
|
|
options: ['primary', 'secondary', 'important'],
|
|
control: 'inline-radio',
|
|
table: { type: { summary: "'primary' | 'secondary' | 'important'" } },
|
|
},
|
|
size: {
|
|
description: 'Button size.',
|
|
options: ['sm', 'md', 'lg', 'full'],
|
|
control: 'inline-radio',
|
|
table: { type: { summary: "'sm' | 'md' | 'lg' | 'full'" } },
|
|
},
|
|
width: {
|
|
description: 'Button width behavior.',
|
|
options: ['sm', 'md', 'lg', 'full'],
|
|
control: 'inline-radio',
|
|
table: { type: { summary: "'sm' | 'md' | 'lg' | 'full'" } },
|
|
},
|
|
to: {
|
|
description: 'Navigation path. When set, the component renders a `<Link>`.',
|
|
control: 'text',
|
|
table: { type: { summary: 'string' } },
|
|
},
|
|
htmlType: {
|
|
description: 'HTML button type used when rendering a native `<button>`.',
|
|
options: ['button', 'submit', 'reset'],
|
|
control: 'inline-radio',
|
|
table: { type: { summary: "'button' | 'submit' | 'reset'" } },
|
|
},
|
|
disabled: {
|
|
description: 'Disables interaction and hover/click states.',
|
|
control: 'boolean',
|
|
table: { type: { summary: 'boolean' } },
|
|
},
|
|
icon: {
|
|
description: 'Optional icon component (for example Heroicons).',
|
|
control: false,
|
|
table: { type: { summary: 'ElementType' } },
|
|
},
|
|
ariaLabel: {
|
|
description: 'Accessible label. Falls back to `label` when not provided.',
|
|
control: 'text',
|
|
table: { type: { summary: 'string' } },
|
|
},
|
|
className: {
|
|
description: 'Extra CSS classes for the root element.',
|
|
control: 'text',
|
|
table: { type: { summary: 'string' } },
|
|
},
|
|
onClick: {
|
|
description: 'Click handler callback.',
|
|
action: 'clicked',
|
|
table: { type: { summary: 'MouseEventHandler<HTMLElement>' } },
|
|
},
|
|
},
|
|
args: {
|
|
type: 'solid',
|
|
variant: 'primary',
|
|
size: 'md',
|
|
width: 'md',
|
|
label: 'Save',
|
|
},
|
|
} satisfies Meta<typeof Button>;
|
|
|
|
export default meta;
|
|
type Story = StoryObj<typeof meta>;
|
|
|
|
export const SolidPrimary: Story = {};
|
|
|
|
export const SolidImportant: Story = {
|
|
args: {
|
|
type: 'solid',
|
|
variant: 'important',
|
|
label: 'Delete',
|
|
},
|
|
};
|
|
|
|
export const OutlinedSecondary: Story = {
|
|
args: {
|
|
type: 'outlined',
|
|
variant: 'secondary',
|
|
label: 'Cancel',
|
|
},
|
|
};
|
|
|
|
export const IconOnly: Story = {
|
|
args: {
|
|
icon: PlusIcon,
|
|
label: undefined,
|
|
ariaLabel: 'Add item',
|
|
},
|
|
};
|
|
|
|
export const LinkButton: Story = {
|
|
args: {
|
|
to: '/demo',
|
|
label: 'Go to demo',
|
|
},
|
|
};
|
|
|
|
export const Disabled: Story = {
|
|
args: {
|
|
disabled: true,
|
|
},
|
|
};
|
|
|
|
export const SizeMatrix: Story = {
|
|
render: (args) => (
|
|
<div className="grid grid-cols-1 gap-3">
|
|
<Button {...args} size="sm" label="Small" />
|
|
<Button {...args} size="md" label="Medium" />
|
|
<Button {...args} size="lg" label="Large" />
|
|
<Button {...args} size="md" width="full" label="Full width" />
|
|
</div>
|
|
),
|
|
};
|