# @explita/daily-toolset-form

A powerful and extensible React form hook for building scalable forms with Zod validation, persistence, and full control.

## ✨ Features

- ✅ Built-in Zod schema validation
- ✅ Controlled and uncontrolled modes
- ✅ Persistent form state via `localStorage`
- ✅ Field-level error handling and parsing
- ✅ Debounced input validation
- ✅ Works seamlessly with any UI library (e.g. shadcn/ui)

## 📦 Installation

```bash
npm install @explita/daily-toolset-form
# or
yarn add @explita/daily-toolset-form
```

## 🧪 Usage

```tsx
import { z } from "zod";
import { useForm, Form, Field } from "@explita/daily-toolset-form";
import { Input } from "@/components/ui/input";

const schema = z.object({
  email: z.email({ error: "Invalid email" }),
  password: z
    .string()
    .min(6, { error: "Password must be at least 6 characters" }),
});

export default function LoginForm() {
  const form = useForm({
    schema,
    defaultValues: { email: "", password: "" },
    onSubmit: async (values) => {
      console.log("Submitted", values);
      // call server action here or perform an HTTP request
      // const response = await login(values)
      // return response
      return values;
    },
    onSuccess: (result, ctx) => {
      console.log("Success", result);
      // result is the result of onSubmit
      // ctx.reset(); - reset the form, you don't need this if resetOnSuccess is true
    },
    onError: (error, ctx) => {
      console.log("Error", error, ctx);
      // error - the error object (usually from schema or server)
      // ctx.setErrors({ email: "Email is required" }); - useful for server errors
    },
    persistKey: "login-form", // Optional – saves input across reloads
    errorParser: (msg) => msg, // Optional – customize error messages
    mode: "controlled", // Optional – "controlled" is the default
    resetOnSuccess: true, // Optional – clears the form on success
  });

  //Field meta is an object that contains the value, error, and hasError properties

  return (
    <Form use={form}>
      <Field name="email" label="Email" isRequired>
        {(props, meta) => <Input {...props} />}
      </Field>

      <Field name="password" label="Password" isRequired>
        {(props, meta) => <Input type="password" {...props} />}
      </Field>

      <button type="submit" disabled={form.isSubmitting}>
        Submit
      </button>
    </Form>
  );
}
```

## 🧩 API Overview

### `useForm(options)`

| Option           | Type                                  | Description                                 |
| ---------------- | ------------------------------------- | ------------------------------------------- |
| `schema`         | `ZodObject`                           | Optional Zod schema for validation          |
| `defaultValues`  | `Partial<T>`                          | Initial form values                         |
| `onSubmit`       | `(values, formData) => Promise<void>` | Async submission handler                    |
| `onSuccess`      | `(result) => void`                    | Called on successful submission             |
| `onError`        | `(error, ctx) => void`                | Called on error, with access to `setErrors` |
| `persistKey`     | `string`                              | Key to store form values under              |
| `errorParser`    | `(msg: string) => string`             | Optional formatter for error messages       |
| `mode`           | `controlled`\|`uncontrolled`          | Default to controlled                       |
| `resetOnSuccess` | `boolean`                             | Clear the form on successful submission     |

### `useFormContext()`

Can be used in any component nested inside the `Form` component to access the form context.

##

### 📄 License

MIT — Made with ❤️ by [Explita](https://explita.ng)
