import * as React from 'react'; import { cn } from '@/lib/utils'; import { Eye, EyeOff, Search } from 'lucide-react'; import { useState } from 'react'; import { Button } from './button'; export interface InputProps extends Omit, 'prefix'> { value?: string | number | readonly string[] | undefined; prefix?: React.ReactNode; suffix?: React.ReactNode; } const Input = React.forwardRef( ({ className, type, value, onChange, prefix, suffix, ...props }, ref) => { const isControlled = value !== undefined; const { defaultValue, ...restProps } = props; const inputValue = isControlled ? value : defaultValue; const [showPassword, setShowPassword] = useState(false); const handleChange: React.ChangeEventHandler = (e) => { if (type === 'number') { const numValue = e.target.value === '' ? '' : Number(e.target.value); onChange?.({ ...e, target: { ...e.target, value: numValue, }, } as React.ChangeEvent); } else { onChange?.(e); } }; const isPasswordInput = type === 'password'; const inputEl = ( ); if (prefix || suffix || isPasswordInput) { return (
{prefix && ( {prefix} )} {inputEl} {suffix && ( {suffix} )} {isPasswordInput && ( )}
); } return inputEl; }, ); Input.displayName = 'Input'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ExpandedInputProps extends InputProps {} const ExpandedInput = Input; const SearchInput = (props: InputProps) => { return } />; }; type Value = string | readonly string[] | number | undefined; export const InnerBlurInput = React.forwardRef< HTMLInputElement, InputProps & { value: Value; onChange(value: Value): void } >(({ value, onChange, ...props }, ref) => { const [val, setVal] = React.useState(); const handleChange: React.ChangeEventHandler = React.useCallback((e) => { setVal(e.target.value); }, []); const handleBlur: React.FocusEventHandler = React.useCallback( (e) => { onChange?.(e.target.value); }, [onChange], ); React.useEffect(() => { setVal(value); }, [value]); return ( ); }); if (process.env.NODE_ENV !== 'production') { InnerBlurInput.whyDidYouRender = true; } export const BlurInput = React.memo(InnerBlurInput); export { ExpandedInput, Input, SearchInput }; type NumberInputProps = { onChange?(value: number): void } & InputProps; export const NumberInput = React.forwardRef< HTMLInputElement, NumberInputProps & { value: Value; onChange(value: Value): void } >(function NumberInput({ onChange, ...props }, ref) { return ( { const value = ev.target.value; onChange?.(value === '' ? 0 : Number(value)); // convert to number }} {...props} ref={ref} > ); });