1- import React from 'react' ;
1+ import React , { useState } from 'react' ;
2+ import { Eye , EyeOff } from 'lucide-react' ;
23import { useTheme } from '../../contexts/ThemeContext' ;
34import { THEMES } from '../../constants' ;
45
@@ -7,8 +8,12 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
78 error ?: string ;
89}
910
10- export const Input : React . FC < InputProps > = ( { label, error, className = '' , ...props } ) => {
11+ export const Input : React . FC < InputProps > = ( { label, error, className = '' , type , ...props } ) => {
1112 const { style, mode } = useTheme ( ) ;
13+ const [ showPassword , setShowPassword ] = useState ( false ) ;
14+
15+ const isPassword = type === 'password' ;
16+ const inputType = isPassword ? ( showPassword ? 'text' : 'password' ) : type ;
1217
1318 let inputStyles = "w-full outline-none transition-all duration-200" ;
1419
@@ -18,10 +23,34 @@ export const Input: React.FC<InputProps> = ({ label, error, className = '', ...p
1823 inputStyles += ` p-3 rounded-lg border border-white/20 bg-white/5 backdrop-blur-sm focus:bg-white/10 focus:border-blue-400 focus:ring-2 focus:ring-blue-500/20 ${ mode === 'dark' ? 'text-white placeholder-white/40' : 'text-gray-900 placeholder-gray-500' } ` ;
1924 }
2025
26+ if ( isPassword ) {
27+ inputStyles += " pr-10" ;
28+ }
29+
2130 return (
2231 < div className = "flex flex-col gap-1 w-full" >
2332 { label && < label className = { `text-sm font-semibold ${ style === THEMES . NEOBRUTALISM ? 'uppercase' : 'ml-1 opacity-80' } ` } > { label } </ label > }
24- < input className = { `${ inputStyles } ${ className } ` } { ...props } />
33+ < div className = "relative" >
34+ < input
35+ type = { inputType }
36+ className = { `${ inputStyles } ${ className } ` }
37+ { ...props }
38+ />
39+ { isPassword && (
40+ < button
41+ type = "button"
42+ onClick = { ( ) => setShowPassword ( ! showPassword ) }
43+ className = { `absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-md transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-1 ${
44+ style === THEMES . NEOBRUTALISM
45+ ? ( mode === 'dark' ? 'text-white opacity-80 focus:ring-white' : 'text-black opacity-60 focus:ring-black' )
46+ : 'text-white/60 hover:text-white focus:ring-white/50'
47+ } `}
48+ aria-label = { showPassword ? "Hide password" : "Show password" }
49+ >
50+ { showPassword ? < EyeOff size = { 18 } /> : < Eye size = { 18 } /> }
51+ </ button >
52+ ) }
53+ </ div >
2554 { error && < span className = "text-red-500 text-xs font-bold mt-1" > { error } </ span > }
2655 </ div >
2756 ) ;
0 commit comments