You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
1.6 KiB
60 lines
1.6 KiB
2 years ago
|
import { forwardRef, PropsWithoutRef, ComponentPropsWithoutRef } from "react"
|
||
|
import { useFormContext } from "react-hook-form"
|
||
|
|
||
|
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"
|
||
|
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
|
||
|
labelProps?: ComponentPropsWithoutRef<"label">
|
||
|
}
|
||
|
|
||
|
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(
|
||
|
({ label, outerProps, labelProps, name, ...props }, ref) => {
|
||
|
const {
|
||
|
register,
|
||
|
formState: { isSubmitting, errors },
|
||
|
} = useFormContext()
|
||
|
const error = Array.isArray(errors[name])
|
||
|
? errors[name].join(", ")
|
||
|
: errors[name]?.message || errors[name]
|
||
|
|
||
|
return (
|
||
|
<div {...outerProps}>
|
||
|
<label {...labelProps}>
|
||
|
{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>
|
||
|
)
|
||
|
}
|
||
|
)
|
||
|
|
||
|
export default LabeledTextField
|