# onaris-ui · Handoff para Claude Code

Paquete de especificación para generar la librería **onaris-ui** (React 18 + TypeScript) a partir de la guía de estilo Onaris (by Inase). Lee este archivo primero; el resto son anexos.

## Contenido del paquete

| Archivo | Qué es |
|---|---|
| `spec/README.md` | Este documento: decisiones, estructura, reglas y criterios de aceptación. |
| `spec/tokens.json` | Todos los tokens agrupados (color, brand, tipografía, sombra, radius, size, motion, zIndex, breakpoint). Fuente: `tokens.css`. |
| `spec/components.json` | 32 componentes: nombre exportado, categoría, descripción, variantes/estados y tabla de props. |
| `spec/COMPONENTS.md` | Lo mismo que `components.json` en formato legible, con ejemplos JSX. |
| `tokens.css` | Variables CSS canónicas. Copiar tal cual como `src/styles/tokens.css`. |
| `components.css` | Implementación CSS de referencia (clases `.ou-*`). Úsala como verdad visual. |
| `pages/*.html` | Guía visual navegable: marca, fundamentos, iconos y componentes. |
| `assets/brand/*.svg` | Logotipos e isotipo oficiales (extraídos del Brand Guidelines, sept. 2024). |

## Decisiones cerradas

- **Stack**: React 18 + TypeScript estricto. CSS Modules o CSS plano con las clases `.ou-*`; los valores siempre vía `var(--token)`, nunca hex en componentes.
- **Compatibilidad**: los nombres de componentes y props deben coincidir con la librería actual para que la migración sea un cambio de import. Si un nombre de este spec choca con uno existente, gana el existente; documenta el alias.
- **Dirección visual**: Sharp & Technical. Radios contenidos (`--radius-md` 6px en controles, `--radius-xl` 8px en modales/drawers), sin sombras salvo overlays.
- **Densidad**: densa. Altura por defecto de controles **32px** (`--size-md`), `sm` 28px, `lg` 40px.
- **Modo de color**: solo light. Los tokens están preparados para un tema oscuro futuro sin tocar componentes.
- **Botón primario**: color **Leading** (`#172836`), no coral. Coral (`--color-accent`) se reserva para foco, selección, estados activos de navegación y la variante `soft-accent` («Destacar»).
- **Sombra**: una sola, `--shadow-md`, solo para elementos superpuestos (dropdown, popover, drawer, modal, toast, slider).
- **Foco**: Input, Textarea, Select y pickers marcan foco **solo con borde `--color-accent`**, sin sombra. Botones y checkbox/radio/switch usan `--shadow-focus` (anillo) solo con `:focus-visible`.
- **Input de texto**: con foco y con valor, muestra botón para borrar (icono `x`). PasswordInput alterna mostrar/ocultar con `eye` / `eye-off`.
- **Semánticos**: success, warning (en progreso, tono ámbar/naranja), danger (error) e info. Cada uno con base + `-text`; `soft`/`border`/`hover` se derivan con `color-mix` en tokens.
- **Tipografía**: Plus Jakarta Sans, solo pesos **400, 500, 600, 700** (el manual de marca no permite otros). JetBrains Mono para SKU, IDs, códigos y cifras tabulares. Ocho roles: title, subtitle, body, body-strong, body-sm, caption, eyebrow, mono (`--text-<rol>-size|weight|lh|ls`).
- **Iconos**: `lucide-react`, trazo 2, tamaños 14 (inline), 16 (default), 20 (lg). Solo los iconos documentados en `pages/06-icons.html`; no mezclar con otros sets ni con iconos rellenos.
- **Marca**: cumplir `pages/00-brand.html`. Logotipo mín. 160px (con baseline horizontal 240px), isotipo mín. 50px, espacio libre = altura de la «n» / un módulo. Sobre fondo oscuro o coral, logo en blanco. Nunca recolorear, distorsionar, rotar, añadir efectos ni degradados al logo.
- **Paleta de marca** (`--brand-*`) y degradados (`--brand-gradient-*`): para comunicación, webs públicas e ilustración/gráficos. No sustituyen a los semánticos en la UI.

## Estructura de paquete propuesta

```
onaris-ui/
├─ src/
│  ├─ styles/        tokens.css · base.css (reset + fuentes)
│  ├─ tokens/        index.ts  (export const tokens = … generado desde tokens.json)
│  ├─ brand/         Logo.tsx · LogoBaseline.tsx · Isotype.tsx (SVG inline, prop variant: coral|white|navy|current)
│  ├─ icons/         Icon.tsx  (wrapper de lucide-react con size: 'sm'|'md'|'lg')
│  ├─ components/    <Nombre>/<Nombre>.tsx · <Nombre>.module.css · <Nombre>.stories.tsx · index.ts
│  └─ index.ts       re-export público
├─ .storybook/
└─ package.json      peerDeps: react, react-dom, lucide-react
```

## Orden de trabajo

1. Tokens + base + `Icon` + componentes de marca.
2. Forms: Button, IconButton, Input, PasswordInput, Textarea, Select, DatePicker, TimePicker, ColorPicker, Checkbox, Radio/RadioGroup, Switch, Field.
3. Feedback: Badge, Pill, Alert, Toast (+ `toast()` y `<Toaster/>`), Progress, Spinner, Skeleton, Empty.
4. Overlays: Modal, Drawer, Tooltip, Popover, Menu.
5. Navigation: Tabs, Accordion, Breadcrumbs, Pagination, Tree.
6. Data: Table, Card, Avatar.
7. Storybook con una historia por variante y estado documentado en `components.json`.

## Reglas de implementación

- Cada componente acepta `className` y reenvía `ref` (`forwardRef`) al elemento nativo principal.
- Props nativas HTML se propagan (`...rest`) al elemento raíz.
- Estados `hover / focus-visible / active / disabled` exactamente como en `components.css`. `disabled` = opacidad reducida + `cursor: not-allowed`, sin eventos.
- Overlays: portal a `document.body`, trampa de foco, cierre con `Esc`, devolver foco al disparador, `aria-modal` en Modal/Drawer. Se puede usar Radix UI como base headless si ya está en el stack actual.
- Accesibilidad: `IconButton` exige `aria-label`; labels asociados con `htmlFor`; contraste AA.
- Sin colores literales en componentes: todo vía tokens. Sin pesos de fuente fuera de 400–700.

## Criterios de aceptación

- Cada componente de `components.json` existe con sus props y valores por defecto.
- Las historias de Storybook coinciden visualmente con `pages/components-*.html`.
- `npm run build` genera ESM + tipos `.d.ts`; `tsc --noEmit` sin errores.
- Sustituir el import de la librería actual por `onaris-ui` en un proyecto existente compila sin cambios de nombres.
