Preguntas frecuentes
Por qué no hay mecanismo de instalación con app.use()
React no tiene un sistema de plugins como Vue. @lh-ui/react son exclusivamente exportaciones con nombre: importa lo que necesites, bajo demanda, lo que además facilita el tree-shaking. La configuración global se hace envolviendo la aplicación con el componente LhConfigProvider.
Por qué los estilos no se inyectan automáticamente
Estrategia de importación bajo demanda, alineada con @lh-ui/vue2: la entrada del paquete no inyecta la hoja de estilos completa como side-effect; el usuario importa explícitamente @lh-ui/react/theme.css y @lh-ui/react/style/<name>. El motivo es que, en el ecosistema React, la importación bajo demanda es la práctica habitual, y un side-effect con todos los estilos rompería el tree-shaking.
Por qué onChange lleva dos parámetros
El diseño de dos parámetros (value, event) es isomorfo con el emit('change', [val, e]) de lh-ui-plus, lo que facilita la migración desde Vue y conserva la posibilidad de obtener el evento nativo.
Por qué la posición de las capas flotantes no usa floating-ui
Línea roja de la familia: el cálculo geométrico de las capas flotantes está implementado en @lh-ui/share/core/shared/popper, y todas las plataformas comparten la misma lógica y el mismo tratamiento de casos límite (volteo, repliegue por desbordamiento, flecha). Introducir una biblioteca de terceros provocaría divergencia de comportamiento entre plataformas.
Por qué las animaciones de transición no usan react-transition-group
Por la misma razón. useTransition es una máquina de estados montaje + fase desarrollada internamente; los nombres de clase son exactamente los mismos que en el SCSS de share (*-enter-from / *-enter-active / *-enter-to), y es seguro bajo StrictMode.
Por qué Dialog es puramente controlado
open lo mantiene por completo el estado externo; cualquier ruta de cierre (clic en la máscara / Esc / botón de cerrar) solo llama a onClose. lh-ui-plus mantiene internamente un estado intermedio isVisible + una sincronización bidireccional con watch; la versión de React elimina esa capa: la semántica controlada es más pura y se evita la condición de carrera entre props y estado interno.
Con varios Dialog abiertos, por qué Esc solo cierra uno
useLhOverlayStack mantiene una pila con el orden de apertura, y Esc solo cierra la capa superior. Es lo que exige el patrón de diálogo de APG, para evitar que una sola pulsación se lleve todas las capas emergentes.
Los servicios imperativos crean varias React root
No. Servicios como message comparten un único contenedor root de creación perezosa: solo se crea en la primera llamada y entonces se añade al body; la cola de mensajes la gestiona el estado interno de los componentes. destroyContainer() llama explícitamente a root.unmount().
Qué pasa si se llama a message en SSR
Solo se emite una advertencia en desarrollo y no-op (no se crea DOM). Todas las manipulaciones de DOM se realizan dentro de useEffect / useIsomorphicLayoutEffect, y useLhLocale usa useSyncExternalStore para ofrecer una instantánea SSR consistente.
Por qué hace falta forwardRef en vez de usar la prop ref directamente
Para dar soporte a React 18 y 19 por igual. El ref como prop de React 19 no existe en la 18, y forwardRef es el superconjunto común a ambas versiones. Todos los componentes enfocables (button / input / select / dialog / tooltip) reenvían ref.
Se puede usar junto con lh-ui-plus en el mismo proyecto
Sí: ambas bibliotecas comparten exactamente los mismos nombres de clase y los mismos tokens, por lo que los estilos no entran en conflicto. Normalmente no es necesario, pues son dos formas de la misma familia de componentes. Si se mezclan en una migración gradual, ten en cuenta que los rangos de versión de @lh-ui/share de ambas bibliotecas deben ser compatibles.
Qué falta por implementar en esta primera fase
Los componentes de P1/P2 (Popover, Drawer, Dropdown, Table, etc.) no están implementados. Los tres servicios imperativos
(message / notification / loading) sí están completos.