{"_id":"@core-tecnologias-empresariales/core-ui","_rev":"3-86db31ba37308d070db1bbf7e87e7b06","name":"@core-tecnologias-empresariales/core-ui","dist-tags":{"latest":"0.3.1"},"versions":{"0.2.0":{"name":"@core-tecnologias-empresariales/core-ui","version":"0.2.0","license":"UNLICENSED","_id":"@core-tecnologias-empresariales/core-ui@0.2.0","maintainers":[{"name":"balamchac","email":"marcelosazop@gmail.com"}],"dist":{"shasum":"c04b556201eca74f0af3e71d4341b15e9f99ca37","tarball":"https://registry.npmjs.org/@core-tecnologias-empresariales/core-ui/-/core-ui-0.2.0.tgz","fileCount":15,"integrity":"sha512-6HsGKbIAY2C0jEstQCZ3zNwsxQE3ion5kzXGRBwzazc7x2ALdInEY4LGUtcSq6ubf6OFsykUCLdbLO1FpOCXwQ==","signatures":[{"sig":"MEUCIDky8+HijDUnu8aR5pHPuRSJiECq9zC/L1sIh45MkODIAiEA6SoyMg6dbN5XgUgmWkTvHjhUowoFWb6qqoDQPzhALNU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":92367},"main":"./dist/index.js","type":"module","_from":"file:core-tecnologias-empresariales-core-ui-0.2.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./components":{"types":"./dist/components/index.d.ts","default":"./dist/components/index.js"},"./tailwind-preset":{"types":"./dist/tailwind-preset.d.ts","default":"./dist/tailwind-preset.js"},"./styles/tokens.css":"./styles/tokens.css"},"scripts":{"test":"vitest run","build":"tsup && node dist/scripts/build-css.js","typecheck":"tsc --noEmit -p tsconfig.json"},"_npmUser":{"name":"balamchac","email":"marcelosazop@gmail.com"},"_resolved":"C:\\Users\\Administrador\\AppData\\Local\\Temp\\8940bfbb6284321852c2bfe28f64bd66\\core-tecnologias-empresariales-core-ui-0.2.0.tgz","_integrity":"sha512-6HsGKbIAY2C0jEstQCZ3zNwsxQE3ion5kzXGRBwzazc7x2ALdInEY4LGUtcSq6ubf6OFsykUCLdbLO1FpOCXwQ==","_npmVersion":"11.11.0","description":"Sistema visual transversal (design tokens, 11 temas oficiales, componentes) del ecosistema Core Tecnología Empresarial.","directories":{},"_nodeVersion":"20.20.0","dependencies":{"clsx":"^2.1.1","tailwind-merge":"^2.5.5","tailwindcss-animate":"^1.0.7","@radix-ui/react-slot":"^1.1.1","@radix-ui/react-tabs":"^1.1.2","@radix-ui/react-avatar":"^1.1.2","@radix-ui/react-dialog":"^1.1.4","@radix-ui/react-select":"^2.1.4","@radix-ui/react-switch":"^1.1.2","@radix-ui/react-popover":"^1.1.4","@radix-ui/react-tooltip":"^1.1.6","@radix-ui/react-checkbox":"^1.1.3","@radix-ui/react-radio-group":"^1.2.2","@radix-ui/react-dropdown-menu":"^2.1.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","jsdom":"^25.0.1","react":"^18.3.1","vitest":"^2.1.8","react-dom":"^18.3.1","typescript":"^5.7.0","@types/node":"^20.14.0","@types/react":"^18.3.12","lucide-react":"^0.468.0","@types/react-dom":"^18.3.1","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.5.2"},"peerDependencies":{"react":">=18","react-dom":">=18","lucide-react":">=0.400.0"},"_npmOperationalInternal":{"tmp":"tmp/core-ui_0.2.0_1788053524055_0.7629180487559915","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@core-tecnologias-empresariales/core-ui","version":"0.3.0","license":"UNLICENSED","_id":"@core-tecnologias-empresariales/core-ui@0.3.0","maintainers":[{"name":"balamchac","email":"marcelosazop@gmail.com"}],"dist":{"shasum":"b9ab41b034c48c45c3e52d97edbf8b1f67784abd","tarball":"https://registry.npmjs.org/@core-tecnologias-empresariales/core-ui/-/core-ui-0.3.0.tgz","fileCount":15,"integrity":"sha512-dAdzz8k3HndUo4P/sJaiTB/mU8zKXc+ueKrUOu8bjWyXumxsgOSmEQz6KOZElyaJItWM7F3YF7ppMTD9soYxfA==","signatures":[{"sig":"MEUCIHuIa7NkV4d0Lrbwi864/zn8gokrKVtEeSUd1CFrTyeuAiEA4eIZqAyrZcYQlN1c+L27l+3yiipTJPqG0ecEeLKt34E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCw8nFlyu2JcXtNX7ruS6GDYIFoqnLy9JySt0SPfLlAbQIgdd9PaUjFwJ3yCpUySmS5W+Qa/YjSpyHSXAx7OBXZ/H0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":105037},"main":"./dist/index.js","type":"module","_from":"file:core-tecnologias-empresariales-core-ui-0.3.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./components":{"types":"./dist/components/index.d.ts","default":"./dist/components/index.js"},"./tailwind-preset":{"types":"./dist/tailwind-preset.d.ts","default":"./dist/tailwind-preset.js"},"./styles/tokens.css":"./styles/tokens.css"},"scripts":{"test":"vitest run","build":"tsup && node dist/scripts/build-css.js","typecheck":"tsc --noEmit -p tsconfig.json"},"_npmUser":{"name":"balamchac","email":"marcelosazop@gmail.com"},"_resolved":"C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\8516d6220eeb1d60f84d32deb7fa4be5\\core-tecnologias-empresariales-core-ui-0.3.0.tgz","_integrity":"sha512-dAdzz8k3HndUo4P/sJaiTB/mU8zKXc+ueKrUOu8bjWyXumxsgOSmEQz6KOZElyaJItWM7F3YF7ppMTD9soYxfA==","_npmVersion":"11.11.0","description":"Sistema visual transversal (design tokens, 11 temas oficiales, componentes) del ecosistema Core Tecnología Empresarial.","directories":{},"_nodeVersion":"20.20.0","dependencies":{"clsx":"^2.1.1","tailwind-merge":"^2.5.5","tailwindcss-animate":"^1.0.7","@radix-ui/react-slot":"^1.1.1","@radix-ui/react-tabs":"^1.1.2","@radix-ui/react-avatar":"^1.1.2","@radix-ui/react-dialog":"^1.1.4","@radix-ui/react-select":"^2.1.4","@radix-ui/react-switch":"^1.1.2","@radix-ui/react-popover":"^1.1.4","@radix-ui/react-tooltip":"^1.1.6","@radix-ui/react-checkbox":"^1.1.3","@radix-ui/react-radio-group":"^1.2.2","@radix-ui/react-dropdown-menu":"^2.1.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","jsdom":"^25.0.1","react":"^18.3.1","vitest":"^2.1.8","react-dom":"^18.3.1","typescript":"^5.7.0","@types/node":"^20.14.0","@types/react":"^18.3.12","lucide-react":"^0.468.0","@types/react-dom":"^18.3.1","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.5.2"},"peerDependencies":{"react":">=18","react-dom":">=18","lucide-react":">=0.400.0"},"_npmOperationalInternal":{"tmp":"tmp/core-ui_0.3.0_1790467995465_0.8572129895033196","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"_id":"@core-tecnologias-empresariales/core-ui@0.3.1","dist":{"shasum":"79bfd31d41fd0282aa73a0beaf0f8ee4d310e662","tarball":"https://registry.npmjs.org/@core-tecnologias-empresariales/core-ui/-/core-ui-0.3.1.tgz","fileCount":15,"integrity":"sha512-3ev8KCAc2WAfrU2zAiVk3zpKzqbk8nIUgdtRvRUHUekkodZzNcVLrnn4cLDEN3ymuXvKO+MVagG6xYJtYuEwnQ==","signatures":[{"sig":"MEUCIQC1v1AUFzLE+h0dWPNCxl109gOOdEuTE8vultcWRfQeOAIgYJWEyy0y9BsqL2psR0/b7xZVWwAxY4uruBuUwXgVhvE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICItz9ct1vMBfnhuwJNxr9NENQ21FNJc6BMiapdrAZj0AiAZf4WyptJ063zq0acF2BXY+Uud75Bhsrk3BYXBvQWl1Q=="}],"unpackedSize":105126},"main":"./dist/index.js","name":"@core-tecnologias-empresariales/core-ui","type":"module","_from":"file:core-tecnologias-empresariales-core-ui-0.3.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./components":{"types":"./dist/components/index.d.ts","default":"./dist/components/index.js"},"./tailwind-preset":{"types":"./dist/tailwind-preset.d.ts","default":"./dist/tailwind-preset.js"},"./styles/tokens.css":"./styles/tokens.css"},"license":"UNLICENSED","scripts":{"test":"vitest run","build":"tsup && node dist/scripts/build-css.js","typecheck":"tsc --noEmit -p tsconfig.json"},"version":"0.3.1","_npmUser":{"name":"balamchac","email":"marcelosazop@gmail.com"},"_resolved":"C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\ace5c6793361968f53a912f5e8383704\\core-tecnologias-empresariales-core-ui-0.3.1.tgz","_integrity":"sha512-3ev8KCAc2WAfrU2zAiVk3zpKzqbk8nIUgdtRvRUHUekkodZzNcVLrnn4cLDEN3ymuXvKO+MVagG6xYJtYuEwnQ==","_npmVersion":"11.11.0","description":"Sistema visual transversal (design tokens, 11 temas oficiales, componentes) del ecosistema Core Tecnología Empresarial.","directories":{},"maintainers":[{"name":"balamchac","email":"marcelosazop@gmail.com"}],"_nodeVersion":"20.20.0","dependencies":{"clsx":"^2.1.1","tailwind-merge":"^2.5.5","tailwindcss-animate":"^1.0.7","@radix-ui/react-slot":"^1.1.1","@radix-ui/react-tabs":"^1.1.2","@radix-ui/react-avatar":"^1.1.2","@radix-ui/react-dialog":"^1.1.4","@radix-ui/react-select":"^2.1.4","@radix-ui/react-switch":"^1.1.2","@radix-ui/react-popover":"^1.1.4","@radix-ui/react-tooltip":"^1.1.6","@radix-ui/react-checkbox":"^1.1.3","@radix-ui/react-radio-group":"^1.2.2","@radix-ui/react-dropdown-menu":"^2.1.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","jsdom":"^25.0.1","react":"^18.3.1","vitest":"^2.1.8","react-dom":"^18.3.1","typescript":"^5.7.0","@types/node":"^20.14.0","@types/react":"^18.3.12","lucide-react":"^0.468.0","@types/react-dom":"^18.3.1","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.5.2"},"peerDependencies":{"react":">=18","react-dom":">=18","lucide-react":">=0.400.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core-ui_0.3.1_1790469857283_0.2457406740968473"}}},"time":{"created":"2026-08-30T01:32:03.880Z","modified":"2026-09-27T00:44:23.591Z","0.2.0":"2026-08-30T01:32:04.200Z","0.3.0":"2026-09-27T00:13:15.542Z","0.3.1":"2026-09-27T00:44:17.378Z"},"license":"UNLICENSED","description":"Sistema visual transversal (design tokens, 11 temas oficiales, componentes) del ecosistema Core Tecnología Empresarial.","maintainers":[{"name":"balamchac","email":"marcelosazop@gmail.com"}],"readme":"# @core-tecnologias-empresariales/core-ui\n\nSistema visual transversal del ecosistema Core Tecnología Empresarial. Todos los productos (CorePyme, Core Tributario, Core Contador) consumen esta capa — no crean sistemas visuales paralelos.\n\n## Entradas del paquete\n\n```ts\nimport { THEMES, applyTheme } from \"@core-tecnologias-empresariales/core-ui\";            // tokens/temas, sin React\nimport { Sheet, VerificationCodeInput } from \"@core-tecnologias-empresariales/core-ui/components\"; // capa React\nimport { tailwindPreset } from \"@core-tecnologias-empresariales/core-ui/tailwind-preset\";\n```\n\nEstán separadas a propósito: un `tailwind.config` o un proceso backend importa los temas sin arrastrar React.\n\n### Los 11 temas oficiales\n\n```text\nLIGHT: light-1 … light-6     DARK: dark-1 … dark-5\n```\n\nTranscritos literalmente del `CLAUDE.md` §8 — 110 valores de color, verificados por tests. Default: `light-4` / `dark-1`.\n\n> **Histórico:** las versiones previas del documento maestro enumeraban un `light-7` con paleta idéntica a `light-5`. Se resolvió como duplicación accidental y se eliminó del catálogo (decisión del 2026-08-29, registrada en `CLAUDE.md`). Un test impide que dos temas vuelvan a compartir paleta.\n\n### Uso\n\n```css\n/* Una vez, en el entry CSS de la app */\n@import \"@core-tecnologias-empresariales/core-ui/styles/tokens.css\";\n```\n\n```ts\nimport { applyTheme, THEME_IDS, defaultThemeFor } from \"@core-tecnologias-empresariales/core-ui\";\n\napplyTheme(document.documentElement, \"dark-1\");   // cambia el tema, sin tocar componentes\ndefaultThemeFor(\"dark\");                           // \"dark-1\"\nTHEME_IDS;                                         // para poblar un selector de temas\n```\n\nCambiar de tema es escribir `data-theme` en el elemento raíz. **Nunca requiere modificar un componente** (CLAUDE.md §8). Sin `data-theme`, la hoja respeta `prefers-color-scheme` del sistema.\n\n### Tailwind\n\n```js\n// tailwind.config.js del producto\nimport { tailwindPreset } from \"@core-tecnologias-empresariales/core-ui/tailwind-preset\";\nexport default { presets: [tailwindPreset], content: [...] };\n```\n\nLas clases quedan mapeadas a los tokens: `bg-bg-200`, `text-text-100`, `text-primary`, `shadow-md`, `rounded-lg`, `z-drawer`, `font-mono`. Un producto que escribe `bg-[#123456]` está violando la regla contra hardcoding (§8) — el preset existe para que no haga falta.\n\n### Tokens disponibles\n\n| Grupo | Tokens |\n|---|---|\n| Paleta | `--primary-100/200/300`, `--accent-100/200`, `--text-100/200`, `--bg-100/200/300` |\n| Semánticos | `--color-success/warning/danger/info` |\n| Estado | `--color-border/muted/hover/active/focus/selected/disabled` (derivados del tema) |\n| Tipografía | `--font-sans` (IBM Plex Sans), `--font-mono` (IBM Plex Mono) |\n| Escalas | `--space-*`, `--radius-*`, `--shadow-*`, `--z-*`, `--breakpoint-*`, `--motion-*` |\n\nLos semánticos se definen una vez por modo (light/dark) en lugar de 4 × 12 temas: menos superficie, mismo resultado accesible. Los de estado se derivan del tema, así que nunca hay que hardcodearlos por producto.\n\n### Tipografía\n\nEl paquete define el *stack* (`--font-sans` / `--font-mono`) pero **no empaqueta los archivos de fuente** — cargarlos es decisión del producto (`next/font`, self-host o CDN), y evita arrastrar ~2MB de woff2 a todos los consumidores. Regla de uso: IBM Plex Sans para toda la interfaz, IBM Plex Mono solo para RUT, folios, IDs, códigos, JSON y logs.\n\n## Decisiones tomadas\n\n- **Drawer: shadcn/ui `Sheet` sobre `@radix-ui/react-dialog`** — CLAUDE.md §15 manda preferir shadcn/Radix. Google Analytics es la referencia de *UX* (§14), no de librería: se replica su comportamiento (panel lateral, scrim, header con cierre, cuerpo scrolleable, acciones abajo) sin traer Material, que rompería Tailwind y Lucide (§12).\n- **Sin `vaul`** — el bottom-sheet con gesto de arrastre es patrón móvil/consumer; el Sheet de Radix ya cubre móvil a ancho completo. Se agrega solo si la experiencia móvil lo pide.\n- **Los temas se generan desde datos tipados**, no se escriben a mano: `src/themes.ts` es la única fuente de verdad y alimenta tanto `styles/tokens.css` como el selector de temas.\n\n## Componentes (v0.3)\n\n### `Sheet` — panel lateral\n\nEl patrón principal de interacción del ecosistema, sobre `@radix-ui/react-dialog` (que aporta focus trap, cierre con Esc, scroll lock y ARIA sin código propio).\n\n```tsx\n<Sheet>\n  <SheetTrigger>Nuevo usuario</SheetTrigger>\n  <SheetContent side=\"right\">\n    <SheetHeader>\n      <SheetTitle>Nuevo usuario</SheetTitle>\n      <SheetDescription>Completa los datos.</SheetDescription>\n    </SheetHeader>\n    <SheetBody>{/* formulario */}</SheetBody>\n    <SheetFooter>\n      <SheetClose>Cancelar</SheetClose>\n      <button type=\"submit\">Guardar</button>\n    </SheetFooter>\n  </SheetContent>\n</Sheet>\n```\n\nEstructura `Header / Body / Footer` obligatoria: el cuerpo scrollea y el footer nunca se va de la vista. Ancho contenido en desktop (`420px`), full-width bajo `sm`. `side` acepta `right` (default), `left`, `top`, `bottom`.\n\n**Cuándo NO usarlo:** procesos de múltiples etapas, navegación interna compleja o pantallas de trabajo completas — ahí va una página dedicada.\n\n### `VerificationCodeInput` — código de verificación\n\nPara recuperación de contraseña y MFA. Placeholder de guiones y presentación monoespaciada según el documento maestro.\n\n```tsx\n<VerificationCodeInput\n  length={6}\n  value={code}\n  onChange={setCode}\n  onComplete={(code) => verificar(code)}\n  error={codigoInvalido}\n/>\n```\n\nImplementado como **un solo input monoespaciado**, no como N casillas: el pegado del código, la navegación con teclado, el borrado y el autocompletado del SMS (`autoComplete=\"one-time-code\"`) los resuelve el input nativo. Las casillas segmentadas exigirían ~100 líneas de manejo de refs y foco para el mismo resultado visible.\n\n> No lleva `maxLength`: ese atributo cuenta caracteres crudos y truncaba un pegado con separadores (`\"48-39 20\"` → `\"48-39 \"`) antes de poder extraer los dígitos. El recorte se hace después de limpiar.\n\n### `Toaster` + `toast` + `Message` — notificaciones (v0.3)\n\nUn solo sistema de notificaciones (CLAUDE.md §13): `success | info | warning | error`, con **el mismo diseño** flotante (`Toaster`) y en línea (`Message`). Existe porque el Toast que traía cada producto se veía distinto y sin contraste en modo oscuro; su primer consumidor real fue Core Tributario.\n\n```tsx\n// Una vez, en el layout raíz de la app\nimport { Toaster } from \"@core-tecnologias-empresariales/core-ui/components\";\n<Toaster position=\"top-center\" offset=\"4.25rem\" />  {/* offset = alto del header fijo */}\n\n// Desde cualquier lugar (sin hook ni context)\nimport { toast } from \"@core-tecnologias-empresariales/core-ui/components\";\ntoast.success({ title: \"Certificado cargado\" });\ntoast.error({ title: \"No se pudo cargar el CAF\", description: \"El RUT del CAF no coincide con el de la empresa.\" });\n\n// En línea: errores de carga, resultado de un formulario, avisos que deben quedarse a la vista\n<Message variant=\"error\" title=\"No se pudieron cargar los clientes\" />\n```\n\n- **Contraste**: el color vive en el ícono y en la barra de tiempo, nunca en el texto — el texto siempre tiene el contraste pleno del tema, en claro y oscuro.\n- **Copiar**: cada mensaje trae el botón de copiar (`copyable={false}` lo oculta); usa la API moderna del portapapeles y, si el navegador la niega, el método clásico.\n- **Cierre**: los errores duran 9 s, el resto 4,5–7 s (`duration` lo cambia; `null` = no se cierra sola). La cuenta regresiva se ve como una barra y **se pausa** con el cursor encima o el foco dentro.\n- **Sin ruido**: una notificación idéntica a una visible no se apila; máximo 4 a la vez.\n- **Posición**: `top-center` por defecto (donde el usuario ya está mirando), `top-right`, `bottom-right`, `bottom-center`. `offset` deja espacio bajo un header fijo.\n- **Accesibilidad**: `role=\"alert\"` para errores y `role=\"status\"` para el resto; el movimiento respeta `prefers-reduced-motion`.\n- El paquete no depende de ningún producto: no sabe qué es un \"movimiento\" ni un \"documento\", sólo muestra texto.\n\n### Resto de primitivos\n\n`Button` (variants `primary/secondary/ghost/danger/outline`, `loading`, `asChild` para renderizar como `<a>`), `Input`, `Textarea`, `Label` (con `required`), `Card`/`CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`, `Badge`, `Alert` (con ícono propio por variante — el color nunca es el único indicador, CLAUDE.md §26), `Skeleton`, `EmptyState`, `ErrorState`, `Tabs`, `Tooltip`, `Avatar`, `Dialog` (confirmaciones/acciones destructivas, distinto de `Sheet`), `DropdownMenu`, `Checkbox`, `RadioGroup`, `Switch`, `Progress` (nativo, sin dependencia), `Popover`, `Select`.\n\n> `Badge`/`Alert` no usan fondos translúcidos (`bg-danger/15`): los tokens de color son hex planos y no soportan el modificador de opacidad de Tailwind sin convertirlos a `rgb()`+`<alpha-value>`. Usan fondo neutro + texto en el color semántico.\n\n## Aún no incluido\n\n`Combobox`, `DatePicker`, `DataTable`, `Form` (wrapper RHF+Zod), `Pagination`, y los empresariales `RutInput`/`CurrencyInput`/`PercentageInput`/`PhoneInput`. Se agregan cuando `core-dashboard`/`core-shell` (o un producto) tengan un consumidor real que dicte su forma — no de manera especulativa.\n\n## Tests lentos bajo jsdom (conocido, no bloqueante)\n\nLos tests de `Tooltip`, `DropdownMenu`, `Select`, `Popover` tardan más que el default de vitest: el detector de animaciones de Radix Presence (`getAnimations()`/`animationend`) no tiene equivalente real en jsdom y cae a un fallback lento (15-100s por test en este entorno). Se resolvió con dos técnicas, documentadas inline en cada archivo:\n- Controlar `open` directamente en vez de simular el toggle con click/hover, cuando el test no necesita verificar la transición en sí.\n- Timeout explícito por test cuando sí hace falta una interacción real (`userEvent.click`).\n\nEn corridas de la suite completa que superan ~10-15 min continuos, el canal RPC interno de vitest (worker↔main thread) puede caerse por agotamiento de recursos del sandbox (`Timeout calling \"onTaskUpdate\"`), típicamente durante el test de click de `dropdown-menu.test.tsx` — no es un fallo de aserción ni un bug del componente (su lógica es idéntica a la de `Sheet`/`Dialog`, verificados). Si aparece, correr ese archivo solo.\n\n## Desarrollo\n\n```bash\npnpm build   # compila TS y regenera styles/tokens.css\npnpm test\n```\n\n`styles/tokens.css` es **generado** — no editarlo a mano; cambiar `src/themes.ts` o `src/tokens.ts` y rebuildear.\n","readmeFilename":"README.md"}