8.5 KiB
Sistema UI Rdx
Propósito: explicar qué foundations y componentes visuales existen. Este documento, junto con Arquitectura frontend y UI patterns, forma la fuente de verdad (SSOT) de frontend/UI.
1. Principios
- Claridad antes que abstracción.
- UI pura: recibe datos preparados y emite eventos.
- Composición antes que configuración extensa.
- KISS: no existe un framework CRUD genérico.
- Tema claro y oscuro desde el inicio.
- Accesibilidad y densidad informativa.
- Tokens semánticos en lugar de colores físicos.
2. Responsabilidad de rdx-ui
packages/rdx-ui contiene foundations y composiciones visuales reutilizables. No conoce React Query, routing, DTOs, entidades de dominio, controllers, permisos, casos de uso ni errores de transporte. El consumidor decide contenido, acciones, orden, labels y estados disabled.
Los componentes públicos propios usan prefijo Rdx, API pequeña, props explícitas y className solo como escape controlado.
3. Arquitectura visual
AppMain
└── RdxPageFrame
├── header
│ ├── RdxPageHeader
│ └── RdxEditorHeader
├── content (scroll principal)
│ └── RdxPageContainer
│ └── RdxPageContent
└── footer opcional
└── RdxEditorActionBar
Cada nivel tiene una sola responsabilidad. No se reconstruye viewport, anchura y scroll en componentes de página.
4. Foundations
Espaciado y anchura
RdxPageContainer controla ancho, centrado y padding:
| Propiedad | Resultado |
|---|---|
| padding móvil | px-4 py-4 |
| padding desktop | md:px-6 md:py-6 |
width="full" |
ancho completo |
width="wide" |
centrado, max-w-screen-2xl |
width="content" |
centrado, max-w-5xl |
padding="none" elimina únicamente su padding. El container no controla altura ni scroll.
RdxPageContent establece el ritmo vertical del main:
| Spacing | Gap |
|---|---|
compact |
4 |
default |
6 |
relaxed |
8 |
Tema
Se usan tokens como bg-background, text-foreground, bg-muted, text-muted-foreground, border-border, bg-primary y bg-destructive. El color nunca es el único indicador de estado. Toda foundation nueva debe verificarse en light y dark.
5. Componentes públicos
RdxPageFrame
Compone header, contenido y footer y es propietario del scroll principal. No conoce routing, queries, width, formularios ni negocio.
<RdxPageFrame
header={<RdxEditorHeader title={title} />}
footer={<RdxEditorActionBar primary={saveButton} />}
>
<RdxPageContainer width="content">{content}</RdxPageContainer>
</RdxPageFrame>
contentClassName="overflow-hidden" se reserva para layouts especializados con panes y scrolls internos; no desplaza la responsabilidad del scroll estructural de Page a wrappers locales.
Headers
RdxPageHeader es la cabecera editorial estándar. Presenta title, description, leading, metadata, actions y contenido opcional.
RdxEditorHeader es la cabecera compacta fullscreen. Presenta title, retorno mediante onBack/backLabel, status, actions y contenido contextual opcional.
Ninguno usa sticky para seleccionar una variante. El frame coloca el header fuera del scroll.
RdxPageActions
Ordena regiones secondary, primary y overflow. No decide qué acciones existen ni sus permisos.
RdxPageContent
Apila verticalmente el main y distribuye un aside opcional. No controla width, padding ni scroll. Sin aside no reserva una columna. En desktop, el aside usa 22rem; en anchos menores se apila. spacing afecta únicamente al main.
El aside aloja contexto secundario, metadata o configuración auxiliar. No se mueven campos allí solo por estética.
RdxEditorActionBar
Compone leading, status, secondary y primary. El patrón normal la coloca en RdxPageFrame.footer, fuera del scroll. La capacidad sticky solo se usa si la barra vive justificadamente dentro de un área scrollable.
RdxPanel
Agrupa una sección con título, descripción, icono, acciones y contenido:
variant="plain": sección plana con divisor; valor predeterminado.variant="card": superficie independiente. RdxPanel no sustituye un div estructural: solo representa una sección con identidad semántica, como fiscalidad, dirección o preferencias.
RdxFormGrid
Proporciona la retícula de campos. No conoce React Hook Form ni debe envolver tablas, line editors o layouts especializados.
RdxRowActions
Renderiza acciones primarias y overflow. El consumidor decide acciones, orden, navegación, disabledReason y destructividad. Las destructivas van en overflow por defecto.
RdxContextPanel
Compone cabecera, cierre, body y footer de un panel contextual. La geometría redimensionable y el contenido de dominio permanecen en el consumidor.
6. Scroll y viewport
Regla canónica:
AppMain (espacio disponible, sin scroll)
└── RdxPageFrame
└── content: overflow-y-auto
Una Page no debe usar fixed inset-0, h-screen, h-dvh, overflow-y-auto ni overflow-auto para reconstruir viewport o scroll principal.
Excepción: un detalle documental puede configurar el contenido del frame con overflow-hidden y delegar scroll interno a document panes o inspectors. Ese scroll es funcional al workspace —por ejemplo, ProformaDetailContent e IssuedInvoiceDetailContent— y no sustituye el scroll estructural de Page. Dialogs, sheets, drawers, overlays, viewers y paneles internos también pueden necesitar posicionamiento o scroll propios.
7. Superficies
- El contenido principal es plano por defecto.
- Las secciones se separan con spacing y divisores.
- Una card es una excepción, no el envoltorio automático de cada sección.
- El aside puede usar cards cuando necesita una superficie independiente.
- Tablas y editores de líneas conservan su layout funcional.
- Evitar card dentro de card y sombras acumuladas.
Composición del contenido principal
RdxPageContent es el compositor estructural de los hijos principales de una página.
Los avisos, errores inline, secciones y contenido funcional deben ser hijos directos cuando pertenezcan al mismo nivel visual.
RdxPanel no es un wrapper genérico. Se usa únicamente cuando existe una sección con identidad visual o semántica propia.
En LIST, toolbar, búsqueda, filtros, tabs, tabla/lista/grid y paginación son bloques funcionales de RdxPageContent. Una tabla no implica un RdxPanel, y su scroll horizontal, virtualizado o interno es legítimo: no sustituye el scroll estructural de RdxPageFrame. No se anidan containers ni contents para filtros, alertas o paginación.
<RdxPageContent>
{error ? <ErrorAlert /> : null}
<Editor />
</RdxPageContent>
No deben introducirse wrappers adicionales únicamente para controlar gap, ancho, padding o centrado. No se anidan RdxPageContainer ni RdxPageContent salvo razón arquitectónica explícita. Los errores inline participan como hijos directos del spacing estándar de RdxPageContent; no crean su propio layout.
8. Responsive y accesibilidad
- Las columnas se apilan antes de producir overflow horizontal.
- Todo contenedor flexible susceptible de truncado usa
min-w-0. - Botones de icono tienen nombre accesible y foco visible.
- No se crean
divclicables. - El orden DOM debe ser coherente con lectura y teclado.
- Los iconos decorativos usan
aria-hidden. - Estados no dependen exclusivamente del color.
9. UI Kit
/development/ui-kit muestra las foundations públicas vigentes y sirve para revisar tema, responsive y composición. No es una especificación alternativa: debe mantenerse sincronizado con implementación, este documento y tests.
10. Testing
Los componentes públicos se prueban por comportamiento y contrato observable. No se fijan clases Tailwind salvo cuando expresan una responsabilidad estructural esencial, como el ownership de scroll o la ausencia de una columna aside.
Cada cambio de API pública debe actualizar conjuntamente:
- implementación;
- documentación;
- UI Kit;
- tests aplicables.
11. Anti-patterns
- Variantes genéricas
simple/complexpara mezclar width y geometría. - Layouts CRUD universales.
- Scroll principal fuera de
RdxPageFrame. - Padding duplicado entre shell, container y superficie.
- Routing, permisos o queries dentro de
rdx-ui. - Acciones completas duplicadas en header y footer.
- Cards por sección sin necesidad funcional.
- Colores físicos o color como única señal.
Las recetas para construir páginas concretas están en UI patterns.