import type { Meta, StoryObj } from '@storybook/vue3-vite' import { computed, ref, watch } from 'vue' import CpSegmentedControl from '@/components/CpSegmentedControl.vue' import { docCellStyle, docLabelStyle, docRowColumnStyle } from '@/stories/documentationStyles' const segmentedControlSizes = ['sm', 'md', 'lg'] as const const meta = { title: 'Molecules/CpSegmentedControl', component: CpSegmentedControl, argTypes: { modelValue: { control: 'text', description: 'The selected option value', }, name: { control: 'text', description: 'Name attribute for the radio group', }, options: { control: 'object', description: 'Array of segmented options', }, size: { control: 'select', options: segmentedControlSizes, description: 'The size of the segmented control', }, isDisabled: { control: 'boolean', description: 'Whether the control is disabled', }, isFullWidth: { control: 'boolean', description: 'Whether each option stretches to fill the available width', }, isInvalid: { control: 'boolean', description: 'Whether the control is in an invalid state', }, orientation: { control: 'select', options: ['horizontal', 'vertical'], description: 'The orientation of the control', }, }, } satisfies Meta export default meta type Story = StoryObj const sampleOptions = [ { value: 'option1', label: 'Option 1', leadingIcon: 'dashed-circle', trailingIcon: 'dashed-circle' }, { value: 'option2', label: 'Option 2', leadingIcon: 'dashed-circle', trailingIcon: 'dashed-circle' }, { value: 'option3', label: 'Option 3', leadingIcon: 'dashed-circle', trailingIcon: 'dashed-circle' }, ] const createRender = (label: string) => (args: { modelValue?: string; isFullWidth?: boolean }) => ({ components: { CpSegmentedControl }, setup() { const value = ref(args.modelValue) watch( () => args.modelValue, (modelValue) => { value.value = modelValue }, ) const boundArgs = computed(() => { const { modelValue: _modelValue, ...rest } = args return rest }) const cellStyle = args.isFullWidth ? `${docCellStyle} width: 100%;` : docCellStyle return { boundArgs, value, label, cellStyle, docLabelStyle, docRowColumnStyle } }, template: `
{{ label }}

modelValue: {{ value }}

`, }) /** * Default segmented control. Use the controls to experiment with each prop * in isolation. */ export const Default: Story = { args: { modelValue: 'option1', name: 'segmented-control-default', options: sampleOptions, size: 'md', isFullWidth: false, isInvalid: false, }, render: createRender('Default'), } /** * Options rendered with leading and trailing icons. */ export const WithIcons: Story = { args: { ...Default.args, name: 'segmented-control-icons', options: [ { value: 'list', label: 'List', leadingIcon: 'dashed-circle', trailingIcon: 'dashed-circle' }, { value: 'grid', label: 'Grid', leadingIcon: 'dashed-circle', trailingIcon: 'dashed-circle' }, { value: 'map', label: 'Map', leadingIcon: 'dashed-circle', trailingIcon: 'dashed-circle' }, ], modelValue: 'list', }, render: createRender('With icons'), } /** * Available sizes side by side — `sm` and `md`. */ export const Sizes: Story = { args: { ...Default.args, name: 'segmented-control-sizes', }, parameters: { controls: { disable: true } }, render: () => ({ components: { CpSegmentedControl }, setup() { const values = ref({ sm: 'option1', md: 'option1', }) return { values, sampleOptions, segmentedControlSizes, docCellStyle, docLabelStyle, docRowColumnStyle } }, template: `
{{ size }}

modelValue: {{ values[size] }}

`, }), } /** * Stretch each option so the control fills its container with * `isFullWidth`. */ export const FullWidth: Story = { args: { ...Default.args, name: 'segmented-control-full-width', isFullWidth: true, }, parameters: { layout: 'padded', }, decorators: [ () => ({ template: '
', }), ], render: (args) => ({ components: { CpSegmentedControl }, setup() { const value = ref(args.modelValue) watch( () => args.modelValue, (modelValue) => { value.value = modelValue }, ) const boundArgs = computed(() => { const { modelValue: _modelValue, ...rest } = args return rest }) const cellStyle = `${docCellStyle} width: 100%;` return { boundArgs, value, cellStyle, docLabelStyle, docRowColumnStyle } }, template: `
Full width

modelValue: {{ value }}

`, }), } /** * Disable the whole control. */ export const WithDisabledOption: Story = { args: { ...Default.args, name: 'segmented-control-disabled', isDisabled: true, modelValue: undefined, }, render: createRender('Disabled'), } /** * A disabled option can still be the current value. Use this pattern for * read-only pre-selections. */ export const CheckedDisabled: Story = { args: { ...Default.args, name: 'segmented-control-checked-disabled', isDisabled: true, modelValue: 'option1', }, render: createRender('Checked disabled'), } /** * Error state — highlights the control border when validation fails. */ export const Invalid: Story = { args: { ...Default.args, name: 'segmented-control-invalid', isInvalid: true, }, render: createRender('Invalid'), } /** * Vertical orientation */ export const Vertical: Story = { args: { ...Default.args, name: 'segmented-control-vertical', orientation: 'vertical', }, render: createRender('Vertical'), }