Árboles con sangría profunda, contraer y expandir
Especificación del desplazamiento horizontal automático para listas en árbol con muchos niveles. Referencia de diseño: docs/design-system-sgd.md («Árboles con sangría profunda»). Primer uso: árbol del modal «Seguimiento» (app/src/features/documents/components/follow-up-modal.tsx). Segundo uso: árbol de referencias del modal «Anexos» del documento administrativo, con el componente compartido ReferenceTreePanel (app/src/features/documents/components/reference-tree-panel.tsx): contraer y expandir, «Expandir todo», barra horizontal en el pie y detalle con anexos a la derecha. Tercer uso: modal de anexos de los reportes de documentos (features/doc-reports/components/report-annexes-modal.tsx), de solo lectura. El de Mesa de partes (features/mesa-partes/components/bandeja/annexes-modal.tsx) no lleva el panel porque su árbol es un solo nodo hasta que el servidor entregue las referencias: muestra una fila con «Ver estructura» y el detalle y los anexos en dos columnas.
Cuándo usarlo
Árboles anidados con líneas guía (.sgd-tree) cuya profundidad puede superar los 15 o 20 niveles. En árboles poco profundos no cambia nada: no aparece barra horizontal ni corrimiento.
Comportamiento
| Posición vertical | Desplazamiento horizontal |
|---|---|
| Arriba del todo | 0 (sangría normal) |
| A mitad | Proporcional al avance vertical |
| Abajo del todo | Máximo: el último elemento se lee con el mayor ancho posible |
- Al subir, el desplazamiento vuelve hacia 0 con el mismo criterio. Un único movimiento continuo, sin saltos ni animación propia.
- Tope: el corrimiento no supera la sangría de la fila más profunda a la vista menos 8 px, para que ninguna fila visible quede totalmente fuera por la izquierda ni el panel quede en blanco en árboles con una sola rama profunda.
- Cuándo se recalcula: al cambiar el desplazamiento vertical, al abrir o cerrar ramas, al filtrar, al cambiar de vista y al cambiar el ancho del panel. Si solo cambia el desplazamiento horizontal (quien arrastra la barra), no se interviene.
- Movimiento reducido: no se anima nada; el corrimiento es el propio desplazamiento del navegador.
Estructura
Hook useDeepTreeScroll y clase DEEP_TREE_ROW_CLASS en src/components/ui/deep-tree-scroll.ts. Ejemplo interactivo en /design-system/componentes («Árbol: sangría profunda, contraer y expandir», con detalle a la derecha; solo desarrollo).
- Contenedor con
overflow: autoyposition: relative; su ancho se observa conResizeObservery se publica como--tree-list-w(ancho útil sin el relleno). - Cada fila (
.sgd-tree-row) llevamin-width: min(var(--seg-list-w), 38rem): se desborda hacia la derecha solo cuando la sangría ya no deja ese ancho. - Degradado de 24 px (
from-card) fijo en el borde izquierdo del contenedor, visible solo cuando el desplazamiento es mayor que 0. - La barra horizontal nativa se oculta (
overflow-x-hidden) y su lugar lo tomaDeepTreeScrollbaren el pie del panel: pista fina y larga (hasta 20 rem) con el tramo visible y el rótulo «Desplazamiento horizontal». Se arrastra, se pulsa y responde a las flechas, Inicio y Fin (role="scrollbar",aria-valuenowen %). El gesto horizontal del trackpad y Mayús + rueda se atienden cononWheel.
Contraer y expandir
- Cada rama con hijos lleva una flecha (
expand_moreabierta,chevron_rightcerrada) conaria-expandedy nombre «Contraer / Expandir + documento». - Estado inicial: abierta solo la ruta hasta «Usted está aquí».
- «Expandir todo» abre todas las ramas; «Contraer todo» las cierra todas (queda el nivel superior). El botón alterna su texto según el estado y no se muestra con búsqueda o filtro activos (todo se ve abierto).
- Una rama contraída muestra «N documentos más (rama contraída)»; ese texto también la abre.
Detalle al elegir un documento
Al pulsar un elemento queda resaltado (aria-current, fondo primario) y su detalle aparece en el panel derecho: título con estado, «Ver documento», expediente, oficina, elaborado por, fecha y estado del trámite. En pantallas angostas el detalle va debajo. El elemento «Usted está aquí» conserva su contorno y su insignia aunque se elija otro.
Accesibilidad
- No se oculta información: el contenido recortado sigue en el DOM y es alcanzable con teclado (el foco lleva la fila a la vista) y con la barra horizontal.
- El degradado es decorativo (
aria-hidden). La barra del pie es enfocable y se maneja con el teclado. - Contraste y objetivos táctiles sin cambios respecto de las filas del árbol.
Verificación
Cadena simulada de 31 documentos en Chrome: 0 px arriba, 312 de 623 px a mitad y 623 de 623 px abajo; vuelve a 0 al subir.
No probado: con datos reales, con lector de pantalla, en teléfonos físicos ni con árboles anchos de varias ramas profundas.
Línea de tiempo (alternativa sin sangría)
El ejemplo de /design-system/componentes incluye la vista «Línea de tiempo»: los mismos documentos agrupados por día de emisión, del más antiguo al más reciente, sin anidación y por tanto sin desplazamiento horizontal. Es la misma vista del modal «Seguimiento» (TimelineList en follow-up-modal.tsx). El «Nivel N» de cada fila cuenta desde 1 en la raíz y suma uno por cada documento derivado.