@arolariu/components
Version:
🎨 70+ beautiful, accessible React components built on Radix UI. TypeScript-first, tree-shakeable, SSR-ready. Perfect for modern web apps, design systems & rapid prototyping. Zero config, maximum flexibility! ⚡
96 lines (95 loc) • 3.63 kB
JavaScript
"use client";
import { jsx } from "react/jsx-runtime";
import { Slot } from "@radix-ui/react-slot";
import { createContext, forwardRef, useContext, useId } from "react";
import { Controller, FormProvider, useFormContext } from "react-hook-form";
import { Label } from "./label.js";
import { cn } from "../../lib/utilities.js";
const Form = FormProvider;
const FormFieldContext = /*#__PURE__*/ createContext(null);
const FormField = ({ ...props })=>/*#__PURE__*/ jsx(FormFieldContext.Provider, {
value: {
name: props.name
},
children: /*#__PURE__*/ jsx(Controller, {
...props
})
});
const useFormField = ()=>{
const fieldContext = useContext(FormFieldContext);
const itemContext = useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();
if (!fieldContext) throw new Error("useFormField should be used within <FormField>");
if (!itemContext) throw new Error("useFormField should be used within <FormItem>");
const fieldState = getFieldState(fieldContext.name, formState);
const { id } = itemContext;
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState
};
};
const FormItemContext = /*#__PURE__*/ createContext(null);
const FormItem = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>{
const id = useId();
return /*#__PURE__*/ jsx(FormItemContext.Provider, {
value: {
id
},
children: /*#__PURE__*/ jsx("div", {
ref: ref,
className: cn("space-y-2", className),
...props
})
});
});
FormItem.displayName = "FormItem";
const FormLabel = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>{
const { error, formItemId } = useFormField();
return /*#__PURE__*/ jsx(Label, {
ref: ref,
className: cn(error && "text-red-500 dark:text-red-900", className),
htmlFor: formItemId,
...props
});
});
FormLabel.displayName = "FormLabel";
const FormControl = /*#__PURE__*/ forwardRef(({ ...props }, ref)=>{
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
return /*#__PURE__*/ jsx(Slot, {
ref: ref,
id: formItemId,
"aria-describedby": error ? `${formDescriptionId} ${formMessageId}` : `${formDescriptionId}`,
"aria-invalid": Boolean(error),
...props
});
});
FormControl.displayName = "FormControl";
const FormDescription = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>{
const { formDescriptionId } = useFormField();
return /*#__PURE__*/ jsx("p", {
ref: ref,
id: formDescriptionId,
className: cn("text-[0.8rem] text-neutral-500 dark:text-neutral-400", className),
...props
});
});
FormDescription.displayName = "FormDescription";
const FormMessage = /*#__PURE__*/ forwardRef(({ className, children, ...props }, ref)=>{
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message ?? "") : children;
if (!body) return null;
return /*#__PURE__*/ jsx("p", {
ref: ref,
id: formMessageId,
className: cn("text-[0.8rem] font-medium text-red-500 dark:text-red-900", className),
...props,
children: body
});
});
FormMessage.displayName = "FormMessage";
export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField };
//# sourceMappingURL=form.js.map