Files
aegis/src/components/ui/Input.tsx
T

98 lines
3.0 KiB
TypeScript

import React, { forwardRef, useId } from 'react';
import { cn } from '@/utils/utils';
import { NEUMORPHISM } from '@/styles/Neumorphism';
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
label?: string;
error?: string;
size?: keyof typeof NEUMORPHISM.sizeStyles;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({
className,
label,
error,
id,
size = 'md',
leftIcon,
rightIcon,
required,
disabled,
...props
}, ref) => {
const autoId = useId();
const inputId = id || autoId;
return (
<div className="w-full flex flex-col gap-1.5">
{/* Label */}
{label && (
<label
htmlFor={inputId}
className="block text-sm font-bold text-slate-700 dark:text-slate-300"
>
{label} {required && <span className="text-rose-500 font-bold">*</span>}
</label>
)}
<div className="relative flex items-center w-full">
{/* Icône à gauche */}
{leftIcon && (
<span className="absolute left-4 text-slate-400 dark:text-slate-500 pointer-events-none flex items-center justify-center">
{leftIcon}
</span>
)}
{/* Champ HTML avec les ombres creusées centralisées */}
<input
id={inputId}
ref={ref}
disabled={disabled}
className={cn(
// Base & Couleurs de fond
"w-full transition-all duration-300 ease-in-out outline-none border border-transparent",
"bg-[#e8e8e8] dark:bg-[#1e293b]",
"text-slate-800 dark:text-slate-100 font-medium placeholder:text-slate-400 dark:placeholder:text-slate-500",
// 🎯 Utilisation directe de tes constantes Neumorphic creusées
NEUMORPHISM.insetLight,
NEUMORPHISM.insetDark,
// Focus & État désactivé
"focus:border-blue-500/40 dark:focus:border-blue-400/40",
"disabled:opacity-50 disabled:cursor-not-allowed",
// Tailles & Marges d'icônes
NEUMORPHISM.sizeStyles[size],
leftIcon && "pl-11",
rightIcon && "pr-11",
// Style en cas d'erreur
error && "border-rose-500 focus:border-rose-500 text-rose-600 dark:text-rose-400",
className
)}
{...props}
/>
{/* Icône à droite */}
{rightIcon && (
<span className="absolute right-4 text-slate-400 dark:text-slate-500 pointer-events-none flex items-center justify-center">
{rightIcon}
</span>
)}
</div>
{/* Message d'erreur */}
{error && (
<p className="text-xs font-semibold text-rose-500 dark:text-rose-400">{error}</p>
)}
</div>
);
}
);
Input.displayName = "Input";