create-lexy 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +7 -2
  2. package/assets/fonts/{OFL-NotoSans.txt → LICENSE-Geist.txt} +4 -5
  3. package/assets/fonts/geist-mono-variable-italic.woff2 +0 -0
  4. package/assets/fonts/geist-mono-variable.woff2 +0 -0
  5. package/assets/fonts/geist-sans-variable-italic.woff2 +0 -0
  6. package/assets/fonts/geist-sans-variable.woff2 +0 -0
  7. package/assets/r/accordion.json +3 -3
  8. package/assets/r/alert-dialog.json +3 -3
  9. package/assets/r/app-accordion.json +1 -1
  10. package/assets/r/app-dialog.json +3 -3
  11. package/assets/r/app-header-bar.json +2 -2
  12. package/assets/r/app-sidebar.json +2 -2
  13. package/assets/r/avatar.json +3 -3
  14. package/assets/r/badge.json +3 -3
  15. package/assets/r/brand-background.json +1 -1
  16. package/assets/r/breadcrumb.json +3 -3
  17. package/assets/r/button-group.json +3 -3
  18. package/assets/r/button.json +3 -3
  19. package/assets/r/calendar.json +2 -2
  20. package/assets/r/card.json +3 -3
  21. package/assets/r/chart.json +2 -2
  22. package/assets/r/checkbox.json +2 -2
  23. package/assets/r/combobox.json +3 -3
  24. package/assets/r/command.json +3 -3
  25. package/assets/r/confirmacion.json +1 -1
  26. package/assets/r/counter-badge.json +3 -3
  27. package/assets/r/crm-desk.json +1 -1
  28. package/assets/r/crm-detalle-caso.json +5 -5
  29. package/assets/r/date-picker.json +1 -1
  30. package/assets/r/dialog.json +3 -3
  31. package/assets/r/dropdown-menu.json +3 -3
  32. package/assets/r/empty.json +2 -2
  33. package/assets/r/feature-card.json +3 -3
  34. package/assets/r/form.json +3 -3
  35. package/assets/r/header-bar.json +2 -2
  36. package/assets/r/input.json +3 -3
  37. package/assets/r/intake-wizard.json +1 -1
  38. package/assets/r/label.json +3 -3
  39. package/assets/r/logo.json +2 -2
  40. package/assets/r/menubar.json +3 -3
  41. package/assets/r/navigation-menu.json +3 -3
  42. package/assets/r/pagination.json +2 -2
  43. package/assets/r/popover.json +3 -3
  44. package/assets/r/profile-card.json +3 -3
  45. package/assets/r/progress.json +2 -2
  46. package/assets/r/radio-group.json +2 -2
  47. package/assets/r/registry.json +47 -47
  48. package/assets/r/scroll-area.json +2 -2
  49. package/assets/r/searchbox.json +3 -3
  50. package/assets/r/select.json +3 -3
  51. package/assets/r/separator.json +2 -2
  52. package/assets/r/sheet.json +2 -2
  53. package/assets/r/sidebar.json +3 -3
  54. package/assets/r/skeleton.json +2 -2
  55. package/assets/r/slider.json +3 -3
  56. package/assets/r/snippet.json +3 -3
  57. package/assets/r/spinner.json +2 -2
  58. package/assets/r/status-dot.json +3 -3
  59. package/assets/r/switch.json +3 -3
  60. package/assets/r/table.json +3 -3
  61. package/assets/r/tabs.json +3 -3
  62. package/assets/r/tag.json +3 -3
  63. package/assets/r/textarea.json +3 -3
  64. package/assets/r/toaster.json +3 -3
  65. package/assets/r/tooltip.json +3 -3
  66. package/assets/r/tree.json +3 -3
  67. package/assets/registry-version +1 -1
  68. package/assets/theme/lexy-theme.css +562 -112
  69. package/dist/index.js +590 -276
  70. package/package.json +4 -2
  71. package/templates/.claude/skills/lexy-design/SKILL.md +189 -0
  72. package/templates/.claude/skills/lexy-dev/SKILL.md +168 -0
  73. package/templates/.claude/skills/lexy-mock-data/SKILL.md +50 -0
  74. package/templates/.github/copilot-instructions.md +50 -0
  75. package/templates/.mcp.json +8 -0
  76. package/templates/AGENTS.md +243 -0
  77. package/templates/CLAUDE.md +61 -0
  78. package/templates/ai/IMPLEMENTATION-PROTOCOL.md +148 -0
  79. package/templates/ai/PRODUCTION-CLEANUP.md +17 -0
  80. package/templates/ai/PROJECT-CONTEXT.md +65 -0
  81. package/templates/ai/README.md +19 -0
  82. package/templates/ai/TECHNICAL-USAGE.md +220 -0
  83. package/templates/ai/pautas/arquitectura-informacion-ux.md +243 -0
  84. package/templates/ai/pautas/buenas-practicas.md +236 -0
  85. package/templates/ai/pautas/calidad-industria.md +109 -0
  86. package/templates/ai/pautas/diseno-cliente.md +136 -0
  87. package/templates/ai/pautas/diseno-crm-lexy.md +109 -0
  88. package/templates/ai/pautas/patrones-de-codigo.md +234 -0
  89. package/templates/ai/pautas/recetas-layout.md +419 -0
  90. package/templates/ai/pautas/sistema-visual.md +197 -0
  91. package/templates/ai/pautas/ux-writing.md +214 -0
  92. package/templates/scripts/check-geometry.mjs +139 -0
  93. package/assets/fonts/noto-sans-latin.woff2 +0 -0
@@ -3,7 +3,7 @@
3
3
  "name": "textarea",
4
4
  "type": "registry:ui",
5
5
  "title": "Textarea",
6
- "description": "Campo de texto multilínea, redimensionable verticalmente (alto mínimo predefinido). Renderiza un `<textarea>` nativo. El componente vive en tu proyecto: instálalo con `create-lexy add textarea` y edítalo con libertad.",
6
+ "description": "Campo de texto multilínea, redimensionable verticalmente (alto mínimo predefinido). Renderiza un `<textarea>` nativo.",
7
7
  "dependencies": [],
8
8
  "registryDependencies": [],
9
9
  "files": [
@@ -11,13 +11,13 @@
11
11
  "path": "components/base/Textarea.tsx",
12
12
  "type": "registry:ui",
13
13
  "target": "components/base/Textarea.tsx",
14
- "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<\"textarea\">>(\n ({ className, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n \"flex min-h-20 w-full resize-y rounded border border-input bg-background px-3 py-2.5 text-sm text-foreground outline-none transition-colors duration-150\",\n \"placeholder:text-muted-foreground\",\n \"hover:border-muted-foreground/40\",\n \"focus-visible:border-primary\",\n \"aria-invalid:border-destructive aria-invalid:hover:border-destructive aria-invalid:focus-visible:border-destructive\",\n \"disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-input\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n"
14
+ "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<\"textarea\">>(\n ({ className, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n \"type-supporting flex min-h-20 w-full resize-y rounded-control border border-input bg-background px-3 py-2.5 text-foreground outline-none transition-colors duration-[var(--duration-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none\",\n \"placeholder:text-muted-foreground\",\n \"hover:border-muted-foreground/40\",\n \"focus-visible:border-primary\",\n \"aria-invalid:border-destructive aria-invalid:hover:border-destructive aria-invalid:focus-visible:border-destructive\",\n \"disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-input\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n"
15
15
  },
16
16
  {
17
17
  "path": "components/base/Textarea.md",
18
18
  "type": "registry:file",
19
19
  "target": "components/base/Textarea.md",
20
- "content": "# Textarea — guía de uso\n\nCampo de texto multilínea, redimensionable verticalmente (alto mínimo predefinido). Renderiza un `<textarea>` nativo. El componente vive en tu proyecto: instálalo con `create-lexy add textarea` y edítalo con libertad.\n\n## Cuándo usarlo\n\nPara texto libre de varias líneas: descripciones, comentarios, relatos. El alto inicial insinúa la extensión esperada. Para respuestas de una línea, `Input`.\n\n## Composición\n\nUna sola pieza (`Textarea`, un `<textarea>` nativo redimensionable en vertical) con `Label` visible; en formularios validados va dentro de `FormControl`.\n\n## Uso básico\n\n```tsx\n<div className=\"grid gap-1.5\">\n <Label htmlFor=\"notas\">Notas del caso</Label>\n <Textarea id=\"notas\" placeholder=\"Resumen de la reunión…\" rows={4} />\n</div>\n```\n\n## Reglas\n\n- Asocia siempre un `Label` por `htmlFor`/`id`.\n- Usa `rows` para insinuar la longitud esperada de la respuesta.\n- Si hay límite de caracteres, muéstralo cerca del campo (no solo un `maxLength` silencioso).\n- Marca errores con `aria-invalid` + mensaje de texto.\n\n## Cuándo NO usar\n\n- **Una sola línea** (nombre, email, RUT) → `Input`.\n- **Editor con formato/markdown** → no existe en el registry; documenta la decisión si usas algo a medida.\n\n## Import\n\n```tsx\nimport { Textarea } from \"@/components/base/Textarea\";\n```\n\n## Props\n\n| Prop | Tipo | Default | Descripción |\n|---|---|---|---|\n| `rows` | `number` | — | Alto inicial en líneas. |\n| `aria-invalid` | `boolean` | — | Activa el estilo de error. |\n| `disabled` | `boolean` | `false` | Deshabilita el campo. |\n| ...resto | `textarea` props | — | `value`, `onChange`, `placeholder`, `maxLength`, etc. |\n\n## Para IA\n\n1. Úsalo solo cuando se espera texto de varias líneas (comentarios, descripciones, notas).\n2. Empareja con `Label`.\n3. Ajusta `rows` a la longitud esperada.\n4. Si hay tope de caracteres, hazlo visible y redacta el error como corregir.\n"
20
+ "content": "# Textarea\nCampo de texto multilínea, redimensionable verticalmente (alto mínimo predefinido). Renderiza un `<textarea>` nativo.\n\n## Cuándo usarlo\n\nPara texto libre de varias líneas: descripciones, comentarios, relatos. El alto inicial insinúa la extensión esperada. Para respuestas de una línea, `Input`.\n\n## Composición\n\nUna sola pieza (`Textarea`, un `<textarea>` nativo redimensionable en vertical) con `Label` visible; en formularios validados va dentro de `FormControl`.\n\n## Uso básico\n\n```tsx\n<div className=\"grid gap-1.5\">\n <Label htmlFor=\"notas\">Notas del caso</Label>\n <Textarea id=\"notas\" placeholder=\"Resumen de la reunión…\" rows={4} />\n</div>\n```\n\n## Reglas\n\n- Asocia siempre un `Label` por `htmlFor`/`id`.\n- Usa `rows` para insinuar la longitud esperada de la respuesta.\n- Si hay límite de caracteres, muéstralo cerca del campo (no solo un `maxLength` silencioso).\n- Marca errores con `aria-invalid` + mensaje de texto.\n\n## Cuándo NO usar\n\n- **Una sola línea** (nombre, email, RUT) → `Input`.\n- **Editor con formato/markdown** → no existe en el registry; documenta la decisión si usas algo a medida.\n\n## Import\n\n```tsx\nimport { Textarea } from \"@/components/base/Textarea\";\n```\n\n## Props\n\n| Prop | Tipo | Default | Descripción |\n|---|---|---|---|\n| `rows` | `number` | — | Alto inicial en líneas. |\n| `aria-invalid` | `boolean` | — | Activa el estilo de error. |\n| `disabled` | `boolean` | `false` | Deshabilita el campo. |\n| ...resto | `textarea` props | — | `value`, `onChange`, `placeholder`, `maxLength`, etc. |\n\n## Para IA\n\n1. Úsalo solo cuando se espera texto de varias líneas (comentarios, descripciones, notas).\n2. Empareja con `Label`.\n3. Ajusta `rows` a la longitud esperada.\n4. Si hay tope de caracteres, hazlo visible y redacta el error como corregir.\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -3,7 +3,7 @@
3
3
  "name": "toaster",
4
4
  "type": "registry:ui",
5
5
  "title": "Toaster",
6
- "description": "Notificaciones efímeras de la app (sobre **Sonner**, tematizado con tokens Lexy). Se monta **una vez** en el layout raíz y se dispara imperativo con `toast.*` desde cualquier parte. Reemplaza al `Toast` presentacional del sistema antiguo (deprecado). El componente vive en tu proyecto: instálalo con `create-lexy add toaster` y edítalo con libertad.",
6
+ "description": "Notificaciones efímeras de la app (sobre **Sonner**, tematizado con tokens Lexy). Se monta **una vez** en el layout raíz y se dispara imperativo con `toast.*` desde cualquier parte. Reemplaza al `Toast` presentacional del sistema antiguo (deprecado).",
7
7
  "dependencies": [
8
8
  "sonner@^2.0.0"
9
9
  ],
@@ -13,13 +13,13 @@
13
13
  "path": "components/base/Toaster.tsx",
14
14
  "type": "registry:ui",
15
15
  "target": "components/base/Toaster.tsx",
16
- "content": "import * as React from \"react\";\nimport { toast, Toaster as Sonner } from \"sonner\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\n// Toaster de la app (Sonner) tematizado con tokens Lexy. Se monta UNA vez en\n// el layout raíz; después se dispara imperativo desde cualquier parte:\n//\n// toast.success(\"Cambios guardados\");\n// toast.error(\"No pudimos guardar. Intenta de nuevo.\");\n//\n// Los tipos success/error/warning/info colorean con los tokens semánticos del\n// theme (--color-success, --color-destructive, --color-warning, --color-info)\n// vía las CSS vars de Sonner, así que cambiar el theme re-tematiza los toasts.\n//\n// Defaults pensados para CRM (denso, escritorio): bottom-right, 4s, cola de 3.\n// Para mundo cliente (flujos guiados, móvil) se recomienda position=\"top-center\"\n// y duration={6000} — ver criterio en Toaster.md.\n\nexport type ToasterProps = React.ComponentProps<typeof Sonner>;\n\nconst Toaster = ({ className, style, toastOptions, ...props }: ToasterProps) => (\n <Sonner\n className={cn(\"toaster group\", className)}\n position=\"bottom-right\"\n duration={4000}\n visibleToasts={3}\n richColors\n style={\n {\n \"--normal-bg\": \"var(--color-background)\",\n \"--normal-text\": \"var(--color-foreground)\",\n \"--normal-border\": \"var(--color-border)\",\n \"--success-bg\": \"var(--color-background)\",\n \"--success-text\": \"var(--color-success)\",\n \"--success-border\": \"color-mix(in oklab, var(--color-success) 30%, transparent)\",\n \"--error-bg\": \"var(--color-background)\",\n \"--error-text\": \"var(--color-destructive)\",\n \"--error-border\": \"color-mix(in oklab, var(--color-destructive) 30%, transparent)\",\n \"--warning-bg\": \"var(--color-background)\",\n \"--warning-text\": \"var(--color-warning)\",\n \"--warning-border\": \"color-mix(in oklab, var(--color-warning) 30%, transparent)\",\n \"--info-bg\": \"var(--color-background)\",\n \"--info-text\": \"var(--color-info)\",\n \"--info-border\": \"color-mix(in oklab, var(--color-info) 30%, transparent)\",\n \"--border-radius\": \"var(--radius-md)\",\n ...style,\n } as React.CSSProperties\n }\n toastOptions={{\n ...toastOptions,\n classNames: {\n ...toastOptions?.classNames,\n // Capa flotante según el contrato de geometría: shadow-md.\n toast: cn(\"group toast !shadow-md\", toastOptions?.classNames?.toast),\n description: cn(\"!text-muted-foreground\", toastOptions?.classNames?.description),\n actionButton: cn(\n \"!bg-primary !text-primary-foreground\",\n toastOptions?.classNames?.actionButton,\n ),\n cancelButton: cn(\n \"!bg-muted !text-muted-foreground\",\n toastOptions?.classNames?.cancelButton,\n ),\n },\n }}\n {...props}\n />\n);\n\nexport { toast, Toaster };\n"
16
+ "content": "import * as React from \"react\";\nimport { toast, Toaster as Sonner } from \"sonner\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\n// Toaster de la app (Sonner) tematizado con tokens Lexy. Se monta UNA vez en\n// el layout raíz; después se dispara imperativo desde cualquier parte:\n//\n// toast.success(\"Cambios guardados\");\n// toast.error(\"No pudimos guardar. Intenta de nuevo.\");\n//\n// Los tipos success/error/warning/info colorean con los tokens semánticos del\n// theme (--color-success, --color-destructive, --color-warning, --color-info)\n// vía las CSS vars de Sonner, así que cambiar el theme re-tematiza los toasts.\n//\n// Defaults pensados para CRM (denso, escritorio): bottom-right, 4s, cola de 3.\n// Para mundo cliente (flujos guiados, móvil) se recomienda position=\"top-center\"\n// y duration={6000} — ver criterio en Toaster.md.\n\nexport type ToasterProps = React.ComponentProps<typeof Sonner>;\n\nconst Toaster = ({ className, style, toastOptions, ...props }: ToasterProps) => (\n <Sonner\n className={cn(\"toaster group\", className)}\n position=\"bottom-right\"\n duration={4000}\n visibleToasts={3}\n richColors\n style={\n {\n \"--normal-bg\": \"var(--color-background)\",\n \"--normal-text\": \"var(--color-foreground)\",\n \"--normal-border\": \"var(--color-border)\",\n \"--success-bg\": \"var(--color-background)\",\n \"--success-text\": \"var(--color-success)\",\n \"--success-border\": \"color-mix(in oklab, var(--color-success) 30%, transparent)\",\n \"--error-bg\": \"var(--color-background)\",\n \"--error-text\": \"var(--color-destructive)\",\n \"--error-border\": \"color-mix(in oklab, var(--color-destructive) 30%, transparent)\",\n \"--warning-bg\": \"var(--color-background)\",\n \"--warning-text\": \"var(--color-warning)\",\n \"--warning-border\": \"color-mix(in oklab, var(--color-warning) 30%, transparent)\",\n \"--info-bg\": \"var(--color-background)\",\n \"--info-text\": \"var(--color-info)\",\n \"--info-border\": \"color-mix(in oklab, var(--color-info) 30%, transparent)\",\n \"--border-radius\": \"var(--radius-md)\",\n ...style,\n } as React.CSSProperties\n }\n toastOptions={{\n ...toastOptions,\n classNames: {\n ...toastOptions?.classNames,\n // Capa flotante según el contrato de geometría: shadow-overlay.\n toast: cn(\"group toast !shadow-overlay\", toastOptions?.classNames?.toast),\n description: cn(\"!text-muted-foreground\", toastOptions?.classNames?.description),\n actionButton: cn(\n \"!bg-primary !text-primary-foreground\",\n toastOptions?.classNames?.actionButton,\n ),\n cancelButton: cn(\n \"!bg-muted !text-muted-foreground\",\n toastOptions?.classNames?.cancelButton,\n ),\n },\n }}\n {...props}\n />\n);\n\nexport { toast, Toaster };\n"
17
17
  },
18
18
  {
19
19
  "path": "components/base/Toaster.md",
20
20
  "type": "registry:file",
21
21
  "target": "components/base/Toaster.md",
22
- "content": "# Toaster — guía de uso\n\nNotificaciones efímeras de la app (sobre **Sonner**, tematizado con tokens Lexy). Se monta **una vez** en el layout raíz y se dispara imperativo con `toast.*` desde cualquier parte. Reemplaza al `Toast` presentacional del sistema antiguo (deprecado). El componente vive en tu proyecto: instálalo con `create-lexy add toaster` y edítalo con libertad.\n\n## Cuándo usarlo\n\nPara confirmar resultados de acciones sin interrumpir: “Guardado”, “Enviado”, un error recuperable. Es efímero — si la persona debe decidir algo, usa `AppDialog`; si el error bloquea el flujo, muéstralo en el lugar del error.\n\n## Composición\n\nDos piezas: `Toaster` se monta una sola vez en el layout raíz, y `toast.*` (success, error, info…) se dispara imperativo desde cualquier parte. Construido sobre Sonner, tematizado con tokens Lexy.\n\n## Montaje\n\n```tsx\nfunction App() {\n return (\n <>\n <Rutas />\n <Toaster />\n </>\n );\n}\n```\n\n## Uso básico\n\n```tsx\ntoast(\"Borrador guardado\");\ntoast.success(\"Cambios guardados\");\ntoast.error(\"No pudimos guardar. Intenta de nuevo.\");\ntoast.warning(\"Tu sesión expira en 5 minutos\");\ntoast.info(\"Hay una versión nueva disponible\");\n\n// Con acción y descripción:\ntoast.success(\"Contrato enviado\", {\n description: \"Le avisamos al cliente por correo.\",\n action: { label: \"Ver contrato\", onClick: () => navigate(`/contratos/${id}`) },\n});\n\n// Operación async de una vez:\ntoast.promise(guardar(), {\n loading: \"Guardando…\",\n success: \"Cambios guardados\",\n error: \"No pudimos guardar. Intenta de nuevo.\",\n});\n```\n\n## Tematización\n\nLos tipos colorean con los tokens semánticos del theme vía las CSS vars de Sonner: `success` → `--color-success`, `error` → `--color-destructive`, `warning` → `--color-warning`, `info` → `--color-info`. Cambiar los tokens re-tematiza los toasts sin tocar el componente.\n\n## Posición, duración y cola (criterio por mundo)\n\nDefaults del componente: `position=\"bottom-right\"`, `duration={4000}`, `visibleToasts={3}` — pensados para **CRM** (escritorio denso: la esquina inferior derecha no tapa toolbars ni encabezados, y la cola corta evita ruido en flujos de alta frecuencia).\n\nPara **mundo cliente** (flujos guiados, móvil primero) configura el montaje:\n\n```tsx\n<Toaster position=\"top-center\" duration={6000} visibleToasts={2} />\n```\n\nArriba y centrado entra en el campo visual del flujo paso a paso, y la duración mayor da tiempo de lectura a personas no expertas.\n\n## Reglas (UX writing)\n\n- Éxito puntual (guardado, envío) → toast con el **siguiente paso** cuando exista (*\"Contrato enviado\"* + acción *\"Ver contrato\"*).\n- Error en toast solo si es transitorio y re-intentable (*\"No pudimos guardar. Intenta de nuevo.\"*); errores de validación van en el formulario (`FormMessage`), y errores que bloquean la página van en la vista, no en un toast.\n- Mensajes cortos, verbo primero, sin tecnicismos ni códigos de error.\n- No comuniques con color solamente: el texto debe bastar.\n\n## Cuándo NO usar\n\n- **Confirmar antes de actuar** → `AlertDialog`.\n- **Estado persistente de la vista** (vacío, error de carga) → `Empty` o estado en la página.\n- **Errores de campos** → `FormMessage`.\n\n## Import\n\n```tsx\n// En el layout raíz (una sola vez):\nimport { Toaster } from \"@/components/base/Toaster\";\n\n// Donde dispares notificaciones:\nimport { toast } from \"@/components/base/Toaster\";\n```\n\n## Props\n\n`Toaster` acepta todas las props de Sonner (`position`, `duration`, `visibleToasts`, `closeButton`, `toastOptions`…); los defaults y el mapeo de tokens viven en el componente y son editables. Exporta también `toast` (la API imperativa completa de Sonner).\n\n## Para IA\n\n1. Monta `<Toaster />` una vez en el layout raíz; nunca por vista.\n2. Importa `toast` desde el componente local, no desde `sonner` directo (así hereda el tema).\n3. Tras una mutación: éxito → `toast.success` con siguiente paso; fallo re-intentable → `toast.error` con cómo arreglarlo.\n4. En mundo cliente configura `position=\"top-center\" duration={6000}`; en CRM deja los defaults.\n"
22
+ "content": "# Toaster\nNotificaciones efímeras de la app (sobre **Sonner**, tematizado con tokens Lexy). Se monta **una vez** en el layout raíz y se dispara imperativo con `toast.*` desde cualquier parte. Reemplaza al `Toast` presentacional del sistema antiguo (deprecado).\n\n## Cuándo usarlo\n\nPara confirmar resultados de acciones sin interrumpir: “Guardado”, “Enviado”, un error recuperable. Es efímero — si la persona debe decidir algo, usa `AppDialog`; si el error bloquea el flujo, muéstralo en el lugar del error.\n\n## Composición\n\nDos piezas: `Toaster` se monta una sola vez en el layout raíz, y `toast.*` (success, error, info…) se dispara imperativo desde cualquier parte. Construido sobre Sonner, tematizado con tokens Lexy.\n\n## Montaje\n\n```tsx\nfunction App() {\n return (\n <>\n <Rutas />\n <Toaster />\n </>\n );\n}\n```\n\n## Uso básico\n\n```tsx\ntoast(\"Borrador guardado\");\ntoast.success(\"Cambios guardados\");\ntoast.error(\"No pudimos guardar. Intenta de nuevo.\");\ntoast.warning(\"Tu sesión expira en 5 minutos\");\ntoast.info(\"Hay una versión nueva disponible\");\n\n// Con acción y descripción:\ntoast.success(\"Contrato enviado\", {\n description: \"Le avisamos al cliente por correo.\",\n action: { label: \"Ver contrato\", onClick: () => navigate(`/contratos/${id}`) },\n});\n\n// Operación async de una vez:\ntoast.promise(guardar(), {\n loading: \"Guardando…\",\n success: \"Cambios guardados\",\n error: \"No pudimos guardar. Intenta de nuevo.\",\n});\n```\n\n## Tematización\n\nLos tipos colorean con los tokens semánticos del theme vía las CSS vars de Sonner: `success` → `--color-success`, `error` → `--color-destructive`, `warning` → `--color-warning`, `info` → `--color-info`. Cambiar los tokens re-tematiza los toasts sin tocar el componente.\n\n## Posición, duración y cola (criterio por mundo)\n\nDefaults del componente: `position=\"bottom-right\"`, `duration={4000}`, `visibleToasts={3}` — pensados para **CRM** (escritorio denso: la esquina inferior derecha no tapa toolbars ni encabezados, y la cola corta evita ruido en flujos de alta frecuencia).\n\nPara **mundo cliente** (flujos guiados, móvil primero) configura el montaje:\n\n```tsx\n<Toaster position=\"top-center\" duration={6000} visibleToasts={2} />\n```\n\nArriba y centrado entra en el campo visual del flujo paso a paso, y la duración mayor da tiempo de lectura a personas no expertas.\n\n## Reglas (UX writing)\n\n- Éxito puntual (guardado, envío) → toast con el **siguiente paso** cuando exista (*\"Contrato enviado\"* + acción *\"Ver contrato\"*).\n- Error en toast solo si es transitorio y re-intentable (*\"No pudimos guardar. Intenta de nuevo.\"*); errores de validación van en el formulario (`FormMessage`), y errores que bloquean la página van en la vista, no en un toast.\n- Mensajes cortos, verbo primero, sin tecnicismos ni códigos de error.\n- No comuniques con color solamente: el texto debe bastar.\n\n## Cuándo NO usar\n\n- **Confirmar antes de actuar** → `AlertDialog`.\n- **Estado persistente de la vista** (vacío, error de carga) → `Empty` o estado en la página.\n- **Errores de campos** → `FormMessage`.\n\n## Import\n\n```tsx\n// En el layout raíz (una sola vez):\nimport { Toaster } from \"@/components/base/Toaster\";\n\n// Donde dispares notificaciones:\nimport { toast } from \"@/components/base/Toaster\";\n```\n\n## Props\n\n`Toaster` acepta todas las props de Sonner (`position`, `duration`, `visibleToasts`, `closeButton`, `toastOptions`…); los defaults y el mapeo de tokens viven en el componente y son editables. Exporta también `toast` (la API imperativa completa de Sonner).\n\n## Para IA\n\n1. Monta `<Toaster />` una vez en el layout raíz; nunca por vista.\n2. Importa `toast` desde el componente local, no desde `sonner` directo (así hereda el tema).\n3. Tras una mutación: éxito → `toast.success` con siguiente paso; fallo re-intentable → `toast.error` con cómo arreglarlo.\n4. En mundo cliente configura `position=\"top-center\" duration={6000}`; en CRM deja los defaults.\n"
23
23
  }
24
24
  ]
25
25
  }
@@ -3,7 +3,7 @@
3
3
  "name": "tooltip",
4
4
  "type": "registry:ui",
5
5
  "title": "Tooltip",
6
- "description": "Etiqueta breve que aparece al pasar el cursor o enfocar (Radix). Para **ayuda complementaria**, nunca para información esencial. El componente vive en tu proyecto: instálalo con `create-lexy add tooltip` y edítalo con libertad.",
6
+ "description": "Etiqueta breve que aparece al pasar el cursor o enfocar (Radix). Para **ayuda complementaria**, nunca para información esencial.",
7
7
  "dependencies": [
8
8
  "@radix-ui/react-tooltip"
9
9
  ],
@@ -13,13 +13,13 @@
13
13
  "path": "components/base/Tooltip.tsx",
14
14
  "type": "registry:ui",
15
15
  "target": "components/base/Tooltip.tsx",
16
- "content": "import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\nconst TooltipProvider = TooltipPrimitive.Provider;\nconst Tooltip = TooltipPrimitive.Root;\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 overflow-hidden rounded bg-foreground px-3 py-1.5 text-xs text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\n"
16
+ "content": "import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\nconst TooltipProvider = TooltipPrimitive.Provider;\nconst Tooltip = TooltipPrimitive.Root;\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 overflow-hidden rounded bg-foreground px-3 py-1.5 type-meta text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\n"
17
17
  },
18
18
  {
19
19
  "path": "components/base/Tooltip.md",
20
20
  "type": "registry:file",
21
21
  "target": "components/base/Tooltip.md",
22
- "content": "# Tooltip — guía de uso\n\nEtiqueta breve que aparece al pasar el cursor o enfocar (Radix). Para **ayuda complementaria**, nunca para información esencial. El componente vive en tu proyecto: instálalo con `create-lexy add tooltip` y edítalo con libertad.\n\n## Cuándo usarlo\n\nPara ayuda complementaria al pasar el cursor o enfocar: el nombre de un botón solo-icono, una aclaración breve. Nunca para información esencial — en móvil no hay hover, y lo esencial debe estar visible.\n\n## Composición\n\n`TooltipProvider` una vez, arriba en el árbol; por cada caso, `Tooltip` con `TooltipTrigger` (el elemento que lo invoca) y `TooltipContent` (el texto breve).\n\n## Uso básico\n\nEnvuelve la app (o la zona) una vez con `TooltipProvider`:\n\n```tsx\n<TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button size=\"icon\" aria-label=\"Archivar\"><Archive /></Button>\n </TooltipTrigger>\n <TooltipContent>Archivar conversación</TooltipContent>\n </Tooltip>\n</TooltipProvider>\n```\n\n## Reglas\n\n- El contenido es **complementario**: la interfaz debe entenderse sin leerlo.\n- En botones solo-icono, el tooltip **no** reemplaza al `aria-label`: pon ambos.\n- Usa `asChild` en el trigger para no anidar botones.\n- Texto corto; no metas párrafos ni acciones dentro del tooltip.\n- Coloca un `TooltipProvider` arriba en el árbol; no anides uno por tooltip.\n\n## Cuándo NO usar\n\n- **Información necesaria para decidir o actuar** → muéstrala en pantalla (texto de ayuda, `Label`, descripción).\n- **Contenido rico o interactivo** (links, botones, formularios) → `Popover`.\n- **Mensajes de error de formulario** → texto bajo el campo con `aria-describedby`.\n\n## Import\n\n```tsx\nimport {\n Tooltip, TooltipTrigger, TooltipContent, TooltipProvider,\n} from \"@/components/base/Tooltip\";\n```\n\n## Props (esenciales)\n\n| Parte | Prop | Default | Descripción |\n|---|---|---|---|\n| `TooltipProvider` | `delayDuration` | `700` | Retardo antes de mostrar. |\n| `TooltipTrigger` | `asChild` | — | Usa tu propio elemento como disparador. |\n| `TooltipContent` | `side` | `\"top\"` | Lado: `top`/`right`/`bottom`/`left`. |\n| `TooltipContent` | `sideOffset` | `4` | Separación del trigger. |\n\n## Para IA\n\n1. Pregúntate si el dato es prescindible; si es necesario, NO uses tooltip.\n2. Envuelve con un `TooltipProvider` (una vez por zona).\n3. Usa `TooltipTrigger asChild` sobre el control real.\n4. En iconos, mantén `aria-label` además del tooltip.\n5. Si necesitas contenido interactivo, cambia a `Popover`.\n"
22
+ "content": "# Tooltip\nEtiqueta breve que aparece al pasar el cursor o enfocar (Radix). Para **ayuda complementaria**, nunca para información esencial.\n\n## Cuándo usarlo\n\nPara ayuda complementaria al pasar el cursor o enfocar: el nombre de un botón solo-icono, una aclaración breve. Nunca para información esencial — en móvil no hay hover, y lo esencial debe estar visible.\n\n## Composición\n\n`TooltipProvider` una vez, arriba en el árbol; por cada caso, `Tooltip` con `TooltipTrigger` (el elemento que lo invoca) y `TooltipContent` (el texto breve).\n\n## Uso básico\n\nEnvuelve la app (o la zona) una vez con `TooltipProvider`:\n\n```tsx\n<TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button size=\"icon\" aria-label=\"Archivar\"><Archive /></Button>\n </TooltipTrigger>\n <TooltipContent>Archivar conversación</TooltipContent>\n </Tooltip>\n</TooltipProvider>\n```\n\n## Reglas\n\n- El contenido es **complementario**: la interfaz debe entenderse sin leerlo.\n- En botones solo-icono, el tooltip **no** reemplaza al `aria-label`: pon ambos.\n- Usa `asChild` en el trigger para no anidar botones.\n- Texto corto; no metas párrafos ni acciones dentro del tooltip.\n- Coloca un `TooltipProvider` arriba en el árbol; no anides uno por tooltip.\n\n## Cuándo NO usar\n\n- **Información necesaria para decidir o actuar** → muéstrala en pantalla (texto de ayuda, `Label`, descripción).\n- **Contenido rico o interactivo** (links, botones, formularios) → `Popover`.\n- **Mensajes de error de formulario** → texto bajo el campo con `aria-describedby`.\n\n## Import\n\n```tsx\nimport {\n Tooltip, TooltipTrigger, TooltipContent, TooltipProvider,\n} from \"@/components/base/Tooltip\";\n```\n\n## Props (esenciales)\n\n| Parte | Prop | Default | Descripción |\n|---|---|---|---|\n| `TooltipProvider` | `delayDuration` | `700` | Retardo antes de mostrar. |\n| `TooltipTrigger` | `asChild` | — | Usa tu propio elemento como disparador. |\n| `TooltipContent` | `side` | `\"top\"` | Lado: `top`/`right`/`bottom`/`left`. |\n| `TooltipContent` | `sideOffset` | `4` | Separación del trigger. |\n\n## Para IA\n\n1. Pregúntate si el dato es prescindible; si es necesario, NO uses tooltip.\n2. Envuelve con un `TooltipProvider` (una vez por zona).\n3. Usa `TooltipTrigger asChild` sobre el control real.\n4. En iconos, mantén `aria-label` además del tooltip.\n5. Si necesitas contenido interactivo, cambia a `Popover`.\n"
23
23
  }
24
24
  ]
25
25
  }
@@ -3,7 +3,7 @@
3
3
  "name": "tree",
4
4
  "type": "registry:ui",
5
5
  "title": "Tree",
6
- "description": "Árbol jerárquico. Para navegación en profundidad. El componente vive en tu proyecto: instálalo con `create-lexy add tree` y edítalo con libertad.",
6
+ "description": "Árbol jerárquico. Para navegación en profundidad.",
7
7
  "dependencies": [],
8
8
  "registryDependencies": [],
9
9
  "files": [
@@ -11,13 +11,13 @@
11
11
  "path": "components/base/Tree.tsx",
12
12
  "type": "registry:ui",
13
13
  "target": "components/base/Tree.tsx",
14
- "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\nconst DepthCtx = React.createContext(0);\n\nconst svgProps = {\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: \"2\",\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n};\n\nexport type TreeProps = React.HTMLAttributes<HTMLDivElement>;\n\nexport function Tree({ className, ...props }: TreeProps) {\n return (\n <div\n role=\"tree\"\n className={cn(\"w-full rounded-lg border border-border bg-background p-1\", className)}\n {...props}\n />\n );\n}\n\nexport interface TreeItemProps extends React.HTMLAttributes<HTMLDivElement> {\n label: React.ReactNode;\n kind?: \"folder\" | \"file\";\n defaultExpanded?: boolean;\n /** Sub-ítems anidados (solo tiene efecto en kind=\"folder\"). */\n children?: React.ReactNode;\n}\n\nconst TreeItem = React.forwardRef<HTMLDivElement, TreeItemProps>(function TreeItem(\n { label, kind = \"file\", defaultExpanded = false, children, className, ...props },\n ref,\n) {\n const depth = React.useContext(DepthCtx);\n const [expanded, setExpanded] = React.useState(defaultExpanded);\n const isFolder = kind === \"folder\";\n const hasChildren = Boolean(children);\n\n return (\n <div\n ref={ref}\n role=\"treeitem\"\n aria-expanded={isFolder ? expanded : undefined}\n aria-selected={false}\n className={className}\n {...props}\n >\n <div\n onClick={() => isFolder && setExpanded((value) => !value)}\n onKeyDown={(event) => {\n if (!isFolder) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setExpanded((value) => !value);\n }\n }}\n role={isFolder ? \"button\" : undefined}\n tabIndex={isFolder ? 0 : undefined}\n style={{ paddingLeft: depth * 16 + 8 }}\n className={cn(\n \"flex h-8 items-center gap-1.5 rounded pr-2 text-sm text-foreground transition-colors hover:bg-primary/15 hover:text-primary\",\n isFolder && \"cursor-pointer\",\n )}\n >\n {isFolder ? (\n <>\n <svg\n className={cn(\n \"h-4 w-4 flex-shrink-0 text-muted-foreground transition-transform\",\n expanded && \"rotate-90\",\n )}\n {...svgProps}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n {expanded ? (\n <svg className=\"h-4 w-4 flex-shrink-0 text-primary\" {...svgProps}>\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n ) : (\n <svg className=\"h-4 w-4 flex-shrink-0 text-primary\" {...svgProps}>\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n )}\n </>\n ) : (\n <>\n <span className=\"w-4 flex-shrink-0\" />\n <svg className=\"h-4 w-4 flex-shrink-0 text-muted-foreground\" {...svgProps}>\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n </svg>\n </>\n )}\n <span className=\"truncate\">{label}</span>\n </div>\n {isFolder && expanded && hasChildren && (\n <DepthCtx.Provider value={depth + 1}>\n <div role=\"group\">{children}</div>\n </DepthCtx.Provider>\n )}\n </div>\n );\n});\n\nTree.Item = TreeItem;\n\nexport { TreeItem };\n"
14
+ "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils/cn\";\n\nconst DepthCtx = React.createContext(0);\n\nconst svgProps = {\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: \"2\",\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n};\n\nexport type TreeProps = React.HTMLAttributes<HTMLDivElement>;\n\nexport function Tree({ className, ...props }: TreeProps) {\n return (\n <div\n role=\"tree\"\n className={cn(\"w-full rounded-lg border border-border bg-background p-1\", className)}\n {...props}\n />\n );\n}\n\nexport interface TreeItemProps extends React.HTMLAttributes<HTMLDivElement> {\n label: React.ReactNode;\n kind?: \"folder\" | \"file\";\n defaultExpanded?: boolean;\n /** Sub-ítems anidados (solo tiene efecto en kind=\"folder\"). */\n children?: React.ReactNode;\n}\n\nconst TreeItem = React.forwardRef<HTMLDivElement, TreeItemProps>(function TreeItem(\n { label, kind = \"file\", defaultExpanded = false, children, className, ...props },\n ref,\n) {\n const depth = React.useContext(DepthCtx);\n const [expanded, setExpanded] = React.useState(defaultExpanded);\n const isFolder = kind === \"folder\";\n const hasChildren = Boolean(children);\n\n return (\n <div\n ref={ref}\n role=\"treeitem\"\n aria-expanded={isFolder ? expanded : undefined}\n aria-selected={false}\n className={className}\n {...props}\n >\n <div\n onClick={() => isFolder && setExpanded((value) => !value)}\n onKeyDown={(event) => {\n if (!isFolder) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setExpanded((value) => !value);\n }\n }}\n role={isFolder ? \"button\" : undefined}\n tabIndex={isFolder ? 0 : undefined}\n style={{ paddingLeft: depth * 16 + 8 }}\n className={cn(\n \"flex h-8 items-center gap-1.5 rounded-nav-item pr-2 type-supporting text-foreground transition-colors hover:bg-primary/15 hover:text-primary\",\n isFolder && \"cursor-pointer\",\n )}\n >\n {isFolder ? (\n <>\n <svg\n className={cn(\n \"size-(--icon-size-inline) flex-shrink-0 text-muted-foreground transition-transform\",\n expanded && \"rotate-90\",\n )}\n {...svgProps}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n {expanded ? (\n <svg className=\"size-(--icon-size-inline) flex-shrink-0 text-primary\" {...svgProps}>\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n ) : (\n <svg className=\"size-(--icon-size-inline) flex-shrink-0 text-primary\" {...svgProps}>\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n )}\n </>\n ) : (\n <>\n <span className=\"w-4 flex-shrink-0\" />\n <svg\n className=\"size-(--icon-size-inline) flex-shrink-0 text-muted-foreground\"\n {...svgProps}\n >\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n </svg>\n </>\n )}\n <span className=\"truncate\">{label}</span>\n </div>\n {isFolder && expanded && hasChildren && (\n <DepthCtx.Provider value={depth + 1}>\n <div role=\"group\">{children}</div>\n </DepthCtx.Provider>\n )}\n </div>\n );\n});\n\nTree.Item = TreeItem;\n\nexport { TreeItem };\n"
15
15
  },
16
16
  {
17
17
  "path": "components/base/Tree.md",
18
18
  "type": "registry:file",
19
19
  "target": "components/base/Tree.md",
20
- "content": "# Tree — guía de uso\n\nÁrbol jerárquico. Para navegación en profundidad. El componente vive en tu proyecto: instálalo con `create-lexy add tree` y edítalo con libertad.\n\n## Cuándo usarlo\n\nPara navegar jerarquías con profundidad real: carpetas, expedientes anidados, estructuras organizacionales. Si la jerarquía tiene un solo nivel de agrupación, un acordeón o una lista con secciones es más simple.\n\n## Composición\n\n`Tree` contiene `TreeItem`s anidables: cada item puede expandirse y contener hijos.\n\n## Uso básico\n\n```tsx\n<Tree />\n```\n\n## Reglas\n\n- Usa Tree según el propósito descrito.\n- No abuses de este componente en contexts donde no aplica.\n\n## Import\n\n```tsx\nimport { Tree } from \"@/components/base/Tree\";\n```\n\n## Props\n\nConsulta la story en Storybook para ver las props disponibles.\n\n## Para IA\n\n1. Identifica el contexto de uso del componente.\n2. Importa Tree desde el path correcto.\n3. Configura las props según la necesidad.\n4. Verifica que el componente se integre correctamente en el layout.\n5. Solo usa variantes documentadas.\n"
20
+ "content": "# Tree\nÁrbol jerárquico. Para navegación en profundidad.\n\n## Cuándo usarlo\n\nPara navegar jerarquías con profundidad real: carpetas, expedientes anidados, estructuras organizacionales. Si la jerarquía tiene un solo nivel de agrupación, un acordeón o una lista con secciones es más simple.\n\n## Composición\n\n`Tree` contiene `TreeItem`s anidables: cada item puede expandirse y contener hijos.\n\n## Uso básico\n\n```tsx\n<Tree />\n```\n\n## Reglas\n\n- Usa Tree según el propósito descrito.\n- No abuses de este componente en contexts donde no aplica.\n\n## Import\n\n```tsx\nimport { Tree } from \"@/components/base/Tree\";\n```\n\n## Props\n\nConsulta la story en Storybook para ver las props disponibles.\n\n## Para IA\n\n1. Identifica el contexto de uso del componente.\n2. Importa Tree desde el path correcto.\n3. Configura las props según la necesidad.\n4. Verifica que el componente se integre correctamente en el layout.\n5. Solo usa variantes documentadas.\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -1 +1 @@
1
- 0.1.17
1
+ 0.1.34