<div align="center">

# huaira-ui

**React 19 component library built on DaisyUI — with first-class React Hook Form + Zod integration, per-component tree-shaking, and full SSR support.**

[![npm version](https://img.shields.io/npm/v/huaira-ui/canary?color=2563eb&label=npm&logo=npm)](https://www.npmjs.com/package/huaira-ui)
[![npm downloads](https://img.shields.io/npm/dm/huaira-ui?color=10b981)](https://www.npmjs.com/package/huaira-ui)
[![bundle size](https://img.shields.io/bundlephobia/minzip/huaira-ui?label=min%2Bgzip)](https://bundlephobia.com/package/huaira-ui)
[![license](https://img.shields.io/npm/l/huaira-ui?color=eab308)](https://gitlab.com/daxstack/huaira-ui/-/blob/main/LICENSE)

[![React 19](https://img.shields.io/badge/React-19-61dafb?logo=react&logoColor=white)](https://react.dev)
[![Tailwind v4](https://img.shields.io/badge/Tailwind-v4-38bdf8?logo=tailwindcss&logoColor=white)](https://tailwindcss.com)
[![DaisyUI v5](https://img.shields.io/badge/DaisyUI-v5-a991f7?logo=daisyui&logoColor=white)](https://daisyui.com)
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
[![React Compiler](https://img.shields.io/badge/React_Compiler-ready-000)](https://react.dev/learn/react-compiler)

[**Documentation**](https://huaira-ui.dev) · [**Components**](https://huaira-ui.dev/docs/components) · [**Install Guide**](https://huaira-ui.dev/docs/getting-started/install) · [**Theming**](https://huaira-ui.dev/docs/getting-started/theming) · [**Changelog**](https://huaira-ui.dev/docs/getting-started/changelog)

</div>

---

## Why huaira-ui?

Most DaisyUI wrappers stop at "render the markup". `huaira-ui` adds the layers a product needs:

- 📝 **Form-aware primitives.** `Input`, `Select`, `SelectSearch`, `Checkbox`, `Radio`, `Range`, `Rating`, `PinCode`, `Textarea`, `Toggle`, `Swap` read RHF context automatically — zero `Controller` boilerplate.
- 🌳 **Per-component entry points.** Deep-import `huaira-ui/Button` or named-import from the root — both tree-shake. Vendor chunks hoisted to `libs/vendor/<pkg>.js` to dedupe across entries.
- 🎨 **DaisyUI v5 tokens.** Theme by editing CSS variables in one `@plugin` block. Swap palettes at runtime with `data-theme` — no provider, no JS.
- ⚛️ **React 19 + React Compiler.** No manual `useMemo` / `useCallback`. Clean Rules of React throughout.
- 🚀 **SSR-ready.** Static components render in Server Components; only interactive ones opt into `"use client"`.
- 🛡️ **Typed end-to-end.** Each component exports `<Name>Props`. Variant unions are real string literals.

---

## Install

```bash
pnpm add huaira-ui
# or
npm install huaira-ui
# or
yarn add huaira-ui
```

### Peer dependencies

```bash
pnpm add react@^19.2 react-dom@^19.2 tailwindcss@^4.2 react-hook-form@^7.65
```

Optional, for schema-validated forms:

```bash
pnpm add zod @hookform/resolvers
```

> ℹ️ Published under the `canary` tag while APIs stabilize. Pin a version if you want a frozen install.

---

## Wire the stylesheet

Tailwind v4 reads everything from CSS — no `tailwind.config.js`, no `postcss.config.js` boilerplate. In your global stylesheet (`app/globals.css`, `src/index.css`):

```css
@import "tailwindcss";
@import "huaira-ui/styles";

@plugin "daisyui/theme" {
  name: "light";
  default: true;
  --color-primary: #252f3e;
  --color-secondary: #0284c7;
  --color-accent: #37cdbe;
  --color-base-100: #ffffff;
}

@plugin "daisyui/theme" {
  name: "dark";
  prefersdark: true;
  --color-primary: #661ae6;
  --color-secondary: #d926aa;
  --color-accent: #1fb2a5;
  --color-base-100: #2a303c;
}
```

Then add the PostCSS (Next.js) or Vite plugin — see [the install guide](https://huaira-ui.dev/docs/getting-started/install) for the full per-framework setup.

---

## Quick start

```tsx
import { Button } from "huaira-ui";

export default function Page() {
  return (
    <Button color="primary" size="lg" onClick={() => alert("it works")}>
      Click me
    </Button>
  );
}
```

### Forms with React Hook Form + Zod

```tsx
"use client";

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Form, Input, Select, Checkbox, Button } from "huaira-ui";

const schema = z.object({
  email: z.string().email("Invalid email"),
  password: z.string().min(8, "At least 8 characters"),
  country: z.string().min(1, "Pick a country"),
  acceptTerms: z.literal(true, { message: "You must accept" }),
});

type FormData = z.infer<typeof schema>;

export function SignUpForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  return (
    <Form onSubmit={handleSubmit(console.log)} className="space-y-4">
      <Input name="email" label="Email" type="email" register={register} error={errors.email} />
      <Input name="password" label="Password" type="password" register={register} error={errors.password} />
      <Select
        name="country"
        label="Country"
        register={register}
        error={errors.country}
        options={[
          { value: "us", label: "United States" },
          { value: "ca", label: "Canada" },
          { value: "mx", label: "Mexico" },
        ]}
      />
      <Checkbox name="acceptTerms" label="I accept the terms" register={register} error={errors.acceptTerms} />
      <Button type="submit" color="primary" size="lg">Submit</Button>
    </Form>
  );
}
```

---

## Components

| Category    | Components |
| ----------- | ---------- |
| **Actions** | `Button`, `Fab` |
| **Forms** | `Form`, `Input`, `InputPassword`, `Select`, `SelectSearch`, `Checkbox`, `Radio`, `Range`, `Rating`, `PinCode`, `Textarea`, `Toggle`, `Swap`, `Label` |
| **Display** | `Avatar`, `Badge`, `Card`, `List`, `Loading`, `Progress`, `RadialProgress`, `Skeleton`, `Stat`, `Table`, `Timeline` |
| **Feedback** | `Alert`, `Toast` |
| **Layout** | `Accordion`, `Collapse`, `Divider` |
| **Navigation** | `Breadcrumbs`, `Tab` |
| **Overlay** | `Drawer`, `Dropdown`, `Modal`, `Tooltip` |

Browse every component with live examples and full prop tables at **[huaira-ui.dev/docs/components](https://huaira-ui.dev/docs/components)**.

---

## Theming

Components consume DaisyUI tokens (`--color-primary`, `--color-base-100`, …). Swap palettes anywhere in the tree:

```tsx
<section data-theme="dark">
  <Button color="primary">Dark</Button>
</section>

<section data-theme="cupcake">
  <Button color="primary">Cupcake</Button>
</section>
```

Full token reference and a flash-free dark-mode recipe → **[Theming guide](https://huaira-ui.dev/docs/getting-started/theming)**.

---

## Requirements

| Peer | Version | Required | Notes |
| ---- | ------- | -------- | ----- |
| `react` / `react-dom` | `>= 19.1` | yes | Targets the React 19 runtime. |
| `tailwindcss` | `>= 4.1` | yes | v4 syntax (`@import`, `@plugin`). |
| `daisyui` | `>= 5.0` | yes | Loaded as Tailwind v4 `@plugin`. |
| `react-hook-form` | `>= 7.61` | optional | Only needed when you validate. |
| `zod` | `>= 4.1` | optional | Pair with `@hookform/resolvers/zod`. |

---

## What's NOT in scope

Setting expectations up front:

- **No data grid.** `Table` is presentational — pair with TanStack Table for sorting / virtualization.
- **No date picker.** Use native `<input type="date">` via `Input type="date"`.
- **No charts.** Drop in Recharts, Visx, or Chart.js.
- **No animation runtime.** Components forward refs — wrap with `framer-motion` or `@gsap/react` as needed.
- **No router, fetcher, or state manager.** This is a UI lib, not a framework.

---

## Links

- 🌐 **Docs:** [huaira-ui.dev](https://huaira-ui.dev)
- 📦 **npm:** [npmjs.com/package/huaira-ui](https://www.npmjs.com/package/huaira-ui)
- 💻 **Source:** [gitlab.com/daxstack/huaira-ui](https://gitlab.com/daxstack/huaira-ui)
- 🐛 **Issues:** [gitlab.com/daxstack/huaira-ui/-/issues](https://gitlab.com/daxstack/huaira-ui/-/issues)

---

<div align="center">

**MIT Licensed** · Built with React 19, Tailwind v4, and DaisyUI v5.

</div>
