feat: implement RdxEditor components including layout, section, and sticky footer with tests feat: introduce RdxFormGrid for form layout management feat: create RdxPage components for structured page layout with actions and headers feat: add RdxRowActions for handling row-level actions with dropdown support
1226 lines
27 KiB
Markdown
1226 lines
27 KiB
Markdown
# Frontend ERP — Sistema visual Rdx para páginas y patrones UI/UX
|
||
|
||
## 1. Estado
|
||
|
||
**DISEÑO APROBADO PARA IMPLEMENTACIÓN PROGRESIVA**
|
||
|
||
Este documento consolida las decisiones visuales, arquitectónicas y de adopción para construir un sistema UI/UX uniforme en el frontend del ERP.
|
||
|
||
El sistema se implementará dentro de:
|
||
|
||
```txt
|
||
packages/rdx-ui
|
||
```
|
||
|
||
Todos los componentes públicos propios del sistema deberán usar el prefijo:
|
||
|
||
```txt
|
||
Rdx
|
||
```
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
RdxPageContainer
|
||
RdxPageHeader
|
||
RdxPageActions
|
||
RdxContextPanel
|
||
RdxRowActions
|
||
RdxListPageLayout
|
||
RdxEditorPageLayout
|
||
RdxEditorSection
|
||
RdxFormGrid
|
||
RdxEditorStickyFooter
|
||
RdxDetailPageLayout
|
||
```
|
||
|
||
El prefijo distingue los componentes propios de la aplicación frente a primitives de terceros como Shadcn/UI y evita colisiones de naming.
|
||
|
||
---
|
||
|
||
## 2. Contexto
|
||
|
||
El frontend ERP está basado en:
|
||
|
||
- React 19
|
||
- TypeScript estricto
|
||
- Shadcn/UI
|
||
- Tailwind CSS v4
|
||
- React Hook Form
|
||
- TanStack Query
|
||
- TanStack Table
|
||
- React Router
|
||
|
||
La arquitectura general mantiene el flujo:
|
||
|
||
```txt
|
||
API → DTO → adapter → Entity → hook → controller → page controller → UI
|
||
```
|
||
|
||
Separación de responsabilidades:
|
||
|
||
```txt
|
||
shared/api → transporte remoto
|
||
shared/adapters → DTO → Entity
|
||
shared/hooks → React Query y entities
|
||
controllers → orquestación del caso de uso
|
||
page controllers → composición e integración externa
|
||
Page → wiring y composición
|
||
UI → render puro
|
||
```
|
||
|
||
El sistema visual Rdx debe respetar estrictamente esta arquitectura.
|
||
|
||
---
|
||
|
||
## 3. Objetivo
|
||
|
||
Crear un estándar visual y estructural común para los principales tipos de pantalla del ERP:
|
||
|
||
```txt
|
||
Listados
|
||
Vistas de detalle
|
||
Pantallas de creación
|
||
Pantallas de edición
|
||
```
|
||
|
||
El sistema debe unificar:
|
||
|
||
- márgenes;
|
||
- padding;
|
||
- separación entre elementos;
|
||
- anchuras;
|
||
- jerarquía tipográfica;
|
||
- disposición de acciones;
|
||
- iconografía;
|
||
- estados visuales;
|
||
- superficies;
|
||
- responsive;
|
||
- accesibilidad;
|
||
- soporte claro/oscuro;
|
||
- documentación y ejemplos interactivos.
|
||
|
||
El objetivo no es crear un framework CRUD universal, sino una biblioteca pequeña de primitives y composiciones visuales explícitas.
|
||
|
||
---
|
||
|
||
## 4. Principios rectores
|
||
|
||
### 4.1 Claridad antes que abstracción
|
||
|
||
```txt
|
||
Primero claridad local.
|
||
Después repetición real.
|
||
Solo entonces abstraer.
|
||
```
|
||
|
||
No se crearán componentes genéricos sin evidencia suficiente de repetición.
|
||
|
||
### 4.2 UI pura
|
||
|
||
Los componentes Rdx no deben conocer:
|
||
|
||
- React Query;
|
||
- DTOs;
|
||
- APIs;
|
||
- controllers;
|
||
- routing;
|
||
- permisos de negocio;
|
||
- estados de dominio;
|
||
- errores de transporte.
|
||
|
||
Deben recibir props ya preparadas.
|
||
|
||
### 4.3 Composición, no configuración excesiva
|
||
|
||
Preferir:
|
||
|
||
```tsx
|
||
<RdxPageContainer>
|
||
<RdxPageStack>
|
||
<RdxPageHeader />
|
||
<RdxListPageLayout main={...} aside={...} />
|
||
</RdxPageStack>
|
||
</RdxPageContainer>
|
||
```
|
||
|
||
Evitar:
|
||
|
||
```tsx
|
||
<RdxCrudPage
|
||
entity="customers"
|
||
filters={...}
|
||
permissions={...}
|
||
routing={...}
|
||
query={...}
|
||
/>
|
||
```
|
||
|
||
### 4.4 Diseño compacto y ordenado
|
||
|
||
La interfaz debe:
|
||
|
||
- evitar espacio vacío que no aporte jerarquía;
|
||
- mantener alta densidad informativa;
|
||
- conservar suficiente separación para lectura;
|
||
- evitar ruido visual;
|
||
- evitar card dentro de card;
|
||
- usar superficies solo cuando tengan una función clara.
|
||
|
||
### 4.5 Tema claro y oscuro desde el inicio
|
||
|
||
Todo componente debe diseñarse y validarse en:
|
||
|
||
```txt
|
||
Tema claro
|
||
Tema oscuro
|
||
```
|
||
|
||
No se aceptará una implementación diseñada solo para tema claro y corregida posteriormente.
|
||
|
||
---
|
||
|
||
## 5. Referencias visuales
|
||
|
||
### 5.1 Pantalla de referencia principal
|
||
|
||
La pantalla de listado de proformas es la referencia visual inicial para:
|
||
|
||
- densidad;
|
||
- toolbar;
|
||
- espaciado;
|
||
- jerarquía de acciones;
|
||
- tratamiento de tabla;
|
||
- iconografía;
|
||
- filtros;
|
||
- composición general.
|
||
|
||
Ruta:
|
||
|
||
```txt
|
||
modules/customer-invoices/src/web/proformas/list
|
||
```
|
||
|
||
Estado de adopción a 6 de agosto de 2026:
|
||
|
||
- primera pantalla piloto migrada a `RdxPageContainer`, `RdxPageStack`, `RdxPageHeader` y `RdxPageActions`;
|
||
- se ha sustituido el header legacy solo en la Page de listado, sin tocar controllers, grid, filtros, panel lateral ni dialogs;
|
||
- el piloto confirma que las foundations actuales cubren la geometría exterior de la página sin justificar todavía `RdxListPageLayout`, `RdxResponsivePageGrid` ni `RdxContextPanel`.
|
||
- segundo piloto migrado en `modules/customers/src/web/list` con el mismo perímetro de cambio;
|
||
- ambos listados confirman la reutilización de container, stack, header y CTA principal, pero todavía no justifican abstraer la geometría interior del listado;
|
||
- los dos paneles contextuales reales confirman una separación válida entre `RightPanel` como primitive de superficie y `RdxContextPanel` como composición visual contextual.
|
||
|
||
### 5.2 Pantallas de contraste
|
||
|
||
Se usarán además:
|
||
|
||
```txt
|
||
modules/customers/src/web/list
|
||
modules/customers/src/web/create
|
||
modules/customers/src/web/update
|
||
modules/customers/src/web/view
|
||
modules/customer-invoices/src/web/proformas/create
|
||
modules/customer-invoices/src/web/proformas/update
|
||
modules/customer-invoices/src/web/proformas/detail
|
||
```
|
||
|
||
Estas pantallas permiten validar listados, editor simple, editor complejo y detalle.
|
||
|
||
---
|
||
|
||
## 6. Tipos de pantalla
|
||
|
||
## 6.1 Listados
|
||
|
||
Reglas:
|
||
|
||
```txt
|
||
Anchura completa
|
||
Toolbar compacta
|
||
Tabla densa
|
||
Acción principal en cabecera
|
||
Panel lateral opcional
|
||
Paginación integrada
|
||
Estados vacíos y errores consistentes
|
||
```
|
||
|
||
El listado no debe estar obligado a usar filtros, panel lateral o tabs.
|
||
|
||
## 6.2 Editor simple
|
||
|
||
Reglas:
|
||
|
||
```txt
|
||
Una columna por defecto
|
||
Ancho máximo centrado
|
||
Lateral opcional
|
||
No reservar espacio si el lateral no existe
|
||
Secciones planas con divisores
|
||
```
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
customers/create
|
||
customers/update
|
||
suppliers/create
|
||
suppliers/update
|
||
```
|
||
|
||
## 6.3 Editor complejo
|
||
|
||
Reglas:
|
||
|
||
```txt
|
||
Todo el ancho disponible
|
||
Main flexible
|
||
Lateral derecho permitido como región estructural estándar
|
||
Footer sticky cuando exista scroll significativo
|
||
Paneles laterales para resumen, configuración o contexto
|
||
```
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
proformas/update
|
||
issued-invoices/update, si existiera
|
||
```
|
||
|
||
## 6.4 Vista de detalle
|
||
|
||
Reglas:
|
||
|
||
```txt
|
||
Anchura wide o full
|
||
Main + lateral opcional
|
||
Lateral para metadata, actividad, resumen o acciones
|
||
Patrón label/value consistente
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Política de anchuras
|
||
|
||
Se define el siguiente contrato inicial:
|
||
|
||
```ts
|
||
export type RdxPageWidth = "full" | "wide" | "content";
|
||
```
|
||
|
||
### `full`
|
||
|
||
Uso:
|
||
|
||
- listados;
|
||
- editores complejos;
|
||
- tablas;
|
||
- pantallas documentales.
|
||
|
||
### `wide`
|
||
|
||
Uso:
|
||
|
||
- vistas de detalle;
|
||
- pantallas con mucha información sin necesidad de ocupar todo el viewport.
|
||
|
||
### `content`
|
||
|
||
Uso:
|
||
|
||
- formularios y editores simples.
|
||
|
||
Referencia inicial:
|
||
|
||
```txt
|
||
max-w-5xl o max-w-6xl
|
||
```
|
||
|
||
La decisión exacta se centraliza en `RdxPageContainer`.
|
||
|
||
---
|
||
|
||
## 8. Foundations visuales
|
||
|
||
## 8.1 Espaciado
|
||
|
||
Escala inicial recomendada:
|
||
|
||
```txt
|
||
compact → 1rem
|
||
normal → 1.5rem
|
||
relaxed → 2rem
|
||
```
|
||
|
||
Propuesta de uso:
|
||
|
||
```txt
|
||
Page padding mobile: 1rem
|
||
Page padding desktop: 1.5rem
|
||
Main block gap: 1.5rem
|
||
Section internal gap: 1rem
|
||
Form grid horizontal: 1.5rem
|
||
Form grid vertical: 1.25rem
|
||
Compact element gap: 0.5–0.75rem
|
||
```
|
||
|
||
No se fija `gap-12` como foundation global.
|
||
|
||
## 8.2 Tipografía
|
||
|
||
Funciones tipográficas:
|
||
|
||
```txt
|
||
Page title
|
||
Page description
|
||
Section title
|
||
Section description
|
||
Field label
|
||
Body
|
||
Metadata
|
||
Numeric value
|
||
Status
|
||
```
|
||
|
||
Referencia inicial:
|
||
|
||
```txt
|
||
Page title: text-2xl font-semibold tracking-tight
|
||
Page description: text-sm text-muted-foreground
|
||
Section title: text-base font-semibold
|
||
Section description: text-sm text-muted-foreground
|
||
Metadata label: text-xs font-medium text-muted-foreground
|
||
Numeric value: font-medium tabular-nums
|
||
```
|
||
|
||
## 8.3 Superficies
|
||
|
||
Política:
|
||
|
||
```txt
|
||
Contenido principal → plano
|
||
Secciones → divisores y spacing
|
||
Aside → paneles permitidos
|
||
Tabla compleja → superficie independiente permitida
|
||
Notices → superficie semántica
|
||
Cards → excepción, no default
|
||
```
|
||
|
||
## 8.4 Bordes y radios
|
||
|
||
Reglas:
|
||
|
||
- evitar border en cada bloque;
|
||
- preferir `border-b` o `Separator` entre secciones;
|
||
- reservar radios para paneles o superficies independientes;
|
||
- los radios hijos no deben exceder los radios del contenedor padre.
|
||
|
||
## 8.5 Sombras
|
||
|
||
Reglas:
|
||
|
||
```txt
|
||
Página y secciones → sin sombra
|
||
Panel contextual → sombra suave opcional
|
||
Header/footer sticky → borde como primera opción
|
||
```
|
||
|
||
Las sombras deben ser mínimas.
|
||
|
||
## 8.6 Color
|
||
|
||
Usar tokens semánticos:
|
||
|
||
```txt
|
||
background
|
||
foreground
|
||
card
|
||
muted
|
||
muted-foreground
|
||
border
|
||
primary
|
||
primary-foreground
|
||
destructive
|
||
destructive-foreground
|
||
```
|
||
|
||
Se deberán consolidar también tokens para:
|
||
|
||
```txt
|
||
success
|
||
warning
|
||
info
|
||
```
|
||
|
||
No usar directamente colores físicos cuando exista un token semántico adecuado.
|
||
|
||
Evitar:
|
||
|
||
```txt
|
||
text-green-600
|
||
bg-yellow-100
|
||
border-blue-300
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Arquitectura de componentes
|
||
|
||
## 9.1 Ubicación
|
||
|
||
```txt
|
||
packages/rdx-ui/src/components/
|
||
```
|
||
|
||
Estructura objetivo progresiva:
|
||
|
||
```txt
|
||
components/
|
||
├── layout/
|
||
├── page-states/
|
||
├── list-page/
|
||
├── detail-page/
|
||
├── editor-page/
|
||
├── form/
|
||
└── right-panel/
|
||
```
|
||
|
||
No es obligatorio crear toda la estructura desde la primera fase.
|
||
|
||
## 9.2 Naming
|
||
|
||
Todos los componentes públicos propios usan `Rdx`.
|
||
|
||
Ejemplo:
|
||
|
||
```ts
|
||
export interface RdxPageHeaderProps {
|
||
// ...
|
||
}
|
||
|
||
export const RdxPageHeader = ({
|
||
// ...
|
||
}: RdxPageHeaderProps) => {
|
||
// ...
|
||
};
|
||
```
|
||
|
||
No es obligatorio usar `Rdx` en:
|
||
|
||
- helpers internos;
|
||
- tipos privados;
|
||
- variantes locales;
|
||
- tokens CSS.
|
||
|
||
---
|
||
|
||
## 10. Foundations implementadas y siguientes candidatos
|
||
|
||
Fase 1 implementada:
|
||
|
||
```txt
|
||
RdxPageContainer
|
||
RdxPageStack
|
||
RdxPageHeader
|
||
RdxPageActions
|
||
RdxContextPanel
|
||
RdxRowActions
|
||
RdxEditorPageLayout
|
||
RdxEditorSection
|
||
RdxFormGrid
|
||
RdxEditorStickyFooter
|
||
```
|
||
|
||
Candidatos posteriores a validar con pantallas piloto reales:
|
||
|
||
```txt
|
||
RdxResponsivePageGrid
|
||
RdxListPageLayout
|
||
```
|
||
|
||
También deberán evaluarse y adaptar, no necesariamente reescribir:
|
||
|
||
```txt
|
||
PageHeader
|
||
PageFormHeader
|
||
RightPanel
|
||
DataTable
|
||
```
|
||
|
||
No se implementarán todavía:
|
||
|
||
```txt
|
||
RdxDetailPageLayout
|
||
RdxDetailField
|
||
RdxNotice
|
||
RdxEmptyState
|
||
```
|
||
|
||
Estos componentes se diseñarán en fases posteriores con pantallas piloto específicas.
|
||
|
||
---
|
||
|
||
## 11. Contratos iniciales
|
||
|
||
## 11.1 `RdxPageContainer`
|
||
|
||
Responsabilidad:
|
||
|
||
- ancho;
|
||
- padding exterior;
|
||
- centrado;
|
||
- comportamiento responsive.
|
||
|
||
```ts
|
||
export interface RdxPageContainerProps {
|
||
children: React.ReactNode;
|
||
width?: RdxPageWidth;
|
||
className?: string;
|
||
}
|
||
```
|
||
|
||
No debe gestionar ritmo vertical.
|
||
|
||
## 11.2 `RdxPageStack`
|
||
|
||
Responsabilidad:
|
||
|
||
- separación vertical entre bloques principales.
|
||
|
||
```ts
|
||
export type RdxPageStackSpacing = "compact" | "default" | "relaxed";
|
||
|
||
export interface RdxPageStackProps {
|
||
children: React.ReactNode;
|
||
spacing?: RdxPageStackSpacing;
|
||
className?: string;
|
||
}
|
||
```
|
||
|
||
## 11.3 `RdxPageHeader`
|
||
|
||
Responsabilidad:
|
||
|
||
- título;
|
||
- descripción;
|
||
- leading opcional;
|
||
- metadata opcional;
|
||
- acciones;
|
||
|
||
```ts
|
||
export interface RdxPageHeaderProps {
|
||
title: React.ReactNode;
|
||
description?: React.ReactNode;
|
||
leading?: React.ReactNode;
|
||
metadata?: React.ReactNode;
|
||
actions?: React.ReactNode;
|
||
className?: string;
|
||
}
|
||
```
|
||
|
||
No debe conocer routing.
|
||
|
||
## 11.4 `RdxPageActions`
|
||
|
||
Responsabilidad:
|
||
|
||
- agrupar acciones;
|
||
- diferenciar primarias, secundarias y overflow;
|
||
- resolver layout responsive.
|
||
|
||
```ts
|
||
export interface RdxPageActionsProps {
|
||
primary?: React.ReactNode;
|
||
secondary?: React.ReactNode;
|
||
overflow?: React.ReactNode;
|
||
className?: string;
|
||
}
|
||
```
|
||
|
||
No debe decidir permisos ni disponibilidad.
|
||
|
||
## 11.5 `RdxResponsivePageGrid`
|
||
|
||
Responsabilidad:
|
||
|
||
- layout `main + aside`;
|
||
- stacking responsive;
|
||
- ancho limitado del aside.
|
||
|
||
```ts
|
||
export type RdxPageAsideWidth = "sm" | "md" | "lg";
|
||
export type RdxPageAsideBehavior = "static" | "sticky";
|
||
|
||
export interface RdxResponsivePageGridProps {
|
||
main: React.ReactNode;
|
||
aside?: React.ReactNode;
|
||
asideWidth?: RdxPageAsideWidth;
|
||
asideBehavior?: RdxPageAsideBehavior;
|
||
className?: string;
|
||
mainClassName?: string;
|
||
asideClassName?: string;
|
||
}
|
||
```
|
||
|
||
Reglas:
|
||
|
||
```txt
|
||
Desktop → main + aside
|
||
Tablet/móvil → aside debajo de main
|
||
Sin aside → no reservar espacio
|
||
Sticky → variante explícita
|
||
```
|
||
|
||
## 11.6 `RdxListPageLayout`
|
||
|
||
Responsabilidad:
|
||
|
||
- geometría del área de listado;
|
||
- composición `main + aside`.
|
||
|
||
```ts
|
||
export interface RdxListPageLayoutProps {
|
||
main: React.ReactNode;
|
||
aside?: React.ReactNode;
|
||
className?: string;
|
||
}
|
||
```
|
||
|
||
No debe conocer:
|
||
|
||
- DataTable;
|
||
- búsqueda;
|
||
- filtros;
|
||
- selección;
|
||
- React Query;
|
||
- estado remoto;
|
||
- dominio.
|
||
|
||
## 11.7 `RdxRowActions`
|
||
|
||
Responsabilidad:
|
||
|
||
- renderizar acciones visibles;
|
||
- renderizar acciones overflow;
|
||
- representar disabled y destructive;
|
||
- ofrecer tooltips y labels accesibles.
|
||
|
||
```ts
|
||
export interface RdxRowAction {
|
||
id: string;
|
||
label: string;
|
||
icon: React.ReactNode;
|
||
onSelect: () => void;
|
||
disabled?: boolean;
|
||
disabledReason?: string;
|
||
destructive?: boolean;
|
||
}
|
||
|
||
export interface RdxRowActionsProps {
|
||
primaryActions?: RdxRowAction[];
|
||
overflowActions?: RdxRowAction[];
|
||
overflowLabel: string;
|
||
className?: string;
|
||
}
|
||
```
|
||
|
||
El componente no decide qué acciones existen.
|
||
La UI solo renderiza; el consumidor conserva permisos, labels, disabled reasons y callbacks.
|
||
|
||
---
|
||
|
||
## 12. Política de acciones
|
||
|
||
## 12.1 Listados
|
||
|
||
```txt
|
||
Acción principal → cabecera
|
||
Acciones frecuentes → visibles en fila
|
||
Acciones infrecuentes → overflow
|
||
Acciones destructivas → overflow por defecto
|
||
```
|
||
|
||
Orden recomendado:
|
||
|
||
```txt
|
||
Ver
|
||
Editar
|
||
Más acciones
|
||
```
|
||
|
||
## 12.2 Formularios cortos
|
||
|
||
Acciones en cabecera o al final del formulario.
|
||
|
||
## 12.3 Formularios largos
|
||
|
||
Acciones principales en footer sticky.
|
||
|
||
## 12.4 Editores complejos
|
||
|
||
```txt
|
||
Cabecera → navegación, estado y acciones documentales
|
||
Footer sticky → cancelar, guardar y submit principal
|
||
```
|
||
|
||
La ubicación depende de la distancia real del usuario a la acción primaria, no solo del tipo CRUD.
|
||
|
||
---
|
||
|
||
## 13. Política de iconos
|
||
|
||
Catálogo inicial:
|
||
|
||
| Acción | Icono recomendado |
|
||
|---|---|
|
||
| Ver | `Eye` |
|
||
| Editar | `Pencil` |
|
||
| Crear | `Plus` |
|
||
| Eliminar | `Trash2` |
|
||
| Descargar | `Download` |
|
||
| Imprimir | `Printer` |
|
||
| Duplicar | `Copy` |
|
||
| Más acciones | `Ellipsis` |
|
||
| Volver | `ArrowLeft` |
|
||
| Guardar | `Save` |
|
||
| Filtrar | `ListFilter` |
|
||
| Buscar | `Search` |
|
||
| Configurar columnas | `Columns3` |
|
||
| Cerrar | `X` |
|
||
|
||
Reglas:
|
||
|
||
- iconos con tamaño consistente;
|
||
- botón solo icono con `aria-label`;
|
||
- tooltip cuando la acción no sea inequívoca;
|
||
- no usar iconos diferentes para la misma acción sin justificación.
|
||
|
||
---
|
||
|
||
## 14. Responsive
|
||
|
||
## 14.1 Listados
|
||
|
||
```txt
|
||
Desktop → toolbar horizontal y tabla completa
|
||
Tablet → filtros colapsables cuando sea necesario
|
||
Mobile → scroll horizontal o adaptación específica
|
||
```
|
||
|
||
No se implementará todavía una vista móvil universal de cards para tablas.
|
||
|
||
## 14.2 Editor simple
|
||
|
||
```txt
|
||
Desktop → ancho máximo centrado
|
||
Mobile → una columna
|
||
```
|
||
|
||
## 14.3 Editor complejo
|
||
|
||
```txt
|
||
Desktop → main + aside
|
||
Tablet/móvil → aside debajo de main
|
||
Footer sticky → debe respetar safe areas
|
||
```
|
||
|
||
## 14.4 Detalle
|
||
|
||
```txt
|
||
Desktop → main + aside opcional
|
||
Tablet/móvil → aside debajo de main
|
||
```
|
||
|
||
---
|
||
|
||
## 15. Accesibilidad
|
||
|
||
Reglas obligatorias:
|
||
|
||
- un único `h1` por página;
|
||
- jerarquía correcta de headings;
|
||
- botones reales para acciones;
|
||
- links reales para navegación;
|
||
- foco visible;
|
||
- botones de icono con `aria-label`;
|
||
- estados no representados solo mediante color;
|
||
- `type="button"` en botones internos de formularios;
|
||
- targets táctiles suficientes;
|
||
- tooltips accesibles;
|
||
- dialogs con restauración de foco;
|
||
- loading que conserve el significado de la acción;
|
||
- acciones disabled con explicación cuando sea útil.
|
||
|
||
---
|
||
|
||
## 16. Reutilización de componentes existentes
|
||
|
||
Antes de crear un componente nuevo se debe comparar su contrato con:
|
||
|
||
```txt
|
||
modules/core/src/web/components/page-header.tsx
|
||
modules/core/src/web/components/form/form-actions/page-form-header.tsx
|
||
modules/core/src/web/components/page-error-state.tsx
|
||
modules/core/src/web/components/error-alert.tsx
|
||
packages/rdx-ui/src/components/right-panel/right-panel.tsx
|
||
packages/rdx-ui/src/components/datatable/data-table.tsx
|
||
packages/rdx-ui/src/components/form/form-section-card.tsx
|
||
packages/rdx-ui/src/components/form/form-section-grid.tsx
|
||
```
|
||
|
||
Proceso obligatorio:
|
||
|
||
```txt
|
||
1. Definir contrato objetivo Rdx.
|
||
2. Comparar con componente existente.
|
||
3. Adaptar si es viable.
|
||
4. Exportar con naming Rdx.
|
||
5. Mantener alias temporal si hay consumidores.
|
||
6. Migrar progresivamente.
|
||
7. Retirar alias cuando no se use.
|
||
```
|
||
|
||
No se harán renombrados globales sin estrategia de compatibilidad.
|
||
|
||
---
|
||
|
||
## 17. Documentación
|
||
|
||
## 17.1 Markdown
|
||
|
||
Ubicación canónica:
|
||
|
||
```txt
|
||
packages/rdx-ui/docs/
|
||
├── visual-system-design.md
|
||
├── foundations.md
|
||
├── page-layouts.md
|
||
└── contributing-ui.md
|
||
```
|
||
|
||
## 17.2 UI Kit interactivo
|
||
|
||
Se creará una ruta interna:
|
||
|
||
```txt
|
||
/development/ui-kit
|
||
```
|
||
|
||
El UI Kit debe mostrar:
|
||
|
||
- foundations;
|
||
- componentes aislados;
|
||
- variantes;
|
||
- estados;
|
||
- tema claro y oscuro;
|
||
- comportamiento responsive;
|
||
- composiciones completas;
|
||
- ejemplos correctos;
|
||
- anti-patterns relevantes.
|
||
|
||
Ejemplos completos mínimos:
|
||
|
||
```txt
|
||
Listado
|
||
Detalle
|
||
Editor simple
|
||
Editor complejo
|
||
Error
|
||
Vacío
|
||
Loading
|
||
```
|
||
|
||
## 17.3 Regla de sincronización
|
||
|
||
Todo cambio que afecte a API pública, comportamiento o apariencia debe actualizar en la misma intervención:
|
||
|
||
```txt
|
||
1. implementación;
|
||
2. documentación Markdown;
|
||
3. UI Kit interactivo;
|
||
4. tests aplicables.
|
||
```
|
||
|
||
Un cambio se considera incompleto si alguno de estos recursos queda desactualizado.
|
||
|
||
---
|
||
|
||
## 18. Testing
|
||
|
||
Los tests deben centrarse en comportamiento:
|
||
|
||
- render de slots;
|
||
- variantes;
|
||
- accesibilidad;
|
||
- acciones disabled;
|
||
- overflow;
|
||
- responsive inferible por clases;
|
||
- ausencia de columna aside cuando no se proporciona;
|
||
- compatibilidad con tema.
|
||
|
||
No testear detalles internos irrelevantes.
|
||
|
||
Herramientas:
|
||
|
||
```txt
|
||
Testing Library
|
||
Vitest
|
||
```
|
||
|
||
---
|
||
|
||
## 19. Plan de implementación
|
||
|
||
## Fase 0 — Documentación y UI Kit base
|
||
|
||
Crear o mantener sincronizados:
|
||
|
||
```txt
|
||
packages/rdx-ui/docs/visual-system-design.md
|
||
packages/rdx-ui/docs/foundations.md
|
||
packages/rdx-ui/docs/page-layouts.md
|
||
packages/rdx-ui/docs/contributing-ui.md
|
||
```
|
||
|
||
Crear la infraestructura mínima de `/development/ui-kit`.
|
||
|
||
## Fase 1 — Foundations de página
|
||
|
||
Implementar:
|
||
|
||
```txt
|
||
RdxPageContainer
|
||
RdxPageStack
|
||
RdxPageHeader
|
||
RdxPageActions
|
||
```
|
||
|
||
## Fase 2 — Piloto `proformas/list`
|
||
|
||
Aplicar foundations sin rediseño funcional.
|
||
|
||
Objetivos:
|
||
|
||
```txt
|
||
Misma funcionalidad
|
||
Misma densidad
|
||
Menos clases estructurales locales
|
||
Contrato reusable validado
|
||
```
|
||
|
||
Resultado observado:
|
||
|
||
- `RdxPageContainer` absorbe el padding exterior de página y evita mantener `p-6` local;
|
||
- `RdxPageStack` absorbe el ritmo vertical principal y evita mantener `space-y-6` local;
|
||
- `RdxPageHeader` cubre la cabecera de listado con composición directa;
|
||
- `RdxPageActions` cubre correctamente una acción primaria única;
|
||
- el layout interno del listado sigue necesitando composición específica local mientras no se compare este piloto con `customers/list`.
|
||
|
||
## Fase 3 — Layout de listado y panel
|
||
|
||
Implementar:
|
||
|
||
```txt
|
||
RdxResponsivePageGrid
|
||
RdxListPageLayout
|
||
```
|
||
|
||
Validar con:
|
||
|
||
```txt
|
||
proformas/list
|
||
customers/list
|
||
```
|
||
|
||
Estado tras comparar ambos pilotos:
|
||
|
||
- `RdxListPageLayout`: prematuro;
|
||
- `RdxResponsivePageGrid`: prematuro en listados que dependen de `ResizablePanelGroup`;
|
||
- `RdxContextPanel`: candidato confirmado para una fase específica sobre `RightPanel`, `CustomerSummaryPanel` y `ProformaSummaryPanel`.
|
||
|
||
## Fase 4 — Panel contextual
|
||
|
||
Normalizar:
|
||
|
||
```txt
|
||
RightPanel
|
||
RdxContextPanel
|
||
CustomerSummaryPanel
|
||
ProformaSummaryPanel
|
||
```
|
||
|
||
Resultado esperado:
|
||
|
||
- `RightPanel` mantiene la superficie lateral reusable;
|
||
- `RdxContextPanel` concentra cabecera, cierre, jerarquía y footer contextual;
|
||
- no existe doble header;
|
||
- no existe doble cierre;
|
||
- no existe doble sombra.
|
||
|
||
## Fase 5 — Acciones de fila
|
||
|
||
Implementar `RdxRowActions` tomando proformas como referencia.
|
||
|
||
Resultado observado a 6 de agosto de 2026:
|
||
|
||
- `RdxRowActions` ya existe en `packages/rdx-ui` y se exporta públicamente;
|
||
- `proformas/list` y `customers/list` consumen el mismo contrato visual;
|
||
- las acciones destructivas quedan en overflow;
|
||
- el consumidor sigue decidiendo permisos, estado, callbacks y razones de disabled;
|
||
- en `customers/list` se ha corregido el bug que renderizaba delete cuando no existía `onDeleteClick`.
|
||
|
||
## Fase 6 — Editor simple
|
||
|
||
Usar `customers/update` como piloto para:
|
||
|
||
```txt
|
||
RdxEditorPageLayout
|
||
RdxEditorSection
|
||
RdxFormGrid
|
||
```
|
||
|
||
Resultado observado a 6 de agosto de 2026:
|
||
|
||
- `RdxEditorPageLayout` absorbe el ancho centrado y el padding interior del editor simple;
|
||
- `RdxEditorSection` sustituye en `customers/update` el uso sistemático de `FormSectionCard` cuando la superficie no necesita card;
|
||
- `RdxFormGrid` consolida la retícula ya existente sin mover lógica de formulario fuera del consumidor;
|
||
- `PageFormHeader` se mantiene sin cambios funcionales;
|
||
- queda pendiente validar visualmente si el header sticky full-width se percibe demasiado separado del ancho centrado del editor.
|
||
|
||
## Fase 7 — Confirmación de editor simple
|
||
|
||
Validar el mismo patrón en:
|
||
|
||
```txt
|
||
customers/create
|
||
```
|
||
|
||
Resultado observado a 6 de agosto de 2026:
|
||
|
||
- `customers/create` reutiliza `RdxEditorPageLayout`, `RdxEditorSection` y `RdxFormGrid` sin requerir nuevas primitives;
|
||
- create y update comparten shell, header legacy, superficie editable única y secciones planas internas;
|
||
- las diferencias reales quedan en defaults, submit y wiring del controller, no en la composición visual;
|
||
- `PageFormHeader` sigue siendo funcionalmente suficiente, aunque se mantiene una deuda visual menor por su anchura full-width frente al contenido centrado.
|
||
|
||
## Fase 8 — Editor complejo
|
||
|
||
Usar `proformas/update` como piloto para:
|
||
|
||
```txt
|
||
main + aside
|
||
sticky footer
|
||
totales
|
||
acciones según scroll
|
||
```
|
||
|
||
Resultado observado a 10 de agosto de 2026:
|
||
|
||
- `proformas/update` valida `RdxEditorPageLayout` con `complexity="complex"` a ancho completo, `main` flexible y `aside` estructural aproximado de `22rem`;
|
||
- el `main` concentra la única superficie editable real del documento y el bloque de líneas mantiene su layout propio;
|
||
- el `aside` conserva únicamente controles secundarios ya presentes en la pantalla, sin convertirlo en `RightPanel` ni mover allí los totales;
|
||
- el footer sticky de totales se mantiene como dominio visual y económico de Proformas;
|
||
- `RdxEditorStickyFooter` queda justificado para combinar en una única superficie sticky la región de totales/contexto y las acciones `Cancelar` / `Guardar`;
|
||
- `PageFormHeader` queda reducido a navegación y contexto solo en `proformas/update`, sin cambio global del componente legacy;
|
||
- `RdxEditorSection` y `RdxFormGrid` siguen siendo válidos para bloques de campos, pero no deben forzar el layout del editor de líneas ni el footer de totales.
|
||
|
||
## Fase 8 — Detalle
|
||
|
||
Usar primero `proformas/detail` y después `customers/view`.
|
||
|
||
---
|
||
|
||
## 20. Anti-patterns prohibidos
|
||
|
||
No crear:
|
||
|
||
```txt
|
||
RdxCrudPage
|
||
RdxCrudEditor
|
||
RdxGenericEntityPage
|
||
RdxUniversalToolbar
|
||
RdxFormSectionEngine
|
||
GenericPageFactory
|
||
```
|
||
|
||
No hacer:
|
||
|
||
- routing dentro de `packages/rdx-ui`;
|
||
- React Query dentro de componentes Rdx;
|
||
- interpretación de `ApiClientError` en UI;
|
||
- permisos dentro de `RdxRowActions`;
|
||
- hardcodes de dominio;
|
||
- colors físicos cuando exista token semántico;
|
||
- megacomponentes configurables;
|
||
- migraciones globales sin alias temporal;
|
||
- abstracciones genéricas antes de validarlas en varias pantallas.
|
||
|
||
---
|
||
|
||
## 21. Evidencia de pilotos de listado
|
||
|
||
### DECISIÓN_CONFIRMADA
|
||
|
||
- `RdxPageContainer` resuelve de forma estable el padding exterior y la anchura de `proformas/list` y `customers/list`.
|
||
- `RdxPageStack` resuelve el ritmo vertical principal entre cabecera, error inline y contenido.
|
||
- `RdxPageHeader` sustituye correctamente al `PageHeader` legacy en ambos listados sin conocer navegación.
|
||
- `RdxPageActions` cubre la CTA principal de cabecera en ambos pilotos sin necesidad de variantes adicionales.
|
||
- `RightPanel` es suficiente como primitive de superficie lateral y no debe renombrarse globalmente.
|
||
- `RdxContextPanel` está justificado como composición visual común sobre `RightPanel`.
|
||
- `RdxRowActions` está justificado para normalizar icon buttons, overflow, disabled reason y destructivas en tablas.
|
||
- `RdxEditorPageLayout`, `RdxEditorSection` y `RdxFormGrid` quedan confirmados tras migrar `customers/update` y `customers/create`.
|
||
- `RdxEditorPageLayout` también es apto para `proformas/update` cuando el `aside` contiene bloques secundarios ya existentes y el `main` conserva la única superficie editable.
|
||
- `RdxEditorSection` soporta tanto secciones planas de formulario como grupos secundarios del `aside` sin volver a `Card` por defecto.
|
||
- `RdxFormGrid` queda confirmado para campos en editores complejos, pero no debe envolver tablas o editores de líneas.
|
||
- `RdxEditorStickyFooter` está justificado para el patrón de editor complejo con una sola zona inferior persistente y sin duplicidad de acciones con el header.
|
||
|
||
### DECISIÓN_PROVISIONAL
|
||
|
||
- La extracción de una Page View pura es útil cuando reduce wiring y facilita tests sin controllers reales, pero no debe convertirse todavía en convención global.
|
||
- El patrón `main + aside` existe en ambos listados, pero hoy depende de `ResizablePanelGroup`, tamaños y apertura específicos de cada pantalla.
|
||
- El contrato final del footer contextual puede seguir afinándose cuando aparezcan paneles con resúmenes o acciones más heterogéneas.
|
||
- `RdxEditorPageLayout` ya cubre el editor simple, pero la convivencia visual con `PageFormHeader` debe seguir validándose antes de tocar el header legacy.
|
||
- la densidad final de la sticky zone inferior en móvil sigue requiriendo validación visual manual en múltiples resoluciones y tema oscuro.
|
||
|
||
### NO_ABSTRAER_TODAVÍA
|
||
|
||
- `RdxListPageLayout`: la geometría exterior ya queda resuelta por `RdxPageContainer`, `RdxPageStack` y la propia Page.
|
||
- `RdxResponsivePageGrid`: no encaja todavía como abstracción para listados con resize persistente.
|
||
- layouts superiores de listado mientras `ResizablePanelGroup` siga gobernando el split real.
|
||
- un layout superior específico de editor complejo mientras `RdxEditorPageLayout` + `RdxEditorStickyFooter` sigan cubriendo la geometría exterior.
|
||
|
||
---
|
||
|
||
## 22. Criterios de aceptación
|
||
|
||
La fase inicial se considerará correcta si:
|
||
|
||
- `packages/rdx-ui` contiene los primeros componentes Rdx;
|
||
- los contratos son puramente visuales;
|
||
- no existe dependencia de routing, datos o dominio;
|
||
- `proformas/list` puede adoptarlos sin perder comportamiento;
|
||
- la documentación Markdown está actualizada;
|
||
- el UI Kit muestra los componentes y sus variantes;
|
||
- tema claro y oscuro están validados;
|
||
- los tests aplicables pasan;
|
||
- no se ha creado un framework CRUD;
|
||
- las clases estructurales repetidas disminuyen;
|
||
- la Page sigue componiendo y haciendo wiring explícito.
|
||
|
||
---
|
||
|
||
## 23. Regla mental final
|
||
|
||
```txt
|
||
Rdx define geometría, jerarquía y comportamiento visual.
|
||
La Page compone.
|
||
Los controllers orquestan.
|
||
La UI no interpreta dominio ni transporte.
|
||
```
|
||
|
||
Y como criterio de calidad:
|
||
|
||
```txt
|
||
Si una abstracción ahorra pocas líneas pero empeora la lectura, no se usa.
|
||
Si un componente necesita conocer el caso de uso, no pertenece a rdx-ui.
|
||
Si un cambio visual no actualiza documentación y UI Kit, está incompleto.
|
||
```
|