import type { Meta, StoryObj } from '@storybook/vue3'; import { ref } from 'vue'; import TitanSelect from './TitanSelect.vue'; const meta = { component: TitanSelect, title: 'UI/TitanSelect', tags: ['autodocs'], argTypes: { modelValue: { control: 'text', description: 'The select\'s current value (v-model)', table: { type: { summary: 'string | number | (string | number)[]' }, }, }, options: { control: 'object', description: 'Array of options (strings or objects with label/value)', table: { type: { summary: 'string[] | SelectOption[]' }, }, }, label: { control: 'text', description: 'Label text displayed above options', table: { type: { summary: 'string' }, }, }, multiple: { control: 'boolean', description: 'Enable multi-select mode', table: { type: { summary: 'boolean' }, defaultValue: { summary: false }, }, }, disabled: { control: 'boolean', description: 'Whether the select is disabled', table: { type: { summary: 'boolean' }, defaultValue: { summary: false }, }, }, required: { control: 'boolean', description: 'Whether the select is required', table: { type: { summary: 'boolean' }, defaultValue: { summary: false }, }, }, error: { control: 'boolean', description: 'Whether the select has an error state', table: { type: { summary: 'boolean' }, defaultValue: { summary: false }, }, }, errorMessage: { control: 'text', description: 'Error message to display', table: { type: { summary: 'string' }, }, }, allowCustom: { control: 'boolean', description: 'Enable custom value entry via text input. The last option becomes a trigger.', table: { type: { summary: 'boolean' }, defaultValue: { summary: false }, }, }, }, } satisfies Meta; export default meta; type Story = StoryObj; /** * Default single-select with string options. */ export const Default: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref(''); return { args, value }; }, template: '', }), args: { label: 'Select a Casket Type', options: ['Wood', 'Metal', 'Cremation', 'Rental'], }, }; /** * Single-select with object options (label/value pairs). */ export const WithObjectOptions: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref(''); return { args, value }; }, template: '', }), args: { label: 'Select a Color', options: [ { label: 'Cherry Wood', value: 'cherry' }, { label: 'Oak', value: 'oak' }, { label: 'Mahogany', value: 'mahogany' }, { label: 'Pine', value: 'pine' }, ], }, }; /** * Multi-select mode for selecting multiple options. */ export const MultiSelect: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref<(string | number)[]>([]); return { args, value }; }, template: '', }), args: { label: 'Select Features', options: ['Silk Interior', 'Velvet Lining', 'Memorial Plaque', 'Custom Engraving'], multiple: true, }, }; /** * Multi-select with initial values. */ export const MultiSelectWithValue: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref<(string | number)[]>(['Silk Interior', 'Memorial Plaque']); return { args, value }; }, template: '', }), args: { label: 'Selected Features', options: ['Silk Interior', 'Velvet Lining', 'Memorial Plaque', 'Custom Engraving'], multiple: true, }, }; /** * Single-select with pre-selected value. */ export const WithValue: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref('Metal'); return { args, value }; }, template: '', }), args: { label: 'Selected Casket Type', options: ['Wood', 'Metal', 'Cremation', 'Rental'], }, }; /** * Required select field. */ export const Required: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref(''); return { args, value }; }, template: '', }), args: { label: 'Casket Type', options: ['Wood', 'Metal', 'Cremation', 'Rental'], required: true, }, }; /** * Select with error state. */ export const WithError: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref(''); return { args, value }; }, template: '', }), args: { label: 'Casket Type', options: ['Wood', 'Metal', 'Cremation', 'Rental'], error: true, errorMessage: 'Please select at least one option', required: true, }, }; /** * Disabled select field. */ export const Disabled: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref('Wood'); return { args, value }; }, template: '', }), args: { label: 'Locked Selection', options: ['Wood', 'Metal', 'Cremation', 'Rental'], disabled: true, }, }; /** * Select with many options. */ export const ManyOptions: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref(''); return { args, value }; }, template: '', }), args: { label: 'Select a State', options: [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', ], }, }; /** * Multi-select with custom value entry. * Click "Other" to reveal input field for adding custom values. */ export const WithCustomInput: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref<(string | number)[]>([]); return { args, value }; }, template: '', }), args: { label: 'Select Features (with custom options)', options: ['Silk Interior', 'Velvet Lining', 'Memorial Plaque', 'Other'], multiple: true, allowCustom: true, }, }; /** * Custom values persist across component remounts. * This demonstrates the fix for the custom value persistence bug. * The component reconstructs custom values from modelValue on mount. */ export const WithCustomValuesPrePopulated: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref<(string | number)[]>(['Reading', 'Photography', 'Hiking']); return { args, value }; }, template: '', }), args: { label: 'Select Hobbies (pre-populated with custom values)', options: ['Reading', 'Sports', 'Music', 'Gaming', 'Cooking', 'Other (specify)'], multiple: true, allowCustom: true, }, }; /** * Interactive playground for all select props. */ export const Playground: Story = { render: (args) => ({ components: { TitanSelect }, setup() { const value = ref(args.multiple ? [] : ''); return { args, value }; }, template: '', }), args: { label: 'Select Options', options: ['Option 1', 'Option 2', 'Option 3', 'Option 4'], multiple: false, disabled: false, required: false, error: false, allowCustom: false, }, };