import type { Meta, StoryObj } from '@storybook/react' import type { ComponentType } from 'react' import { expect, fireEvent, userEvent, waitFor, within } from 'storybook/test' import { Svg3DPerspectiveGrid } from '@chainlink/blocks-icons' import type { LegacyComboboxProps } from './LegacyCombobox' import { LegacyCombobox, LegacyComboboxContent, LegacyComboboxTrigger, LegacyComboboxValue, OptionRow, } from './LegacyCombobox' type LegacyComboboxStoryProps = Omit type DemoOption = { value: string label: string src: string } const meta = { component: LegacyCombobox as ComponentType, title: 'Form/LegacyCombobox', subcomponents: { LegacyComboboxTrigger, LegacyComboboxValue, LegacyComboboxContent, OptionRow, }, argTypes: { size: { control: { type: 'select' }, options: ['default', 'sm'], table: { type: { summary: 'default | sm' }, defaultValue: { summary: 'default' }, }, }, disabled: { control: 'boolean', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, clearable: { control: 'boolean', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'true' }, }, }, placeholder: { control: 'text', }, }, args: { size: 'default', disabled: false, clearable: true, placeholder: 'Select network...', }, } satisfies Meta export default meta const demoOptions: DemoOption[] = [ { value: 'arbitrum', label: 'Arbitrum', src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/arbitrum.svg?auto=compress%2Cformat', }, { value: 'avalanche', label: 'Avalanche', src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/avalanche.svg?auto=compress%2Cformat', }, { value: 'base', label: 'Base', src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/base.svg?auto=compress%2Cformat', }, { value: 'ethereum', label: 'Ethereum', src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/ethereum.svg?auto=compress%2Cformat', }, { value: 'solana', label: 'Solana', src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/solana.svg?auto=compress%2Cformat', }, { value: 'polygon', label: 'Polygon', src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/polygon.svg?auto=compress%2Cformat', }, ] type Story = StoryObj export const Default: Story = { render: (_args) => { const options = [ { value: 'arbitrum', label: 'Arbitrum' }, { value: 'avalanche', label: 'Avalanche' }, { value: 'base', label: 'Base' }, { value: 'ethereum', label: 'Ethereum' }, ] return ( {options.map((option) => ( {option.label} ))} ) }, parameters: { test: { dangerouslyIgnoreUnhandledErrors: true, }, }, } export const SmallSize: Story = { render: (_args) => { const options = [ { value: 'arbitrum', label: 'Arbitrum' }, { value: 'avalanche', label: 'Avalanche' }, { value: 'base', label: 'Base' }, { value: 'ethereum', label: 'Ethereum' }, ] return ( {options.map((option) => ( {option.label} ))} ) }, } export const WithIcons: Story = { render: (_args) => { const options = [ { value: 'arbitrum', label: 'Arbitrum' }, { value: 'avalanche', label: 'Avalanche' }, { value: 'base', label: 'Base' }, { value: 'ethereum', label: 'Ethereum' }, ] return ( {options.map((option) => ( {option.label} ))} ) }, } export const OpenState: Story = { render: (args: LegacyComboboxStoryProps, context: any) => { const openProp = context.viewMode === 'story' ? { defaultOpen: true } : {} return ( {demoOptions.map((option) => ( {option.label} ))} ) }, args: {}, play: async ({ canvasElement }) => { const canvas = within(canvasElement) const comboboxValue = canvasElement.querySelector( '[data-slot="combobox-value"]', ) as HTMLElement // Step 1: Search for "Solana" (menu is already open via defaultOpen) const searchInput = await canvas.findByPlaceholderText('Search...') await userEvent.type(searchInput, 'Solana') // Step 2: Select Solana option (menu closes) const solanaOption = await canvas.findByRole('option', { name: /Solana/i }) await userEvent.click(solanaOption) // Verify Solana is selected (displayed in combobox-value span) await waitFor( async () => { await expect(comboboxValue).toHaveTextContent('Solana') }, { timeout: 3000 }, ) // Step 3: Click the clear icon (using fireEvent to bypass pointer-events check in test) const clearButton = canvasElement.querySelector( '[data-slot="combobox-clear"]', ) as HTMLElement await fireEvent.click(clearButton) // Step 4: Verify there is no value (placeholder is shown) await waitFor( async () => { await expect(comboboxValue).toHaveTextContent('Select network...') }, { timeout: 3000 }, ) // Step 5: Leave open for visual regression await userEvent.click(comboboxValue) await userEvent.clear(searchInput) }, } export const WithImages: Story = { render: (args: LegacyComboboxStoryProps, context: any) => { const openProp = context.viewMode === 'story' ? { defaultOpen: true } : {} const optionsWithIcons = demoOptions return ( {optionsWithIcons.map((option) => ( {option.label} ))} ) }, args: {}, } export const ClearButton: Story = { render: (args: LegacyComboboxStoryProps) => { const optionsWithIcons = demoOptions return (
{optionsWithIcons.map((option) => ( {option.label} ))}
) }, args: { value: 'ethereum' }, } export const Disabled: Story = { render: (args: LegacyComboboxStoryProps) => { return ( {demoOptions.map((option) => ( {option.label} ))} ) }, args: { disabled: true, defaultOpen: false }, } export const NonClearable: Story = { render: (args: LegacyComboboxStoryProps) => { return ( {demoOptions.map((option) => ( {option.label} ))} ) }, args: { clearable: false, value: 'ethereum' }, }