import type { Meta, StoryObj } from '@storybook/react' import * as React from 'react' import { within, userEvent, expect } from 'storybook/test' import { SvgPasswordBlock, SvgUserCircleSingle } from '@chainlink/blocks-icons' import { createSizeDecorator } from '../../utils/decorators' import { Card } from '../Card' import { Field, FieldLabel, FieldHelper } from '../Field' import { FieldInput } from './FieldInput' import { INPUT_SIZE_OPTIONS, INPUT_WIDTH_OPTIONS } from './Input' const FIELD_INPUT_TYPE_OPTIONS = [ 'text', 'password', 'email', 'number', 'tel', 'url', 'search', ] satisfies React.HTMLInputTypeAttribute[] const meta = { title: 'Form/Input/FieldInput', component: FieldInput, decorators: [createSizeDecorator('XS')], argTypes: { width: { control: 'select', options: INPUT_WIDTH_OPTIONS, table: { type: { summary: INPUT_WIDTH_OPTIONS.map((value) => value).join(' | '), }, defaultValue: { summary: 'responsive' }, }, }, size: { control: { type: 'select', }, options: INPUT_SIZE_OPTIONS, table: { type: { summary: INPUT_SIZE_OPTIONS.map((value) => value).join(' | ') }, defaultValue: { summary: 'default' }, }, }, type: { control: 'select', options: FIELD_INPUT_TYPE_OPTIONS, defaultValue: 'text', description: 'Specifies the type of the input element.', table: { type: { summary: 'string' }, defaultValue: { summary: 'text' }, }, }, placeholder: { control: 'text', description: 'Placeholder text for the input field.', table: { type: { summary: 'string' }, }, }, disabled: { control: 'boolean', defaultValue: false, description: 'Disables the input if set to true.', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, isLoading: { control: 'boolean', defaultValue: false, description: 'Shows a loading spinner and disables other state icons.', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, isValid: { control: 'boolean', defaultValue: false, description: 'Shows a valid checkmark icon.', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, isInvalid: { control: 'boolean', defaultValue: false, description: 'Shows an invalid error icon.', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, required: { control: 'boolean', defaultValue: false, description: 'Marks the input as required.', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, clearable: { control: 'boolean', description: 'When false, the hover clear control is not shown (default true).', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'true' }, }, }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { render: (args) => , args: { placeholder: 'Placeholder', type: 'text', clearable: true, }, } export const NotClearable: Story = { render: (args) => ( Read-only style value ), args: { defaultValue: 'Value without hover clear', clearable: false, }, parameters: { docs: { description: { story: 'Set clearable to false when the field value should not expose the hover clear action.', }, }, }, play: async ({ canvasElement }) => { await expect( canvasElement.querySelector('[aria-label="Clear input"]'), ).toBeNull() }, } export const Small: Story = { render: (args) => ( Username ), } export const LeftIcon: Story = { render: (args) => ( ), } export const Disabled: Story = { render: (args) => ( Disabled Input ), args: { disabled: true, type: 'text', }, } export const WithError: Story = { render: (args) => , args: { error: true, }, } export const WithErrorMessage: Story = { render: (args) => ( Email Address ), args: { type: 'email', error: 'Please enter a valid email address.', }, } export const WithErrorMessageAndLeftIcon: Story = { render: (args) => ( Email Address ), args: { type: 'email', error: 'Please enter a valid email address.', }, } export const LoadingState: Story = { render: (args) => ( Search ), args: { isLoading: true, type: 'search', }, } export const ValidState: Story = { render: (args) => ( Email Address Email address is valid! ), args: { type: 'email', isValid: true, value: 'user@example.com', }, } export const InvalidState: Story = { render: (args) => ( Email Address ), args: { type: 'email', isInvalid: true, }, } export const Number: Story = { render: (args) => ( Age Must be 18 or older ), args: { type: 'number', min: 18, }, } export const Email: Story = { render: (args) => ( Email Address We'll use this to contact you about your account. ), args: { type: 'email', autoComplete: 'email', }, } export const Widths: Story = { render: (args) => ( Responsive Width (default) Full Width Hug Content ), args: { type: 'text', }, } export const Clearable: Story = { render: (args) => { function ClearableDemo() { const [value, setValue] = React.useState('Hover to see clear button') return ( Clearable Input Hover over the input to see the clear button setValue(e.target.value)} /> ) } return }, } export const PasswordHidden: Story = { render: (args) => { return ( Password Type in the password field to see the show/hide toggle icon ) }, args: { type: 'password', defaultValue: 'password123', }, } export const PasswordShown: Story = { render: (args) => { return ( Password Password is shown (toggle button was clicked automatically) ) }, args: { type: 'password', defaultValue: 'password123', }, play: async ({ canvasElement }) => { const canvas = within(canvasElement) // Wait for the password toggle button to appear const toggleButton = await canvas.findByRole('button', { name: /show password/i, }) // Click the toggle button to show the password await userEvent.click(toggleButton) }, } export const PasswordWithLeftIcon: Story = { render: (args) => { return ( Password with Left Icon Type in the password field to see the show/hide toggle icon ) }, args: { type: 'password', defaultValue: 'password123', }, } export const PasswordWithLeftIconSmall: Story = { render: (args) => { return ( Password with Left Icon Type in the password field to see the show/hide toggle icon ) }, args: { type: 'password', defaultValue: 'password123', }, }