npm package: @gvaz/gvaz-ui
Description: Design system e biblioteca de componentes React com Tailwind CSS
Latest version: 0.3.1

# @gvaz/gvaz-ui

Design system e biblioteca de componentes React com Tailwind CSS.

## Instalação

```bash
npm install @gvaz/gvaz-ui
```

---

## Setup (Next.js)

### 1. Configurar o Tailwind

No `tailwind.config.ts`, adicione o preset da lib e inclua os arquivos do `dist` no `content`:

```ts
import type { Config } from "tailwindcss";
import gvazPreset from "@gvaz/gvaz-ui/tailwind-preset";

const config: Config = {
  presets: [gvazPreset],
  content: [
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
    "./node_modules/@gvaz/gvaz-ui/dist/**/*.{js,mjs}",
  ],
};

export default config;
```

### 2. Adicionar as variáveis CSS

No seu `globals.css` (ou qualquer CSS global), cole as variáveis de tema:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}

@layer base {
  * { @apply border-border; }
  body { @apply bg-background text-foreground; }
}
```

> As cores usam variáveis CSS em formato HSL. Você pode customizar qualquer cor sobrescrevendo as variáveis no seu CSS.

---

## Layout com Sidebar

A lib fornece um layout completo com sidebar colapsável, contexto de estado e header de página.

### Estrutura recomendada

```
app/
  layout.tsx       ← SidebarProvider + MainLayout aqui
  page.tsx         ← PageHeader + conteúdo aqui
components/
  layout/
    sidebar.tsx    ← wrapper com Link do seu router
    page-header.tsx ← wrapper com toggle da sidebar
```

### `layout.tsx`

```tsx
import { SidebarProvider, MainLayout } from "@gvaz/gvaz-ui";
import { Sidebar } from "@/components/layout/sidebar";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="pt-BR">
      <body>
        <SidebarProvider>
          <div className="flex min-h-screen">
            <Sidebar />
            <MainLayout>
              <main className="flex-1 p-8">{children}</main>
            </MainLayout>
          </div>
        </SidebarProvider>
      </body>
    </html>
  );
}
```

### `components/layout/sidebar.tsx`

Crie um wrapper que conecta o `Link` do seu router e o estado de colapso:

```tsx
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { Sidebar as GvazSidebar, useSidebar, type SidebarNavItem } from "@gvaz/gvaz-ui";
import { LayoutDashboard, Settings, Users } from "lucide-react";

const navItems: Omit<SidebarNavItem, "isActive">[] = [
  { title: "Dashboard", href: "/",        icon: LayoutDashboard },
  { title: "Usuários",  href: "/users",   icon: Users },
  { title: "Configurações", href: "/settings", icon: Settings },
];

export function Sidebar() {
  const pathname = usePathname();
  const { open } = useSidebar();

  const withActive = (items: Omit<SidebarNavItem, "isActive">[]): SidebarNavItem[] =>
    items.map((item) => ({
      ...item,
      isActive: pathname === item.href || (item.href !== "/" && pathname.startsWith(item.href)),
    }));

  return (
    <GvazSidebar
      collapsed={!open}
      logo={{ name: "Meu App" }}
      navItems={withActive(navItems)}
      user={{ name: "Usuário", role: "Admin", fallback: "US" }}
      LinkComponent={Link}
    />
  );
}
```

### `components/layout/page-header.tsx`

```tsx
"use client";

import { PageHeader as GvazPageHeader, useSidebar, type PageHeaderProps } from "@gvaz/gvaz-ui";
import Link from "next/link";

type Props = Omit<PageHeaderProps, "onMenuToggle" | "LinkComponent">;

export function PageHeader(props: Props) {
  const { toggle } = useSidebar();
  return <GvazPageHeader {...props} onMenuToggle={toggle} LinkComponent={Link} />;
}
```

### Usando nas páginas

```tsx
import { PageHeader } from "@/components/layout/page-header";

export default function DashboardPage() {
  return (
    <div>
      <PageHeader
        title="Dashboard"
        breadcrumbs={[{ label: "Início", href: "/" }]}
        actions={<Button>Nova ação</Button>}
      />
      {/* conteúdo */}
    </div>
  );
}
```

---

## Componentes disponíveis

Todos importados direto de `@gvaz/gvaz-ui`:

### UI

| Componente | Descrição |
|---|---|
| `Button` | Botão com variantes: `default`, `destructive`, `outline`, `secondary`, `ghost`, `link` |
| `Input` | Campo de texto |
| `Textarea` | Campo de texto multilinha |
| `Label` | Label de formulário |
| `Select` + `SelectTrigger` `SelectContent` `SelectItem` `SelectValue` | Select nativo Radix |
| `Switch` | Toggle on/off |
| `Badge` | Etiqueta com variantes |
| `Avatar` | Avatar com imagem ou fallback de iniciais |
| `Progress` | Barra de progresso |
| `Separator` | Divisor horizontal ou vertical |

### Layout

| Componente | Descrição |
|---|---|
| `Card` + `CardHeader` `CardTitle` `CardDescription` `CardContent` `CardFooter` | Card container |
| `Tabs` + `TabsList` `TabsTrigger` `TabsContent` | Abas com estilo underline |
| `Table` + `TableHeader` `TableBody` `TableRow` `TableHead` `TableCell` | Tabela |

### Overlays

| Componente | Descrição |
|---|---|
| `Dialog` + `DialogTrigger` `DialogContent` `DialogHeader` `DialogTitle` `DialogDescription` `DialogFooter` `DialogClose` | Modal |
| `DropdownMenu` + `DropdownMenuTrigger` `DropdownMenuContent` `DropdownMenuItem` `DropdownMenuSeparator` `DropdownMenuLabel` | Menu dropdown |

### Navegação / App shell

| Componente / Hook | Descrição |
|---|---|
| `Sidebar` | Sidebar colapsável com logo, nav, notificações e usuário |
| `PageHeader` | Header de página com toggle, breadcrumb e slot de ações |
| `SidebarProvider` | Context provider para estado open/collapsed |
| `MainLayout` | Wrapper do conteúdo principal que se adapta ao estado da sidebar |
| `useSidebar()` | Hook para ler `open` e chamar `toggle()` de qualquer componente |

### Utilitário

| Export | Descrição |
|---|---|
| `cn(...classes)` | Merge de classes Tailwind (`clsx` + `tailwind-merge`) |

---

## Customizando o tema

As cores são totalmente customizáveis via variáveis CSS. Exemplo — trocar a cor primária para roxo:

```css
:root {
  --primary: 262 80% 50%;
  --primary-foreground: 0 0% 100%;
}
```

Você pode alterar qualquer variável do tema sem reconstruir a lib.

---

## Publicando uma atualização

```bash
# ajuste a versão no package.json (ex: 0.1.0 → 0.2.0)
npm run build
npm publish --access public
```


## Instalação

```bash
npm install gvaz-ui
```

## Uso

### 1. Adicionar o preset do Tailwind

No `tailwind.config.ts` do seu projeto:

```ts
import type { Config } from "tailwindcss";
import gvazPreset from "gvaz-ui/tailwind-preset";

const config: Config = {
  presets: [gvazPreset],
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "./node_modules/gvaz-ui/dist/**/*.{js,mjs}",
  ],
  // ...
};

export default config;
```

### 2. Importar os estilos base

No seu `globals.css` ou layout:

```css
@import "gvaz-ui/styles";
```

Ou importe diretamente no layout:

```tsx
import "gvaz-ui/styles";
```

### 3. Usar os componentes

```tsx
import { Button, Card, CardHeader, CardTitle, CardContent, Input, Label, Badge } from "gvaz-ui";

export default function Page() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Login</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        <div>
          <Label htmlFor="email">Email</Label>
          <Input id="email" type="email" placeholder="seu@email.com" />
        </div>
        <Button>Entrar</Button>
        <Badge variant="secondary">Novo</Badge>
      </CardContent>
    </Card>
  );
}
```

## Componentes disponíveis

- **Button** — botão com variantes (default, destructive, outline, secondary, ghost, link)
- **Input** — campo de input estilizado
- **Label** — label para formulários
- **Badge** — badge/tag com variantes
- **Card** — card container com Header, Title, Description, Content e Footer

## Tema

O tema é baseado em CSS variables (HSL). Edite as variáveis em `globals.css` para customizar cores. Suporte a dark mode via classe `.dark`.

## Scripts

```bash
npm run build   # build da lib
npm run dev     # build em watch mode
npm run typecheck   # checar tipos
npm run clean   # limpar dist/
```