Аргументы storybook
У меня есть компонент input:
import clsx from 'clsx'
import styles from './input.module.scss'
import {ChangeEvent, ComponentPropsWithoutRef, ElementRef, forwardRef, useState} from 'react'
import {EyeOutline, EyeOffOutline, SearchOutline} from '@/assets'
import {Typography} from '@/components'
export type InputProps = {
errorMessage?: string
label?: string
variant?: 'text' | 'password' | 'search',
} & ComponentPropsWithoutRef<'input'>
/**
* Input component with optional search and password toggle functionality.
*
* @component
* @param {Object} props - The component props.
* @param {string} [props.className] - Additional class name for styling the component.
* @param {string} [props.errorMessage] - Error message displayed below the input field.
* @param {string} [props.label] - Label text for the input field.
* @param {boolean} [props.search] - If true, a search icon is displayed inside the input field.
* @param {boolean} [props.disabled] - If true, the input field is disabled.
* @param {string} [props.type] - The type of the input field (e.g., 'text' or 'password').
* @param {string | number} [props.value] - The current value of the input field.
* @param {function(ChangeEvent<HTMLInputElement>): void} [props.onChange] - Callback function invoked when the input value changes.
* @param {React.Ref<HTMLInputElement>} ref - Reference to the input element.
* @returns {JSX.Element} The Input component.
*/
export const Input = forwardRef<ElementRef<'input'>, InputProps>(
(
{
label,
variant = 'text',
errorMessage,
className,
onChange,
disabled,
value,
type,
placeholder,
...rest
},
ref
) => {
const [showPassword, setShowPassword] = useState(false)
const isPassword = variant === 'password'
const changedType = type || (isPassword && !showPassword ? 'password' : 'text')
const isSearch = variant === 'search'
const classNames = {
wrapper: styles.wrapper,
label: clsx(styles.label, disabled && styles.disabledLabel),
container: styles.container,
input: clsx(
styles.input,
errorMessage && styles.error,
isSearch && styles.search,
isPassword && styles.password,
className
),
eyeBtn: styles.eyeButton,
search: clsx(
styles.searchIcon,
disabled && styles.disabledSearch,
errorMessage && styles.errorSearch
),
} as const
const onChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
onChange?.(e)
}
const showPasswordHandler = () => {
setShowPassword(prev => !prev)
}
return (
<div className={classNames.wrapper}>
{label && (
<Typography className={classNames.label} variant="text14">
{label}
</Typography>
)}
<div className={classNames.container}>
{isSearch && <SearchOutline height={24} width={24} className={classNames.search}/>}
<input
className={classNames.input}
onChange={onChangeHandler}
placeholder={placeholder}
type={changedType}
value={value}
disabled={disabled}
ref={ref}
{...rest}
/>
{isPassword && (
<button
className={classNames.eyeBtn}
disabled={disabled}
onClick={showPasswordHandler}
type={'button'}
>
{showPassword ? (
<EyeOffOutline height={24} width={24}/>
) : (
<EyeOutline height={24} width={24}/>
)}
</button>
)}
</div>
{errorMessage && (
<Typography variant="text14" color={'var(--danger-500)'}>
{errorMessage}
</Typography>
)}
</div>
)
}
)
вот его история для сторибука:
import type { Meta, StoryObj } from '@storybook/react'
import { Input } from './input'
import { useState } from 'react'
const meta = {
component: Input,
tags: ['autodocs'],
argTypes: {
type: {
control: { type: 'select' },
options: ['password', 'text'],
},
},
args: {
disabled: false,
label: 'Label',
value: '[email protected]',
},
title: 'Components/Input',
} satisfies Meta<typeof Input>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {},
}
export const Disabled: Story = {
args: {
disabled: true,
},
}
export const Password: Story = {
args: {
},
render: args => {
const { disabled, errorMessage } = args
const [value, setValue] = useState('')
const [type, setType] = useState<'text' | 'password'>('password')
const togglePasswordVisibility = () => {
setType(prevType => (prevType === 'password' ? 'text' : 'password'))
}
return (
<Input
placeholder={'Password'}
variant={'password'}
disabled={disabled}
errorMessage={errorMessage}
value={value}
type={type}
onChange={e => setValue(e.target.value)}
onClick={togglePasswordVisibility} // Ensure this event handler is not conflicting with button click.
/>
)
},
}
export const Search: Story = {
args: {},
render: args => {
const { disabled, errorMessage } = args
const [value, setValue] = useState('')
return (
<Input
variant={'search'}
disabled={disabled}
errorMessage={errorMessage}
value={value}
onChange={e => setValue(e.target.value)}
/>
)
},
}
export const InputWithError: Story = {
args: {
errorMessage: 'Error',
},
}
Как в сторибуке при варианте инпута password менять менять и аргумент type который есть в интерфейсе storybook:
argTypes: {
type: {
control: { type: 'select' },
options: ['password', 'text'],
},
},
Интерфейс сторибука где type должен меняться когда нажимаем на иконку