This commit is contained in:
@@ -10,94 +10,96 @@ const meta = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: 'Text input field with optional label, validation state, size/layout variants, and password visibility toggle.'
|
||||
}
|
||||
}
|
||||
component:
|
||||
'Text input field with optional label, validation state, size/layout variants, and password visibility toggle.',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
label: {
|
||||
description: 'Label text shown above (stacked) or on the left (inline).',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
placeholder: {
|
||||
description: 'Input placeholder text.',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
type: {
|
||||
description: 'Native input type.',
|
||||
options: ['text', 'password', 'email'],
|
||||
control: 'inline-radio',
|
||||
table: { type: { summary: "'text' | 'password' | 'email'" } }
|
||||
table: { type: { summary: "'text' | 'password' | 'email'" } },
|
||||
},
|
||||
size: {
|
||||
description: 'Input size.',
|
||||
options: ['sm', 'md', 'lg', 'full'],
|
||||
control: 'inline-radio',
|
||||
table: { type: { summary: "'sm' | 'md' | 'lg' | 'full'" } }
|
||||
table: { type: { summary: "'sm' | 'md' | 'lg' | 'full'" } },
|
||||
},
|
||||
layout: {
|
||||
description: 'Label/input layout mode.',
|
||||
options: ['stacked', 'inline'],
|
||||
control: 'inline-radio',
|
||||
table: { type: { summary: "'stacked' | 'inline'" } }
|
||||
table: { type: { summary: "'stacked' | 'inline'" } },
|
||||
},
|
||||
value: {
|
||||
description: 'Controlled input value.',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
name: {
|
||||
description: 'Native input `name` attribute.',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
disabled: {
|
||||
description: 'Disables the input.',
|
||||
control: 'boolean',
|
||||
table: { type: { summary: 'boolean' } }
|
||||
table: { type: { summary: 'boolean' } },
|
||||
},
|
||||
required: {
|
||||
description: 'Sets the native HTML `required` attribute.',
|
||||
control: 'boolean',
|
||||
table: { type: { summary: 'boolean' } }
|
||||
table: { type: { summary: 'boolean' } },
|
||||
},
|
||||
error: {
|
||||
description: 'Validation message shown below the field.',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
rightIcon: {
|
||||
description: 'Optional trailing icon node (ignored for password type because toggle icon is used).',
|
||||
description:
|
||||
'Optional trailing icon node (ignored for password type because toggle icon is used).',
|
||||
control: false,
|
||||
table: { type: { summary: 'ReactNode' } }
|
||||
table: { type: { summary: 'ReactNode' } },
|
||||
},
|
||||
className: {
|
||||
description: 'Extra CSS classes for the outer wrapper.',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
inputClassName: {
|
||||
description: 'Extra CSS classes for the `<input>` element.',
|
||||
control: 'text',
|
||||
table: { type: { summary: 'string' } }
|
||||
table: { type: { summary: 'string' } },
|
||||
},
|
||||
onChange: {
|
||||
description: 'Change handler callback.',
|
||||
action: 'changed',
|
||||
table: { type: { summary: 'ChangeEventHandler<HTMLInputElement>' } }
|
||||
table: { type: { summary: 'ChangeEventHandler<HTMLInputElement>' } },
|
||||
},
|
||||
onBlur: {
|
||||
description: 'Blur handler callback.',
|
||||
control: false,
|
||||
table: { type: { summary: 'FocusEventHandler<HTMLInputElement>' } }
|
||||
table: { type: { summary: 'FocusEventHandler<HTMLInputElement>' } },
|
||||
},
|
||||
inputRef: {
|
||||
description: 'Ref forwarded to the native `<input>` element.',
|
||||
control: false,
|
||||
table: { type: { summary: 'Ref<HTMLInputElement>' } }
|
||||
}
|
||||
table: { type: { summary: 'Ref<HTMLInputElement>' } },
|
||||
},
|
||||
},
|
||||
args: {
|
||||
label: 'Email',
|
||||
@@ -105,8 +107,8 @@ const meta = {
|
||||
placeholder: 'name@example.com',
|
||||
value: '',
|
||||
size: 'md',
|
||||
layout: 'stacked'
|
||||
}
|
||||
layout: 'stacked',
|
||||
},
|
||||
} satisfies Meta<typeof InputField>;
|
||||
|
||||
export default meta;
|
||||
@@ -116,7 +118,7 @@ export const Text: Story = {
|
||||
args: {
|
||||
type: 'text',
|
||||
label: 'Title',
|
||||
placeholder: 'Write a title'
|
||||
placeholder: 'Write a title',
|
||||
},
|
||||
render: (args) => {
|
||||
const [value, setValue] = useState('Storybook integration');
|
||||
@@ -130,14 +132,14 @@ export const Text: Story = {
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const PasswordWithToggle: Story = {
|
||||
args: {
|
||||
type: 'password',
|
||||
label: 'Password',
|
||||
placeholder: 'Type a strong password'
|
||||
placeholder: 'Type a strong password',
|
||||
},
|
||||
render: (args) => {
|
||||
const [value, setValue] = useState('pa55word');
|
||||
@@ -151,7 +153,7 @@ export const PasswordWithToggle: Story = {
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const InlineWithIcon: Story = {
|
||||
@@ -160,7 +162,7 @@ export const InlineWithIcon: Story = {
|
||||
label: 'Search',
|
||||
layout: 'inline',
|
||||
size: 'sm',
|
||||
rightIcon: <MagnifyingGlassIcon className="h-4 w-4 ui-body-secondary" />
|
||||
rightIcon: <MagnifyingGlassIcon className="h-4 w-4 ui-body-secondary" />,
|
||||
},
|
||||
render: (args) => {
|
||||
const [value, setValue] = useState('posts');
|
||||
@@ -174,7 +176,7 @@ export const InlineWithIcon: Story = {
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const Error: Story = {
|
||||
@@ -182,8 +184,8 @@ export const Error: Story = {
|
||||
type: 'email',
|
||||
label: 'Email',
|
||||
value: 'invalid.mail',
|
||||
error: 'Enter a valid email address'
|
||||
}
|
||||
error: 'Enter a valid email address',
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
@@ -191,25 +193,45 @@ export const Disabled: Story = {
|
||||
type: 'text',
|
||||
label: 'Read only field',
|
||||
value: 'Locked content',
|
||||
disabled: true
|
||||
}
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const SizeMatrix: Story = {
|
||||
args: {
|
||||
type: 'text',
|
||||
label: 'Name',
|
||||
placeholder: 'Enter value'
|
||||
placeholder: 'Enter value',
|
||||
},
|
||||
render: (args) => {
|
||||
const [value, setValue] = useState('Beatrice');
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-3">
|
||||
<InputField {...args} value={value} size="sm" onChange={(event) => setValue(event.target.value)} />
|
||||
<InputField {...args} value={value} size="md" onChange={(event) => setValue(event.target.value)} />
|
||||
<InputField {...args} value={value} size="lg" onChange={(event) => setValue(event.target.value)} />
|
||||
<InputField {...args} value={value} size="full" onChange={(event) => setValue(event.target.value)} />
|
||||
<InputField
|
||||
{...args}
|
||||
value={value}
|
||||
size="sm"
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>
|
||||
<InputField
|
||||
{...args}
|
||||
value={value}
|
||||
size="md"
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>
|
||||
<InputField
|
||||
{...args}
|
||||
value={value}
|
||||
size="lg"
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>
|
||||
<InputField
|
||||
{...args}
|
||||
value={value}
|
||||
size="full"
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user