UNPKG

laif-ds

Version:

Design System di Laif con componenti React basati su principi di Atomic Design

138 lines (109 loc) 4.94 kB
# FormComposer ## Overview Declarative form builder using `react-hook-form` (with optional Zod). Renders inputs, selects, textareas, and checkboxes from a simple items config, handles validation, and provides a submit button with loading state. --- ## Types ### FormComposerItem ```ts interface FormComposerItem { label: string; component: "input" | "select" | "textarea" | "checkbox"; name: string; defaultValue?: string | boolean | number; options?: AppSelectOption[]; // only for "select" disabled?: boolean; placeholder?: string; } ``` --- ## Props | Prop | Type | Default | Description | | -------------- | ------------------------ | ----------- | ----------------------------------------------------- | | `cols` | `"1" | "2" | "3"` | `"2"` | Grid columns for the items. | | `items` | `FormComposerItem[]` | **required**| Field configuration list. | | `schema` | `ZodTypeAny` | `undefined` | Optional Zod schema to enable validation/resolver. | | `defaultValues`| `Record<string, any>` | `undefined` | RHF default values; overrides item `defaultValue`. | | `submitText` | `string` | `"Invia"` | Submit button label. | | `onSubmit` | `(data: any) => void` | `undefined` | Called with valid form values. | | `isSubmitting` | `boolean` | `false` | Controls submit button loading/disabled state. | --- ## Behavior - **Validation**: If `schema` is provided, a Zod resolver is attached; otherwise native validity is used. - **Defaults**: Each `item.defaultValue` is merged into RHF defaults, unless `defaultValues` is passed. - **Components**: - `component: "input"` → `Input` with `label` and `placeholder`. - `component: "textarea"` → `Textarea` with `label`. - `component: "select"` → `AppSelect` with `options`. - `component: "checkbox"` → `Checkbox` + `Label` inline. - **Errors**: Zod error messages are rendered under each field. - **Layout**: Items are placed in a responsive grid with `cols` columns; last item may span full width. --- ## Examples ### With Zod Schema ```tsx import { z } from "zod"; import { FormComposer } from "laif-ds"; const formSchema = z.object({ name: z.string().min(2, "Il nome è troppo corto"), email: z.string().email("Email non valida"), message: z.string().min(10, "Almeno 10 caratteri"), select: z.string().min(1, "Seleziona una opzione"), checkbox: z.boolean().default(false), }); export function ContactForm() { return ( <div className="w-[800px]"> <FormComposer schema={formSchema} items={[ { label: "Name", component: "input", name: "name", placeholder: "Inserisci il tuo nome", defaultValue: "ciao" }, { label: "Select", component: "select", name: "select", defaultValue: "1", options: [ { value: "1", label: "Option 1" }, { value: "2", label: "Option 2" }, { value: "3", label: "Option 3" }, ] }, { label: "Email", component: "input", name: "email", placeholder: "Inserisci la tua email" }, { label: "Checkbox", component: "checkbox", name: "checkbox", defaultValue: true }, { label: "Message", component: "textarea", name: "message", placeholder: "Inserisci il tuo messaggio" }, ]} onSubmit={(data) => console.log(data)} /> </div> ); } ``` ### Submit State ```tsx import * as React from "react"; import { z } from "zod"; import { FormComposer } from "laif-ds"; const schema = z.object({ name: z.string().min(2), email: z.string().email() }); export function SubmitExample() { const [values, setValues] = React.useState({}); const [isSubmitting, setSubmitting] = React.useState(false); const onSubmit = (data: any) => { setSubmitting(true); setTimeout(() => setSubmitting(false), 2000); setValues(data); }; return ( <div className="w-[800px]"> <FormComposer schema={schema} items={[ { label: "Name", component: "input", name: "name" }, { label: "Email", component: "input", name: "email" }, ]} onSubmit={onSubmit} isSubmitting={isSubmitting} /> <pre>{JSON.stringify(values, null, 2)}</pre> </div> ); } ``` --- ## Notes - **Extensibility**: Use `startContent`, `endContent`, `iconLeft`, `iconRight` props of `Input` for richer fields. - **Select**: Provide `options` for `component: "select"` (`AppSelectOption[]`). - **Accessibility**: Labels are wired via `htmlFor`/`id`; errors use `role="alert"` and `aria-live` when relevant.