shellphone.app/app/core/components/labeled-text-field.tsx

59 lines
1.4 KiB
TypeScript
Raw Normal View History

import { forwardRef, PropsWithoutRef } from "react";
import { useFormContext } from "react-hook-form";
2021-07-31 14:33:18 +00:00
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string;
2021-07-31 14:33:18 +00:00
/** Field label. */
label: string;
2021-07-31 14:33:18 +00:00
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number";
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>;
2021-07-31 14:33:18 +00:00
}
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(
({ label, outerProps, name, ...props }, ref) => {
const {
register,
formState: { isSubmitting, errors },
} = useFormContext();
2021-07-31 14:33:18 +00:00
const error = Array.isArray(errors[name])
? errors[name].join(", ")
: errors[name]?.message || errors[name];
2021-07-31 14:33:18 +00:00
return (
<div {...outerProps}>
<label>
{label}
<input disabled={isSubmitting} {...register(name)} {...props} />
</label>
{error && (
<div role="alert" style={{ color: "red" }}>
{error}
</div>
)}
<style jsx>{`
label {
display: flex;
flex-direction: column;
align-items: start;
font-size: 1rem;
}
input {
font-size: 1rem;
padding: 0.25rem 0.5rem;
border-radius: 3px;
border: 1px solid purple;
appearance: none;
margin-top: 0.5rem;
}
`}</style>
</div>
);
2021-08-01 12:04:04 +00:00
},
);
2021-07-31 14:33:18 +00:00
export default LabeledTextField;