91 lines
1.9 KiB
TypeScript
91 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState, type FocusEvent } from "react";
|
|
import styles from "./AuthShell.module.css";
|
|
|
|
function clearAutofillOnFocus(event: FocusEvent<HTMLInputElement>) {
|
|
event.currentTarget.removeAttribute("readonly");
|
|
}
|
|
|
|
export function AuthField({
|
|
label,
|
|
type = "text",
|
|
name,
|
|
placeholder,
|
|
autoComplete,
|
|
required,
|
|
disabled,
|
|
dir,
|
|
}: {
|
|
label: string;
|
|
type?: string;
|
|
name: string;
|
|
placeholder?: string;
|
|
autoComplete?: string;
|
|
required?: boolean;
|
|
disabled?: boolean;
|
|
dir?: "ltr" | "rtl" | "auto";
|
|
}) {
|
|
return (
|
|
<label className={styles.field}>
|
|
<span>{label}</span>
|
|
<input
|
|
type={type}
|
|
name={name}
|
|
placeholder={placeholder}
|
|
autoComplete={autoComplete ?? "off"}
|
|
required={required}
|
|
disabled={disabled}
|
|
dir={dir}
|
|
defaultValue=""
|
|
readOnly
|
|
onFocus={clearAutofillOnFocus}
|
|
/>
|
|
</label>
|
|
);
|
|
}
|
|
|
|
export function AuthPasswordField({
|
|
label,
|
|
name,
|
|
autoComplete,
|
|
required,
|
|
disabled,
|
|
}: {
|
|
label: string;
|
|
name: string;
|
|
autoComplete?: string;
|
|
required?: boolean;
|
|
disabled?: boolean;
|
|
}) {
|
|
const [visible, setVisible] = useState(false);
|
|
|
|
return (
|
|
<div className={styles.passwordWrap}>
|
|
<label className={styles.field}>
|
|
<span>{label}</span>
|
|
<input
|
|
type={visible ? "text" : "password"}
|
|
name={name}
|
|
autoComplete={autoComplete ?? "off"}
|
|
required={required}
|
|
disabled={disabled}
|
|
minLength={8}
|
|
defaultValue=""
|
|
readOnly
|
|
onFocus={clearAutofillOnFocus}
|
|
/>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
className={styles.eyeBtn}
|
|
aria-label={visible ? "Hide password" : "Show password"}
|
|
onClick={() => setVisible((v) => !v)}
|
|
disabled={disabled}
|
|
>
|
|
<img src="/images/icons/eye.svg" alt="" />
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|