2025-03-16 00:56:02 +07:00
|
|
|
import {
|
|
|
|
|
DetailedHTMLProps,
|
|
|
|
|
FC,
|
|
|
|
|
InputHTMLAttributes,
|
|
|
|
|
ReactElement,
|
2025-03-27 07:19:46 +07:00
|
|
|
useState,
|
2025-03-16 00:56:02 +07:00
|
|
|
} from 'react';
|
2025-03-27 07:19:46 +07:00
|
|
|
import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons'; // Import Ant Design icons
|
2025-03-16 00:56:02 +07:00
|
|
|
import { cn } from '@imphnen-frontend-service/utils';
|
2025-03-27 07:19:46 +07:00
|
|
|
import { Button } from '../button';
|
2025-03-16 00:56:02 +07:00
|
|
|
|
2025-11-25 01:47:56 +07:00
|
|
|
type TInputType =
|
|
|
|
|
| 'text'
|
|
|
|
|
| 'email'
|
|
|
|
|
| 'number'
|
|
|
|
|
| 'password'
|
|
|
|
|
| 'file'
|
|
|
|
|
| 'date'
|
|
|
|
|
| 'time';
|
2025-03-16 00:56:02 +07:00
|
|
|
type TInputSize = 'sm' | 'md' | 'lg';
|
2025-11-25 01:47:56 +07:00
|
|
|
type Width = 'standard' | 'custom';
|
2025-03-16 00:56:02 +07:00
|
|
|
|
|
|
|
|
type TInputProps = Omit<
|
|
|
|
|
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
|
|
|
|
|
'size' | 'type'
|
|
|
|
|
> & {
|
|
|
|
|
type?: TInputType;
|
|
|
|
|
size?: TInputSize;
|
2025-04-09 12:59:33 +07:00
|
|
|
widthform?: Width;
|
2025-03-27 07:19:46 +07:00
|
|
|
disabled?: boolean;
|
2025-03-16 00:56:02 +07:00
|
|
|
};
|
|
|
|
|
|
2025-03-27 07:19:46 +07:00
|
|
|
const sizeClasses: Record<TInputSize, { textSize: string; iconSize: string }> =
|
|
|
|
|
{
|
2025-11-26 15:51:38 +07:00
|
|
|
sm: { textSize: 'text-[10px] h-[28px]', iconSize: 'text-[10px]' },
|
|
|
|
|
md: { textSize: 'text-[12px] h-[30px]', iconSize: 'text-[12px]' },
|
|
|
|
|
lg: { textSize: 'text-[15px] h-[34px]', iconSize: 'text-[15px]' },
|
2025-03-27 07:19:46 +07:00
|
|
|
};
|
2025-03-16 00:56:02 +07:00
|
|
|
|
|
|
|
|
const disabledClass = 'opacity-50 hover:border-neutral-200 cursor-not-allowed';
|
|
|
|
|
|
|
|
|
|
export const Input: FC<TInputProps> = ({
|
2025-03-27 05:25:02 +07:00
|
|
|
type = 'text',
|
2025-03-27 07:19:46 +07:00
|
|
|
size = 'md',
|
2025-03-16 00:56:02 +07:00
|
|
|
placeholder = 'Placeholder',
|
2025-11-25 01:47:56 +07:00
|
|
|
widthform = 'standard',
|
2025-03-16 00:56:02 +07:00
|
|
|
disabled,
|
|
|
|
|
className,
|
|
|
|
|
...rest
|
|
|
|
|
}): ReactElement => {
|
2025-03-27 07:19:46 +07:00
|
|
|
const [showPassword, setShowPassword] = useState(false); // State for password visibility
|
|
|
|
|
|
2025-04-03 06:10:07 +07:00
|
|
|
const togglePasswordVisibility = (e: React.FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
2025-03-27 07:19:46 +07:00
|
|
|
if (!disabled) setShowPassword((prev) => !prev);
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-16 00:56:02 +07:00
|
|
|
const mergedClassName = cn(
|
2025-11-25 01:47:56 +07:00
|
|
|
`px-[12px] py-[8px] text-neutral-800 bg-white placeholder:text-neutral-300 border border-neutral-200 hover:border-blue-300 focus:outline-1 focus:outline-blue-500 rounded-md font-bai-jamjuree w-full ${
|
|
|
|
|
widthform === 'standard' ? 'min-w-70' : ''
|
|
|
|
|
}`,
|
2025-03-27 07:19:46 +07:00
|
|
|
sizeClasses[size].textSize,
|
2025-03-16 00:56:02 +07:00
|
|
|
disabled && disabledClass,
|
|
|
|
|
className
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
2025-03-27 16:55:54 +07:00
|
|
|
<div className="relative flex items-center">
|
2025-03-27 07:19:46 +07:00
|
|
|
<input
|
|
|
|
|
className={mergedClassName}
|
|
|
|
|
type={type === 'password' && showPassword ? 'text' : type}
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
{...rest}
|
|
|
|
|
/>
|
|
|
|
|
{type === 'password' && (
|
2025-11-25 01:47:56 +07:00
|
|
|
<div className="absolute end-0 px-3 h-full flex items-center">
|
2025-03-27 07:19:46 +07:00
|
|
|
<Button
|
2025-04-03 06:10:07 +07:00
|
|
|
type="button"
|
2025-03-27 07:19:46 +07:00
|
|
|
variant="text"
|
|
|
|
|
size={size}
|
|
|
|
|
onClick={togglePasswordVisibility}
|
|
|
|
|
className={cn(
|
2025-11-25 01:47:56 +07:00
|
|
|
'relative aspect-square -me-2 p-1.5',
|
2025-03-27 07:19:46 +07:00
|
|
|
sizeClasses[size].iconSize,
|
|
|
|
|
disabled && 'cursor-not-allowed'
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
{showPassword ? (
|
|
|
|
|
<EyeInvisibleOutlined
|
|
|
|
|
style={{ color: 'var(--color-neutral-500)' }}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<EyeOutlined style={{ color: 'var(--color-neutral-500)' }} />
|
|
|
|
|
)}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2025-03-16 00:56:02 +07:00
|
|
|
);
|
|
|
|
|
};
|