@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
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-modal-sheet
|
|
3
|
+
selector: sui-modal-sheet
|
|
4
|
+
resumen: Hoja que sube desde abajo, se arrastra entre alturas fijas y puede dejar usable lo de atrás (un mapa)
|
|
5
|
+
alternativas: [sui-modal (pide terminar algo antes de seguir, sin fondo usable), sui-popover (contenido chico anclado a un botón), sui-dropdown-menu (lista de acciones)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-modal-sheet
|
|
9
|
+
|
|
10
|
+
Story: [Organisms/Modal/Modal Sheet](https://sui-design-system.web.app/?path=/docs/organisms-modal-modal-sheet--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** cuando el contenido **convive con lo de atrás** o se mira a distintas alturas:
|
|
15
|
+
|
|
16
|
+
- El panel del seguimiento sobre un mapa (pedido, envío, viaje): a 25 % se ve el mapa, a 100 %
|
|
17
|
+
el detalle. El mapa sigue respondiendo.
|
|
18
|
+
- Una lista o un detalle que se abre desde abajo y se cierra deslizando (reseñas, movimientos
|
|
19
|
+
de la billetera, elegir la hora de entrega).
|
|
20
|
+
|
|
21
|
+
**No lo uses** para:
|
|
22
|
+
|
|
23
|
+
- Un formulario o una confirmación que hay que terminar: `sui-modal`. El sheet se cierra con un
|
|
24
|
+
deslizón y se pierde lo escrito.
|
|
25
|
+
- Desktop como superficie principal: en una pantalla de 1440 px un sheet a todo el ancho se lee
|
|
26
|
+
como un error (ver tamaño). Si en desktop hay sitio, un panel lateral sirve mejor.
|
|
27
|
+
|
|
28
|
+
## Qué variante usar
|
|
29
|
+
|
|
30
|
+
> **No está en la guía del DS: es extensión de SUI**, inspirada en el `ion-modal` en modo sheet
|
|
31
|
+
> de Ionic y en las hojas de Apple Maps. No hay Figma que la legisle. Lo marcado **canon** sale
|
|
32
|
+
> de `master-pedidos/CLAUDE.md`; lo demás es **propuesta** sacada del uso real.
|
|
33
|
+
>
|
|
34
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: 13 sheets, sin contar prototipos ni
|
|
35
|
+
> vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`, `dx/*`, `master-rutina`,
|
|
36
|
+
> `master-medico`, `dev-index`) ni las copias de `components/sui/`.
|
|
37
|
+
|
|
38
|
+
### Lo que sí dice la guía del DS
|
|
39
|
+
|
|
40
|
+
Nada: el sheet no está en la guía. Lo único que hereda del DS es el criterio del body (20 px) y
|
|
41
|
+
el radio Android (`--sui-radius-20`).
|
|
42
|
+
|
|
43
|
+
### Los dos patrones de la app
|
|
44
|
+
|
|
45
|
+
El sheet no tiene variantes: se configura con tres números. En la app salen **dos recetas**, y
|
|
46
|
+
conviene copiar una de las dos en vez de inventar otra.
|
|
47
|
+
|
|
48
|
+
| patrón | `breakpoints` | `initialBreakpoint` | `backdropBreakpoint` | cuándo | ejemplo real de la app | fuente |
|
|
49
|
+
|---|---|---|---|---|---|---|
|
|
50
|
+
| **Sobre un mapa** | `[0.25, 0.5, 0.7, 1]` (sin `0`) | `0.5` | `1` | el seguimiento: el mapa se usa a cualquier altura y la hoja no se puede cerrar | `pages/customer/order-tracking/order-tracking.html:130` · `pages/driver/driver-order-detail/driver-order-detail.html:60` | propuesta |
|
|
51
|
+
| **Hoja de lectura** | `[0, 0.92]` | `0.92` | `0` | una lista o detalle que se abre y se cierra deslizando, con el fondo apagado | `pages/customer/order-tracking/order-tracking.html:809` (reseñas) · `pages/customer/checkout/checkout.html:448` (hora) | propuesta |
|
|
52
|
+
|
|
53
|
+
Hoy: 4 «sobre un mapa» (más 2 variantes con alturas propias: `pages/envios/envios.html:578` y
|
|
54
|
+
`pages/customer/viaje/viaje.html:24`), 5 hojas de lectura en `0.92`–`0.96`, 2 en `[0, 1]` y 1 en
|
|
55
|
+
`[0, 0.6, 0.95]`.
|
|
56
|
+
|
|
57
|
+
| input | regla | fuente |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `breakpoints` | Con `0` en la lista, la hoja **se cierra deslizando**. Sin `0`, no se cierra con el dedo (solo por código o backdrop). | componente |
|
|
60
|
+
| `initialBreakpoint` | Tiene que estar en `breakpoints`. | componente |
|
|
61
|
+
| `backdropBreakpoint` | `0` = fondo apagado desde que abre. `1` = **nunca hay backdrop**: el mapa de atrás se toca siempre. | componente |
|
|
62
|
+
| tope en las hojas de lectura | `0.92`, no `1`: deja ver arriba un borde de la pantalla de atrás, que es lo que dice «esto es una hoja». | propuesta |
|
|
63
|
+
| `showHandle` | Déjalo en `true` siempre que la hoja se arrastre. Hoy nadie lo apaga. | propuesta |
|
|
64
|
+
| `fullBody` | Solo para contenido a sangre (una foto, un mapa dentro de la hoja). | canon (CLAUDE.md, 2026-07-21) |
|
|
65
|
+
|
|
66
|
+
**Usos de hoy a revisar:**
|
|
67
|
+
|
|
68
|
+
- `pages/customer/viaje/viaje.html:24` reabre la hoja en `(closed)` (`hojaAbierta.set(true)`)
|
|
69
|
+
para que no se pueda cerrar. Sin `0` en `breakpoints` y con `[closeOnBackdrop]="false"` ya no se
|
|
70
|
+
cierra; el reabrir sobra o tapa otro caso.
|
|
71
|
+
- 2 footers de modal metidos en hojas: van sin `slot` (no hay slot de footer). Está bien, pero el
|
|
72
|
+
botón scrollea con el contenido: `pages/customer/checkout/checkout.html:490`,
|
|
73
|
+
`pages/super-admin/master-sonidos-push/master-sonidos-push.html:146`.
|
|
74
|
+
|
|
75
|
+
## Tamaño en mobile y en web
|
|
76
|
+
|
|
77
|
+
El sheet **no tiene `size`**. Mide lo que mide su contenido, con tope en el breakpoint más alto
|
|
78
|
+
(y nunca más que la pantalla menos el safe-area de arriba y 16 px).
|
|
79
|
+
|
|
80
|
+
| | mobile | web desktop | fuente |
|
|
81
|
+
|---|---|---|---|
|
|
82
|
+
| ancho | toda la pantalla menos 8 px a cada lado | **igual: todo el ancho menos 8 px** | componente |
|
|
83
|
+
| esquinas | iOS 36 arriba / 54 abajo · Android 20 | igual | canon (CLAUDE.md, 2026-07-22) |
|
|
84
|
+
| padding del body | `0 20px 20px` | igual | canon (CLAUDE.md, 2026-07-21) |
|
|
85
|
+
| ancho en desktop | — | acotarlo a una columna centrada de 560 px | propuesta (hoy lo hace cada pantalla a mano) |
|
|
86
|
+
|
|
87
|
+
**El sheet no se acota en desktop.** La app lo arregla con CSS propio, cinco reglas en cuatro archivos:
|
|
88
|
+
`components/store-ratings-modal/store-ratings-modal.scss:81`,
|
|
89
|
+
`pages/driver/movimientos/movimientos-sheet.scss:24`,
|
|
90
|
+
`pages/driver/driver-order-detail/driver-order-detail.scss:1028` y
|
|
91
|
+
`pages/customer/order-tracking/order-tracking.scss:1175` y `:1238`, todos a 560 px. Propuesta:
|
|
92
|
+
que el DS traiga ese tope (`max-width` desde 768 px, centrado) y se borren esos parches.
|
|
93
|
+
|
|
94
|
+
## API
|
|
95
|
+
|
|
96
|
+
<!-- api:inicio -->
|
|
97
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
98
|
+
|
|
99
|
+
| input | tipo | default |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `open` · model, `[(open)]` | `boolean` | `false` |
|
|
102
|
+
| `breakpoints` | `number[]` | `[0, 1]` |
|
|
103
|
+
| `initialBreakpoint` | `number` | `1` |
|
|
104
|
+
| `backdropBreakpoint` | `number` | `0` |
|
|
105
|
+
| `showHandle` | `boolean` | `true` |
|
|
106
|
+
| `closeOnBackdrop` | `boolean` | `true` |
|
|
107
|
+
| `closeOnEscape` | `boolean` | `true` |
|
|
108
|
+
| `fullBody` | `boolean` | `false` |
|
|
109
|
+
|
|
110
|
+
| output | payload |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `closed` | `void` |
|
|
113
|
+
| `breakpointChange` | `number` |
|
|
114
|
+
<!-- api:fin -->
|
|
115
|
+
|
|
116
|
+
Métodos públicos: `setCurrentBreakpoint(bp, animated = true)` (avisa por consola y no hace nada
|
|
117
|
+
si `bp` no está en `breakpoints`) y `close()`.
|
|
118
|
+
|
|
119
|
+
Signals públicas: `currentBreakpoint` y `progress` (cambian al soltar, no durante el arrastre) y
|
|
120
|
+
`dragging`.
|
|
121
|
+
|
|
122
|
+
Slot: un solo `<ng-content>`, el body. No hay header ni footer.
|
|
123
|
+
|
|
124
|
+
## Trampas
|
|
125
|
+
|
|
126
|
+
- **El padding del body es fuente única** (`0 20px 20px`). No le pongas padding lateral ni abajo
|
|
127
|
+
a tus secciones ni lo pises con `::ng-deep .sui-sheet__body`: el margen queda doble (pasó en el
|
|
128
|
+
tracking del repartidor: ~36 px a los lados y ~68 px bajo el último botón).
|
|
129
|
+
- **Anidar radios**: el body ya cumple `exterior = interior + padding` (36 − 20 = 16, el radio de
|
|
130
|
+
`sui-card`). Una card adentro no necesita otro radio.
|
|
131
|
+
- **`breakpointChange` y `progress` no cambian durante el arrastre**, solo al soltar. Si algo
|
|
132
|
+
tiene que seguir al dedo (el padding del mapa), usa `breakpointChange` y acepta el salto, o lee
|
|
133
|
+
la posición del panel.
|
|
134
|
+
- **Arrastre y scroll**: en la altura máxima el body scrollea; desde arriba del todo, jalar hacia
|
|
135
|
+
abajo mueve la hoja. En alturas intermedias el body entero arrastra (`touch-action: none`): un
|
|
136
|
+
carrusel o un slider dentro puede pelear con el gesto. Los campos (`input`, `textarea`,
|
|
137
|
+
`select`) no arrancan arrastre; para otro control que necesita el dedo, ponle el atributo
|
|
138
|
+
`data-sui-no-sheet-drag` (o a un ancestro).
|
|
139
|
+
- **Sin `0` en `breakpoints` no se cierra deslizando.** Si quieres que se cierre y no lo hace, es
|
|
140
|
+
eso.
|
|
141
|
+
- **`closeOnBackdrop` solo actúa cuando hay backdrop** (altura actual por encima de
|
|
142
|
+
`backdropBreakpoint`). Con `backdropBreakpoint` en `1` nunca hay.
|
|
143
|
+
- **El transform es tuyo, el movimiento no**: el sheet se mueve con la propiedad `translate` del
|
|
144
|
+
panel interno, así que puedes escribir `left` / `right` / `transform` sobre `.sui-sheet` (por
|
|
145
|
+
ejemplo para centrarlo en desktop) sin romper el arrastre.
|
|
146
|
+
- Pide ocultar la barra inferior de la app por `SUI_NAVBAR_VISIBILITY`, igual que `sui-modal`.
|
|
147
|
+
|
|
148
|
+
## Ejemplo
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<!-- Sobre un mapa: no se cierra, el mapa se usa siempre -->
|
|
152
|
+
<sui-modal-sheet
|
|
153
|
+
[(open)]="hojaAbierta"
|
|
154
|
+
[breakpoints]="[0.25, 0.5, 0.7, 1]"
|
|
155
|
+
[initialBreakpoint]="0.5"
|
|
156
|
+
[backdropBreakpoint]="1"
|
|
157
|
+
(breakpointChange)="mapa.setSheetRatio($event)">
|
|
158
|
+
<h2>Tu pedido va en camino</h2>
|
|
159
|
+
…
|
|
160
|
+
</sui-modal-sheet>
|
|
161
|
+
|
|
162
|
+
<!-- Hoja de lectura: se cierra deslizando -->
|
|
163
|
+
<sui-modal-sheet
|
|
164
|
+
[(open)]="resenasAbiertas"
|
|
165
|
+
[breakpoints]="[0, 0.92]"
|
|
166
|
+
[initialBreakpoint]="0.92"
|
|
167
|
+
[backdropBreakpoint]="0">
|
|
168
|
+
<app-ratings-detail … />
|
|
169
|
+
</sui-modal-sheet>
|
|
170
|
+
```
|
|
@@ -101,8 +101,8 @@ La fila **no tiene `size`**: foto de 40 px, 12 px de relleno, texto de 14.
|
|
|
101
101
|
| uso | mobile | web | fuente |
|
|
102
102
|
|---|---|---|---|
|
|
103
103
|
| la fila | toda la fila se toca para abrirla: mide 64 px o más | igual | según el componente |
|
|
104
|
-
| ⋮ (`showMore`) |
|
|
105
|
-
| la X (`dismissible`) | se ve de 20 px; **se toca en
|
|
104
|
+
| ⋮ (`showMore`) | se ve de 24 y se toca en 44 × 44 cuando está visible (foco o fila activa); oculto no recibe toques | 24 px | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
|
|
105
|
+
| la X (`dismissible`) | se ve de 20 px; **se toca en 44 × 44** | se ve de 20; se toca en 40 × 40 | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono (antes 40, pedido del dueño 03-10-2026): área táctil invisible, extensión SUI |
|
|
106
106
|
| botones de `type="button"` | los pone quien la usa: `[size]="bp.isMobile() ? 'large' : 'xsmall'"` | `xsmall` | propuesta |
|
|
107
107
|
|
|
108
108
|
## «No usar»: por qué no hoy y cuándo sí
|
|
@@ -147,9 +147,9 @@ Slots: `[slot=company-logo]`, `[slot=file]`, `[slot=message]`, el contenido libr
|
|
|
147
147
|
|
|
148
148
|
## Trampas
|
|
149
149
|
|
|
150
|
-
- **La X se toca en 40 × 40
|
|
151
|
-
desde
|
|
152
|
-
abrirla.
|
|
150
|
+
- **La X se toca en 44 × 44 en el teléfono** (40 × 40 en web) aunque se vea de 20 (un `::before`
|
|
151
|
+
invisible sobre su `<button>`; 44 desde el 04-10-2026): en una fila que se toca entera, el toque a
|
|
152
|
+
12 px de la X la cierra en vez de abrirla. La X y el ⋮ comparten la esquina: no se usan juntos.
|
|
153
153
|
- **Es el avatar el que decide el modelo**: con `avatar` es una fila plana (`role="article"`); sin
|
|
154
154
|
`avatar` es un alert con borde y sombra (`role="status"`, que el lector de pantalla anuncia).
|
|
155
155
|
- **El avatar no es `sui-avatar`**: lo dibuja la fila, en un círculo **negro** con iniciales.
|
|
@@ -161,7 +161,9 @@ Slots: `[slot=company-logo]`, `[slot=file]`, `[slot=message]`, el contenido libr
|
|
|
161
161
|
- `feature` usa `sparkling-fill` aquí y en el alert, y `magic-fill` en el banner.
|
|
162
162
|
- `dismissible` solo emite `(dismissed)`: la fila **no se esconde sola** (a diferencia de alert y
|
|
163
163
|
banner). La saca quien la usa.
|
|
164
|
-
- El ⋮ de `showMore` se ve solo con el mouse encima
|
|
164
|
+
- El ⋮ de `showMore` se ve solo con el mouse encima, con `active` o cuando le llega el foco de
|
|
165
|
+
teclado: en mobile no aparece. **Mientras está oculto no recibe toques** (desde el 04-10-2026;
|
|
166
|
+
antes un toque en la esquina disparaba `moreClicked` sin que se viera nada).
|
|
165
167
|
- **`showMore` y `dismissible` juntos se pisan**: el ⋮ y la X van los dos arriba a la derecha.
|
|
166
168
|
- Con avatar (o con `type` distinto de `basic`) y **sin `description`**, queda un «∙» colgando
|
|
167
169
|
después de la hora («Hace 8 min ∙»).
|
|
@@ -44,7 +44,7 @@ la barra superior, con filas `sui-notification` y la cabecera `sui-notification-
|
|
|
44
44
|
|
|
45
45
|
| uso | mobile | web | fuente |
|
|
46
46
|
|---|---|---|---|
|
|
47
|
-
| el pie entero | no aplica: es ayuda de teclado; en mobile no se muestra |
|
|
47
|
+
| el pie entero | no aplica: es ayuda de teclado; en mobile no se muestra (el componente no se oculta solo: lo esconde quien lo usa) | 48 px de alto (14 + 20 de la tecla + 14) | alto: según el componente · ocultarlo en mobile: propuesta |
|
|
48
48
|
| el link de ajustes | si hiciera falta, un `sui-link-button` `large` suelto | `small` (16 px) | propuesta |
|
|
49
49
|
|
|
50
50
|
```html
|
|
@@ -59,7 +59,7 @@ la barra superior, con filas `sui-notification` y la cabecera `sui-notification-
|
|
|
59
59
|
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
60
60
|
|---|---|---|
|
|
61
61
|
| el componente | no hay panel de campana | si el panel del local o el super admin suman una campana con la bandeja desplegable en la barra superior (web) |
|
|
62
|
-
| `manage` con el texto por defecto | está en
|
|
62
|
+
| `manage` con el texto por defecto | ya está en español («Administrar notificaciones», 03-10-2026), pero el link debe nombrar la pantalla a la que lleva | nunca: siempre un texto propio |
|
|
63
63
|
|
|
64
64
|
## API
|
|
65
65
|
|
|
@@ -44,8 +44,8 @@ texto) y el filtro es un compact-button de 24 px.
|
|
|
44
44
|
|
|
45
45
|
| uso | mobile | web | fuente |
|
|
46
46
|
|---|---|---|---|
|
|
47
|
-
| las pestañas | **no alcanza**: 20 px de alto
|
|
48
|
-
| el filtro | 24 px, **bajo
|
|
47
|
+
| las pestañas | **no alcanza**: 20 px de alto (el `line-height` del texto; el botón no tiene relleno), lejos de los 44 del dedo. Usar `sui-tab-chips` | 20 px de alto, en una fila de 48 | según el componente |
|
|
48
|
+
| el filtro | 24 px (compact-button `large`), **bajo los 44 px del dedo** | 24 px | según el componente |
|
|
49
49
|
|
|
50
50
|
```html
|
|
51
51
|
@if (bp.isMobile()) {
|
|
@@ -97,7 +97,9 @@ interface SuiNotificationTab<T = string> {
|
|
|
97
97
|
- La raya de la pestaña activa usa el primario de la app (naranja), no el azul del Figma.
|
|
98
98
|
- El badge no tiene tope: 120 sale «120». Si hace falta, el texto lo recorta quien lo usa («99+» va
|
|
99
99
|
en `label`, no en `badge`, porque `badge` es un número).
|
|
100
|
-
-
|
|
100
|
+
- Las pestañas van en su propio `role="tablist"` (el botón de filtro queda afuera, desde el
|
|
101
|
+
04-10-2026) y cada una es `role="tab"` con `aria-selected`. Un solo tab stop: ← → mueven y
|
|
102
|
+
activan con vuelta al inicio, Home/End a los extremos. No hay `tabpanel` asociado: lo arma quien lo usa.
|
|
101
103
|
|
|
102
104
|
## Ejemplo
|
|
103
105
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-page-header
|
|
3
|
+
selector: sui-page-header
|
|
4
|
+
resumen: Título y subtítulo de una pantalla, con las acciones de la pantalla a la derecha en desktop y debajo en mobile
|
|
5
|
+
alternativas: [sui-modal-header (cabecera de un modal), sui-drawer-header (cabecera de un panel lateral), sui-topbar (barra superior de la app, no de la pantalla)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-page-header
|
|
9
|
+
|
|
10
|
+
Story: [Organisms/Page Header](https://sui-design-system.web.app/?path=/docs/organisms-page-header--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** una vez por pantalla, **arriba del todo**, antes de cualquier contenido: dice dónde
|
|
15
|
+
está la persona («Pedidos», «Descuentos») y, si hace falta, junta las acciones que valen para
|
|
16
|
+
toda la pantalla («Agregar», «Exportar»).
|
|
17
|
+
|
|
18
|
+
**No lo uses** para:
|
|
19
|
+
|
|
20
|
+
- Títulos de sección dentro de la pantalla: un `<h2>` con el token de tipografía, o el título de
|
|
21
|
+
la `sui-card`.
|
|
22
|
+
- Modales y paneles: `sui-modal-header` / `sui-drawer-header`.
|
|
23
|
+
- Meter contenido debajo del título: **solo** acepta `slot="actions"`; todo lo demás se descarta
|
|
24
|
+
sin avisar.
|
|
25
|
+
- Re-implementarlo con un `<h1>` y CSS propio (canon, CANON-SUI §0: «no re-implementar»).
|
|
26
|
+
|
|
27
|
+
## Qué variante usar
|
|
28
|
+
|
|
29
|
+
> **No está en la guía del DS: es extensión de SUI.** Nació como el título de las pantallas del
|
|
30
|
+
> panel de empresa y no tiene Figma. Lo marcado **canon** sale de `master-pedidos/docs/CANON-SUI.md`;
|
|
31
|
+
> lo demás es **propuesta**.
|
|
32
|
+
>
|
|
33
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: 64 page headers, sin contar prototipos ni
|
|
34
|
+
> vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`, `dx/*`, `master-rutina`,
|
|
35
|
+
> `master-medico`, `dev-index`) ni las copias de `components/sui/`. 50 llevan `subtitle` fijo, 14
|
|
36
|
+
> calculado; 17 tienen acciones; 0 usan `sticky`.
|
|
37
|
+
|
|
38
|
+
### Lo que sí dice la guía del DS
|
|
39
|
+
|
|
40
|
+
Nada: el page header no está en la guía. Su tipografía (24/600, 28 en desktop) **no existe en la
|
|
41
|
+
escala del DS** (CANON-SUI §7): si se homologa, sería `title-h5`.
|
|
42
|
+
|
|
43
|
+
### Contenido
|
|
44
|
+
|
|
45
|
+
| pieza | regla | ejemplo real de la app | fuente |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| `title` | El nombre de la pantalla, el mismo que en el menú. Sentence case, sin punto. Nunca un ID. | `pages/discounts/discounts.html:2` | canon (CANON-SUI, copy) |
|
|
48
|
+
| `subtitle` | Una línea que dice **qué se hace aquí**, no que repite el título. | `pages/super-admin/master-orders/master-orders.html:1` | propuesta |
|
|
49
|
+
| acciones | Las que valen para toda la pantalla: una `filled` como máximo (la principal) y el resto `stroke`. Hoy: 9 `filled`, 7 `stroke`. | `pages/drivers/drivers.html:2` | canon para «una principal» (CANON-SUI §6.2), propuesta el resto |
|
|
50
|
+
|
|
51
|
+
**Usos de hoy que rompen el copy canon** (sentence case en botones): `pages/drivers/drivers.html:8`
|
|
52
|
+
(«Nuevo Repartidor»).
|
|
53
|
+
|
|
54
|
+
### `sticky`
|
|
55
|
+
|
|
56
|
+
| valor | cuándo | fuente |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `false` (default) | el caso normal: el título se va con el scroll | propuesta |
|
|
59
|
+
| `true` | listas largas donde las acciones del header se usan mientras se recorre (filtros, «Agregar»). Le pone fondo blanco. 0 usos hoy | propuesta |
|
|
60
|
+
|
|
61
|
+
## Tamaño en mobile y en web
|
|
62
|
+
|
|
63
|
+
El page header **no tiene `size`**. Cambia solo en 767 px:
|
|
64
|
+
|
|
65
|
+
| | mobile (< 767 px) | web (≥ 767 px) | fuente |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| título | 24 px | 28 px | componente |
|
|
68
|
+
| disposición | título y subtítulo arriba, acciones **debajo** | título a la izquierda, acciones a la derecha, alineadas abajo | componente |
|
|
69
|
+
| padding vertical | 24 arriba y abajo | 32 arriba, 16 abajo | componente |
|
|
70
|
+
| padding lateral | ninguno: lo pone el contenedor del layout | igual | componente |
|
|
71
|
+
| botones de las acciones | `large` (48) | `small` (36) | propuesta |
|
|
72
|
+
|
|
73
|
+
Los botones de las acciones hoy: 10 `small` fijos, 2 `bp.isMobile() ? 'large' : 'small'`, 2
|
|
74
|
+
`bp.controlSize()` (`large`/`xlarge`), 2 `large`, 1 `medium`. La propuesta es la pareja que ya
|
|
75
|
+
usan dos pantallas: en mobile las acciones bajan a su fila y tienen sitio para 48 px; en desktop
|
|
76
|
+
van al lado del título de 28 y `small` no le compite.
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<sui-button [size]="bp.isMobile() ? 'large' : 'small'" slot="actions">Agregar</sui-button>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API
|
|
83
|
+
|
|
84
|
+
<!-- api:inicio -->
|
|
85
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
86
|
+
|
|
87
|
+
| input | tipo | default |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `title` | `string` | — (requerido) |
|
|
90
|
+
| `subtitle` | `string \| null` | `null` |
|
|
91
|
+
| `sticky` | `boolean` | `false` |
|
|
92
|
+
|
|
93
|
+
Outputs: ninguno.
|
|
94
|
+
<!-- api:fin -->
|
|
95
|
+
|
|
96
|
+
Slot: `slot="actions"`, a la derecha (desktop) o debajo (mobile), gap 8. No hay slot default.
|
|
97
|
+
|
|
98
|
+
## Trampas
|
|
99
|
+
|
|
100
|
+
- **Lo que proyectas sin `slot="actions"` desaparece.** El JSDoc viejo hablaba de un slot
|
|
101
|
+
default; no existe.
|
|
102
|
+
- **No respeta el safe-area de arriba**: el padding es fijo. El layout de la pantalla se encarga
|
|
103
|
+
del notch; si lo pones en una pantalla sin layout, el título queda bajo la barra de estado.
|
|
104
|
+
- **Sin padding lateral**: depende de que el contenedor de la página lo tenga
|
|
105
|
+
(`.layout__body`, `.ml__content`). Fuera de esos layouts queda pegado al borde.
|
|
106
|
+
- `sticky` se pega a `top: 0` del **contenedor que scrollea**, no de la ventana. En los layouts de
|
|
107
|
+
la app el scroll vive en `.layout__body` / `.ml__content`, así que funciona; en un contenedor
|
|
108
|
+
sin overflow no hace nada.
|
|
109
|
+
- El breakpoint es `min-width: 767px`: a 767 px exactos ya está en modo desktop, un píxel antes
|
|
110
|
+
que el `max-width: 767px` de los mixins de la app.
|
|
111
|
+
- `title` es requerido: sin él, Angular falla al compilar la plantilla.
|
|
112
|
+
- El host borra el atributo `title` nativo (sin tooltip gris del navegador).
|
|
113
|
+
|
|
114
|
+
## Ejemplo
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<sui-page-header title="Descuentos" subtitle="Promociones y campañas activas de tu negocio.">
|
|
118
|
+
<sui-button slot="actions" variant="filled"
|
|
119
|
+
[size]="bp.isMobile() ? 'large' : 'small'" (click)="crear()">
|
|
120
|
+
Crear descuento
|
|
121
|
+
</sui-button>
|
|
122
|
+
</sui-page-header>
|
|
123
|
+
```
|
|
@@ -18,7 +18,8 @@ página.
|
|
|
18
18
|
**No lo uses** para:
|
|
19
19
|
|
|
20
20
|
- **Mobile**: las listas se recorren con el dedo. Va scroll infinito (la directiva
|
|
21
|
-
`appInfiniteScroll` que ya usan productos, clientes y
|
|
21
|
+
`appInfiniteScroll` que ya usan productos, clientes, el historial del repartidor y del cliente,
|
|
22
|
+
usuarios del super admin y las listas de la central).
|
|
22
23
|
- **Listas que se leen de Firestore por cursor** (`getCollectionPage`): con cursores solo se puede
|
|
23
24
|
pedir la página siguiente. Saltar a la página 7 obliga a leer las 6 anteriores, y Firestore las
|
|
24
25
|
cobra igual. El canon de la app para esas listas es scroll infinito (CLAUDE.md, «Performance —
|
|
@@ -36,8 +37,10 @@ Regla corta: **tabla con todo cargado en web → pagination · lista de Firestor
|
|
|
36
37
|
> cuándo cada forma.
|
|
37
38
|
>
|
|
38
39
|
> Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`): **0 usos**.
|
|
39
|
-
> Las
|
|
40
|
-
> `pages/
|
|
40
|
+
> Las listas largas de la app usan scroll infinito con `appInfiniteScroll` (por ejemplo
|
|
41
|
+
> `pages/products/products.html:242` y `pages/customers/customers.html:161`). Equipo
|
|
42
|
+
> (`pages/settings/team/team.ts:339`) pagina por cursor con `loadMore()`, pero hoy nada lo llama
|
|
43
|
+
> (medido el 04-10-2026).
|
|
41
44
|
|
|
42
45
|
### `type`
|
|
43
46
|
|
|
@@ -63,7 +66,7 @@ Regla corta: **tabla con todo cargado en web → pagination · lista de Firestor
|
|
|
63
66
|
| `firstLast` | `true` | Más de 20 páginas, donde ir al final es un caso de uso (la última semana de un export). | según la guía del DS (los botones existen); el cuándo es propuesta |
|
|
64
67
|
| `siblingCount` | `1` (default) | Siempre. Más números a cada lado ensanchan sin ayudar. | propuesta, falta aprobación |
|
|
65
68
|
| `showInfo` | `true` (default) | Con `infoFormat="items"`: «Mostrando 11-20 de 134». | propuesta, falta aprobación |
|
|
66
|
-
| `infoFormat` | `'items'` (default) |
|
|
69
|
+
| `infoFormat` | `'items'` (default) | «Mostrando 11-20 de 134». | según el código |
|
|
67
70
|
| `infoFormat` | `'pages'` | Imprime «Página 2 de 14» (en español desde 03-10-2026). Cuando no se sabe el total de ítems o no importa. | propuesta, falta aprobación |
|
|
68
71
|
| `pageSizeOptions` | `[]` (default) | Lo normal: sin selector de filas por página. | propuesta, falta aprobación |
|
|
69
72
|
| `pageSizeOptions` | `[10, 25, 50]` | Las opciones dicen «10 / página» (en español desde 03-10-2026). | propuesta, falta aprobación |
|
|
@@ -92,7 +95,7 @@ mobile no se usa.
|
|
|
92
95
|
|---|---|---|
|
|
93
96
|
| el componente entero | las listas de la app leen de Firestore por cursor y usan scroll infinito | una tabla de web con todos los datos ya cargados (un reporte de 300 filas filtrado en el navegador) |
|
|
94
97
|
| `full-radius` | no combina con las esquinas del resto de la app | nunca, salvo que la app pase a botones redondos |
|
|
95
|
-
| `infoFormat="pages"` |
|
|
98
|
+
| `infoFormat="pages"` | la razón original (salía en inglés) ya no aplica: desde el 03-10-2026 dice «Página 2 de 14» | cuando no se sabe el total de ítems o no importa |
|
|
96
99
|
| `firstLast` | ninguna tabla tiene 20+ páginas | un export largo donde ir al final es habitual |
|
|
97
100
|
|
|
98
101
|
## API
|
|
@@ -18,7 +18,7 @@ la barra se llena (rojo, naranja, verde) y cada condición se marca a medida que
|
|
|
18
18
|
|
|
19
19
|
- El login: la contraseña ya existe, no se evalúa.
|
|
20
20
|
- Una sola regla («Mínimo 6 caracteres»): alcanza el `hint` del `sui-input`, como hoy en
|
|
21
|
-
`pages/auth/register/register.html:
|
|
21
|
+
`pages/auth/register/register.html:124`.
|
|
22
22
|
|
|
23
23
|
Regla corta: **contraseña nueva con 2+ reglas → este · una regla → hint.**
|
|
24
24
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: sui-period-range
|
|
3
3
|
selector: sui-period-range
|
|
4
4
|
resumen: Un período predefinido (Hoy, Últimos 7 días) en la columna de presets del calendario de rango
|
|
5
|
-
alternativas: [sui-datepicker mode="range" (ya los trae), sui-
|
|
5
|
+
alternativas: [sui-datepicker mode="range" (ya los trae), sui-segmented-control (2 a 4 períodos fijos a la vista), sui-tab-chips (5 o más períodos fijos o que deslizan)]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# sui-period-range
|
|
@@ -18,9 +18,10 @@ costado del calendario.
|
|
|
18
18
|
|
|
19
19
|
- El rango normal: `sui-datepicker mode="range"` ya pinta los presets con este componente y los
|
|
20
20
|
cambia por `[presets]`.
|
|
21
|
-
- **Cambiar de período en un resumen** («Hoy · 7 días · 30 días»): `sui-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
- **Cambiar de período en un resumen** («Hoy · 7 días · 30 días»): `sui-segmented-control` si son 2
|
|
22
|
+
a 4 opciones, `sui-tab-chips` si son 5 o más o se deslizan (canon, dueño 04-10-2026). Hoy la app
|
|
23
|
+
los tiene en `sui-tab-chips` (super admin `master-overview.html:13`, ganancias del repartidor) y
|
|
24
|
+
en `sui-select` (resumen del local, `overview.html:44`): con 3 opciones pasan a segmented.
|
|
24
25
|
|
|
25
26
|
## Qué variante usar
|
|
26
27
|
|
|
@@ -40,26 +41,28 @@ Usos de hoy que rompen la regla: **0**.
|
|
|
40
41
|
|
|
41
42
|
## Tamaño en mobile y en web
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
Tiene `size`: **`medium`** (default, 168 × 36, Figma) y **`large`** (168 × 44, texto 16/24). El
|
|
45
|
+
`sui-datepicker` `xlarge` pinta sus rangos predefinidos en `large`; en mobile pasan a una fila que
|
|
46
|
+
se desplaza de costado.
|
|
45
47
|
|
|
46
|
-
|
|
|
47
|
-
|
|
48
|
-
|
|
|
48
|
+
| size | alto | texto | uso | fuente |
|
|
49
|
+
|---|---|---|---|---|
|
|
50
|
+
| `large` | **44** (10 + 24 + 10) | 16/24 | mobile | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
|
|
51
|
+
| `medium` (default) | 36 | 14/20 | web, columna de presets | medido (Figma 443:341) |
|
|
49
52
|
|
|
50
53
|
```html
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
<sui-period-range [size]="bp.isMobile() ? 'large' : 'medium'" label="Últimos 7 días"
|
|
55
|
+
[active]="preset() === '7d'" (clicked)="aplicar('7d')" />
|
|
53
56
|
```
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
Fuera del datepicker, en el celular los períodos fijos de 2 a 4 opciones van en
|
|
59
|
+
`sui-segmented-control` y los de más opciones en `sui-tab-chips` (canon del dueño, 04-10-2026).
|
|
57
60
|
|
|
58
61
|
## «No usar»: por qué no hoy y cuándo sí
|
|
59
62
|
|
|
60
63
|
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
61
64
|
|---|---|---|
|
|
62
|
-
| todo el componente suelto (0 usos) | los períodos de la app son fijos y van en tab-chips
|
|
65
|
+
| todo el componente suelto (0 usos) | los períodos de la app son fijos y van en segmented-control (2-4) o tab-chips (5+) | una columna de atajos al lado de un calendario propio, en web |
|
|
63
66
|
| `disabled` | ningún período queda sin datos hoy | presets de un local nuevo («Últimos 12 meses» con 2 semanas de vida) |
|
|
64
67
|
|
|
65
68
|
## API
|
|
@@ -72,6 +75,7 @@ como ya hacen el super admin y las ganancias del repartidor.
|
|
|
72
75
|
| `label` | `string` | — (requerido) |
|
|
73
76
|
| `active` | `boolean` | `false` |
|
|
74
77
|
| `disabled` | `boolean` | `false` |
|
|
78
|
+
| `size` | `'medium' \| 'large'` | `'medium'` |
|
|
75
79
|
|
|
76
80
|
| output | payload |
|
|
77
81
|
|---|---|
|
|
@@ -57,8 +57,8 @@ una función nueva que conviene mostrar donde está («Aquí programas tus pedid
|
|
|
57
57
|
|---|---|---|---|
|
|
58
58
|
| `doubleButton` | `true` (default) | Desde el segundo paso de un recorrido («Atrás» / «Siguiente»), o un aviso suelto con «Ahora no» / «Probar». | propuesta |
|
|
59
59
|
| `doubleButton` | `false` | El primer paso de un recorrido o un aviso suelto con una sola salida («Entendido»). | propuesta |
|
|
60
|
-
| `backLabel` · `nextLabel` | texto en español | Los defaults ya son «Atrás» y «Siguiente» (03-10-2026); el último paso pasa `nextLabel="Listo"`. | canon (
|
|
61
|
-
| orden | secundario a la izquierda, primario a la derecha | Ya lo hace el componente (stroke neutral + filled primary), igual que `sui-modal-footer`. | canon (
|
|
60
|
+
| `backLabel` · `nextLabel` | texto en español | Los defaults ya son «Atrás» y «Siguiente» (03-10-2026); el último paso pasa `nextLabel="Listo"`. | canon (CANON-SUI §5.1 y §5.3: sentence case, tuteo) |
|
|
61
|
+
| orden | secundario a la izquierda, primario a la derecha | Ya lo hace el componente (stroke neutral + filled primary), igual que `sui-modal-footer`. | canon (CLAUDE.md, «Botones — composición y orden») |
|
|
62
62
|
| `step` | `{ current, total }` | Con `stepper`. Sin `step`, el componente asume **1 de 4**. | propuesta |
|
|
63
63
|
|
|
64
64
|
### Flecha, ícono, texto y cierre
|
|
@@ -73,7 +73,7 @@ una función nueva que conviene mostrar donde está («Aquí programas tus pedid
|
|
|
73
73
|
| `position` | `*-left` · `*-center` · `*-right` | Alinea la flecha con el elemento cuando el popover no puede centrarse sobre él (está cerca de un borde). | propuesta |
|
|
74
74
|
| `icon` | el de lo que se explica | Siempre uno que diga el tema (`calendar-schedule-line` para programar). El default es un ícono de persona. | propuesta |
|
|
75
75
|
| `icon` | `null` | Cuando el texto ya basta y el ícono sería decoración. | propuesta |
|
|
76
|
-
| `title` | frase corta | Qué es, en sentence case y sin punto final. | canon (
|
|
76
|
+
| `title` | frase corta | Qué es, en sentence case y sin punto final. | canon (CANON-SUI §5.1 y §5.2) |
|
|
77
77
|
| `description` | una o dos frases | Qué hace o por qué importa. | propuesta |
|
|
78
78
|
| `dismissIcon` | `true` (default) | Siempre: un recorrido se puede saltar. | propuesta |
|
|
79
79
|
| `dismissIcon` | `false` | No usar hoy. **Cuándo sí:** un paso que no se puede saltar porque sin él no funciona lo siguiente. | propuesta |
|
|
@@ -88,20 +88,24 @@ cada lado; en uno más angosto se sale. El `size` cambia **los botones del pie**
|
|
|
88
88
|
|---|---|---|
|
|
89
89
|
| `small` (default) | 36 px (`sui-button` `small`) | Figma |
|
|
90
90
|
| `medium` | 40 px (`sui-button` `medium`) | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
91
|
+
| `large` | 48 px (`sui-button` `large`) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono. Size nuevo del 04-10-2026 |
|
|
91
92
|
|
|
92
|
-
La X se ve de 24 y **se toca en 40 × 40** en
|
|
93
|
+
La X se ve de 24 y **se toca en 40 × 40** en todos (un `::before` invisible sobre su botón,
|
|
93
94
|
extensión SUI 03-10-2026).
|
|
94
95
|
|
|
95
96
|
| uso | mobile | web | fuente |
|
|
96
97
|
|---|---|---|---|
|
|
97
98
|
| el panel | 320 px (cabe desde 352 px de pantalla) | 320 px | según el componente |
|
|
98
|
-
| botones del pie | `
|
|
99
|
+
| botones del pie | `large` (48) | `small` (36) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
|
|
99
100
|
| la X | se ve de 24, se toca en 40 | igual | canon (aprobado por el dueño, 03-10-2026) |
|
|
100
101
|
|
|
101
102
|
```html
|
|
102
|
-
<sui-popover footer="stretch" [size]="bp.isMobile() ? '
|
|
103
|
+
<sui-popover footer="stretch" [size]="bp.isMobile() ? 'large' : 'small'" … />
|
|
103
104
|
```
|
|
104
105
|
|
|
106
|
+
`large` es el siguiente de la escala del `sui-button` (48, el del footer de los modales). `medium`
|
|
107
|
+
(40) queda para quien ya lo usa: no llega al piso de 44.
|
|
108
|
+
|
|
105
109
|
En mobile, si el recorrido es la bienvenida de la app, conviene una pantalla o un
|
|
106
110
|
`sui-modal-sheet` por paso en vez del popover (propuesta, falta aprobación).
|
|
107
111
|
|
|
@@ -135,7 +139,7 @@ Hoy el popover entero tiene **0 usos**; esto es lo que no se usaría aunque lleg
|
|
|
135
139
|
| `nextLabel` | `string` | `'Siguiente'` |
|
|
136
140
|
| `doubleButton` | `boolean` | `true` |
|
|
137
141
|
| `step` | `{ current: number; total: number } \| null` | `null` |
|
|
138
|
-
| `size` | `'small' \| 'medium'` | `'small'` |
|
|
142
|
+
| `size` | `'small' \| 'medium' \| 'large'` | `'small'` |
|
|
139
143
|
|
|
140
144
|
| output | payload |
|
|
141
145
|
|---|---|
|
|
@@ -152,6 +156,8 @@ Slot: `[data-slot=body]` reemplaza título y descripción.
|
|
|
152
156
|
«Paso X de N» (este último no se puede cambiar).
|
|
153
157
|
- **El ícono por defecto es una persona** (`user-6-line`). Si no quieres ícono, `[icon]="null"`.
|
|
154
158
|
- **`step` vacío = 1 de 4**: con `stepper` o `text-stepper`, pásalo siempre.
|
|
159
|
+
- Con `stepper`, los puntos se leen como «Paso X de N» (`role="img"` con `aria-label`, desde el
|
|
160
|
+
04-10-2026; antes eran `aria-hidden` y el lector no sabía en qué paso iba).
|
|
155
161
|
- **No se posiciona solo**: `position` cambia dónde sale la flecha, no dónde aparece el panel.
|
|
156
162
|
Tampoco se cierra al tocar afuera ni con Escape; cierra quien escucha `(dismissed)`.
|
|
157
163
|
- `position` se lee «borde de la flecha, luego su lugar»: `top-left` es flecha **arriba a la
|
|
@@ -32,7 +32,7 @@ Regla corta: **producto en la grilla de la carta → product-card · producto en
|
|
|
32
32
|
>
|
|
33
33
|
> Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **3
|
|
34
34
|
> product-cards en 2 archivos**: la carta del cliente
|
|
35
|
-
> (`pages/customer/restaurant-menu/restaurant-menu.html:
|
|
35
|
+
> (`pages/customer/restaurant-menu/restaurant-menu.html:323` y `:386`) y la grilla del local
|
|
36
36
|
> (`pages/products/products.html:145`, con `action="edit"`).
|
|
37
37
|
|
|
38
38
|
### Las piezas
|
|
@@ -54,9 +54,10 @@ Regla corta: **producto en la grilla de la carta → product-card · producto en
|
|
|
54
54
|
|
|
55
55
|
Outputs: `openDetail` (toque en la card), `add`, `increment`, `decrement`, `edit`.
|
|
56
56
|
|
|
57
|
-
**Usos de hoy que rompen las reglas:** 0. **
|
|
58
|
-
descuento
|
|
59
|
-
deuda anotada)
|
|
57
|
+
**Usos de hoy que rompen las reglas:** 0. **Pendiente de migrar:** el precio tachado y la chapa de
|
|
58
|
+
descuento ya existen en el DS (`precioLista`, ver «Precio con descuento»), pero la carta los sigue
|
|
59
|
+
dibujando afuera (`pages/customer/restaurant-menu/restaurant-menu.scss:426`, deuda anotada) y
|
|
60
|
+
ninguna de las 3 cards pasa `precioLista` ni `size`.
|
|
60
61
|
|
|
61
62
|
## Tamaño en mobile y en web
|
|
62
63
|
|
|
@@ -67,20 +68,23 @@ El ancho lo da la grilla y la card llena su celda. El `size` cambia **los botone
|
|
|
67
68
|
|---|---|---|---|---|
|
|
68
69
|
| `small` (default) | 36 × 36 | 34 × 36 | 18 / 16 | lo que había en el DS |
|
|
69
70
|
| `medium` | 40 × 40 | 40 × 40 (pill de 104) | 20 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
|
|
71
|
+
| `large` | 44 × 44 | 44 × 44 (pill de 112) | 20 | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono. Size nuevo del 04-10-2026 |
|
|
70
72
|
|
|
71
|
-
En `medium` el stepper (104 px) no entra al lado del precio en la grilla de 2
|
|
72
|
-
el pie envuelve y el stepper baja a su propia línea, a la derecha. El «+» y el
|
|
73
|
-
lado del precio.
|
|
73
|
+
En `medium` y `large` el stepper (104 / 112 px) no entra al lado del precio en la grilla de 2
|
|
74
|
+
columnas de mobile: el pie envuelve y el stepper baja a su propia línea, a la derecha. El «+» y el
|
|
75
|
+
lápiz sí siguen al lado del precio.
|
|
74
76
|
|
|
75
77
|
| uso | mobile | web | fuente |
|
|
76
78
|
|---|---|---|---|
|
|
77
79
|
| grilla de la carta | 2 columnas (`1fr 1fr`, gap 12) | `repeat(auto-fill, minmax(220px, 1fr))` desde 600 px y `minmax(180px, 1fr)` en desktop | lo que hay en la app |
|
|
78
|
-
| botón «+», lápiz, stepper | `
|
|
80
|
+
| botón «+», lápiz, stepper | `large` (44) | `small` (36) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
|
|
79
81
|
|
|
80
82
|
```html
|
|
81
|
-
<sui-product-card [size]="bp.isMobile() ? '
|
|
83
|
+
<sui-product-card [size]="bp.isMobile() ? 'large' : 'small'" … />
|
|
82
84
|
```
|
|
83
85
|
|
|
86
|
+
`medium` (40) queda para quien ya lo usa: no llega al piso de 44 del teléfono.
|
|
87
|
+
|
|
84
88
|
## Precio con descuento
|
|
85
89
|
|
|
86
90
|
`precioLista` es el precio de referencia. Si es **mayor** que `price`, la card pinta el precio en
|
|
@@ -116,7 +120,7 @@ por `::after` y chapa por `::before` sobre `.product__price`), que se borra al m
|
|
|
116
120
|
| `unavailableLabel` | `string` | `'Agotado'` |
|
|
117
121
|
| `action` | `'add' \| 'edit'` | `'add'` |
|
|
118
122
|
| `precioLista` | `number \| null` | `null` |
|
|
119
|
-
| `size` | `'small' \| 'medium'` | `'small'` |
|
|
123
|
+
| `size` | `'small' \| 'medium' \| 'large'` | `'small'` |
|
|
120
124
|
|
|
121
125
|
| output | payload |
|
|
122
126
|
|---|---|
|