import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { useState } from 'react'; import { SearchableSelect, type SearchableSelectProps } from '../components/ui/searchable-select'; import { SquareAvatar } from '../components/ui/square-avatar'; import { MonitorIcon, UserPlusIcon } from '../components/icons-v2-generated'; const meta = { title: 'UI/SearchableSelect', component: SearchableSelect, argTypes: { align: { control: 'select', options: ['start', 'center', 'end'], }, isLoading: { control: 'boolean' }, disabled: { control: 'boolean' }, }, parameters: { docs: { description: { component: 'Select-style dropdown whose first item is a search field filtering the option list - ' + 'the ticket assignee "Search users..." pattern generalized for any entity. The default ' + 'trigger matches SelectTrigger; pass a custom trigger for icon-button use cases ' + '(AssigneeDropdown compact is built on this component).', }, }, }, } satisfies Meta; export default meta; type Story = StoryObj; const DEVICES = [ { value: '1', label: "John's MacBook Pro" }, { value: '2', label: 'Design-Studio-iMac' }, { value: '3', label: 'Front-Desk-PC' }, { value: '4', label: 'QA-Windows-11' }, { value: '5', label: 'Server-Room-Linux' }, { value: '6', label: "Olivia's ThinkPad" }, { value: '7', label: 'Warehouse-Scanner-01' }, { value: '8', label: 'Reception-Tablet' }, ]; function ControlledSelect(props: Partial) { const [value, setValue] = useState(props.value ?? null); return ( ); } /** Default select-like trigger; the search input is the first dropdown item. */ export const DeviceSelect: Story = { args: { options: DEVICES, onValueChange: () => {}, placeholder: 'Select Device', searchPlaceholder: 'Search for Device', emptyText: 'No devices found', }, render: args => (
), }; /** Options can carry a leading icon/avatar node. */ export const WithOptionIcons: Story = { args: { options: DEVICES.map(d => ({ ...d, icon: , })), onValueChange: () => {}, placeholder: 'Select Device', searchPlaceholder: 'Search for Device', emptyText: 'No devices found', }, render: args => (
), }; /** Custom icon-button trigger - the AssigneeDropdown compact use case. */ export const CustomTrigger: Story = { args: { options: ['Roman Smith', 'Mike Johnson', 'Olivia Chen', 'Ava Martinez'].map((name, i) => ({ value: String(i + 1), label: name, icon: , })), onValueChange: () => {}, searchPlaceholder: 'Search users...', emptyText: 'No users found', align: 'end', contentClassName: 'w-72', trigger: ( ), }, render: args => (
), }; /** Loading state shown inside the dropdown. */ export const Loading: Story = { args: { options: [], onValueChange: () => {}, placeholder: 'Select Device', searchPlaceholder: 'Search for Device', isLoading: true, }, render: args => (
), };