@ajuarezso/sui-design-system 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/INDEX.md +30 -35
- package/docs/sui-accordion/README.md +171 -0
- package/docs/sui-activity-feed/README.md +154 -0
- package/docs/sui-activity-filter/README.md +100 -0
- package/docs/sui-alert/README.md +28 -19
- package/docs/sui-app-store-badge/README.md +5 -4
- package/docs/sui-avatar/README.md +16 -16
- package/docs/sui-avatar-group/README.md +4 -4
- package/docs/sui-badge/README.md +27 -9
- package/docs/sui-banner/README.md +10 -9
- package/docs/sui-brand-logo/README.md +3 -3
- package/docs/sui-breadcrumbs/README.md +1 -1
- package/docs/sui-button/README.md +64 -21
- package/docs/sui-button-group/README.md +6 -4
- package/docs/sui-button-group-item/README.md +3 -3
- package/docs/sui-card/README.md +17 -19
- package/docs/sui-chart-legend/README.md +8 -7
- package/docs/sui-checkbox/README.md +11 -6
- package/docs/sui-checkbox-card/README.md +24 -19
- package/docs/sui-checkbox-label/README.md +32 -10
- package/docs/sui-circular-progress-bar/README.md +2 -0
- package/docs/sui-color-dot/README.md +1 -1
- package/docs/sui-color-picker/README.md +22 -7
- package/docs/sui-command-menu-footer/README.md +100 -0
- package/docs/sui-command-menu-item/README.md +140 -0
- package/docs/sui-command-menu-search/README.md +105 -0
- package/docs/sui-compact-avatar-group/README.md +4 -3
- package/docs/sui-compact-button/README.md +41 -44
- package/docs/sui-compact-select/README.md +12 -5
- package/docs/sui-compact-select-for-input/README.md +5 -2
- package/docs/sui-content-card/README.md +6 -5
- package/docs/sui-content-divider/README.md +4 -4
- package/docs/sui-content-label/README.md +11 -6
- package/docs/sui-counter-input/README.md +21 -17
- package/docs/sui-date-selector/README.md +16 -12
- package/docs/sui-datepicker/README.md +46 -28
- package/docs/sui-day-cell/README.md +17 -8
- package/docs/sui-day-label/README.md +2 -2
- package/docs/sui-divider/README.md +5 -5
- package/docs/sui-drawer-footer/README.md +19 -5
- package/docs/sui-dropdown-caption/README.md +92 -0
- package/docs/sui-dropdown-item/README.md +163 -0
- package/docs/sui-dropdown-menu/README.md +196 -0
- package/docs/sui-dropdown-search/README.md +113 -0
- package/docs/sui-emoji/README.md +6 -6
- package/docs/sui-empty-state/README.md +13 -23
- package/docs/sui-fancy-button/README.md +24 -18
- package/docs/sui-file-icon/README.md +1 -1
- package/docs/sui-file-upload/README.md +3 -0
- package/docs/sui-file-upload-card/README.md +8 -7
- package/docs/sui-filter/README.md +181 -0
- package/docs/sui-flag/README.md +3 -2
- package/docs/sui-form-hint/README.md +12 -8
- package/docs/sui-form-label/README.md +11 -16
- package/docs/sui-href/README.md +85 -0
- package/docs/sui-icon/README.md +4 -3
- package/docs/sui-image-upload/README.md +28 -16
- package/docs/sui-img-retry/README.md +107 -0
- package/docs/sui-inline-input/README.md +7 -6
- package/docs/sui-inline-select/README.md +8 -5
- package/docs/sui-input/README.md +27 -33
- package/docs/sui-integration-switch/README.md +14 -7
- package/docs/sui-kbd/README.md +4 -4
- package/docs/sui-key-icon/README.md +6 -2
- package/docs/sui-link-button/README.md +21 -17
- package/docs/sui-modal/README.md +238 -0
- package/docs/sui-modal-footer/README.md +178 -0
- package/docs/sui-modal-header/README.md +115 -0
- package/docs/sui-modal-sheet/README.md +170 -0
- package/docs/sui-notification/README.md +8 -6
- package/docs/sui-notification-footer/README.md +2 -2
- package/docs/sui-notification-tab-menu/README.md +5 -3
- package/docs/sui-page-header/README.md +123 -0
- package/docs/sui-pagination/README.md +8 -5
- package/docs/sui-password-strength/README.md +1 -1
- package/docs/sui-period-range/README.md +18 -14
- package/docs/sui-popover/README.md +13 -7
- package/docs/sui-product-card/README.md +14 -10
- package/docs/sui-progress-bar/README.md +4 -2
- package/docs/sui-progress-bar-label/README.md +2 -0
- package/docs/sui-radio/README.md +14 -7
- package/docs/sui-radio-card/README.md +12 -12
- package/docs/sui-radio-label/README.md +36 -11
- package/docs/sui-rating/README.md +28 -9
- package/docs/sui-rich-editor/README.md +3 -3
- package/docs/sui-segmented-control/README.md +33 -19
- package/docs/sui-select/README.md +40 -33
- package/docs/sui-sidebar/README.md +216 -0
- package/docs/sui-slider/README.md +7 -0
- package/docs/sui-social-button/README.md +24 -11
- package/docs/sui-status-badge/README.md +7 -3
- package/docs/sui-stepper/README.md +30 -17
- package/docs/sui-store-card/README.md +9 -4
- package/docs/sui-switch/README.md +16 -11
- package/docs/sui-switch-card/README.md +18 -16
- package/docs/sui-switch-label/README.md +25 -11
- package/docs/sui-tab-chips/README.md +56 -39
- package/docs/sui-tab-menu-horizontal/README.md +19 -11
- package/docs/sui-tab-menu-vertical/README.md +10 -5
- package/docs/sui-table/README.md +264 -0
- package/docs/sui-tag/README.md +25 -11
- package/docs/sui-tag-input/README.md +25 -12
- package/docs/sui-textarea/README.md +23 -20
- package/docs/sui-time-picker/README.md +39 -30
- package/docs/sui-toast/README.md +27 -22
- package/docs/sui-tooltip/README.md +14 -17
- package/docs/sui-topbar/README.md +153 -0
- package/docs/sui-topbar-button/README.md +95 -0
- package/docs/sui-topbar-item/README.md +97 -0
- package/docs/sui-topbar-user/README.md +83 -0
- package/fesm2022/ajuarezso-sui-design-system.mjs +1076 -242
- package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ajuarezso-sui-design-system.d.ts +616 -280
|
@@ -47,7 +47,7 @@ Regla corta: **ajuste con texto → este · ajuste con peso → switch-card · s
|
|
|
47
47
|
| `sublabel` | Precisión corta entre paréntesis: «(beta)». | según la guía del DS |
|
|
48
48
|
| `badge` | Solo novedad. Con string sale naranja `light`: pasa el objeto. | según la guía del DS (pieza «NEW»); el color es propuesta |
|
|
49
49
|
| `link` | «Saber más» que no toca el interruptor. Solo se ve con `description`. | según la guía del DS |
|
|
50
|
-
| `flip` | Interruptor a la **derecha** en listas de ajustes: el texto se lee primero y el control queda bajo el pulgar, como en iOS y Android (es lo que hacen a mano `drivers.html:58`, `discounts.html:
|
|
50
|
+
| `flip` | Interruptor a la **derecha** en listas de ajustes: el texto se lee primero y el control queda bajo el pulgar, como en iOS y Android (es lo que hacen a mano `drivers.html:58`, `discounts.html:207`, `schedule.html:46`). Sin `flip` (izquierda) dentro de un formulario, alineado con las casillas o los switches del resto del form. | canon (aprobado por el dueño, 03-10-2026) |
|
|
51
51
|
| `disabled` | Mientras se guarda el cambio o cuando no aplica. | según la guía del DS |
|
|
52
52
|
|
|
53
53
|
### `size`
|
|
@@ -60,25 +60,37 @@ Regla corta: **ajuste con texto → este · ajuste con peso → switch-card · s
|
|
|
60
60
|
|
|
61
61
|
**Usos de hoy que rompen las reglas:**
|
|
62
62
|
|
|
63
|
-
- **2 en `medium`:** `pages/products/products.html:
|
|
63
|
+
- **2 en `medium`:** `pages/products/products.html:301` («Horario propio
|
|
64
64
|
para esta categoría») y `pages/public/privacidad/privacidad.html:132` («Permitir analítica de uso»).
|
|
65
65
|
- **19 `sui-switch` con texto a mano + 1 nativo** que deberían ser este componente: el detalle
|
|
66
|
-
está en el README de `sui-switch`. Ejemplos: `pages/discounts/discounts.html:
|
|
66
|
+
está en el README de `sui-switch`. Ejemplos: `pages/discounts/discounts.html:207`,
|
|
67
67
|
`pages/drivers/drivers.html:58`, `components/settings-panel/settings-panel.html:97`.
|
|
68
68
|
|
|
69
69
|
## Tamaño en mobile y en web
|
|
70
70
|
|
|
71
|
-
| uso | mobile | web |
|
|
72
|
-
|
|
73
|
-
| fila de ajustes | `
|
|
74
|
-
| ajuste que es la acción principal de la pantalla («Cerrar por hoy») | `
|
|
71
|
+
| uso | mobile | web | fuente |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| fila de ajustes | `2xlarge` (fila de 44 como mínimo, switch 48 × 28) | `large` (40 × 24) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
|
|
74
|
+
| ajuste que es la acción principal de la pantalla («Cerrar por hoy») | `2xlarge` | `xlarge` | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
|
|
75
75
|
|
|
76
76
|
```html
|
|
77
|
-
<sui-switch-label [size]="bp.
|
|
77
|
+
<sui-switch-label [size]="bp.isMobile() ? '2xlarge' : 'large'" … />
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
| size | switch | label | descripción | alto de la fila sin descripción |
|
|
81
|
+
|---|---|---|---|---|
|
|
82
|
+
| `medium` (default, Figma) | 32 × 20 | 14/20 | 12/16 | 20 |
|
|
83
|
+
| `large` | 40 × 24 | 16/24 | 12/16 | 24 |
|
|
84
|
+
| `xlarge` | 48 × 28 | 16/24 | 12/16 | 28 |
|
|
85
|
+
| `2xlarge` | 48 × 28 | 16/24 | 12/16 | **44** (`min-height`) |
|
|
86
|
+
|
|
87
|
+
El bloque entero se toca, así que con descripción la fila pasa los 44 px sola. Sin descripción
|
|
88
|
+
`xlarge` mide 28: en el teléfono va `2xlarge` (canon (dueño, 04-10-2026): piso táctil 44 en el teléfono), que es la misma fila con
|
|
89
|
+
`min-height: 44px` y todo centrado en vertical. `2xlarge` no es un size del switch: el switch
|
|
90
|
+
interno se queda en `xlarge`.
|
|
91
|
+
|
|
92
|
+
En large y xlarge el texto sube a 16 px (regla del 03-10-2026): el label va en 16/24; sublabel y
|
|
93
|
+
descripción se quedan en 12.
|
|
82
94
|
|
|
83
95
|
## «No usar»: por qué no hoy y cuándo sí
|
|
84
96
|
|
|
@@ -98,7 +110,7 @@ dale a la fila un alto mínimo de 44 px.
|
|
|
98
110
|
| `label` | `string` | `''` |
|
|
99
111
|
| `sublabel` | `string \| null` | `null` |
|
|
100
112
|
| `description` | `string \| null` | `null` |
|
|
101
|
-
| `size` | `'medium' \| 'large' \| 'xlarge'` | `'medium'` |
|
|
113
|
+
| `size` | `'medium' \| 'large' \| 'xlarge' \| '2xlarge'` | `'medium'` |
|
|
102
114
|
| `badge` | `SuiBadgeConfig \| string \| null` | `null` |
|
|
103
115
|
| `link` | `SuiLinkConfig \| string \| null` | `null` |
|
|
104
116
|
| `flip` | `boolean` | `false` |
|
|
@@ -124,6 +136,8 @@ Implementa `ControlValueAccessor` (`[(ngModel)]`, `formControlName`).
|
|
|
124
136
|
- Deshabilitado baja todo el bloque a 0.5 de opacidad **además** del gris propio del switch.
|
|
125
137
|
- El badge con string sale naranja; en `sui-switch-card` el default es azul.
|
|
126
138
|
- `flip` usa CSS `order`: el orden de lectura no cambia.
|
|
139
|
+
- El switch de adentro es el tab stop y toma su nombre del `label` y su descripción de la
|
|
140
|
+
`description` (`aria-labelledby` / `aria-describedby`) (revisión 04-10-2026).
|
|
127
141
|
|
|
128
142
|
## Ejemplo
|
|
129
143
|
|
|
@@ -13,8 +13,9 @@ Story: [Molecules/Tabs/Tab Chips](https://sui-design-system.web.app/?path=/docs/
|
|
|
13
13
|
|
|
14
14
|
**Úsalo** para:
|
|
15
15
|
|
|
16
|
-
- **Filtrar una lista** por estado, período, rol o zona
|
|
17
|
-
«
|
|
16
|
+
- **Filtrar una lista** por estado, período, rol o zona con **5 o más opciones**, o con opciones que
|
|
17
|
+
no caben y se deslizan: «Todos · Pendientes · En camino · Entregados · Cancelados», los meses de la
|
|
18
|
+
central.
|
|
18
19
|
- **Saltar entre categorías** de un catálogo que viene de la base («Hamburguesas · Pizzas ·
|
|
19
20
|
Bebidas»), con `sticky` en la carta del local.
|
|
20
21
|
|
|
@@ -22,35 +23,38 @@ Sirve cuando las opciones son muchas, cambian según los datos o no caben y tien
|
|
|
22
23
|
|
|
23
24
|
**No lo uses** para:
|
|
24
25
|
|
|
25
|
-
- **2 a 4 modos de la
|
|
26
|
+
- **2 a 4 opciones excluyentes**, sean modos de la vista (por semana / día vs día) o un período o
|
|
27
|
+
filtro fijo («Hoy · 7 días · 30 días»): `sui-segmented-control`. **Período o filtro con 2 a 4 opciones excluyentes → `sui-segmented-control`; con 5 o más, o si no caben y tienen que deslizarse → `sui-tab-chips`** (canon, dueño 04-10-2026).
|
|
26
28
|
- **Secciones de contenido distinto** (Ventas · Productos · Repartidores): `sui-tab-menu-horizontal`.
|
|
27
29
|
- **Elegir un valor que se guarda** con un botón (radio de visibilidad, motivo de rechazo,
|
|
28
|
-
sumar o descontar): `sui-radio-card
|
|
29
|
-
|
|
30
|
+
sumar o descontar): `sui-radio-card`. (`sui-segmented-control` no sirve para esto: su README lo
|
|
31
|
+
deja para opciones que se aplican en el momento.) El tab-chips **siempre tiene uno elegido** y no
|
|
32
|
+
puede quedar vacío (ver Trampas).
|
|
30
33
|
- Un chip que la persona quita: `sui-tag`.
|
|
31
34
|
|
|
32
|
-
Regla corta (la misma del README de `sui-segmented-control
|
|
33
|
-
|
|
35
|
+
Regla corta (canon, dueño 04-10-2026; la misma del README de `sui-segmented-control`): **2-4
|
|
36
|
+
opciones excluyentes (modo, período o filtro) → segmented · 5+ o que deslizan → tab-chips ·
|
|
37
|
+
secciones → tab menu.**
|
|
34
38
|
|
|
35
39
|
## Qué variante usar
|
|
36
40
|
|
|
37
41
|
> **La guía del DS no tiene este componente**: es una extensión de SUI (la «cat nav» de las apps de
|
|
38
42
|
> delivery). Todo lo que sigue es propuesta salvo lo marcado como canon.
|
|
39
43
|
>
|
|
40
|
-
> Uso medido el
|
|
41
|
-
> `mockup-*`, `dx/*`, `
|
|
42
|
-
> **
|
|
43
|
-
>
|
|
44
|
-
>
|
|
44
|
+
> Uso medido el 04-10-2026 en `master-pedidos/src/app` (sin `master-preview`, `master-prototipos`,
|
|
45
|
+
> `mockup-sheets-*`, `dx/*`, `master-rutina`, `master-medico`, `dev-index`):
|
|
46
|
+
> **42 usos en 29 archivos `.html`** (incluye `master-ejercicios`). `[sticky]="true"`: 2 (la carta
|
|
47
|
+
> del local y `master-ejercicios`). `count`: 5 listas (cifra del 03-10). `[(value)]`: 2; el resto
|
|
48
|
+
> `[value]` + `(valueChange)`. `autoScroll`: 0. `size`: 20, todos `bp.isMobile() ? 'large' : 'medium'`.
|
|
45
49
|
|
|
46
50
|
### Para qué se usa (el contenido de los chips)
|
|
47
51
|
|
|
48
52
|
| caso | cuándo | ejemplo real de la app | fuente |
|
|
49
53
|
|---|---|---|---|
|
|
50
54
|
| filtro de estado | La lista es la misma; los chips la recortan. «Todos» va primero y es el elegido por defecto. | `pages/envios/envios.html:98` («Todos · Activos · Entregados · Cancelados») · `pages/orders/orders.html:64` | propuesta, falta aprobación |
|
|
51
|
-
| filtro de período | Rango de fechas de un reporte o gráfico.
|
|
55
|
+
| filtro de período | Rango de fechas de un reporte o gráfico **con 5 o más opciones** (los meses). Con 2 a 4 («Hoy · 7 días · 30 días») va `sui-segmented-control`. | `pages/central/central-gastos/central-gastos.html:10` (meses) | canon (dueño, 04-10-2026) |
|
|
52
56
|
| categorías del catálogo | Saltar a una categoría de la carta; con `sticky` y `autoScroll`. | `pages/customer/restaurant-menu/restaurant-menu.html:226` | propuesta, falta aprobación |
|
|
53
|
-
| sugerencias rápidas | **No.** Un motivo frecuente que completa un texto no es una selección: el chip elige el primero solo. Si se usa, el primer chip es el neutro («Otro motivo») y el texto lleva su propio signal. | `pages/super-admin/master-orders/master-orders.html:
|
|
57
|
+
| sugerencias rápidas | **No.** Un motivo frecuente que completa un texto no es una selección: el chip elige el primero solo. Si se usa, el primer chip es el neutro («Otro motivo») y el texto lleva su propio signal. | `pages/super-admin/master-orders/master-orders.html:900` (bien resuelto) | propuesta, falta aprobación |
|
|
54
58
|
|
|
55
59
|
### `sticky`
|
|
56
60
|
|
|
@@ -77,47 +81,54 @@ vista → segmented · secciones → tab menu · filtros o categorías → tab-c
|
|
|
77
81
|
|
|
78
82
|
**Usos de hoy que rompen las reglas:**
|
|
79
83
|
|
|
80
|
-
- **
|
|
81
|
-
del super admin
|
|
82
|
-
|
|
83
|
-
«
|
|
84
|
-
|
|
85
|
-
`:924` y `:1002`. Es el mismo bug que se arregló en `master-orders` el 01-09-2026 (signal propio
|
|
86
|
-
para los chips y «Otro motivo» primero).
|
|
84
|
+
- **Resuelto el 03-10-2026: el motivo escrito a mano rebotaba al primer chip.** En los modales de
|
|
85
|
+
rechazo del super admin (`pages/super-admin/master-drivers/master-drivers.html:657`, `:933` y
|
|
86
|
+
`:1012`) los chips y el textarea compartían el signal. Ahora los chips llevan el suyo
|
|
87
|
+
(`master-drivers/motivo-con-chips.ts`, «Otro motivo» primero), igual que `master-orders` desde el
|
|
88
|
+
01-09-2026.
|
|
87
89
|
- **4 son secciones de contenido distinto** (→ `sui-tab-menu-horizontal` en web; en mobile, a
|
|
88
90
|
discutir porque el tab menu no se desliza, ver su README): `pages/products/products.html:6`
|
|
89
91
|
(«Categorías · Productos · Secciones reutilizables»), `pages/promociones/promociones.html:7`
|
|
90
92
|
(«Carrusel pagado · Push notifications»), `pages/super-admin/master-drivers/master-drivers.html:16`,
|
|
91
|
-
`pages/reports/reports.html:
|
|
93
|
+
`pages/reports/reports.html:99` («Ventas · Productos · Repartidores · Clientes»).
|
|
92
94
|
- **2 son modos de la misma vista** (→ `sui-segmented-control`):
|
|
93
|
-
`pages/super-admin/master-semanas/master-semanas.html:
|
|
95
|
+
`pages/super-admin/master-semanas/master-semanas.html:75` (3 métricas del mismo gráfico) y `:80`
|
|
94
96
|
(«Por semana · Día vs día»).
|
|
95
|
-
- **4 eligen un valor de un formulario** (→ `sui-radio-card
|
|
96
|
-
|
|
97
|
-
`
|
|
98
|
-
`pages/
|
|
99
|
-
|
|
97
|
+
- **4 eligen un valor de un formulario** (→ `sui-radio-card`; `sui-segmented-control` solo si se
|
|
98
|
+
aplica en el momento, sin botón «Guardar»):
|
|
99
|
+
`components/option-sections-manager/option-sections-manager.html:177` (a qué se aplica),
|
|
100
|
+
`pages/super-admin/master-drivers/master-drivers.html:99` («Sumar · Descontar»),
|
|
101
|
+
`pages/mi-negocio/mi-negocio.html:952` (radio de visibilidad) y `:988` (tiempo para confirmar).
|
|
102
|
+
A discutir: `pages/customer/checkout/checkout.html:460` (día del pedido programado), que filtra
|
|
100
103
|
las franjas de abajo y se parece más a un filtro.
|
|
101
|
-
- **1 con el número dentro del texto:** `pages/notifications/notifications.ts:
|
|
104
|
+
- **1 con el número dentro del texto:** `pages/notifications/notifications.ts:194`
|
|
102
105
|
(`No leídas (3)` → `count: 3`).
|
|
103
|
-
- **
|
|
104
|
-
|
|
106
|
+
- **22 sin tamaño por plataforma.** Los 20 que ya lo tienen (`bp.isMobile() ? 'large' : 'medium'`)
|
|
107
|
+
entraron el 03-10-2026; los 22 que faltan son casi todos del super admin y de la central.
|
|
105
108
|
|
|
106
109
|
## Tamaño en mobile y en web
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
> publique, todos miden lo de `medium`.
|
|
111
|
+
`size` está publicado desde la 0.20.0; la app usa la 0.22.0.
|
|
110
112
|
|
|
111
|
-
Alto del chip: `small` 32 px · `medium` 36 px (el de siempre, default
|
|
112
|
-
|
|
113
|
+
Alto del chip: `small` 32 px (`height: 32px`) · `medium` 36 px (el de siempre, default; sin alto
|
|
114
|
+
fijo: 8 + 8 de padding + `line-height: normal` + 2 de borde, 36 medido en Storybook con Satoshi) ·
|
|
115
|
+
`large` 40 px (`height: 40px`, con `border-box`) · `xlarge` 44 px (`height: 44px`, padding lateral 18).
|
|
116
|
+
`small` y `medium` con texto de 14 px; cambia el alto y el aire lateral. El scroller suma 12 px arriba
|
|
117
|
+
y abajo, pero ese aire es del `<nav>`, no del botón: tocar ahí no elige el chip.
|
|
118
|
+
|
|
119
|
+
En large y xlarge el texto sube a 16 px (regla del 03-10-2026): el chip va en 16/24. El número del
|
|
120
|
+
contador mide 11 px en `small` y `medium`, y 12 px (pastilla de 20) en `large` y `xlarge`.
|
|
121
|
+
|
|
122
|
+
**Área táctil: 44 px en `xlarge`**, el piso del teléfono (canon del dueño, 04-10-2026: piso táctil
|
|
123
|
+
44 en el teléfono). `large` (40) queda para pantallas que ya lo usan y para tablet.
|
|
113
124
|
|
|
114
125
|
| uso | mobile | web | fuente |
|
|
115
126
|
|---|---|---|---|
|
|
116
|
-
| filtros y categorías | `
|
|
127
|
+
| filtros y categorías | `xlarge` (44) | `medium` | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono; tamaño por plataforma, 03-10-2026 |
|
|
117
128
|
| filtros densos en la cabecera de una tabla | — | `small` | propuesta, falta aprobación |
|
|
118
129
|
|
|
119
130
|
```html
|
|
120
|
-
<sui-tab-chips [chips]="filtros" [(value)]="filtro" [size]="bp.isMobile() ? '
|
|
131
|
+
<sui-tab-chips [chips]="filtros" [(value)]="filtro" [size]="bp.isMobile() ? 'xlarge' : 'medium'" />
|
|
121
132
|
```
|
|
122
133
|
|
|
123
134
|
## «No usar»: por qué no hoy y cuándo sí
|
|
@@ -138,7 +149,7 @@ con texto de 14 px; cambia el alto y el aire lateral. El scroller suma 12 px arr
|
|
|
138
149
|
| `chips` | `readonly (string \| SuiTabChipItem)[]` | — (requerido) |
|
|
139
150
|
| `value` · model, `[(value)]` | `string` | `''` |
|
|
140
151
|
| `sticky` | `boolean` | `false` |
|
|
141
|
-
| `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
|
|
152
|
+
| `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
|
|
142
153
|
| `autoScroll` | `boolean` | `true` |
|
|
143
154
|
|
|
144
155
|
Outputs: ninguno.
|
|
@@ -150,7 +161,7 @@ interface SuiTabChipItem {
|
|
|
150
161
|
label: string;
|
|
151
162
|
count?: number; // 0 o undefined no se dibuja
|
|
152
163
|
}
|
|
153
|
-
type SuiTabChipsSize = 'small' | 'medium' | 'large';
|
|
164
|
+
type SuiTabChipsSize = 'small' | 'medium' | 'large';
|
|
154
165
|
```
|
|
155
166
|
|
|
156
167
|
## Trampas
|
|
@@ -162,6 +173,12 @@ type SuiTabChipsSize = 'small' | 'medium' | 'large'; // repo del DS, no en 0.1
|
|
|
162
173
|
- **`value` es `string`.** Para números (km, minutos) hay que convertir en los dos sentidos
|
|
163
174
|
(`radioEfectivo() + ''` y `+$event`).
|
|
164
175
|
- **Lleva `role="tablist"`** aunque se use como filtro: el lector de pantalla lo anuncia como pestañas.
|
|
176
|
+
- **Teclado (04-10-2026):** un solo tab stop (el chip activo). ← → mueven el foco entre chips con
|
|
177
|
+
vuelta al inicio, Home/End van al primero/último, y Enter/Espacio elige. Las flechas **no**
|
|
178
|
+
seleccionan (activación manual): cada filtro recarga datos y no se dispara una carga por chip
|
|
179
|
+
recorrido. Al salir del grupo, el tab stop vuelve al chip activo.
|
|
180
|
+
- **La cuenta va en el nombre accesible** («Pendientes, 3»): el número visible sigue
|
|
181
|
+
`aria-hidden` para que no se lea dos veces.
|
|
165
182
|
- **No tiene padding lateral propio**: lo pone la pantalla. Sí trae 12 px arriba y abajo.
|
|
166
183
|
- **`sticky` cambia el host a `display: contents`**: las clases que le pongas al host dejan de
|
|
167
184
|
pintar caja (márgenes, anchos). Pon el estilo en un contenedor.
|
|
@@ -49,18 +49,19 @@ segmented · secciones → tab menu · filtros → tab-chips.**
|
|
|
49
49
|
|
|
50
50
|
### `size`
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| `small` · `large` · `xlarge` | No usar: no hacen nada. | según el código |
|
|
52
|
+
Los cuatro valores (`small`, `medium`, `large`, `xlarge`) cambian el alto de la franja y el texto
|
|
53
|
+
desde el 03-10-2026 (`sui-tab-menu-horizontal.scss`, bloque «Tamaños»). Cuándo usar cada uno: ver
|
|
54
|
+
«Tamaño en mobile y en web».
|
|
56
55
|
|
|
57
56
|
**Usos de hoy que rompen las reglas:**
|
|
58
57
|
|
|
59
58
|
- **0** en este componente. Los casos que deberían ser tab menu y hoy son `sui-tab-chips` están en el
|
|
60
59
|
README de `sui-tab-chips` (4: `pages/products/products.html:6`, `pages/promociones/promociones.html:7`,
|
|
61
|
-
`pages/super-admin/master-drivers/master-drivers.html:16`, `pages/reports/reports.html:
|
|
62
|
-
- **A
|
|
63
|
-
|
|
60
|
+
`pages/super-admin/master-drivers/master-drivers.html:16`, `pages/reports/reports.html:99`).
|
|
61
|
+
- **A discutir, 1 sin tamaño por plataforma:** el único uso
|
|
62
|
+
(`components/store-ratings-modal/store-ratings-modal.html:43`) es del modal del local, que el
|
|
63
|
+
cliente abre en el teléfono, y no pasa `size`: mide 48 px tocables (`medium`). Llega a 44, pero la
|
|
64
|
+
propuesta de abajo pide `large` en mobile.
|
|
64
65
|
|
|
65
66
|
## Tamaño en mobile y en web
|
|
66
67
|
|
|
@@ -69,10 +70,13 @@ Cada pestaña ocupa **todo el alto de la franja**, así que lo tocable es la fra
|
|
|
69
70
|
|
|
70
71
|
| size | franja tocable (+ 2 de bordes) | texto | ícono | gap | fuente |
|
|
71
72
|
|---|---|---|---|---|---|
|
|
72
|
-
| `small` | 40 | `label-sm` 14/20 | 20 | 20 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
73
|
-
| `medium` (default) | 48 | `label-sm` 14/20 | 20 | 24 | Figma |
|
|
74
|
-
| `large` | 52 | `label-md` 16/24 | 20 | 24 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
75
|
-
| `xlarge` | 56 | `label-md` 16/24 | 24 | 28 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
73
|
+
| `small` | 40 (10 + 20 + 10) | `label-sm` 14/20 | 20 | 20 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
74
|
+
| `medium` (default) | 48 (14 + 20 + 14) | `label-sm` 14/20 | 20 | 24 | Figma |
|
|
75
|
+
| `large` | 52 (14 + 24 + 14) | `label-md` 16/24 | 20 | 24 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
76
|
+
| `xlarge` | 56 (16 + 24 + 16) | `label-md` 16/24 | 24 | 28 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
77
|
+
|
|
78
|
+
El alto sale del `padding` vertical del botón más el `line-height` del texto. A lo ancho, lo tocable
|
|
79
|
+
es solo el texto: el `gap` entre pestañas no responde.
|
|
76
80
|
|
|
77
81
|
| uso | mobile | web | fuente |
|
|
78
82
|
|---|---|---|---|
|
|
@@ -128,6 +132,10 @@ interface SuiTabMenuHorizontalItem<T = string> {
|
|
|
128
132
|
que Figma pone en el contenedor ahora va dentro de cada pestaña. Si algo de afuera le pone
|
|
129
133
|
padding al `.sui-tab-menu-horizontal__track`, la franja crece al doble.
|
|
130
134
|
- **Emite dos veces**: `tabChange` y `activeChange`. Con `[(active)]` no hace falta `(tabChange)`.
|
|
135
|
+
- **Teclado (04-10-2026):** un solo tab stop (la pestaña activa). ← → mueven el foco **y activan**
|
|
136
|
+
(patrón de tablist con activación automática), con vuelta al inicio y saltando las deshabilitadas;
|
|
137
|
+
Home/End a los extremos. Cada flecha emite `tabChange`. No hay `aria-controls`: el `tabpanel` lo
|
|
138
|
+
arma quien lo usa.
|
|
131
139
|
- **Trae bordes arriba y abajo** (`stroke-soft-200`) y fondo blanco: no lo metas en una card que ya
|
|
132
140
|
tiene borde, o quedan dos líneas.
|
|
133
141
|
- El ícono de la pestaña activa es `strong-950`, no naranja; en el tab menu vertical es naranja.
|
|
@@ -23,8 +23,8 @@ de pago · Repartidores»), el perfil del super admin.
|
|
|
23
23
|
- 2 a 4 secciones arriba del contenido: `sui-tab-menu-horizontal`.
|
|
24
24
|
- Filtros de una lista: `sui-tab-chips`.
|
|
25
25
|
|
|
26
|
-
Regla corta: **secciones de una página de ajustes en web → tab menu
|
|
27
|
-
filas que abren pantalla.**
|
|
26
|
+
Regla corta (propuesta, falta aprobación): **secciones de una página de ajustes en web → tab menu
|
|
27
|
+
vertical · en mobile → lista de filas que abren pantalla.**
|
|
28
28
|
|
|
29
29
|
## Qué variante usar
|
|
30
30
|
|
|
@@ -63,7 +63,8 @@ Usos de hoy que rompen las reglas: **0** (no se usa).
|
|
|
63
63
|
|
|
64
64
|
## Tamaño en mobile y en web
|
|
65
65
|
|
|
66
|
-
Ítem de **36 px** (8 + 20 + 8
|
|
66
|
+
Ítem de **36 px** (padding 8 + `line-height` 20 + padding 8; el ícono de 20 entra en la línea).
|
|
67
|
+
**No tiene `size`** y no tiene tamaño para mobile: no llega a los 44 px del dedo.
|
|
67
68
|
|
|
68
69
|
| uso | mobile | web | fuente |
|
|
69
70
|
|---|---|---|---|
|
|
@@ -114,12 +115,16 @@ type SuiTabMenuVerticalStyle = 'card' | 'list';
|
|
|
114
115
|
|
|
115
116
|
## Trampas
|
|
116
117
|
|
|
117
|
-
- **El estilo se llama `menuStyle`**, no `style` ni `variant` (ni `verticalStyle`,
|
|
118
|
-
|
|
118
|
+
- **El estilo se llama `menuStyle`**, no `style` ni `variant` (ni `verticalStyle`, el input de
|
|
119
|
+
`sui-tabs variant="vertical"`, el componente que existió hasta la v0.2.x y ya no está en el DS).
|
|
119
120
|
- **Sin `active` no se marca ningún ítem.** Pásale un valor inicial.
|
|
120
121
|
- **Ocupa el ancho del padre**: dale un ancho fijo a la columna (240-280 px).
|
|
121
122
|
- **El ícono activo es naranja** (`primary-base`); en el tab menu horizontal es negro. Es a propósito.
|
|
122
123
|
- **Emite dos veces**: `tabChange` y `activeChange`.
|
|
124
|
+
- **Teclado (04-10-2026):** `role="tablist"` con `aria-orientation="vertical"` y un solo tab
|
|
125
|
+
stop. ↑ ↓ mueven el foco **y activan**, con vuelta al inicio y saltando los deshabilitados;
|
|
126
|
+
Home/End a los extremos. Con `dividerLabel`, ese texto es el nombre del grupo
|
|
127
|
+
(`aria-labelledby`).
|
|
123
128
|
- `role="tablist"`: si cada ítem navega a una ruta, el lector de pantalla lo anuncia mal; para
|
|
124
129
|
navegación entre rutas, `sui-sidebar`.
|
|
125
130
|
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-table
|
|
3
|
+
selector: sui-table
|
|
4
|
+
resumen: Tabla de datos — una fila por registro, una columna por dato — para comparar y recorrer listas en web
|
|
5
|
+
alternativas: [tarjetas en grilla con sui-card (la misma lista cuando no entran las columnas), sui-empty-state (no hay nada que listar todavía), sui-pagination (paginar por número de página, debajo de la tabla), sui-activity-feed (historial de quién hizo qué)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-table
|
|
9
|
+
|
|
10
|
+
Story: [Organisms/Table](https://sui-design-system.web.app/?path=/docs/organisms-table--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** cuando la persona tiene que **comparar varios registros por las mismas columnas**:
|
|
15
|
+
pedidos, repartidores, gastos, recargas. La tabla sirve si leer en vertical una columna
|
|
16
|
+
(«¿cuál es el monto más alto?», «¿quién no tiene repartidor?») es parte de la decisión.
|
|
17
|
+
|
|
18
|
+
**No lo uses** para:
|
|
19
|
+
|
|
20
|
+
- Una lista donde cada registro se lee solo (sin comparar con el de al lado): tarjetas.
|
|
21
|
+
- Pantallas del cliente o del repartidor en el teléfono: ahí la lista va en tarjetas o
|
|
22
|
+
filas de una columna. La tabla es de las pantallas de gestión (empresa, super admin, central).
|
|
23
|
+
- Un historial de acciones con autor y hora: `sui-activity-feed`.
|
|
24
|
+
- «Todavía no hay nada» a página completa: `sui-empty-state`. La tabla tiene su propio
|
|
25
|
+
vacío (`emptyMessage`), que es otro registro (ver abajo).
|
|
26
|
+
|
|
27
|
+
Regla corta: **comparar por columnas → tabla · leer de a uno → tarjetas · historial → activity feed.**
|
|
28
|
+
|
|
29
|
+
## Qué variante usar
|
|
30
|
+
|
|
31
|
+
> **La guía del DS casi no dice cuándo ni cómo usar la tabla.** Su página la define como «una
|
|
32
|
+
> estructura de dos dimensiones donde cada fila es un ítem y cada columna un dato del ítem»,
|
|
33
|
+
> muestra un solo ejemplo (un directorio de personas **con selección por checkbox**), le pone
|
|
34
|
+
> `overflow-x-auto` al contenedor y deriva el orden, la selección y la paginación a una
|
|
35
|
+
> librería externa. No trae do/don't, tamaños ni comportamiento en mobile. Casi todo lo de
|
|
36
|
+
> abajo es **práctica de la app** o **propuesta, falta aprobación**; lo marcado «canon» sale de
|
|
37
|
+
> `master-pedidos/CLAUDE.md` o de `docs/CANON-SUI.md`.
|
|
38
|
+
>
|
|
39
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: **9 tablas** en 7 pantallas, sin contar
|
|
40
|
+
> prototipos ni vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`, `dx/*`,
|
|
41
|
+
> `master-rutina`, `master-medico`, `dev-index`). `sortable`, `selectable` y `striped`: 0 usos.
|
|
42
|
+
> `sticky`: 1, en una vitrina.
|
|
43
|
+
|
|
44
|
+
### Lo que sí dice la guía del DS
|
|
45
|
+
|
|
46
|
+
- **Qué es**: filas = ítems, columnas = datos del ítem.
|
|
47
|
+
- **Partes**: cabecera, filas con hover, celdas con esquinas redondeadas y un **divisor entre
|
|
48
|
+
filas**. SUI lo replica (header gris `bg-weak-50`, filas con radio 12 y divisor de 1 px).
|
|
49
|
+
- **Ancho**: el contenedor scrollea en horizontal (`overflow-x-auto`). En SUI eso pasa solo
|
|
50
|
+
**hasta 767 px** o con una columna `sticky` (ver Trampas).
|
|
51
|
+
- **Selección**: su único ejemplo trae checkbox por fila. En SUI es `selectable`.
|
|
52
|
+
|
|
53
|
+
### Las columnas (`SuiTableColumn`)
|
|
54
|
+
|
|
55
|
+
| prop de columna | cuándo | ejemplo real de la app | fuente |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| `priority: 'leading'` + `descriptionKey` | La **primera** columna: el dato que identifica la fila arriba (14/500) y un dato de apoyo debajo (12/400). Se usa en vez de una plantilla propia para la columna principal. | `pages/orders/orders.ts:278` (pedido + «hace 12 min») · `pages/super-admin/master-orders/master-orders.ts:390` | práctica de la app (7 de 9 tablas) |
|
|
58
|
+
| `priority: 'passive'` | Datos de contexto que no deciden nada: fecha, número de comprobante. Se leen en gris (`text-sub-600`). | `pages/super-admin/master-overview/master-overview.ts:192` | propuesta, falta aprobación |
|
|
59
|
+
| `priority: 'none'` | Columna de acciones (íconos) sin texto propio. Con `label: ''` y `width` fijo. | `pages/super-admin/master-gastos/master-gastos.ts:143` | práctica de la app |
|
|
60
|
+
| `align: 'right'` | Montos. Así se comparan en vertical. | `pages/central/central-gastos/central-gastos.ts:82` | propuesta, falta aprobación |
|
|
61
|
+
| `width` | Columnas de largo fijo: monto, estado, fecha, acciones. | `central-gastos.ts:82-83` | práctica de la app |
|
|
62
|
+
| `minWidth` | Columnas de texto que crecen (nombre, concepto): el piso para que no se aplasten. | `master-orders.ts:392` | práctica de la app |
|
|
63
|
+
| `maxWidth` + `truncate` | Nombres que pueden ser muy largos: corta con «…» y el valor completo sale en tooltip. | `master-overview.ts:193` | práctica de la app |
|
|
64
|
+
|
|
65
|
+
**Una ID nunca es el título de la fila** (`CLAUDE.md`, «Pasada de UX/UI»): la columna `leading`
|
|
66
|
+
lleva el nombre o el número legible del pedido, no el uid.
|
|
67
|
+
|
|
68
|
+
### Plantillas por columna (`suiTableCell`)
|
|
69
|
+
|
|
70
|
+
Si una celda necesita algo más que texto, se proyecta un `<ng-template suiTableCell="<key>" let-row>`.
|
|
71
|
+
Dentro va un componente SUI, no HTML a mano:
|
|
72
|
+
|
|
73
|
+
| contenido | componente | fuente |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| estado o categoría | `<sui-badge variant="lighter" size="small">` | canon (CANON-SUI §0: «Chip de estado») |
|
|
76
|
+
| acciones de la fila | `<sui-button variant="ghost" color="neutral" size="2xsmall" [onlyIcon]="true">` | canon (README de `sui-button`: tabla densa = `2xsmall`) |
|
|
77
|
+
| prender/apagar | `<sui-switch>` | propuesta, falta aprobación |
|
|
78
|
+
| calificación | `<sui-rating>` de solo lectura | propuesta, falta aprobación |
|
|
79
|
+
|
|
80
|
+
Si la columna tiene plantilla, `descriptionKey` y `truncate` **no se aplican**: solo funcionan en
|
|
81
|
+
el render de texto plano. Por eso `orders.html:94` deja la columna del pedido sin plantilla.
|
|
82
|
+
|
|
83
|
+
### Cargar las filas: cuenta + página por cursor
|
|
84
|
+
|
|
85
|
+
**Canon** (`master-pedidos/CLAUDE.md`, «Performance — Firestore reads»): una pantalla con tabla
|
|
86
|
+
**no baja la colección entera** para mostrar 30 filas. Los totales salen de `getCount`, las filas
|
|
87
|
+
de `getCollectionPage` con cursor, y debajo de la tabla va un «Cargar más»
|
|
88
|
+
(`sui-button variant="stroke" color="neutral"`). Referencia: `pages/orders/orders.ts:716`
|
|
89
|
+
(`loadMore`) y `orders.html:132`.
|
|
90
|
+
|
|
91
|
+
- El orden de la tabla lo fija la consulta (`orderBy`). **No uses `sortable`** sobre una lista
|
|
92
|
+
paginada: ordenaría solo lo cargado y mentiría sobre el resto.
|
|
93
|
+
- `sui-pagination` (números de página) no calza con cursor: Firestore no salta a «la página 7».
|
|
94
|
+
|
|
95
|
+
### Vacío y carga
|
|
96
|
+
|
|
97
|
+
- `loading` pinta 5 filas esqueleto con las columnas reales. Úsalo mientras llega la primera
|
|
98
|
+
página. Canon (memoria del proyecto: skeleton obligatorio en pantalla nueva).
|
|
99
|
+
- `emptyMessage` es una línea con un ícono de bandeja, sin ilustración ni botón. **Canon**
|
|
100
|
+
(CANON-SUI §5.6): no se mezcla con `sui-empty-state`. Escríbelo como en la app, una frase con
|
|
101
|
+
punto: «Nadie recargó en este período.», «Sin gastos registrados todavía.». El default
|
|
102
|
+
`'No hay datos'` no dice nada: siempre se pasa uno propio (los 9 usos lo hacen).
|
|
103
|
+
|
|
104
|
+
## Tamaño en mobile y en web
|
|
105
|
+
|
|
106
|
+
`size` cambia **el alto mínimo de la fila**, no la letra (14 px en todos):
|
|
107
|
+
|
|
108
|
+
| size | alto | nombre en el Figma | fuente |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `small` | 48 | Large | Figma |
|
|
111
|
+
| `medium` (default) | 64 | X-Large | Figma |
|
|
112
|
+
| `large` | 80 | — | extensión SUI |
|
|
113
|
+
| `xlarge` | 96 | — | extensión SUI |
|
|
114
|
+
|
|
115
|
+
Uso de hoy: 2 `medium` explícitos (`orders`, `drivers`), 1 `small` (`master-overview`, una tabla
|
|
116
|
+
secundaria dentro de un tablero) y 6 sin `size` (o sea `medium`).
|
|
117
|
+
|
|
118
|
+
| uso | mobile | web | fuente |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| tabla principal de una pantalla | `medium` | `medium` | práctica de la app |
|
|
121
|
+
| tabla secundaria dentro de un tablero | `small` | `small` | práctica de la app (1 uso) |
|
|
122
|
+
| filas con dos líneas y un badge | `medium` | `medium` | propuesta, falta aprobación |
|
|
123
|
+
|
|
124
|
+
El patrón `[size]="bp.isMobile() ? 'large' : 'medium'"` de los botones **no aplica aquí**: la fila
|
|
125
|
+
ya mide 64 y el toque es sobre toda la fila. `large`/`xlarge` no tienen uso hoy.
|
|
126
|
+
|
|
127
|
+
**Qué pasa en mobile (≤ 767 px):** la tabla scrollea en horizontal dentro de sí misma; la
|
|
128
|
+
cabecera y el cuerpo miden lo mismo y la barra de scroll se oculta. En la app conviven dos
|
|
129
|
+
salidas, y las dos son práctica, no regla:
|
|
130
|
+
|
|
131
|
+
| salida | dónde | cuándo elegirla (propuesta) |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| la misma tabla, con scroll lateral | `orders`, `master-orders`, `central-gastos`, `central-ingresos` | 3-4 columnas, y la primera (`leading`) ya dice casi todo |
|
|
134
|
+
| tarjetas en grilla por debajo de 1350 px | `drivers` (`drivers.ts:282`), `master-gastos` | 6+ columnas: con el sidebar abierto no entran ni en laptop ni en iPad |
|
|
135
|
+
|
|
136
|
+
**Android (canon del componente, no se repite en la página):** un contenedor con
|
|
137
|
+
`overflow-x: auto` se queda con el gesto vertical y la página deja de scrollear sobre la tabla.
|
|
138
|
+
Ningún `touch-action` solo lo arregla (probado en device). `sui-table` lo resuelve **por dentro y
|
|
139
|
+
solo en Android**: pone `touch-action: pan-x` por JS para que el scroll horizontal sea el nativo,
|
|
140
|
+
y mueve él mismo la página con el gesto vertical (con inercia). En iOS no hace nada: WebKit delega
|
|
141
|
+
el vertical solo. Por eso la página **no** agrega `touch-action` ni un wrapper con `overflow-x`.
|
|
142
|
+
|
|
143
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
144
|
+
|
|
145
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `sortable` | toda tabla de la app es una lista paginada por cursor: el orden lo da la consulta | una tabla chica que se carga entera (≤ 50 filas, un reporte del mes) |
|
|
148
|
+
| `selectable` | no hay acciones en lote | aprobar o rechazar varias recargas de una vez, exportar filas elegidas |
|
|
149
|
+
| `striped` | con divisor entre filas ya se lee la fila; las rayas suman ruido | tablas de muchas columnas numéricas (un reporte contable) |
|
|
150
|
+
| `sticky` | la columna fija tapó otra en 375 px (`central-gastos.ts:80`) | una tabla ancha en desktop donde la primera columna es la única referencia |
|
|
151
|
+
| `large` / `xlarge` | 64 ya alcanza al dedo | filas con avatar grande y tres líneas |
|
|
152
|
+
|
|
153
|
+
## API
|
|
154
|
+
|
|
155
|
+
<!-- api:inicio -->
|
|
156
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
157
|
+
|
|
158
|
+
### `sui-table`
|
|
159
|
+
|
|
160
|
+
| input | tipo | default |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| `columns` | `SuiTableColumn<T>[]` | — (requerido) |
|
|
163
|
+
| `rows` | `T[]` | — (requerido) |
|
|
164
|
+
| `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
|
|
165
|
+
| `loading` | `boolean` | `false` |
|
|
166
|
+
| `emptyMessage` | `string` | `'No hay datos'` |
|
|
167
|
+
| `striped` | `boolean` | `false` |
|
|
168
|
+
| `selectable` | `boolean` | `false` |
|
|
169
|
+
| `rowKey` | `keyof T \| ((row: T) => any)` | `undefined` |
|
|
170
|
+
| `selectedRows` · model, `[(selectedRows)]` | `Set<any>` | `new Set()` |
|
|
171
|
+
| `sortKey` · model, `[(sortKey)]` | `string \| null` | `null` |
|
|
172
|
+
| `sortDir` · model, `[(sortDir)]` | `'asc' \| 'desc' \| null` | `null` |
|
|
173
|
+
|
|
174
|
+
| output | payload |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `rowClicked` | `T` |
|
|
177
|
+
| `sortChanged` | `{ key: string; dir: 'asc' \| 'desc' \| null }` |
|
|
178
|
+
|
|
179
|
+
### `[suiTableCell]`
|
|
180
|
+
|
|
181
|
+
| input | tipo | default |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `suiTableCell` | `string` | — (requerido) |
|
|
184
|
+
|
|
185
|
+
Outputs: ninguno.
|
|
186
|
+
<!-- api:fin -->
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
interface SuiTableColumn<T = any> {
|
|
190
|
+
key: string; // campo de la fila; único
|
|
191
|
+
label: string; // '' para la columna de acciones
|
|
192
|
+
width?: string; // ancho fijo ('100px', '20%')
|
|
193
|
+
minWidth?: string; // piso (manda en el scroll de mobile)
|
|
194
|
+
maxWidth?: string;
|
|
195
|
+
align?: 'left' | 'center' | 'right';
|
|
196
|
+
sortable?: boolean;
|
|
197
|
+
disabled?: boolean; // cabecera apagada, sin orden
|
|
198
|
+
priority?: 'regular' | 'leading' | 'passive' | 'none';
|
|
199
|
+
descriptionKey?: string; // segunda línea (solo texto plano)
|
|
200
|
+
truncate?: boolean; // «…» + tooltip (solo texto plano)
|
|
201
|
+
misc?: SuiTableCellMisc; // documental: qué componente va en la plantilla
|
|
202
|
+
sticky?: boolean; // fija la columna y activa el scroll lateral en cualquier ancho
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`SuiTableCellDirective` se importa aparte (`<ng-template suiTableCell="key" let-row>`).
|
|
207
|
+
El orden cicla `asc → desc → sin orden` y emite `sortChanged` en cada paso; ordenar las filas es
|
|
208
|
+
trabajo de la página.
|
|
209
|
+
|
|
210
|
+
## Trampas
|
|
211
|
+
|
|
212
|
+
- **Por encima de 767 px la tabla recorta, no scrollea.** Sin una columna `sticky`, el contenedor
|
|
213
|
+
es `overflow: hidden` en desktop: lo que no entra **desaparece** a la derecha (monto, estado,
|
|
214
|
+
acciones). Las columnas tienen que entrar en el ancho real, que con el sidebar abierto es
|
|
215
|
+
~483 px en iPad y ~1015 px en una pantalla de 1351. Lo comentan tres pantallas:
|
|
216
|
+
`pages/drivers/drivers.html:210`, `pages/super-admin/master-gastos/master-gastos.html:38`,
|
|
217
|
+
`pages/central/central-gastos/central-gastos.ts:76`. El wrapper `drivers__table-wrap` es un
|
|
218
|
+
respaldo de eso; no se copia.
|
|
219
|
+
- `sticky` en **cualquier** columna activa el scroll lateral en todos los anchos (no solo en mobile)
|
|
220
|
+
y quita el recorte redondeado de las filas.
|
|
221
|
+
- `descriptionKey` y `truncate` **se ignoran** si la columna tiene plantilla `suiTableCell`.
|
|
222
|
+
- Sin `rowKey`, la fila se identifica por su índice: la selección se mezcla al reordenar o al cargar
|
|
223
|
+
más. Si usas `selectable` o la lista cambia en vivo, pasa `rowKey="id"`.
|
|
224
|
+
- `rowClicked` dispara en **toda** la fila. Un botón dentro de una plantilla necesita
|
|
225
|
+
`$event.stopPropagation()` o abre el detalle además de hacer lo suyo.
|
|
226
|
+
- `toggleAll` selecciona **lo cargado**, no la colección: con cursor, «todas» son las de la página.
|
|
227
|
+
- El hover de fila solo existe con mouse (`@media (hover: hover)`); en táctil no hay feedback de
|
|
228
|
+
toque: si la fila abre algo, que se note por el contenido (una pista «Toca un gasto para…», como
|
|
229
|
+
`central-gastos.html:46`).
|
|
230
|
+
- La fila esqueleto son siempre 5, sin importar el tamaño de página.
|
|
231
|
+
- No le pongas `touch-action` ni `overflow-x` desde la página: el componente ya maneja el gesto en
|
|
232
|
+
Android y lo romperías.
|
|
233
|
+
|
|
234
|
+
## Ejemplo
|
|
235
|
+
|
|
236
|
+
```html
|
|
237
|
+
<sui-card>
|
|
238
|
+
<sui-table
|
|
239
|
+
[columns]="columnas"
|
|
240
|
+
[rows]="filas()"
|
|
241
|
+
rowKey="id"
|
|
242
|
+
[loading]="cargando()"
|
|
243
|
+
emptyMessage="Sin pedidos en este estado."
|
|
244
|
+
(rowClicked)="abrirDetalle($event)">
|
|
245
|
+
<ng-template suiTableCell="estado" let-row>
|
|
246
|
+
<sui-badge [color]="row.color" variant="lighter" size="small">{{ row.estadoLabel }}</sui-badge>
|
|
247
|
+
</ng-template>
|
|
248
|
+
</sui-table>
|
|
249
|
+
|
|
250
|
+
@if (hayMas()) {
|
|
251
|
+
<sui-button variant="stroke" color="neutral" [size]="bp.isMobile() ? 'large' : 'small'"
|
|
252
|
+
[disabled]="cargandoMas()" (click)="cargarMas()">Cargar más</sui-button>
|
|
253
|
+
}
|
|
254
|
+
</sui-card>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
readonly columnas: SuiTableColumn[] = [
|
|
259
|
+
{ key: 'numero', label: 'Pedido', priority: 'leading', descriptionKey: 'desdeHace', minWidth: '130px' },
|
|
260
|
+
{ key: 'cliente', label: 'Cliente', minWidth: '160px', maxWidth: '220px', truncate: true },
|
|
261
|
+
{ key: 'total', label: 'Total', align: 'right', width: '100px' },
|
|
262
|
+
{ key: 'estado', label: 'Estado', width: '130px' },
|
|
263
|
+
];
|
|
264
|
+
```
|