password-input.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import * as React from 'react'
  2. import { Eye, EyeOff } from 'lucide-react'
  3. import { cn } from '@/lib/utils'
  4. import { Button } from './ui/button'
  5. type PasswordInputProps = Omit<
  6. React.InputHTMLAttributes<HTMLInputElement>,
  7. 'type'
  8. > & {
  9. ref?: React.Ref<HTMLInputElement>
  10. }
  11. export function PasswordInput({
  12. className,
  13. disabled,
  14. ref,
  15. ...props
  16. }: PasswordInputProps) {
  17. const [showPassword, setShowPassword] = React.useState(false)
  18. return (
  19. <div className={cn('relative rounded-md', className)}>
  20. <input
  21. type={showPassword ? 'text' : 'password'}
  22. className='flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50'
  23. ref={ref}
  24. disabled={disabled}
  25. {...props}
  26. />
  27. <Button
  28. type='button'
  29. size='icon'
  30. variant='ghost'
  31. disabled={disabled}
  32. className='absolute inset-e-1 top-1/2 h-6 w-6 -translate-y-1/2 rounded-md text-muted-foreground'
  33. onClick={() => setShowPassword((prev) => !prev)}
  34. >
  35. {showPassword ? <Eye size={18} /> : <EyeOff size={18} />}
  36. <span className='sr-only'>
  37. {showPassword ? 'Hide password' : 'Show password'}
  38. </span>
  39. </Button>
  40. </div>
  41. )
  42. }