# Getting Started — Xertica UI

Welcome to the Xertica UI ecosystem. This library provides an enterprise-grade React component system for building business applications — dashboards, management panels, data-heavy CRUD interfaces, and AI-powered tools.

---

## For AI Agents

If you are an AI agent (such as Antigravity, Cursor, or Copilot) tasked with adding features to a project that already uses `xertica-ui`:

1. **Start at `docs/llms.md`** — it's the master index and reading guide.
2. **Read `docs/ai-usage.md`** before writing any code — it contains strict rules about what is permitted.
3. **Use what exists** — browse `/docs/components` before creating any custom component.
4. **Follow patterns** — `/docs/patterns` contains pre-validated recipes for common page types.
5. **Never violate guidelines** — `/docs/guidelines.md` defines the visual language of the system.

---

## For Human Developers

### Prerequisites

- Node.js >= 18
- React >= 18
- A project initialized with Vite, Next.js, or CRA

### Step 1 — Initialize a New Project (CLI)

If starting from scratch, use the CLI to scaffold a fully configured project:

```bash
npx xertica-ui@latest init
```

The CLI walks you through an interactive setup:

| Prompt                        | Choices                                        |
| ----------------------------- | ---------------------------------------------- |
| Pages to include              | Login, Home, Template (multi-select)           |
| Languages to support          | pt-BR, English, Español (multi-select, min 1)  |
| Default color theme           | Xertica, Slate, Blue, Violet, Rose, Emerald, … |
| **Enable dark mode support?** | yes (default) / no                             |
| **Include AI Assistant**      | yes (default) / no                             |
| Install dependencies          | yes / no                                       |

This command:

- Creates the project structure with FSD/FDA architecture
- Installs all dependencies
- Configures Tailwind CSS v4
- Injects the theme token system (`tokens.css`)
- Copies only the locale files for the selected languages
- Conditionally scaffolds the AI Assistant (`AssistantPage`, `features/assistant/`) based on your answer
- Persists your choices in `src/locales/.languages.json` and `.xertica.json` (e.g. `hasAssistant`, `disableDarkMode`)

### Step 1b — Update an Existing Project (CLI)

Run `update` to change individual aspects without reinitializing:

```bash
npx xertica-ui@latest update
```

The menu offers:

| Option            | What it does                                                                                                           |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Theme only**    | Re-prompts for color theme, overwrites `tokens.css`                                                                    |
| **Languages**     | Add/remove language support, regenerates `i18n.ts` and `App.tsx`                                                       |
| **Dark Mode**     | Enable or disable dark mode support (updates `.xertica.json` and regenerates `App.tsx` to set `disableDarkMode` flag)  |
| **Assistant**     | Add or remove the AI Assistant (copies/deletes files, regenerates `AuthGuard.tsx`, `HomePage.tsx`, `TemplatePage.tsx`) |
| **Project files** | Updates `app/`, `shared/`, `features/`, `pages/` to a newer version                                                    |

> **Tip:** You can also manually edit `src/styles/xertica/tokens.css` to tweak individual color values — the file is fully commented and designed to be human-readable.

### Step 2 — Install in an Existing Project

```bash
npm install xertica-ui
```

Then follow the manual setup in `docs/installation.md`.

---

## Provider Setup

The **single most critical setup step** is wrapping your app in both `<QueryClientProvider>` and `<XerticaProvider>`. Add `<AuthProvider>` inside the router for authentication state.

```tsx
// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { XerticaProvider } from 'xertica-ui/brand';
import { BrowserRouter as Router } from 'react-router-dom';
import { AuthProvider } from './app/context/AuthContext';
import { AppErrorBoundary, PageErrorBoundary } from './shared/error-boundary';
import 'xertica-ui/style.css';

const queryClient = new QueryClient({
  defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },
});

function App() {
  return (
    <AppErrorBoundary>
      {' '}
      {/* catches provider/context crashes */}
      <QueryClientProvider client={queryClient}>
        <XerticaProvider>
          <Router>
            <AuthProvider>
              {' '}
              {/* must be inside Router */}
              <PageErrorBoundary>
                {' '}
                {/* catches lazy-chunk + page errors */}
                <YourRoutes />
              </PageErrorBoundary>
            </AuthProvider>
          </Router>
        </XerticaProvider>
      </QueryClientProvider>
    </AppErrorBoundary>
  );
}
```

`XerticaProvider` initializes:

- **Theme system** (dark/light mode with token injection)
- **Toast notifications** (Sonner, rendered via portal)
- **Tooltip provider** (wraps Radix TooltipProvider)
- **Layout context** (`useLayout()` hook for sidebar state)
- **AI Assistant context** (if using `XerticaAssistant`)
- **Language context** (`useLanguage()` hook + i18next sync) — defaults to `pt-BR`, `en`, `es`
- **Google Maps loader** (lazy, only activates if `googleMapsApiKey` is provided)

`QueryClientProvider` enables React Query for all server state (see [State Management](./state-management.md)).

`AuthProvider` manages the authentication session — see [Authentication](#authentication) below.

### Configuring languages

By default, `<XerticaProvider>` enables the three built-in languages. Pass `availableLanguages` to override — for example, to lock the app to a single language (the `LanguageSelector` auto-hides) or to add custom locales:

```tsx
import { XerticaProvider, DEFAULT_LANGUAGES } from 'xertica-ui';
import fr from './locales/fr.json';

// Monolingual English
<XerticaProvider availableLanguages={[{ code: 'en', label: 'English' }]}>

// Three defaults + French
<XerticaProvider
  availableLanguages={[
    ...DEFAULT_LANGUAGES,
    { code: 'fr', label: 'Français', shortLabel: 'FR', resources: fr },
  ]}
>
```

See [`docs/i18n.md`](./i18n.md) for the full `LanguageDefinition` and `registerLanguageResource` API.

### Provider Props

| Prop       | Type        | Description                 |
| ---------- | ----------- | --------------------------- |
| `children` | `ReactNode` | Application content to wrap |

---

## Authentication

Authentication state is managed by `AuthContext`. Wrap your route tree with `<AuthProvider>` (inside `<Router>`) to expose `useAuth()` to all pages:

```tsx
import { useAuth } from './app/context/AuthContext';

// Any page or component inside <AuthProvider>
function MyPage() {
  const { user, logout } = useAuth();

  return (
    <div>
      <p>Logged in as {user?.email}</p>
      <button onClick={logout}>Sign out</button>
    </div>
  );
}
```

`useAuth()` returns:

| Property    | Type                           | Description                                |
| ----------- | ------------------------------ | ------------------------------------------ |
| `user`      | `AuthUser \| null`             | Current user (`email`, `name?`, `avatar?`) |
| `isLoading` | `boolean`                      | `true` while the session is being hydrated |
| `login`     | `(email, password) => boolean` | Attempt login; returns `true` on success   |
| `logout`    | `() => void`                   | Clear session and redirect to `/login`     |

### Route Guards

Use `ProtectedRoute` and `GuestRoute` wrappers (provided in the CLI-generated `AuthGuard.tsx`):

```tsx
// Redirect unauthenticated users to /login
function ProtectedRoute({ children }) {
  const { user, isLoading } = useAuth();
  if (isLoading) return null; // wait for localStorage hydration
  if (!user) return <Navigate to="/login" replace />;
  return <>{children}</>;
}

// Redirect already-authenticated users away from login
function GuestRoute({ children }) {
  const { user, isLoading } = useAuth();
  if (isLoading) return null;
  if (user) return <Navigate to="/home" replace />;
  return <>{children}</>;
}
```

---

## Lazy Loading

All routes should use `React.lazy()` + `<Suspense>` to split each page into a separate chunk:

```tsx
import React, { Suspense } from 'react';

const HomePage = React.lazy(() => import('./pages/HomePage').then(m => ({ default: m.HomePage })));

function AppRoutes() {
  return (
    <Suspense fallback={null}>
      <Routes>
        <Route
          path="/home"
          element={
            <ProtectedRoute>
              <HomePage />
            </ProtectedRoute>
          }
        />
      </Routes>
    </Suspense>
  );
}
```

The CLI-generated project configures lazy loading for all routes automatically.

---

## Error Boundaries

Wrap your app with `<AppErrorBoundary>` and your route tree with `<PageErrorBoundary>` to prevent crashes from producing blank screens:

```tsx
import { AppErrorBoundary, PageErrorBoundary, SectionErrorBoundary } from '@/shared/error-boundary';

// In App.tsx
<AppErrorBoundary>
  <QueryClientProvider client={queryClient}>
    <XerticaProvider>
      <Router>
        <AuthProvider>
          <PageErrorBoundary>
            <Suspense fallback={null}>
              <AuthGuard />
            </Suspense>
          </PageErrorBoundary>
        </AuthProvider>
      </Router>
    </XerticaProvider>
  </QueryClientProvider>
</AppErrorBoundary>

// In page content sections
<SectionErrorBoundary>
  <TeamDataTable />
</SectionErrorBoundary>
```

The CLI-generated scaffold adds all three boundaries automatically. See [`docs/components/error-boundary.md`](./components/error-boundary.md) for full API reference.

---

## Internationalization (i18n)

The project uses `i18next` + `react-i18next`. All UI strings are translated via `useTranslation()`:

```tsx
import { useTranslation } from 'react-i18next';

function MyPage() {
  const { t } = useTranslation();
  return <h1>{t('home.welcome')}</h1>;
}
```

The `LanguageSelector` component (rendered by `Header` via `showLanguageSelector`) drives language switching and is wired to `LanguageContext` + `i18next` automatically. See [`docs/i18n.md`](./i18n.md) for setup and locale file structure.

---

## Theme System

The design system is token-driven. All colors, radii, and shadows are controlled by CSS custom properties injected at `:root`.

### Color Token Semantics

| Token Class                                      | Usage                                  |
| ------------------------------------------------ | -------------------------------------- |
| `bg-background` / `text-foreground`              | Page background and primary text       |
| `bg-card` / `text-card-foreground`               | Card surfaces                          |
| `bg-muted` / `text-muted-foreground`             | Subdued backgrounds and secondary text |
| `bg-primary` / `text-primary-foreground`         | Primary actions (buttons, links)       |
| `bg-secondary` / `text-secondary-foreground`     | Secondary actions                      |
| `bg-destructive` / `text-destructive-foreground` | Danger / error states                  |
| `bg-accent` / `text-accent-foreground`           | Hover states                           |
| `border-border`                                  | Standard borders                       |
| `border-input`                                   | Form field borders                     |

**Always use semantic tokens for semantic/status contexts.** Never use raw hex values (`#3b82f6`, `rgb(...)`) in any context. For error, warning, success, and status states, always use semantic tokens (`bg-destructive`, `bg-success`, `bg-warning`, `text-muted-foreground`). For layout, spacing, and general non-semantic UI, standard Tailwind color utilities are acceptable.

### Dark Mode

The theme responds to the `dark` class on `<html>`. Use the `<ThemeToggle>` component which toggles this class automatically:

```tsx
import { ThemeToggle } from 'xertica-ui/brand';

// Typically placed in Header actions or Sidebar footer
<ThemeToggle />;
```

`ThemeToggle` is fully self-contained — it reads and writes `document.documentElement.classList` directly and does not require any context provider.

### CSS Setup (Critical)

The consumer's `src/styles/index.css` **must** follow this exact structure for theme tokens to apply correctly:

```css
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@400;500;700&display=swap');

/* 1. Import the compiled library styles (includes Tailwind base) */
@import 'xertica-ui/style.css';

/* 2. Import YOUR theme tokens (overrides library defaults) */
@import './xertica/tokens.css';

/* 3. Tell Tailwind v4 to scan xertica-ui components for class names */
@source '../node_modules/xertica-ui';

/* 4. Map CSS variables to Tailwind tokens using @theme inline
   ⚠️ MUST be `@theme inline` — NOT plain `@theme`.
   `@theme inline` keeps var() references dynamic so your tokens.css
   overrides cascade correctly into utility classes like bg-destructive. */
@theme inline {
  --color-primary: var(--primary);
  --color-destructive: var(--destructive);
  /* ... full mapping in the generated file */
}
```

> **Why `@theme inline`?** Plain `@theme {}` causes Tailwind v4 to compile color tokens **statically** at build time using the library's default values. With `@theme inline`, Tailwind keeps the `var()` references in the output CSS, so your `tokens.css` overrides cascade correctly at runtime. This is why alert colors, sidebar colors, and brand colors were not applying when using the theme selector.

---

## Layout System

The layout is managed globally through `LayoutContext`. Use the `useLayout()` hook to access and control layout state in any component:

```tsx
import { useLayout } from 'xertica-ui/hooks';

function MyComponent() {
  const {
    sidebarExpanded, // boolean
    sidebarWidth, // number (px)
    setSidebarWidth, // (width: number) => void
    toggleSidebar, // () => void
    assistenteExpanded,
    toggleAssistente,
  } = useLayout();
}
```

See `docs/layout.md` for the complete reference.

---

## Routing

Xertica UI integrates with `react-router-dom` v6. Pass router hooks to navigation components:

```tsx
import { useNavigate, useLocation } from 'react-router-dom';
import { Sidebar } from 'xertica-ui/layout';

function Layout() {
  const navigate = useNavigate();
  const location = useLocation();

  return (
    <Sidebar
      navigate={navigate}
      location={location}
      routes={routes}
      // ...
    />
  );
}
```

---

## Component Import

### Subpath Imports (v2 — Recommended)

Xertica UI v2 exposes granular subpath entries for precise, tree-shaken imports:

```tsx
import { Button, Card, CardContent, Input, Badge } from 'xertica-ui/ui';
import { Sidebar, Header } from 'xertica-ui/layout';
import { XerticaProvider, XerticaLogo } from 'xertica-ui/brand';
import { XerticaAssistant } from 'xertica-ui/assistant';
import { VideoPlayer } from 'xertica-ui/media';
import { useLayout, useTheme } from 'xertica-ui/hooks';
```

### Root Barrel (Backward Compatible)

The root entrypoint exports everything and remains fully supported:

```tsx
import {
  Button,
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  Input,
  Badge,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from 'xertica-ui/ui';
```

> **TypeScript note**: Subpath imports require `"moduleResolution": "bundler"` (or `"node16"` / `"nodenext"`) in your `tsconfig.json`.

Icons are separate — always use `lucide-react`:

```tsx
import { Home, Settings, Users, LogOut } from 'lucide-react';
```

---

## Troubleshooting

### Components render without styles (transparent / unstyled)

**Cause**: Missing CSS import.

**Fix**: Add `import 'xertica-ui/style.css'` to your entry file (`main.tsx` or `index.tsx`), **before** your own styles:

```tsx
import 'xertica-ui/style.css';
import './styles/index.css'; // your tokens and overrides
```

---

### Dark mode doesn't apply

**Cause**: The `dark` class is not being toggled on `<html>`, or `@theme inline` is missing from your CSS.

**Fix 1**: Use `<ThemeToggle>` from `xertica-ui/brand` — it handles the class toggle automatically.

**Fix 2**: Ensure your `index.css` uses `@theme inline` (not plain `@theme`):

```css
/* ✅ Correct */
@theme inline {
  --color-primary: var(--primary);
}

/* ❌ Wrong — compiles tokens statically, ignoring your tokens.css overrides */
@theme {
  --color-primary: var(--primary);
}
```

---

### Subpath imports cause TypeScript errors

**Cause**: `tsconfig.json` uses `"moduleResolution": "node"` which does not support package subpath exports.

**Fix**: Update `tsconfig.json`:

```json
{
  "compilerOptions": {
    "moduleResolution": "bundler"
  }
}
```

Alternatively, use `"moduleResolution": "node16"` or `"nodenext"`.

---

### Toast notifications don't appear

**Cause**: `<Toaster>` is not mounted, or `<XerticaProvider>` is missing.

**Fix**: Wrap your app in `<XerticaProvider>` — it auto-injects `<Toaster>`. If you are not using `XerticaProvider`, add `<Toaster />` manually:

```tsx
import { Toaster } from 'xertica-ui/ui';

function App() {
  return (
    <>
      <YourApp />
      <Toaster />
    </>
  );
}
```

---

### Dialogs / Modals don't appear

**Cause**: Missing `<XerticaProvider>` (which includes `TooltipProvider` and portal context).

**Fix**: Ensure `<XerticaProvider>` wraps the entire application at the root level.

---

### Google Maps doesn't load

**Cause**: Missing or invalid `googleMapsApiKey`, or the Maps API script failed to load.

**Fix**: Pass the key to `XerticaProvider`:

```tsx
<XerticaProvider googleMapsApiKey="YOUR_VALID_KEY">
  <App />
</XerticaProvider>
```

Or use `useApiKey()` to set it at runtime:

```tsx
const { setGoogleMapsApiKey, reloadMapsApi } = useApiKey();
setGoogleMapsApiKey('YOUR_KEY');
await reloadMapsApi();
```

---

### `useLayout()` throws "must be used within LayoutProvider"

**Cause**: The component using `useLayout()` is rendered outside `<XerticaProvider>`.

**Fix**: Ensure `<XerticaProvider>` is an ancestor of all components that use `useLayout()`, `useTheme()`, or any other context hook.

For components that may be used both inside and outside the provider (e.g., in Storybook), use `useOptionalLayout()` instead — it returns `null` when the context is unavailable.

---

### Sidebar width causes content overlap

**Cause**: Content area is not reading `sidebarWidth` from `useLayout()`.

**Fix**: Apply the sidebar width as a left margin or padding on the main content area:

```tsx
const { sidebarWidth } = useLayout();

<main style={{ marginLeft: sidebarWidth }} className="flex-1 overflow-auto">
  {/* content */}
</main>;
```

---

### AI Assistant doesn't respond (real mode)

**Cause**: Missing or invalid Gemini API key.

**Fix**: Set the Gemini API key via `useApiKey()` or pass it to `XerticaProvider`:

```tsx
<XerticaProvider initialGeminiApiKey="YOUR_GEMINI_KEY">
  <App />
</XerticaProvider>
```

Or use the Settings pattern to let users enter their own key. See [`docs/patterns/settings.md`](./patterns/settings.md).

For testing without a real API key, use `demoMode={true}` on `XerticaAssistant`:

```tsx
<XerticaAssistant demoMode={true} />
```
