Ctrl K
ComunidadGuías…

components/PasswordInput.tsx

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
'use client';

import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline';
import { useTranslations } from 'next-intl';
import { forwardRef, useState } from 'react';
import { Input, type InputProps } from '@/components/ui/input';
import { cn } from '@/lib/utils';

export type PasswordInputProps = Omit<InputProps, 'type'>;

/**
 * Renders an initially masked input with a translated show/hide toggle.
 * Forwards the ref and input props to the input; className styles the input,
 * with right padding reserved for the toggle. Requires a next-intl provider.
 */
const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(
  ({ className, ...props }, ref) => {
    const t = useTranslations('PasswordInput');
    const [isVisible, setIsVisible] = useState(false);

    return (
      <div className="relative">
        <Input
          ref={ref}
          {...props}
          type={isVisible ? 'text' : 'password'}
          // pr-10 last so a caller's px-* can't push text under the toggle
          className={cn(className, 'pr-10')}
        />
        <button
          type="button"
          className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
          onClick={() => setIsVisible((v) => !v)}
          aria-label={isVisible ? t('hide') : t('show')}
          aria-pressed={isVisible}
        >
          {isVisible ? (
            <EyeSlashIcon className="h-4 w-4" />
          ) : (
            <EyeIcon className="h-4 w-4" />
          )}
        </button>
      </div>
    );
  },
);
PasswordInput.displayName = 'PasswordInput';

export default PasswordInput;