@ajuarezso/sui-design-system 0.20.0 → 0.21.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 +51 -51
- package/docs/sui-alert/README.md +13 -0
- package/docs/sui-badge/README.md +17 -0
- package/docs/sui-banner/README.md +190 -0
- package/docs/sui-breadcrumb-item/README.md +96 -0
- package/docs/sui-breadcrumbs/README.md +122 -0
- package/docs/sui-button/README.md +17 -0
- package/docs/sui-card/README.md +168 -0
- package/docs/sui-chart-legend/README.md +140 -0
- package/docs/sui-chart-legend-dot/README.md +118 -0
- package/docs/sui-checkbox-card/README.md +150 -0
- package/docs/sui-compact-select/README.md +127 -0
- package/docs/sui-compact-select-for-input/README.md +117 -0
- package/docs/sui-content-card/README.md +147 -0
- package/docs/sui-content-label/README.md +148 -0
- package/docs/sui-counter-input/README.md +145 -0
- package/docs/sui-date-selector/README.md +98 -0
- package/docs/sui-datepicker/README.md +193 -0
- package/docs/sui-day-cell/README.md +118 -0
- package/docs/sui-day-label/README.md +81 -0
- package/docs/sui-drawer-footer/README.md +127 -0
- package/docs/sui-drawer-header/README.md +140 -0
- package/docs/sui-empty-state/README.md +145 -0
- package/docs/sui-file-upload/README.md +154 -0
- package/docs/sui-file-upload-card/README.md +129 -0
- package/docs/sui-image-upload/README.md +200 -0
- package/docs/sui-image-upload-profile/README.md +145 -0
- package/docs/sui-inline-input/README.md +104 -0
- package/docs/sui-inline-select/README.md +101 -0
- package/docs/sui-input/README.md +244 -0
- package/docs/sui-integration-switch/README.md +142 -0
- package/docs/sui-notification/README.md +179 -0
- package/docs/sui-notification-footer/README.md +98 -0
- package/docs/sui-notification-tab-menu/README.md +112 -0
- package/docs/sui-otp-input/README.md +116 -0
- package/docs/sui-pagination/README.md +146 -0
- package/docs/sui-password-strength/README.md +99 -0
- package/docs/sui-period-range/README.md +93 -0
- package/docs/sui-popover/README.md +178 -0
- package/docs/sui-product-card/README.md +173 -0
- package/docs/sui-radio-card/README.md +160 -0
- package/docs/sui-rating/README.md +7 -6
- package/docs/sui-rich-editor/README.md +114 -0
- package/docs/sui-select/README.md +180 -0
- package/docs/sui-stepper/README.md +166 -0
- package/docs/sui-store-card/README.md +147 -0
- package/docs/sui-switch-card/README.md +149 -0
- package/docs/sui-tab-chips/README.md +185 -0
- package/docs/sui-tab-menu-horizontal/README.md +142 -0
- package/docs/sui-tab-menu-vertical/README.md +136 -0
- package/docs/sui-tag-input/README.md +120 -0
- package/docs/sui-textarea/README.md +157 -0
- package/docs/sui-time-picker/README.md +237 -0
- package/docs/sui-toast/README.md +190 -0
- package/docs/sui-tooltip/README.md +201 -0
- package/fesm2022/ajuarezso-sui-design-system.mjs +273 -231
- package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ajuarezso-sui-design-system.d.ts +208 -52
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-day-cell
|
|
3
|
+
selector: sui-day-cell
|
|
4
|
+
resumen: Un día del calendario, con sus estados de elegido, rango, hoy, marcado y bloqueado
|
|
5
|
+
alternativas: [sui-datepicker (el calendario completo, que ya la trae), sui-tab-chips (pocos días para elegir, con nombre: hoy, mañana)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-day-cell
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Date & Time/Day Cell](https://sui-design-system.web.app/?path=/docs/molecules-date-time-day-cell--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** solo para **armar un calendario propio** que el `sui-datepicker` no cubre: una grilla
|
|
15
|
+
de la semana con los días de turno del repartidor, o un mes con los días que el local cerró.
|
|
16
|
+
|
|
17
|
+
**No lo uses** para:
|
|
18
|
+
|
|
19
|
+
- Un calendario normal: `sui-datepicker` ya arma la grilla, las filas y la banda del rango.
|
|
20
|
+
- Elegir entre pocos días: `sui-tab-chips` (la hoja del pedido programado ya lo hace así).
|
|
21
|
+
- Mostrar una fecha como texto: un `<span>` con la fecha formateada.
|
|
22
|
+
|
|
23
|
+
## Qué variante usar
|
|
24
|
+
|
|
25
|
+
> **La guía del DS no tiene página para este componente** (vive dentro del datepicker). Todo es
|
|
26
|
+
> **propuesta, falta aprobación**.
|
|
27
|
+
>
|
|
28
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usa por dentro
|
|
29
|
+
> `sui-datepicker`.
|
|
30
|
+
|
|
31
|
+
### `type` y `rangePosition`
|
|
32
|
+
|
|
33
|
+
| valor | cuándo | fuente |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `type="basic"` (default) | Calendario de una fecha. | propuesta |
|
|
36
|
+
| `type="range"` | Calendario de rango. Va con `rangePosition`. | propuesta |
|
|
37
|
+
| `rangePosition="start"` | Primer día del rango (fondo naranja, esquina izquierda). | propuesta |
|
|
38
|
+
| `rangePosition="end"` | Último día (fondo naranja, esquina derecha). | propuesta |
|
|
39
|
+
| `rangePosition="in"` | Días del medio (texto naranja, sin fondo propio: la banda la pinta la fila). | propuesta |
|
|
40
|
+
| `rangePosition=null` | Fuera del rango. | propuesta |
|
|
41
|
+
|
|
42
|
+
### Estados
|
|
43
|
+
|
|
44
|
+
| input | cuándo | fuente |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `selected` | El día elegido (fondo naranja). Uno solo en `basic`. | propuesta |
|
|
47
|
+
| `today` | Hoy: un punto debajo del número. Siempre, para que la persona se ubique. | propuesta |
|
|
48
|
+
| `marked` | El día tiene algo (pedidos, un turno). Si además es hoy, gana el punto de hoy. | propuesta |
|
|
49
|
+
| `disabled` | Fuera de `min`/`max` o no se puede elegir (local cerrado ese día). | propuesta |
|
|
50
|
+
| `outOfMonth` | Días del mes anterior o siguiente que completan la grilla: se ven apagados. | propuesta |
|
|
51
|
+
| `ariaLabel` | Siempre que el número solo no alcance: «Martes 7 de octubre, con pedidos». El default dice «Día 7». | propuesta |
|
|
52
|
+
|
|
53
|
+
Usos de hoy que rompen la regla: **0**.
|
|
54
|
+
|
|
55
|
+
## Tamaño en mobile y en web
|
|
56
|
+
|
|
57
|
+
**No tiene `size`.** Mide 40 × 40 fijo. En el `sui-datepicker` el paso entre celdas es de 44 px en
|
|
58
|
+
mobile (gap 4) y 48 en web (gap 8): llega justo a los 44.
|
|
59
|
+
|
|
60
|
+
| uso | mobile | web | fuente |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| celda de una grilla | 40 × 40 con gap 4 (paso 44) | 40 × 40 con gap 8 | medido |
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<!-- La grilla da el paso: gap 4 en mobile, 8 en web -->
|
|
66
|
+
<div class="semana" [style.gap.px]="bp.isMobile() ? 4 : 8">
|
|
67
|
+
@for (d of dias(); track d.fecha) {
|
|
68
|
+
<sui-day-cell [day]="d.numero" [today]="d.esHoy" [marked]="d.conTurno" (clicked)="elegir(d)" />
|
|
69
|
+
}
|
|
70
|
+
</div>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
74
|
+
|
|
75
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| todo el componente suelto (0 usos) | no hay calendarios propios | la semana de turnos del repartidor o el mes de cierres del local |
|
|
78
|
+
| `type="range"` suelto | el rango completo lo resuelve el datepicker, con la banda | ninguno fuera del datepicker |
|
|
79
|
+
|
|
80
|
+
## API
|
|
81
|
+
|
|
82
|
+
<!-- api:inicio -->
|
|
83
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
84
|
+
|
|
85
|
+
| input | tipo | default |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `day` | `number \| string` | — (requerido) |
|
|
88
|
+
| `type` | `'basic' \| 'range'` | `'basic'` |
|
|
89
|
+
| `rangePosition` | `'start' \| 'end' \| 'in' \| null` | `null` |
|
|
90
|
+
| `selected` | `boolean` | `false` |
|
|
91
|
+
| `marked` | `boolean` | `false` |
|
|
92
|
+
| `today` | `boolean` | `false` |
|
|
93
|
+
| `disabled` | `boolean` | `false` |
|
|
94
|
+
| `outOfMonth` | `boolean` | `false` |
|
|
95
|
+
| `ariaLabel` | `string \| null` | `null` |
|
|
96
|
+
|
|
97
|
+
| output | payload |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `clicked` | `MouseEvent` |
|
|
100
|
+
<!-- api:fin -->
|
|
101
|
+
|
|
102
|
+
## Trampas
|
|
103
|
+
|
|
104
|
+
- **`day` es el número del día, no una fecha.** Toda la lógica (qué día es, si es hoy) la hace
|
|
105
|
+
quien lo usa.
|
|
106
|
+
- **La banda del rango no la pinta la celda**: en `in` solo cambia el color del texto. La franja
|
|
107
|
+
continua la dibuja la fila en el datepicker; suelta, un rango se ve como números naranjas sueltos.
|
|
108
|
+
- `today` y `marked` juntos: se ve solo el punto de hoy.
|
|
109
|
+
- `outOfMonth` no la bloquea: se puede tocar igual. Para bloquearla, `disabled`.
|
|
110
|
+
- Ya trae el arreglo de iOS para el `:active` pegado.
|
|
111
|
+
|
|
112
|
+
## Ejemplo
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<sui-day-cell day="7" [today]="true" />
|
|
116
|
+
<sui-day-cell day="9" [selected]="true" />
|
|
117
|
+
<sui-day-cell day="12" [marked]="true" ariaLabel="Domingo 12 de octubre, con pedidos" />
|
|
118
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-day-label
|
|
3
|
+
selector: sui-day-label
|
|
4
|
+
resumen: La inicial del día de la semana arriba de cada columna del calendario
|
|
5
|
+
alternativas: [sui-datepicker (el calendario completo, que ya la trae), sui-button-group (elegir días de la semana: L M M J V S D)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-day-label
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Date & Time/Day Label](https://sui-design-system.web.app/?path=/docs/molecules-date-time-day-label--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** solo como **cabecera de columna** de un calendario armado a mano con `sui-day-cell`.
|
|
15
|
+
|
|
16
|
+
**No lo uses** para:
|
|
17
|
+
|
|
18
|
+
- Un calendario normal: `sui-datepicker` ya pone LU, MA, MI, JU, VI, SÁ, DO.
|
|
19
|
+
- **Elegir días de la semana** (el horario del local o los turnos del repartidor): eso se toca,
|
|
20
|
+
y esto es solo texto. Va `sui-button-group` `multi`.
|
|
21
|
+
- El nombre de un día en una lista («Lunes»): texto normal.
|
|
22
|
+
|
|
23
|
+
## Qué variante usar
|
|
24
|
+
|
|
25
|
+
> **La guía del DS no tiene página para este componente** (vive dentro del datepicker). Todo es
|
|
26
|
+
> **propuesta, falta aprobación**.
|
|
27
|
+
>
|
|
28
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usa por dentro
|
|
29
|
+
> `sui-datepicker`.
|
|
30
|
+
|
|
31
|
+
| input | valor | cuándo | fuente |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `label` | dos letras en mayúsculas | Lo normal, igual que el datepicker: `LU MA MI JU VI SÁ DO`. La semana arranca el lunes. | propuesta |
|
|
34
|
+
| `label` | una letra | No usar: «M» es martes y miércoles a la vez. | no usar |
|
|
35
|
+
| `label` | tres letras o más | No usar: «MIÉ» entra justo en 40 px, pero rompe el formato de dos letras del datepicker; «LUNES» ya no entra. | no usar |
|
|
36
|
+
|
|
37
|
+
Usos de hoy que rompen la regla: **0**.
|
|
38
|
+
|
|
39
|
+
## Tamaño en mobile y en web
|
|
40
|
+
|
|
41
|
+
**No tiene `size`.** Mide 40 × 40, igual que `sui-day-cell`, para que las columnas calcen. No se
|
|
42
|
+
toca: el tamaño solo importa para alinear.
|
|
43
|
+
|
|
44
|
+
| uso | mobile | web | fuente |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| cabecera de columna | 40 × 40 | 40 × 40 | medido |
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
@for (d of ['LU','MA','MI','JU','VI','SÁ','DO']; track d) { <sui-day-label [label]="d" /> }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
53
|
+
|
|
54
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| todo el componente suelto (0 usos) | no hay calendarios propios | la cabecera de una semana de turnos armada con `sui-day-cell` |
|
|
57
|
+
| una letra o tres | ambiguo, o rompe el formato del datepicker | ninguno |
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
<!-- api:inicio -->
|
|
62
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
63
|
+
|
|
64
|
+
| input | tipo | default |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `label` | `string` | — (requerido) |
|
|
67
|
+
|
|
68
|
+
Outputs: ninguno.
|
|
69
|
+
<!-- api:fin -->
|
|
70
|
+
|
|
71
|
+
## Trampas
|
|
72
|
+
|
|
73
|
+
- El host lleva `role="columnheader"`: tiene sentido dentro de un `role="grid"`; suelto, confunde
|
|
74
|
+
al lector de pantalla.
|
|
75
|
+
- Acepta cualquier texto, pero el ancho es fijo de 40 px: lo que no entra se corta.
|
|
76
|
+
|
|
77
|
+
## Ejemplo
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<sui-day-label label="LU" />
|
|
81
|
+
```
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-drawer-footer
|
|
3
|
+
selector: sui-drawer-footer
|
|
4
|
+
resumen: Pie de un panel lateral con dos botones y un extra a la izquierda; hoy sin uso, los botones van en sui-modal-footer
|
|
5
|
+
alternativas: [sui-modal-footer (el canon de botones de toda la app), sui-filter-panel-footer (pie de un panel de filtros)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-drawer-footer
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Drawer/Drawer Footer](https://sui-design-system.web.app/?path=/docs/molecules-drawer-drawer-footer--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Hoy no se usa, y aunque aparezca el panel lateral, los botones van en `sui-modal-footer`.** El
|
|
15
|
+
canon de la app (CLAUDE.md, «Botones — composición y orden», 27-07-2026) dice que `sui-modal-footer`
|
|
16
|
+
legisla **todos** los grupos de botones, no solo los de modales. El drawer-footer pone los botones
|
|
17
|
+
en el mismo orden (secundario a la izquierda, primario a la derecha), pero le faltan dos cosas que
|
|
18
|
+
el canon exige:
|
|
19
|
+
|
|
20
|
+
- **No tiene `buttonSize`**: los botones quedan en 40 px. El canon pide `large` (48) en modales.
|
|
21
|
+
- **No admite `color: 'error'`** en el primario (lo ignora): no sirve para confirmar algo destructivo.
|
|
22
|
+
|
|
23
|
+
**No lo uses** para el pie de un modal, un sheet o un formulario: `sui-modal-footer`.
|
|
24
|
+
|
|
25
|
+
Regla corta: **cualquier par de botones → sui-modal-footer.**
|
|
26
|
+
|
|
27
|
+
## Qué variante usar
|
|
28
|
+
|
|
29
|
+
> **Lo que dice la guía del DS**: el drawer es «un panel que sale desde el borde de la pantalla» y
|
|
30
|
+
> su pie es un contenedor libre. No trae tipos ni do/don't.
|
|
31
|
+
>
|
|
32
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`): **0 usos**.
|
|
33
|
+
> `sui-modal-footer` se usa en los modales de toda la app.
|
|
34
|
+
|
|
35
|
+
### `type` — qué va a la izquierda de los botones
|
|
36
|
+
|
|
37
|
+
Cada tipo tiene su equivalente en `sui-modal-footer`, cuyo slot izquierdo admite lo mismo:
|
|
38
|
+
|
|
39
|
+
| type | qué dibuja | equivalente canon | fuente |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| `stretch` (default) | Dos botones 50/50 a todo el ancho. | `sui-modal-footer [stretch]="true"` | canon (CLAUDE.md, botones) |
|
|
42
|
+
| `basic` | Botones a la derecha. | `sui-modal-footer` | canon (CLAUDE.md, botones) |
|
|
43
|
+
| `checkbox` | Un checkbox con texto a la izquierda («No volver a mostrar»). | `sui-checkbox-label` en el slot izquierdo | canon (CLAUDE.md, botones: el slot izquierdo admite checkbox) |
|
|
44
|
+
| `toggle` | Un switch con texto a la izquierda. | `sui-switch-label` en el slot izquierdo | canon (CLAUDE.md, botones) |
|
|
45
|
+
| `stepper` | Puntos del paso actual. | `sui-stepper variant="dot"` en el slot izquierdo | canon (CLAUDE.md, botones) |
|
|
46
|
+
| `link-button` | Una tercera acción como enlace. | `sui-link-button` en el slot izquierdo | canon (CLAUDE.md, botones: la tercera acción es un link-button) |
|
|
47
|
+
|
|
48
|
+
### Botones
|
|
49
|
+
|
|
50
|
+
| input | regla | fuente |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `primaryButton` | Con el verbo de lo que hace («Guardar», «Aplicar filtros»); el default es «Continuar». | según el código |
|
|
53
|
+
| `secondaryButton` | El default es «Cancelar»; `null` para un solo botón. | según el código |
|
|
54
|
+
| `disabled` (en la config) | Primario deshabilitado mientras falta un dato. | propuesta, falta aprobación |
|
|
55
|
+
| `color` (en la config) | **No sirve**: el primario es siempre naranja. | según el código |
|
|
56
|
+
|
|
57
|
+
Usos de hoy que rompen las reglas: **0** (no se usa).
|
|
58
|
+
|
|
59
|
+
## Tamaño en mobile y en web
|
|
60
|
+
|
|
61
|
+
**No tiene tamaño**: los botones miden **40 px**, sin input para cambiarlos. En mobile el canon de
|
|
62
|
+
modales pide 48. El pie mide 80 px de alto.
|
|
63
|
+
|
|
64
|
+
| uso | mobile | web | fuente |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| par de botones | `sui-modal-footer` (botones `large`, 48) | `sui-modal-footer` | canon (CLAUDE.md, botones: size `large` en todos los modales) |
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<sui-modal-footer secondaryButton="Cancelar" primaryButton="Guardar" [stretch]="bp.isMobile()" … />
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
73
|
+
|
|
74
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| el componente entero | `sui-modal-footer` hace lo mismo con tamaño 48 y color de error | ninguno mientras el modal-footer exista; si el DS suma un panel lateral, usa también modal-footer |
|
|
77
|
+
|
|
78
|
+
## API
|
|
79
|
+
|
|
80
|
+
<!-- api:inicio -->
|
|
81
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
82
|
+
|
|
83
|
+
| input | tipo | default |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `type` | `'stretch' \| 'basic' \| 'checkbox' \| 'toggle' \| 'stepper' \| 'link-button'` | `'stretch'` |
|
|
86
|
+
| `primaryButton` | `SuiFooterButtonConfig \| string` | `'Continuar'` |
|
|
87
|
+
| `secondaryButton` | `SuiFooterButtonConfig \| string \| null` | `'Cancelar'` |
|
|
88
|
+
| `checkboxLabel` | `string` | `''` |
|
|
89
|
+
| `checkboxActive` · model, `[(checkboxActive)]` | `boolean` | `false` |
|
|
90
|
+
| `toggleLabel` | `string` | `''` |
|
|
91
|
+
| `toggleActive` · model, `[(toggleActive)]` | `boolean` | `false` |
|
|
92
|
+
| `stepper` | `{ current: number; total: number } \| null` | `null` |
|
|
93
|
+
| `link` | `SuiLinkConfig \| string \| null` | `null` |
|
|
94
|
+
|
|
95
|
+
| output | payload |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `primaryClick` | `Event` |
|
|
98
|
+
| `secondaryClick` | `Event` |
|
|
99
|
+
| `linkClick` | `MouseEvent` |
|
|
100
|
+
<!-- api:fin -->
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
type SuiDrawerFooterType = 'stretch' | 'basic' | 'checkbox' | 'toggle' | 'stepper' | 'link-button';
|
|
104
|
+
interface SuiFooterButtonConfig { label: string; disabled?: boolean; color?: 'primary' | 'error'; }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Trampas
|
|
108
|
+
|
|
109
|
+
- **Defaults en español** (desde 03-10-2026; antes «Continue» / «Cancel»): sin `primaryButton` dice
|
|
110
|
+
«Continuar» y sin `secondaryButton` dice «Cancelar». Para un solo botón pasa
|
|
111
|
+
`[secondaryButton]="null"`.
|
|
112
|
+
- **`color: 'error'` se ignora**: el primario está fijo en `primary`.
|
|
113
|
+
- **Sin tamaño**: botones de 40 px.
|
|
114
|
+
- `stepper` usa `{ current, total }` con `current` desde 0, y dibuja sus propios puntos (no es
|
|
115
|
+
`sui-stepper`).
|
|
116
|
+
- `checkboxActive` y `toggleActive` son `model`: `[(checkboxActive)]`.
|
|
117
|
+
- El borde de arriba ya viene puesto: no le sumes otro.
|
|
118
|
+
|
|
119
|
+
## Ejemplo
|
|
120
|
+
|
|
121
|
+
```html
|
|
122
|
+
<!-- Lo que va en la app -->
|
|
123
|
+
<sui-modal-footer
|
|
124
|
+
secondaryButton="Cancelar"
|
|
125
|
+
[primaryButton]="{ label: 'Guardar' }"
|
|
126
|
+
(secondaryClick)="cerrar()" (primaryClick)="guardar()" />
|
|
127
|
+
```
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-drawer-header
|
|
3
|
+
selector: sui-drawer-header
|
|
4
|
+
resumen: Cabecera de un panel lateral (título, descripción, cerrar); hoy sin contenedor en SUI y sin uso en la app
|
|
5
|
+
alternativas: [sui-modal (con title y description: la cabecera de todos los modales de la app), sui-modal-header (la cabecera suelta del modal), sui-page-header (título de una página)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-drawer-header
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Drawer/Drawer Header](https://sui-design-system.web.app/?path=/docs/molecules-drawer-drawer-header--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Hoy no se usa.** SUI no tiene el contenedor del drawer (el panel que sale del borde): solo esta
|
|
15
|
+
cabecera y su pie. En la app, todo lo que se abre encima es un `sui-modal` (fullscreen en mobile,
|
|
16
|
+
canon) o un `sui-modal-sheet`, y su cabecera sale de los inputs `title` y `description` del modal.
|
|
17
|
+
|
|
18
|
+
**Úsalo** cuando exista un panel lateral de web (un detalle que se abre a la derecha sin tapar la
|
|
19
|
+
lista, como el pedido en el panel de órdenes) y haga falta su cabecera.
|
|
20
|
+
|
|
21
|
+
**No lo uses** para:
|
|
22
|
+
|
|
23
|
+
- La cabecera de un modal o un sheet: `sui-modal` con `title`/`description` (o `sui-modal-header`).
|
|
24
|
+
- El título de una página: `sui-page-header`.
|
|
25
|
+
- Mobile: un panel lateral en 390 px es un modal fullscreen.
|
|
26
|
+
|
|
27
|
+
Regla corta: **modal o sheet → sui-modal con title · panel lateral de web → drawer-header (cuando exista el panel).**
|
|
28
|
+
|
|
29
|
+
## Qué variante usar
|
|
30
|
+
|
|
31
|
+
> **Lo que dice la guía del DS**: el drawer es «un panel que sale desde el borde de la pantalla».
|
|
32
|
+
> Su cabecera trae título y **botón de cerrar visible por default**. No habla de tipos ni tamaños.
|
|
33
|
+
>
|
|
34
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`): **0 usos**.
|
|
35
|
+
|
|
36
|
+
### `type`
|
|
37
|
+
|
|
38
|
+
| type | cuándo | fuente |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `basic` (default) | Lo normal: título y cerrar. | propuesta, falta aprobación |
|
|
41
|
+
| `left-icon` | El ícono dice de qué es el panel antes de leer («history-line» en el historial). En `small` va suelto (24); en `large`/`xlarge`, en un círculo con borde. | propuesta, falta aprobación |
|
|
42
|
+
|
|
43
|
+
### `size`
|
|
44
|
+
|
|
45
|
+
| size | qué cambia | cuándo | fuente |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| `small` (default) | 64 px, todo en una línea; **no muestra `description`** | Panel con título que se explica solo. Es el único que admite `link`. | propuesta, falta aprobación |
|
|
48
|
+
| `large` | 88 px, título arriba y `description` debajo | Panel que necesita una línea de contexto («Últimos 30 días»). | propuesta, falta aprobación |
|
|
49
|
+
| `xlarge` | padding 24, título 20, descripción 16 | No: extensión de SUI sin caso; en web no hace falta letra más grande. | propuesta, falta aprobación |
|
|
50
|
+
|
|
51
|
+
### Lo demás
|
|
52
|
+
|
|
53
|
+
| input | valor | cuándo | fuente |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `showDismiss` | `true` (default) | Siempre. | según la guía del DS (cerrar visible por default) |
|
|
56
|
+
| `showDismiss` | `false` | Solo si el panel no se puede cerrar sin decidir (y entonces es un modal, no un drawer). | propuesta, falta aprobación |
|
|
57
|
+
| `showDivider` | `true` | Cuando el cuerpo scrollea por debajo de la cabecera. | propuesta, falta aprobación |
|
|
58
|
+
| `badge` | número | Pendientes dentro del panel (círculo rojo). | propuesta, falta aprobación |
|
|
59
|
+
| `badge` | texto o `SuiBadgeConfig` | Un estado o etiqueta al lado del título. Pasa `variant: 'lighter'`: el default de aquí es `light` (ver Trampas). | canon (README de `sui-badge`: `lighter` en cabeceras) |
|
|
60
|
+
| `link` | texto | Una acción menor en la cabecera («Ver todo»). Solo en `small`. | propuesta, falta aprobación |
|
|
61
|
+
| `dismissAriaLabel` | «Cerrar» (default) | Ya está en español. | según el código |
|
|
62
|
+
|
|
63
|
+
Usos de hoy que rompen las reglas: **0** (no se usa).
|
|
64
|
+
|
|
65
|
+
## Tamaño en mobile y en web
|
|
66
|
+
|
|
67
|
+
**No tiene tamaño para mobile**: el botón de cerrar mide **24 px** (compact-button `large`), lejos de
|
|
68
|
+
los 40-44 del dedo. Es una pieza de web.
|
|
69
|
+
|
|
70
|
+
| uso | mobile | web | fuente |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| cabecera de panel | no se usa: `sui-modal` fullscreen con `title` | `small` o `large` | propuesta, falta aprobación |
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
@if (!bp.isMobile()) {
|
|
76
|
+
<sui-drawer-header size="large" title="Pedido #1042" description="Sabores Andinos · hace 5 min" (dismiss)="cerrar()" />
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
81
|
+
|
|
82
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| el componente entero | SUI no tiene el panel que lo contiene; los modales traen su cabecera | un panel lateral de detalle en web (el pedido en el panel de órdenes) |
|
|
85
|
+
| `xlarge` | sin caso | nunca en web |
|
|
86
|
+
| `showDismiss` en `false` | un panel siempre se cierra | nunca en un drawer |
|
|
87
|
+
| en mobile | cerrar de 24 px | nunca |
|
|
88
|
+
|
|
89
|
+
## API
|
|
90
|
+
|
|
91
|
+
<!-- api:inicio -->
|
|
92
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
93
|
+
|
|
94
|
+
| input | tipo | default |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `type` | `'basic' \| 'left-icon'` | `'basic'` |
|
|
97
|
+
| `size` | `'small' \| 'large' \| 'xlarge'` | `'small'` |
|
|
98
|
+
| `title` | `string` | `''` |
|
|
99
|
+
| `description` | `string \| null` | `null` |
|
|
100
|
+
| `icon` | `string \| null` | `null` |
|
|
101
|
+
| `badge` | `SuiBadgeConfig \| number \| string \| null` | `null` |
|
|
102
|
+
| `link` | `SuiLinkConfig \| string \| null` | `null` |
|
|
103
|
+
| `showDismiss` | `boolean` | `true` |
|
|
104
|
+
| `showDivider` | `boolean` | `false` |
|
|
105
|
+
| `dismissAriaLabel` | `string` | `'Cerrar'` |
|
|
106
|
+
|
|
107
|
+
| output | payload |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `dismiss` | `MouseEvent` |
|
|
110
|
+
| `linkClick` | `MouseEvent` |
|
|
111
|
+
<!-- api:fin -->
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
type SuiDrawerHeaderType = 'basic' | 'left-icon';
|
|
115
|
+
type SuiDrawerHeaderSize = 'small' | 'large' | 'xlarge';
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Trampas
|
|
119
|
+
|
|
120
|
+
- **`description` no se ve en `small`** y **`link` no se ve en `large`/`xlarge`**: los dos se pasan
|
|
121
|
+
sin error y no aparecen.
|
|
122
|
+
- **El badge de texto sale `orange` + `light` por default**, que va contra el canon del badge
|
|
123
|
+
(`lighter` en cabeceras, naranja solo si pide atención). Pasa un `SuiBadgeConfig` completo.
|
|
124
|
+
- **`badge` en `0` sí se dibuja** (un círculo rojo con «0»). Pasa `null` para no mostrarlo.
|
|
125
|
+
- **`left-icon` sin `icon` no dibuja nada.**
|
|
126
|
+
- El título es un `<h2>`: si la página ya tiene un `h2` al mismo nivel, revisa el orden de títulos.
|
|
127
|
+
- No hay contenedor: el fondo, el ancho y la animación del panel los pones tú.
|
|
128
|
+
|
|
129
|
+
## Ejemplo
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<sui-drawer-header
|
|
133
|
+
type="left-icon"
|
|
134
|
+
size="large"
|
|
135
|
+
icon="history-line"
|
|
136
|
+
title="Historial de pedidos"
|
|
137
|
+
description="Últimos 30 días"
|
|
138
|
+
[showDivider]="true"
|
|
139
|
+
(dismiss)="cerrar()" />
|
|
140
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-empty-state
|
|
3
|
+
selector: sui-empty-state
|
|
4
|
+
resumen: Pantalla o lista sin nada que mostrar (o que no pudo cargar) con emoji animado, título, explicación y una acción opcional
|
|
5
|
+
alternativas: [sui-alert (un aviso dentro de una pantalla que sí tiene contenido), sui-banner (aviso de toda la app), skeleton (mientras carga, nunca un empty)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-empty-state
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Empty State](https://sui-design-system.web.app/?path=/docs/molecules-empty-state--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** cuando una lista o una pantalla no tiene nada que mostrar: el carrito vacío, sin pedidos
|
|
15
|
+
aún, una búsqueda sin resultados, un filtro que no trae nada. También cuando la lista **no pudo
|
|
16
|
+
cargar**, con una acción para reintentar.
|
|
17
|
+
|
|
18
|
+
**No lo uses** para:
|
|
19
|
+
|
|
20
|
+
- Mientras carga: eso es un skeleton. Un empty que aparece y después se llena se lee como «no
|
|
21
|
+
hay nada» por un segundo.
|
|
22
|
+
- Un aviso dentro de una pantalla que sí tiene contenido («Tu local está cerrado»): `sui-alert`.
|
|
23
|
+
- Un error de un formulario: el mensaje va en el campo (`error` / `errorMessage`).
|
|
24
|
+
|
|
25
|
+
Regla corta: **no hay nada que mostrar → empty-state · está cargando → skeleton · hay contenido y
|
|
26
|
+
algo que avisar → alert.**
|
|
27
|
+
|
|
28
|
+
## Qué variante usar
|
|
29
|
+
|
|
30
|
+
> **La guía del DS no tiene página del empty state.** El componente de SUI se construyó a
|
|
31
|
+
> propósito con Fluent Emoji animados en vez de ilustraciones: es una decisión del proyecto
|
|
32
|
+
> (memoria «emojis animados en empty states», 17-04-2026).
|
|
33
|
+
>
|
|
34
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **66
|
|
35
|
+
> empty-states en 40 archivos**. 25 con `action` (10 con `route`). 4 con `emoji` propio, 22 con la
|
|
36
|
+
> URL del zorro pegada a mano (que ya es el default) y 40 sin `emoji`. 29 con un atributo `icon`
|
|
37
|
+
> que el componente no tiene.
|
|
38
|
+
|
|
39
|
+
### Las piezas
|
|
40
|
+
|
|
41
|
+
| prop | cuándo | fuente |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `emoji` vacío (default: el zorro) | Lo normal. El zorro es la mascota de los empty states y sale solo: **no pegues su URL**. | canon (memoria del proyecto) |
|
|
44
|
+
| `emoji` propio | Cuando el emoji dice algo del caso: el reloj de arena en «Aún no tienes facturas» (se está esperando algo), el chef en los avisos del local. Siempre de `FLUENT_EMOJI_ANIM` (`core/fluent-emoji.ts`) o de `assets/emoji-anim/`. | canon (memoria del proyecto) |
|
|
45
|
+
| `title` (obligatorio) | Qué pasa, en corto y sin punto: «Tu carrito está vacío», «Sin pedidos aún». En una búsqueda, repite lo buscado: «Nada con “pollo broaster”». | propuesta (práctica de la app) |
|
|
46
|
+
| `subtitle` | Qué va a pasar o qué puede hacer la persona: «Cuando hagas tu primer pedido, aparecerá aquí.» | propuesta |
|
|
47
|
+
| `action` como string + `(actionClicked)` | La salida es algo de esta misma pantalla: «Reintentar», «Ver todo el catálogo», «Activar captura». | propuesta |
|
|
48
|
+
| `action` como `{ label, route }` | La salida es otra pantalla: «Ver negocios» → `/cliente/inicio`. | propuesta |
|
|
49
|
+
| sin `action` | No hay un paso obvio, o la pantalla ya tiene el botón para llenarla (el «Nuevo local» de arriba). | propuesta |
|
|
50
|
+
| error de carga | Siempre con `action="Reintentar"`. Excepción: la pantalla reintenta sola y lo dice («Seguimos intentando»). | propuesta |
|
|
51
|
+
|
|
52
|
+
**Usos de hoy que rompen las reglas:**
|
|
53
|
+
|
|
54
|
+
- **29 con `icon="…"`**: `icon` no es un input, el atributo no hace nada. Ejemplos:
|
|
55
|
+
`pages/customer/cart/cart.html:18`, `pages/drivers/drivers.html:87`,
|
|
56
|
+
`pages/customer/order-history/order-history.html:20`. Se borra.
|
|
57
|
+
- **22 con la URL del zorro pegada** (`emoji="…/Animals/Fox.png"`), que ya es el default:
|
|
58
|
+
`pages/customers/customers.html:65`, `pages/products/products.html:113`,
|
|
59
|
+
`pages/locations/locations.html:16`. Se borra.
|
|
60
|
+
- **4 errores de carga sin «Reintentar»**:
|
|
61
|
+
`pages/driver/driver-dashboard/driver-dashboard.html:1071`,
|
|
62
|
+
`pages/customer/order-history/order-history.html:20`,
|
|
63
|
+
`pages/super-admin/master-drivers/master-drivers.html:524` y `:754`.
|
|
64
|
+
(`pages/public/pedido-en-vivo/pedido-en-vivo.html:50` no cuenta: reintenta solo.)
|
|
65
|
+
|
|
66
|
+
## Tamaño en mobile y en web
|
|
67
|
+
|
|
68
|
+
El emoji mide 120 en las dos; el padding pasa solo de 48 / 24 en web a 32 / 20 desde tablet hacia
|
|
69
|
+
abajo (media query `bp.medium` del componente). El `size` solo cambia **el botón de la acción**:
|
|
70
|
+
|
|
71
|
+
| size | botón | fuente |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `medium` (default) | 40 px (`sui-button` `medium`) | lo que había en el DS |
|
|
74
|
+
| `large` | 48 px (`sui-button` `large`, texto 16) | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
75
|
+
|
|
76
|
+
| uso | mobile | web | fuente |
|
|
77
|
+
|---|---|---|---|
|
|
78
|
+
| ilustración + texto | lo resuelve el componente | lo resuelve el componente | lo que hay en el DS |
|
|
79
|
+
| botón de la acción | `large` (48) | `medium` (40) | propuesta: el tamaño es extensión SUI aprobada (03-10-2026); el «cuándo» falta aprobarlo |
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<sui-empty-state
|
|
83
|
+
title="Tu carrito está vacío"
|
|
84
|
+
[action]="{ label: 'Ver negocios', route: '/cliente/inicio' }"
|
|
85
|
+
[size]="bp.isMobile() ? 'large' : 'medium'" />
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
89
|
+
|
|
90
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| un emoji que no sea animado (PNG estático, SVG, ícono) | la regla del proyecto es emoji animado | nunca |
|
|
93
|
+
| empty con `action` que hace lo mismo que un botón ya visible en la pantalla | dos botones para lo mismo | nunca |
|
|
94
|
+
|
|
95
|
+
## API
|
|
96
|
+
|
|
97
|
+
<!-- api:inicio -->
|
|
98
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
99
|
+
|
|
100
|
+
| input | tipo | default |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `emoji` | `string` | `''` |
|
|
103
|
+
| `title` | `string` | — (requerido) |
|
|
104
|
+
| `subtitle` | `string` | `''` |
|
|
105
|
+
| `action` | `SuiEmptyStateAction \| string \| null` | `null` |
|
|
106
|
+
| `size` | `'medium' \| 'large'` | `'medium'` |
|
|
107
|
+
|
|
108
|
+
| output | payload |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `actionClicked` | `void` |
|
|
111
|
+
<!-- api:fin -->
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
interface SuiEmptyStateAction { label: string; route?: string; }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`EMPTY_STATE_FOX_EMOJI` (exportada) es la URL del zorro.
|
|
118
|
+
|
|
119
|
+
## Trampas
|
|
120
|
+
|
|
121
|
+
- **`icon` no existe.** Viene de un `app-empty-state` viejo; Angular no se queja porque lo toma
|
|
122
|
+
como atributo HTML.
|
|
123
|
+
- **`emoji` es una URL**, no un nombre de `SuiEmoji` (`'bell'` no funciona).
|
|
124
|
+
- **`title` es obligatorio** y el host borra el atributo `title` del DOM (sin tooltip nativo).
|
|
125
|
+
- Con `route`, el botón usa `routerLink` y **no emite** `actionClicked`.
|
|
126
|
+
- El botón es `sui-button` `filled` `primary`: el color no se cambia; el tamaño sí, con `size` (`medium` 40 · `large` 48).
|
|
127
|
+
- El emoji carga con `loading="lazy"`: en una captura de pantalla completa puede salir vacío.
|
|
128
|
+
|
|
129
|
+
## Ejemplo
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<!-- Lista vacía con salida a otra pantalla -->
|
|
133
|
+
<sui-empty-state
|
|
134
|
+
title="Tu carrito está vacío"
|
|
135
|
+
subtitle="Explora las tiendas y agrega productos para empezar."
|
|
136
|
+
[action]="{ label: 'Ver negocios', route: '/cliente/inicio' }" />
|
|
137
|
+
|
|
138
|
+
<!-- Error de carga -->
|
|
139
|
+
<sui-empty-state
|
|
140
|
+
[emoji]="emoji.thinking"
|
|
141
|
+
title="No se pudieron cargar tus pedidos"
|
|
142
|
+
subtitle="Revisa tu conexión y vuelve a intentar."
|
|
143
|
+
action="Reintentar"
|
|
144
|
+
(actionClicked)="cargar()" />
|
|
145
|
+
```
|