# Xertica UI — Library Guidelines

> **Scope**: These guidelines apply to contributors developing the `xertica-ui` package itself (components, documentation, build system). For guidelines on projects that **consume** the package, see `templates/guidelines/Guidelines.md`.

---

## 1. What Xertica UI Is

Xertica UI is an enterprise-grade React component library distributed as an npm package. It is designed to be consumed by both human developers and AI coding agents (LLMs, Cursor, Claude Code, Copilot). Every design decision — from the component API to the documentation format — must serve both audiences.

**Stack:** React 18 · TypeScript 5 · Tailwind CSS v4 · Radix UI · Lucide React · Vite 6

---

## 2. AI-First Documentation

Documentation is a first-class deliverable. Every component ships with:

| File                        | Purpose                                                                               | Location                 |
| --------------------------- | ------------------------------------------------------------------------------------- | ------------------------ |
| `llms.txt`                  | Index file following the llmstxt.org standard. Links to all docs.                     | `/llms.txt`              |
| `llms-compact.txt`          | ~4K token quick reference. Critical rules, imports, 12 key components with examples.  | `/llms-compact.txt`      |
| `llms-full.txt`             | Complete documentation of all 97 components in one file for large-context LLMs.       | `/llms-full.txt`         |
| `components.json`           | Machine-readable registry: name, category, import path, keywords, related components. | `/components.json`       |
| `docs/decision-tree.md`     | Decision trees: Dialog vs Sheet, Tooltip vs HoverCard, etc.                           | `/docs/decision-tree.md` |
| `docs/components/[name].md` | Individual component reference with props, examples, and AI rules.                    | `/docs/components/`      |
| `docs/ai-usage.md`          | Mandatory rules for AI agents operating on this library.                              | `/docs/ai-usage.md`      |
| `CLAUDE.md`                 | Auto-generated system prompt for consumer projects (injected by CLI).                 | `/templates/CLAUDE.md`   |

### When to update documentation

Every PR that changes a component **must** update:

- `docs/components/[name].md` — if props, behavior, or examples changed
- `llms-full.txt` — the relevant component section
- `components.json` — if the component name, import path, or description changed
- `CHANGELOG.md` — under the current unreleased version

---

## 3. Package Structure

```
xertica-ui/
├── components/                  # Source components (ships in package)
│   ├── ui/                      # Design system primitives
│   ├── layout/                  # Sidebar, Header
│   ├── brand/                   # XerticaProvider, logos, ThemeToggle, LanguageSelector
│   ├── assistant/               # XerticaAssistant, ModernChatInput, MarkdownMessage, CodeBlock, FormattedDocument
│   ├── blocks/                  # Composed dashboard cards + matching *Skeleton variants
│   ├── media/                   # VideoPlayer, AudioPlayer, FloatingMediaWrapper
│   ├── pages/                   # Full-page template components
│   └── shared/                  # Internal utils (use-mobile, assistant-utils, error-boundary, error-fallbacks)
├── contexts/                    # React contexts (LayoutContext, ThemeContext, LanguageContext, etc.)
├── features/                    # Server-state hooks + mock data (home, assistant) — used by Storybook pages
├── hooks/                       # Hook re-exports
├── lib/                         # Shared singletons — currently query-client.ts
├── utils/                       # Utility functions (demo-responses, gemini)
├── locales/                     # i18n translation files — one folder per language
│   ├── pt-BR/                   #   {common,nav,errors,languageSelector,themeToggle}.json
│   │   ├── pages/               #   home, templates, login, resetPassword, verifyEmail,
│   │   │                        #   loginTemplate, formTemplate, dashboardTemplate, crudTemplate
│   │   └── components/          #   assistant, sidebar, media, projectCard, profileCard,
│   │                            #   notificationCard, activityCard, stats, team
│   ├── en/                      #   (same structure)
│   └── es/                      #   (same structure)
├── i18n.ts                      # i18next setup (registerLanguageResource helper exported)
├── styles/                      # Global CSS and token maps
├── templates/                   # CLI scaffold template (FSD/FDA project)
├── bin/                         # CLI source + helpers
│   ├── cli.ts                   #   commander entry point (init, update)
│   ├── language-config.ts       #   language registry + code generators
│   └── generate-tokens.ts       #   color theme generator
├── dist/                        # Compiled library (ES + CJS + CSS + types)
├── docs/                        # Markdown docs (ships in package for AI agents)
├── llms.txt                     # AI documentation index
├── llms-compact.txt             # Compact AI reference
├── llms-full.txt                # Full AI documentation
└── components.json              # Machine-readable component registry
```

### Why source ships with the package

The `components/`, `contexts/`, `hooks/`, `lib/`, `i18n.ts`, and `locales/` directories are intentionally included in the npm package (via the `files` field in `package.json`). AI agents running in consumer projects can inspect source, stories, and documentation directly from `node_modules/xertica-ui/`. This is the primary AI-first design decision.

---

## 4. Subpath Exports

The package exposes 7 entry points. Always use the most specific subpath:

```tsx
import { Button, Card, Input } from 'xertica-ui/ui';
import { QuickActionCard, ActivityCardSkeleton } from 'xertica-ui/blocks';
import { Sidebar, Header } from 'xertica-ui/layout';
import { XerticaProvider, XerticaLogo, LanguageSelector } from 'xertica-ui/brand';
import { XerticaAssistant } from 'xertica-ui/assistant';
import { VideoPlayer, AudioPlayer } from 'xertica-ui/media';
import { useLayout, useTheme, useLanguage } from 'xertica-ui/hooks';
import 'xertica-ui/style.css'; // once, at root
```

The root `from 'xertica-ui'` exports everything (including i18n surface: `DEFAULT_LANGUAGES`, `LanguageDefinition`, `registerLanguageResource`, and `i18n` instance) and remains supported for backward compatibility.

> **Note**: `useLanguage` is exported from `xertica-ui/hooks` and `xertica-ui` (root) — but **not** from `xertica-ui/brand`. The brand subpath exports only the `LanguageSelector` component and the `Language` type.

### Adding a new export to a subpath

1. Add the export to the relevant barrel (`components/[category]/index.ts`)
2. Verify it appears in the compiled `dist/[category].es.js` after `npm run build`
3. If adding a new top-level category, also update `vite.config.ts` (`lib.entry`) and `package.json` (`exports`)

---

## 5. Design Tokens — Rules for Component Authors

All **library components** (`components/ui/`, `components/layout/`, etc.) must use semantic CSS tokens exclusively. Never hardcode colors, radii, or shadows in library source:

```tsx
// ✅ Correct — library component
className="bg-primary text-primary-foreground rounded-[var(--radius)]"

// ❌ Wrong — library component
className="bg-blue-600 text-white rounded-lg"
style={{ backgroundColor: '#3b82f6' }}
```

> **Note for Storybook stories and consumer applications:** The strict "semantic tokens only" rule applies to **library component internals** and to **semantic/status contexts** (error states, warning banners, success indicators, status badges) in all code. For layout, spacing, and general non-semantic UI in stories or consumer apps, standard Tailwind color utilities (`bg-blue-500`, `text-gray-700`) are acceptable when no semantic token maps to the intent. Raw hex values and `rgb()`/`hsl()` literals are **never** acceptable in any context.

### Token reference

```
bg-background / text-foreground       Page background and body 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 and active states
bg-secondary / text-secondary-fg      Secondary actions
bg-destructive                        Danger / error states
bg-accent / text-accent-foreground    Hover states
bg-success / bg-info / bg-warning     Semantic state colors
border-border                         Standard borders
border-input                          Form field borders
ring-ring                             Focus rings
```

### Border radius

Always use `rounded-[var(--radius)]` — never `rounded-sm`, `rounded-lg`, or any fixed radius class. The radius is a brand token that must be overridable by consumers.

---

## 6. Component Authoring Rules

### Non-negotiable

- **Never use native HTML interactive elements** where a library component exists. `<Button>` wraps `<button>`, `<Input>` wraps `<input>`. New components must follow the same pattern.
- **All interactive components must be keyboard navigable** and follow ARIA patterns. Build on Radix UI primitives.
- **Icons come from `lucide-react` only.** No custom SVGs, no other icon libraries.
- **No raw inline styles** (except for dynamic values like `sidebarWidth` that genuinely require them).
- **No hardcoded user-facing strings.** Every label, aria-label, placeholder, tooltip, toast, and error message goes through `useTranslation()` and a key under `locales/*.json`. See section 7 below.
- **Pair every data-bearing block with a matching `*Skeleton`.** See section 8 below.

### Component file structure

```
components/ui/my-component/
  index.ts          ← public re-exports only
  my-component.tsx  ← implementation
  my-component.stories.tsx
  my-component.mdx
  my-component.test.tsx
```

### Stories requirements

Every component must have:

- A `Default` story showing the most common usage
- Stories for all major prop variants
- An MDX page with: overview, when to use / not to use, props table, examples, AI Rules

### AI Rules section (mandatory in every component doc)

The `## AI Rules` section at the bottom of every `docs/components/[name].md` must contain:

- What the agent must NEVER do with this component
- What the agent must ALWAYS do
- Common mistakes the AI makes and their correct form

---

## 7. Internationalization (i18n) Rules

Every library component is fully translated via **`i18next`** + **`react-i18next`**. Follow these rules when authoring components:

### Component code

- **Use `useTranslation()` inside components and custom hooks.** Never hardcode user-facing strings in JSX.
- **Use `i18n.t()` (the imported instance) inside non-component code** (mock fetch functions, utility modules). `useTranslation` is a hook and cannot be called outside React contexts.
- **Add new keys to all three locales** — place the key in the relevant split file (e.g., `locales/pt-BR/components/assistant.json` for a new assistant string, `locales/pt-BR/pages/home.json` for a home-page string) and mirror the same change in `templates/src/locales/<lang>/`. Because `i18n.ts` uses `import.meta.glob`, no import changes are needed.

### Factory functions, not frozen constants

```ts
// ❌ Wrong — i18n.t() evaluated at module load, frozen in initial language
export const MOCK_FEEDBACK_OPTIONS = [i18n.t('assistant.feedback.notWhatIWanted')];

// ✅ Correct — re-evaluated at call time, always returns current language
export function getMockFeedbackOptions() {
  return [i18n.t('assistant.feedback.notWhatIWanted')];
}
```

The same rule applies inside components when building label maps for enums: wrap them in `useMemo` so `t()` re-runs after a language change.

### Language-aware React Query keys

Every server-state hook whose response contains translated strings **must** include the active language in its `queryKey`:

```ts
import { useLanguage } from 'xertica-ui/hooks';

export function useFeatureCards() {
  const { language } = useLanguage();
  return useQuery({
    queryKey: ['home', 'feature-cards', language], // ← language as third element
    queryFn: fetchFeatureCards,
  });
}
```

Switching language creates a new cache key → cache miss → automatic refetch in the new locale. No page reload. Switching back hits the cache (instant). See `docs/state-management.md` and `docs/i18n.md`.

### Runtime-configurable language set

The set of available languages is **not** a strict union — it is a runtime list passed via `availableLanguages` on `<XerticaProvider>` / `<LanguageProvider>`. The `Language` type is `string`, not `'pt-BR' | 'en' | 'es'`.

- **Never modify** `DEFAULT_LANGUAGES` directly to add a new locale for one project.
- **To add a locale to the library itself**: create a folder at `locales/<code>/` mirroring an existing language (all subdirectory files: `common.json`, `nav.json`, `errors.json`, `languageSelector.json`, `themeToggle.json`, `pages/*.json`, `components/*.json`). Mirror the same folder under `templates/src/locales/<code>/`. No changes to `i18n.ts` are needed — `import.meta.glob` auto-discovers the new folder. Then add the descriptor to `DEFAULT_LANGUAGES` in `contexts/LanguageContext.tsx` and add the language to `SUPPORTED_LANGUAGES` in `bin/language-config.ts`.

### LanguageSelector auto-hides

`<LanguageSelector>` renders `null` when `useLanguage().isMonolingual === true`. Never conditionally render the selector yourself — just include it. Pass `showWhenMonolingual` only when you explicitly need it visible.

---

## 8. Loading-State Skeletons

Every data-bearing block component **must** ship with a matching `*Skeleton` companion that mirrors the layout with pulsing placeholders.

### Where to place them

```
components/blocks/card-patterns/
  ProjectCard.tsx
  ProjectCardSkeleton.tsx     ← matching skeleton
  ProjectCard.stories.tsx     ← include stories for both
```

### Naming + API conventions

- Name: `<ComponentName>Skeleton`
- Built from `<Skeleton>` (in `xertica-ui/ui`) + the same `Card`/`CardHeader`/`CardContent` primitives the real component uses — so the placeholder occupies the same vertical footprint
- Expose toggle props for layout regions that can be hidden in the real component (`showStats`, `showActions`, `showViewAll`, etc.)
- Expose `rows` (or `memberCount`) for list/grid sections so callers can match the loaded state's row count

### Export contract

- Re-export from the block's `index.ts` alongside the data component
- Re-export the props type with the matching name (`<ComponentName>SkeletonProps`)
- Document them in the same `docs/components/[name].md` "Loading States" section
- Include them in `card-patterns.stories.tsx` (and any aggregate MDX) so they appear in Storybook Docs

### Usage pattern

```tsx
{
  isLoading ? <ActivityCardSkeleton rows={5} /> : <ActivityCard items={items} />;
}
```

---

## 9. Shared Singletons (`lib/`)

The `lib/` directory holds singletons that bridge React-component code and non-component modules.

- **`lib/query-client.ts`** — the shared `QueryClient` instance. `App.tsx` passes it to `<QueryClientProvider>`. Library code that needs to read the same instance uses `useQueryClient()` (NOT the singleton directly) so consumer-supplied clients also work. The singleton exists so that `App.tsx` can wire `<QueryClientProvider client={queryClient}>` while keeping the rest of the library agnostic.

Do not add new singletons here without a strong cross-cutting reason. Prefer React context.

---

## 10. Adding a New Component

1. Create `components/ui/[name]/` with the 4 required files (source, stories, mdx, test)
2. Export from `components/ui/index.ts`
3. If the component renders data (cards, lists, tables, KPIs), **also create a `[name]Skeleton.tsx`** in the same directory and export it from the same index (see section 8)
4. **Add all user-facing strings to the appropriate split locale file** for all three languages (e.g., `locales/pt-BR/components/<name>.json` for a new UI component, or `locales/pt-BR/pages/<name>.json` for a page template). Mirror under `templates/src/locales/<lang>/`. Use `useTranslation()` in the component. (See section 7.)
5. Create `docs/components/[name].md` following the existing format
6. Add an entry to `components.json` with all fields: `name`, `docPath`, `sourcePath`, `description`, `category`, `import`, `keywords`, `relatedComponents`
7. Add the component to the relevant section of `llms-full.txt`
8. Add a one-line entry to `llms.txt` under the correct category
9. Update `llms-compact.txt` if the component is commonly used
10. Update `docs/decision-tree.md` if it overlaps with existing components
11. Update the component count in `README.md`, `llms.txt`, `llms-full.txt`, and `docs/llms.md`
12. Add a `CHANGELOG.md` entry

---

## 11. Build System

```bash
npm run build             # Vite multi-entry build (ES + CJS, 7 entry points)
npm run build:types       # tsc declarations → dist/components/**/*.d.ts
npm run build:cli         # tsup CLI build → dist/cli.js
npm run build:production  # alias for npm run build
```

**prepublishOnly** runs all three in sequence automatically on `npm publish`.

### Multi-entry build

`vite.config.ts` uses `lib.entry` as an object with 7 keys. Output files follow `[entryName].[format].js`. UMD is NOT used (Vite does not support multi-entry + UMD). Format is `["es", "cjs"]`.

### TypeScript declarations

`tsconfig.build.json` compiles declarations. It includes `components/**/*`, `contexts/**/*`, `hooks/**/*`. The `dist/components/` structure mirrors the source and is referenced by the `types` fields in `package.json` exports.

---

## 12. CLI

The CLI (`bin/cli.ts`) scaffolds new projects via `npx xertica-ui@latest init` and updates existing ones via `npx xertica-ui update`. Helpers live in `bin/language-config.ts` (language registry, code generators, persistence) and `bin/generate-tokens.ts` (color theme generator).

### `init` flow

1. Prompts the user for:
   - Pages to include (Login, Home, Template — multi-select)
   - **Languages to support** (`pt-BR`, `en`, `es` — multi-select, minimum 1)
   - Default color theme
   - **Enable dark mode support?** (confirm, default: true)
   - **Include AI Assistant?** (confirm, default: true)
   - Install dependencies automatically
2. Copies root config files, `CLAUDE.md`, `src/app/components/AppLayout.tsx`, and `src/shared/`
3. **Generates** `src/app/App.tsx` using `generateAppTsx(selectedLanguages, disableDarkMode)` — injects the `availableLanguages` prop on `<XerticaProvider>` (omitted when all 3 defaults are selected) and `disableDarkMode={true}` if disabled.
4. **Generates** `src/i18n.ts` using `generateI18nFile(selectedLanguages)` — imports and `resources` for exactly the selected languages
5. Copies the locale **folders** for the selected languages via `syncLocaleFiles(..., { pruneOthers: true })` — each language is a directory tree (`<lang>/{common.json,nav.json,...,pages/,components/}`). Legacy flat `<lang>.json` files (pre-2.2.0) are automatically removed during sync.
6. Persists the selection in `src/locales/.languages.json` (schema `{ version: 1, codes: string[] }`)
7. Copies selected `src/features/` (auth, home, template); `assistant/` is copied conditionally based on selection (AppLayout depends on it, but features are loaded dynamically)
8. Copies selected `src/pages/` thin wrappers; `AssistantPage.tsx` is copied conditionally based on selection
9. Generates a tailored `AuthGuard.tsx` based on selected pages
10. Generates `src/styles/xertica/tokens.css` for the chosen color theme
11. Persists configuration choices in `.xertica.json` (schema `{ version: 1, hasAssistant: boolean, disableDarkMode: boolean }`)

### `update` flow

The `update` command offers five options:

| Option            | Behavior                                                                                                                                                                                                                                                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Theme only**    | Regenerates `src/styles/xertica/tokens.css` from a new theme                                                                                                                                                                                                                                                                   |
| **Languages**     | Reads `src/locales/.languages.json`, shows current selection, prompts for the new set, computes diff (`+`/`-`), and regenerates `App.tsx` + `i18n.ts`, copies/prunes locale **folders** (migrates legacy flat `.json` files if found)                                                                                          |
| **Dark Mode**     | Toggles dark mode support: enables it or disables it (updates `.xertica.json` and regenerates `App.tsx` to set `disableDarkMode` flag)                                                                                                                                                                                         |
| **Assistant**     | Adds or removes the AI Assistant (copies/deletes files, regenerates `AuthGuard.tsx`, `HomePage.tsx`, `TemplatePage.tsx`)                                                                                                                                                                                                       |
| **Project files** | Re-installs a specific version of `xertica-ui` and copies selected parts (app, shared, features, pages, root config) — for the `app` branch, the user's language selection is **preserved** by reading `.languages.json` (or inferring from `locales/` for legacy projects) and regenerating `App.tsx` + `i18n.ts` accordingly |

### Authoring CLI code

- Generators (`generateAppTsx`, `generateI18nFile`) live in `bin/language-config.ts`. Always update both when changing the App.tsx structure or i18n.ts setup in `templates/src/`.
- Static files in `templates/src/app/App.tsx` and `templates/src/i18n.ts` exist for reference/Storybook but are **not** copied during `init` — they are reconstructed by the generators. Keep them in sync with the generators so contributors reading them see the canonical shape.
- `SUPPORTED_LANGUAGES` in `bin/language-config.ts` is the single source of truth for CLI-exposed locales. Adding a language requires a **folder** at `templates/src/locales/<code>/` (mirroring the existing folder structure), an entry in `SUPPORTED_LANGUAGES`, and a corresponding entry in `DEFAULT_LANGUAGES` in `contexts/LanguageContext.tsx`.

---

## 13. Versioning

This project follows [Semantic Versioning](https://semver.org/):

- **Patch** (2.0.x): Bug fixes, doc updates, export additions that don't break anything
- **Minor** (2.x.0): New components, new subpath exports, new CLI features
- **Major** (x.0.0): Breaking changes to component APIs, token renames, export removals

Every version bump must:

1. Update `version` in `package.json`
2. Update the version badge in `README.md`
3. Add a `CHANGELOG.md` entry with Added / Changed / Fixed sections
4. Update `templates/package.json` `xertica-ui` dependency to `^[new-version]`

> The CLI version is read from `package.json` at runtime (`bin/cli.ts` calls `JSON.parse(readFileSync('package.json'))`). No manual `.version()` update needed.

---

## 14. Pre-Release Checklist

Before running `npm publish`:

- [ ] `npm run build:production` passes without errors
- [ ] `npm run build:types` passes without errors
- [ ] `npm run build:cli` passes without errors
- [ ] `npm test` passes (unit + Storybook chromium)
- [ ] All new components have docs in `docs/components/`, entry in `components.json`, and section in `llms-full.txt`
- [ ] All new user-facing strings are in the appropriate split file under `locales/pt-BR/`, `locales/en/`, `locales/es/` AND mirrored in `templates/src/locales/<lang>/`
- [ ] Data-bearing block components have a matching `*Skeleton` export and documentation
- [ ] `llms.txt` is up to date (component count, new entries)
- [ ] `CHANGELOG.md` has an entry for this version
- [ ] `README.md` version badge is updated
- [ ] `templates/package.json` references the new version
