FactuGES_ERP/docs/frontend/ui-system.md
David 902f7806ed Refactor pages to use RdxPageContent for consistent layout
- Updated IssuedInvoiceDetailPage to wrap PageErrorState in RdxPageContent.
- Modified ProformaDetailPage to include RdxPageContent around PageErrorState.
- Adjusted RecurringProformaDetailPage to utilize RdxPageContent for loading and error states.
- Refactored CustomerViewPage to implement RdxPageContent for PageErrorState and main content.
- Renamed SupplierDetailPage to SupplierViewPage and updated imports accordingly.
- Removed SupplierDetailPage and created SupplierViewPage with similar functionality.
2026-09-15 12:04:27 +02:00

8.2 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.

<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 div clicables.
  • 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:

  1. implementación;
  2. documentación;
  3. UI Kit;
  4. tests aplicables.

11. Anti-patterns

  • Variantes genéricas simple/complex para 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.