import type { Args, Meta, StoryObj } from '@storybook/vue3-vite' import CpButton from '@/components/CpButton.vue' import CpIcon from '@/components/CpIcon.vue' import { docCellStyle, docLabelStyle, docRowWrapStyle } from '@/stories/documentationStyles' const buttonAppearances = ['primary', 'secondary', 'tertiary'] as const const buttonColors = ['neutral', 'accent', 'success', 'warning', 'error'] as const const buttonSizes = ['2xs', 'xs', 'sm', 'md', 'lg'] as const const meta = { title: 'Atoms/CpButton', component: CpButton, argTypes: { appearance: { control: 'select', options: buttonAppearances, description: 'The visual style of the button', }, size: { control: 'select', options: buttonSizes, description: 'The size of the button', }, color: { control: 'select', options: buttonColors, description: 'The color variant of the button', }, disabled: { control: 'boolean', description: 'Whether the button is disabled', }, tag: { control: 'select', options: ['a', 'button', 'label'], description: 'The HTML element to render', }, type: { control: 'select', options: ['button', 'submit', 'reset'], description: 'The type of button', }, isLoading: { control: 'boolean', description: 'Whether the button is in loading state', }, isSquare: { control: 'boolean', description: 'Whether the button has square corners', }, }, } satisfies Meta export default meta type Story = StoryObj const defaultTemplate = 'Button' const defaultRender = (args: Args) => ({ components: { CpButton }, setup() { const handleClick = (event: MouseEvent) => { console.log('Button clicked', event) } return { args, handleClick } }, template: defaultTemplate, }) /** * Default button: primary appearance, neutral color, medium size. Use the * controls to experiment with each prop in isolation. */ export const Default: Story = { args: { appearance: 'primary', color: 'neutral', size: 'md', disabled: false, isLoading: false, isSquare: false, tag: 'button', type: 'button', }, render: defaultRender, } /* -------------------------------------------------------------------------- */ /* Appearances */ /* -------------------------------------------------------------------------- */ /** * Every appearance rendered side by side: `primary`, `secondary`, `tertiary`. */ export const Appearances: Story = { parameters: { controls: { disable: true } }, render: () => ({ components: { CpButton }, setup() { return { buttonAppearances, docCellStyle, docLabelStyle, docRowWrapStyle } }, template: `
{{ appearance }} Button
`, }), } /* -------------------------------------------------------------------------- */ /* Colors */ /* -------------------------------------------------------------------------- */ /** * Every semantic color available for the button. */ export const Colors: Story = { parameters: { controls: { disable: true } }, render: () => ({ components: { CpButton }, setup() { return { buttonColors, docCellStyle, docLabelStyle, docRowWrapStyle } }, template: `
{{ color }} Button
`, }), } /* -------------------------------------------------------------------------- */ /* Sizes */ /* -------------------------------------------------------------------------- */ /** * All sizes rendered side by side, from `2xs` to `lg`. */ export const Sizes: Story = { parameters: { controls: { disable: true } }, render: () => ({ components: { CpButton }, setup() { return { buttonSizes, docCellStyle, docLabelStyle, docRowWrapStyle } }, template: `
{{ size }} Button
`, }), } /* -------------------------------------------------------------------------- */ /* States */ /* -------------------------------------------------------------------------- */ /** * Enabled, disabled and loading states compared side by side. The loading * state is automatically disabled to prevent double submissions. */ export const States: Story = { parameters: { controls: { disable: true } }, render: () => ({ components: { CpButton }, setup() { return { docCellStyle, docLabelStyle, docRowWrapStyle } }, template: `
Enabled Button
Disabled Button
Loading Button
`, }), } /* -------------------------------------------------------------------------- */ /* Square vs rounded */ /* -------------------------------------------------------------------------- */ /** * Fully rounded (default) compared with the square variant. Square fits * better inside forms or grouped controls. */ export const Squared: Story = { parameters: { controls: { disable: true } }, render: () => ({ components: { CpButton }, setup() { return { docCellStyle, docLabelStyle, docRowWrapStyle } }, template: `
Rounded Button
Square Button
`, }), } /* -------------------------------------------------------------------------- */ /* Icons */ /* -------------------------------------------------------------------------- */ /** * Button with a leading icon, a trailing icon, both or an icon-only * configuration (pair with `isSquare` for best visual balance). */ export const Icons: Story = { parameters: { controls: { disable: true } }, render: () => ({ components: { CpButton, CpIcon }, setup() { return { docCellStyle, docLabelStyle, docRowWrapStyle } }, template: `
Leading Button
Trailing Button
Both Button
Icon only
`, }), } /* -------------------------------------------------------------------------- */ /* Element & form integration */ /* -------------------------------------------------------------------------- */ /** * Render the button as an `` anchor while keeping the visual style. * Useful for links that look like buttons. */ export const AsAnchor: Story = { args: { ...Default.args, tag: 'a', color: 'accent' }, render: (args: Args) => ({ components: { CpButton }, setup() { return { args } }, template: `Anchor button`, }), } /** * `type="submit"` submits the parent form. The button is wrapped in a minimal * form to demonstrate the behaviour. */ export const SubmitType: Story = { args: { ...Default.args, type: 'submit', color: 'accent' }, render: (args: Args) => ({ components: { CpButton }, setup() { const handleSubmit = (event: Event) => { event.preventDefault() console.log('Form submitted') } return { args, handleSubmit } }, template: `
Submit form
`, }), } /** * `type="reset"` resets the parent form to its initial values. */ export const ResetType: Story = { args: { ...Default.args, type: 'reset', appearance: 'secondary', color: 'neutral' }, render: (args: Args) => ({ components: { CpButton }, setup() { return { args } }, template: `
Reset
`, }), }