27 lines
1.5 KiB
TypeScript
27 lines
1.5 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useState } from "react";
|
||
|
|
import { Eye, EyeOff } from "lucide-react";
|
||
|
|
|
||
|
|
export const inputClass = "w-full min-h-12 rounded-xl border border-gray-200 bg-white px-3.5 text-base text-[#003D5B] outline-none transition focus:border-[#30638E] focus:ring-3 focus:ring-[#30638E]/10 dark:border-border dark:bg-surface-muted dark:text-white";
|
||
|
|
|
||
|
|
export function PasswordField({ name, label, autoComplete, minLength, hint }: {
|
||
|
|
name: string; label: string; autoComplete: string; minLength?: number; hint?: string;
|
||
|
|
}) {
|
||
|
|
const [visible, setVisible] = useState(false);
|
||
|
|
return (
|
||
|
|
<div>
|
||
|
|
<label htmlFor={name} className="mb-2 block text-sm font-medium">{label}</label>
|
||
|
|
<div className="relative">
|
||
|
|
<input id={name} name={name} type={visible ? "text" : "password"} autoComplete={autoComplete}
|
||
|
|
required minLength={minLength} className={`${inputClass} pr-14`} aria-describedby={hint ? `${name}-hint` : undefined} />
|
||
|
|
<button type="button" onClick={() => setVisible(!visible)} aria-label={`${visible ? "Hide" : "Show"} ${label.toLowerCase()}`}
|
||
|
|
className="absolute right-1 top-0.5 grid h-11 w-11 place-items-center rounded-lg text-gray-500 hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-[#30638E] dark:hover:bg-white/5">
|
||
|
|
{visible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
{hint && <p id={`${name}-hint`} className="mt-2 text-xs leading-relaxed text-gray-500 dark:text-gray-400">{hint}</p>}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|