2024-06-06 11:05:54 +00:00
|
|
|
import { cn } from "@/lib/utils";
|
2024-07-03 15:15:52 +00:00
|
|
|
import { FormControl, FormDescription, FormField, FormItem, Input, InputProps } from "@/ui";
|
2024-06-06 11:05:54 +00:00
|
|
|
|
2024-07-16 18:18:17 +00:00
|
|
|
import { cva, type VariantProps } from "class-variance-authority";
|
2024-06-06 11:05:54 +00:00
|
|
|
import * as React from "react";
|
|
|
|
|
import { createElement } from "react";
|
2024-07-03 15:15:52 +00:00
|
|
|
import { FieldPath, FieldValues, UseControllerProps, useFormContext } from "react-hook-form";
|
|
|
|
|
import { FormErrorMessage } from "./FormErrorMessage";
|
2024-06-06 11:05:54 +00:00
|
|
|
import { FormLabel, FormLabelProps } from "./FormLabel";
|
|
|
|
|
import { FormInputProps, FormInputWithIconProps } from "./FormProps";
|
|
|
|
|
|
2024-07-16 18:18:17 +00:00
|
|
|
const formTextFieldVariants = cva("", {
|
2024-07-11 16:40:46 +00:00
|
|
|
variants: {
|
|
|
|
|
variant: {
|
|
|
|
|
default: "",
|
2024-08-25 12:14:21 +00:00
|
|
|
ghost:
|
2024-07-11 16:40:46 +00:00
|
|
|
"border-0 focus-visible:border focus-visible:border-input focus-visible:ring-0 focus-visible:ring-offset-0 ",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
defaultVariants: {
|
|
|
|
|
variant: "default",
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2024-06-06 11:05:54 +00:00
|
|
|
export type FormTextFieldProps<
|
|
|
|
|
TFieldValues extends FieldValues = FieldValues,
|
2024-06-17 10:42:44 +00:00
|
|
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
2024-06-06 11:05:54 +00:00
|
|
|
> = {
|
2024-06-17 10:42:44 +00:00
|
|
|
button?: (props?: React.PropsWithChildren) => React.ReactNode;
|
2024-06-06 11:05:54 +00:00
|
|
|
} & InputProps &
|
|
|
|
|
FormInputProps &
|
|
|
|
|
Partial<FormLabelProps> &
|
|
|
|
|
FormInputWithIconProps &
|
2024-07-16 18:18:17 +00:00
|
|
|
UseControllerProps<TFieldValues, TName> &
|
|
|
|
|
VariantProps<typeof formTextFieldVariants>;
|
2024-06-06 11:05:54 +00:00
|
|
|
|
2024-07-11 16:40:46 +00:00
|
|
|
export const FormTextField = React.forwardRef<HTMLInputElement, FormTextFieldProps>(
|
|
|
|
|
(props, ref) => {
|
|
|
|
|
const {
|
|
|
|
|
name,
|
|
|
|
|
label,
|
|
|
|
|
hint,
|
|
|
|
|
description,
|
|
|
|
|
placeholder,
|
|
|
|
|
className,
|
|
|
|
|
disabled,
|
|
|
|
|
defaultValue,
|
|
|
|
|
rules,
|
|
|
|
|
type,
|
|
|
|
|
variant,
|
2024-08-25 12:14:21 +00:00
|
|
|
required,
|
2024-07-10 18:54:33 +00:00
|
|
|
|
2024-07-11 16:40:46 +00:00
|
|
|
button,
|
|
|
|
|
leadIcon,
|
|
|
|
|
trailIcon,
|
|
|
|
|
} = props;
|
2024-06-06 11:05:54 +00:00
|
|
|
|
2024-07-11 16:40:46 +00:00
|
|
|
const { control } = useFormContext();
|
2024-06-29 19:39:25 +00:00
|
|
|
|
2024-07-11 16:40:46 +00:00
|
|
|
return (
|
|
|
|
|
<FormField
|
|
|
|
|
defaultValue={defaultValue}
|
|
|
|
|
control={control}
|
|
|
|
|
name={name}
|
|
|
|
|
disabled={disabled}
|
2024-08-25 12:14:21 +00:00
|
|
|
rules={{
|
|
|
|
|
required,
|
|
|
|
|
...rules,
|
|
|
|
|
}}
|
2024-07-11 16:40:46 +00:00
|
|
|
render={({ field, fieldState }) => {
|
|
|
|
|
return (
|
|
|
|
|
<FormItem ref={ref} className={cn(className, "space-y-3")}>
|
|
|
|
|
{label && (
|
2024-08-25 12:14:21 +00:00
|
|
|
<FormLabel
|
|
|
|
|
label={label}
|
|
|
|
|
hint={hint}
|
|
|
|
|
required={Boolean(rules?.required ?? required)}
|
|
|
|
|
/>
|
2024-07-11 16:40:46 +00:00
|
|
|
)}
|
|
|
|
|
<div className={cn(button ? "flex" : null)}>
|
|
|
|
|
<div
|
|
|
|
|
className={cn(
|
|
|
|
|
leadIcon ? "relative flex items-stretch flex-grow focus-within:z-10" : ""
|
|
|
|
|
)}
|
2024-07-03 15:15:52 +00:00
|
|
|
>
|
2024-07-11 16:40:46 +00:00
|
|
|
{leadIcon && (
|
|
|
|
|
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none'>
|
|
|
|
|
{React.createElement(
|
|
|
|
|
leadIcon,
|
|
|
|
|
{
|
|
|
|
|
className: "h-5 w-5 text-muted-foreground",
|
|
|
|
|
"aria-hidden": true,
|
|
|
|
|
},
|
|
|
|
|
null
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<FormControl
|
|
|
|
|
className={cn("block", leadIcon ? "pl-10" : "", trailIcon ? "pr-10" : "")}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
type={type}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
className={cn(
|
|
|
|
|
fieldState.error ? "border-destructive focus-visible:ring-destructive" : "",
|
2024-07-16 18:18:17 +00:00
|
|
|
formTextFieldVariants({ variant, className })
|
2024-07-11 16:40:46 +00:00
|
|
|
)}
|
|
|
|
|
{...field}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
2024-07-03 15:15:52 +00:00
|
|
|
|
2024-07-11 16:40:46 +00:00
|
|
|
{trailIcon && (
|
|
|
|
|
<div className='absolute inset-y-0 right-0 flex items-center pl-3 pointer-events-none'>
|
|
|
|
|
{createElement(
|
|
|
|
|
trailIcon,
|
|
|
|
|
{
|
|
|
|
|
className: "h-5 w-5 text-muted-foreground",
|
|
|
|
|
"aria-hidden": true,
|
|
|
|
|
},
|
|
|
|
|
null
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{button && <>{createElement(button)}</>}
|
2024-07-03 15:15:52 +00:00
|
|
|
</div>
|
|
|
|
|
|
2024-07-11 16:40:46 +00:00
|
|
|
{description && <FormDescription>{description}</FormDescription>}
|
|
|
|
|
<FormErrorMessage />
|
|
|
|
|
</FormItem>
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|