shellphone.app/app/auth/components/labeled-text-field.tsx
2021-09-25 20:58:28 +08:00

67 lines
2.0 KiB
TypeScript

import { forwardRef, PropsWithoutRef } from "react";
import { Link, Routes } from "blitz";
import { useFormContext } from "react-hook-form";
import clsx from "clsx";
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string;
/** Field label. */
label: string;
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number";
showForgotPasswordLabel?: boolean;
}
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(
({ label, name, showForgotPasswordLabel, ...props }, ref) => {
const {
register,
formState: { isSubmitting, errors },
} = useFormContext();
const error = Array.isArray(errors[name]) ? errors[name].join(", ") : errors[name]?.message || errors[name];
return (
<div className="mb-6">
<label
htmlFor="name"
className={clsx("text-sm font-medium leading-5 text-gray-700", {
block: !showForgotPasswordLabel,
"flex justify-between": showForgotPasswordLabel,
})}
>
{label}
{showForgotPasswordLabel ? (
<div>
<Link href={Routes.ForgotPasswordPage()}>
<a className="font-medium text-primary-600 hover:text-primary-500 focus:outline-none focus:underline transition ease-in-out duration-150">
Forgot your password?
</a>
</Link>
</div>
) : null}
</label>
<div className="mt-1 rounded-md shadow-sm">
<input
id="name"
type="text"
tabIndex={1}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:shadow-outline-primary focus:border-primary-300 transition duration-150 ease-in-out sm:text-sm sm:leading-5"
disabled={isSubmitting}
{...register(name)}
{...props}
/>
</div>
{error ? (
<div role="alert" style={{ color: "red" }}>
{error}
</div>
) : null}
</div>
);
},
);
export default LabeledTextField;