import type { Meta, StoryObj } from '@storybook/vue3-vite' import { ref } from 'vue' import CpInput from '@/components/CpInput.vue' import CpSelect from '@/components/CpSelect.vue' import { docCellStyle, docLabelStyle, docRowColumnStyle } from '@/stories/documentationStyles' const selectSizes = ['sm', 'md', 'lg'] as const const selectStackStyle = `${docCellStyle} width: 100%; max-width: 360px;` const meta = { title: 'Molecules/CpSelect', component: CpSelect, argTypes: { modelValue: { control: 'text', description: 'The selected value', }, label: { control: 'text', description: 'Label text for the select', }, options: { control: 'object', description: 'Array of options to display', }, defaultValue: { control: 'text', description: 'Default option text', }, hideDefaultValue: { control: 'boolean', description: 'Whether to hide the default option', }, required: { control: 'boolean', description: 'Whether the field is required', }, disabled: { control: 'boolean', description: 'Whether the field is disabled', }, isInvalid: { control: 'boolean', description: 'Whether the field is in an invalid state', }, errorMessage: { control: 'text', description: 'Error message to display', }, size: { control: 'select', options: selectSizes, description: 'The size of the select', }, autocomplete: { control: 'text', description: 'Autocomplete attribute value', }, name: { control: 'text', description: 'Name attribute for the select', }, help: { control: 'text', description: 'Help text to display', }, tooltip: { control: 'text', description: 'Tooltip text to display', }, }, } satisfies Meta export default meta type Story = StoryObj const sampleOptions = [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, { value: '4', label: 'Option 4' }, ] /** * Default select. Use the controls to experiment with each prop in isolation. */ export const Default: Story = { args: { label: 'Select Label', options: sampleOptions, defaultValue: 'Select an option', hideDefaultValue: false, required: false, disabled: false, isInvalid: false, errorMessage: '', size: 'md', autocomplete: 'on', name: 'select-field', }, render: (args) => ({ components: { CpSelect }, setup() { const value = ref('3') return { args, value } }, template: `
`, }), } /* -------------------------------------------------------------------------- */ /* Sizes */ /* -------------------------------------------------------------------------- */ /** * All sizes rendered side by side, from `sm` to `lg`. */ export const Sizes: Story = { parameters: { controls: { disable: true, }, }, args: { ...Default.args, }, render: () => ({ components: { CpSelect }, setup() { const value = ref('3') return { value, sampleOptions, selectSizes, docRowColumnStyle, selectStackStyle, docLabelStyle } }, template: `
{{ size }}
`, }), } /* -------------------------------------------------------------------------- */ /* States */ /* -------------------------------------------------------------------------- */ /** * Default, required, disabled and invalid states compared side by side. */ export const States: Story = { parameters: { controls: { disable: true, }, }, args: { ...Default.args, }, render: () => ({ components: { CpSelect }, setup() { const value = ref('3') return { value, sampleOptions, docRowColumnStyle, selectStackStyle, docLabelStyle } }, template: `
Default
Required
Disabled
Invalid
`, }), } /* -------------------------------------------------------------------------- */ /* Misc */ /* -------------------------------------------------------------------------- */ /** * Hides the default "Select an option" entry. Use this when an option must * always be picked. */ export const WithoutDefaultOption: Story = { args: { ...Default.args, hideDefaultValue: true, }, } /** * Long option labels are truncated with an ellipsis. */ export const WithLongOptions: Story = { args: { ...Default.args, options: [ { value: '1', label: 'This is a very long option text that might need to be truncated' }, { value: '2', label: 'Another long option that demonstrates text truncation' }, { value: '3', label: 'Short option' }, { value: '4', label: 'Yet another long option to show how the select handles long text' }, ], }, } /** * Combines a select and an input on the same line — for example a currency * and an amount. */ export const NextToInput: Story = { args: { ...Default.args, hideDefaultValue: true, }, render: (args) => ({ components: { CpSelect, CpInput }, setup() { const value = ref('') const textValue = ref('') return { args, value, textValue } }, template: `
`, }), }