homework 1: components

This commit is contained in:
2023-07-29 12:47:02 +02:00
parent e0792c6b6f
commit 06afed2826
35 changed files with 1343 additions and 14 deletions

View File

@@ -0,0 +1,94 @@
import { ChangeEvent, ComponentProps, ComponentPropsWithoutRef, forwardRef, useState } from 'react'
import { clsx } from 'clsx'
import s from './text-field.module.scss'
import { VisibilityOff, Eye } from '@/assets'
import { Typography } from '@/components'
export type TextFieldProps = {
onValueChange?: (value: string) => void
containerProps?: ComponentProps<'div'>
labelProps?: ComponentProps<'label'>
errorMessage?: string
label?: string
} & ComponentPropsWithoutRef<'input'>
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
(
{
className,
errorMessage,
placeholder,
type,
containerProps,
labelProps,
label,
onChange,
onValueChange,
...restProps
},
ref
) => {
const [showPassword, setShowPassword] = useState(false)
const isShowPasswordButtonShown = type === 'password'
const finalType = getFinalType(type, showPassword)
function handleChange(e: ChangeEvent<HTMLInputElement>) {
onChange?.(e)
onValueChange?.(e.target.value)
}
const classNames = {
root: clsx(s.root, containerProps?.className),
fieldContainer: clsx(s.fieldContainer),
field: clsx(s.field, !!errorMessage && s.error, className),
label: clsx(s.label, labelProps?.className),
error: clsx(s.error),
}
return (
<div className={classNames.root}>
{label && (
<Typography variant="body2" as="label" className={classNames.label}>
{label}
</Typography>
)}
<div className={classNames.fieldContainer}>
<input
className={classNames.field}
placeholder={placeholder}
ref={ref}
type={finalType}
onChange={handleChange}
{...restProps}
/>
{isShowPasswordButtonShown && (
<button
className={s.showPassword}
type={'button'}
onClick={() => setShowPassword(prev => !prev)}
>
{showPassword ? <VisibilityOff /> : <Eye />}
</button>
)}
</div>
<Typography variant="error" className={classNames.error}>
{errorMessage}
</Typography>
</div>
)
}
)
function getFinalType(type: ComponentProps<'input'>['type'], showPassword: boolean) {
if (type === 'password' && showPassword) {
return 'text'
}
return type
}