@ajuarezso/sui-design-system 0.20.0 → 0.22.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 +75 -80
- package/docs/sui-accordion/README.md +171 -0
- package/docs/sui-activity-feed/README.md +155 -0
- package/docs/sui-activity-filter/README.md +100 -0
- 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 +36 -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-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-select/README.md +130 -0
- package/docs/sui-compact-select-for-input/README.md +120 -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 +148 -0
- package/docs/sui-date-selector/README.md +98 -0
- package/docs/sui-datepicker/README.md +197 -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-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-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-filter/README.md +181 -0
- package/docs/sui-href/README.md +85 -0
- package/docs/sui-image-upload/README.md +200 -0
- package/docs/sui-image-upload-profile/README.md +145 -0
- package/docs/sui-img-retry/README.md +107 -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 +247 -0
- package/docs/sui-integration-switch/README.md +142 -0
- 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 +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-page-header/README.md +123 -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-segmented-control/README.md +3 -0
- package/docs/sui-select/README.md +183 -0
- package/docs/sui-sidebar/README.md +217 -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-switch-label/README.md +3 -0
- package/docs/sui-tab-chips/README.md +188 -0
- package/docs/sui-tab-menu-horizontal/README.md +142 -0
- package/docs/sui-tab-menu-vertical/README.md +136 -0
- package/docs/sui-table/README.md +264 -0
- package/docs/sui-tag-input/README.md +123 -0
- package/docs/sui-textarea/README.md +160 -0
- package/docs/sui-time-picker/README.md +240 -0
- package/docs/sui-toast/README.md +190 -0
- package/docs/sui-tooltip/README.md +201 -0
- 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 +291 -246
- package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ajuarezso-sui-design-system.d.ts +208 -50
|
@@ -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
|
+
```
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-file-upload
|
|
3
|
+
selector: sui-file-upload
|
|
4
|
+
resumen: Área para arrastrar o elegir archivos que no son una foto (PDF, Excel, CSV)
|
|
5
|
+
alternativas: [sui-image-upload (una sola imagen con vista previa: logo, portada, comprobante), sui-image-upload-profile (foto de perfil con botones Subir/Cambiar/Eliminar), sui-file-upload-card (el archivo ya elegido, con su progreso)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-file-upload
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Upload/File Upload](https://sui-design-system.web.app/?path=/docs/molecules-upload-file-upload--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** para subir **documentos**: un PDF, un Excel, un CSV, o varios archivos a la vez. La
|
|
15
|
+
persona arrastra el archivo o toca para buscarlo.
|
|
16
|
+
|
|
17
|
+
**No lo uses** para:
|
|
18
|
+
|
|
19
|
+
- **Una imagen** (logo, portada, foto del producto, captura del Yape): `sui-image-upload`, que
|
|
20
|
+
muestra la vista previa y se integra con el recortador y el compresor de la app.
|
|
21
|
+
- Una foto de perfil con botones: `sui-image-upload-profile`.
|
|
22
|
+
- Mostrar el archivo que ya se eligió: va `sui-file-upload-card` debajo.
|
|
23
|
+
|
|
24
|
+
Regla corta: **foto → image-upload · documento o varios archivos → file-upload · el archivo ya
|
|
25
|
+
elegido → file-upload-card.**
|
|
26
|
+
|
|
27
|
+
## Qué variante usar
|
|
28
|
+
|
|
29
|
+
> **Lo que dice la guía del DS** (página del file upload): es la forma de **arrastrar y soltar, o
|
|
30
|
+
> buscar en el equipo**, para subir un archivo. Su ejemplo arma el texto así: una línea que invita
|
|
31
|
+
> («Elige un archivo o arrástralo aquí»), una línea con **formatos y tamaño máximo** («JPEG, PNG,
|
|
32
|
+
> PDF y MP4, hasta 50 MB») y el botón **«Buscar archivo»**. Trae aparte el ícono por tipo de
|
|
33
|
+
> archivo (en SUI, `sui-file-icon`). No dice cuándo usar cada tamaño. El resto es **propuesta,
|
|
34
|
+
> falta aprobación**.
|
|
35
|
+
>
|
|
36
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. Hoy todo lo que se sube es
|
|
37
|
+
> imagen y va con `sui-image-upload` (13) o con un `<input type="file">` a mano (3: `renewal-modal`,
|
|
38
|
+
> `add-product` y la miniatura de `option-image`; ver el README de `sui-image-upload`).
|
|
39
|
+
|
|
40
|
+
### Textos: `title`, `subtitle`, `browseLabel`
|
|
41
|
+
|
|
42
|
+
| input | cuándo | fuente |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `title` | Qué se sube, en la voz de la persona: «Sube tu carta en PDF», «Arrastra tu Excel aquí». Si se omite, sale «Arrastra y suelta el archivo aquí». | guía (línea que invita) |
|
|
45
|
+
| `subtitle` | **Formatos y tamaño máximo**, siempre: «PDF o Excel, hasta 10 MB». El default «o haz clic para seleccionar» no dice nada que el área no diga. | guía (formatos y tamaño) |
|
|
46
|
+
| `browseLabel` | El default ya es «Buscar archivo»; se pasa solo para otro texto («Elegir foto»). | guía (el botón) · el texto es propuesta |
|
|
47
|
+
|
|
48
|
+
### `accept`, `multiple`, `maxSize`
|
|
49
|
+
|
|
50
|
+
| input | cuándo | fuente |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `accept` | Siempre, con lo mismo que dice el `subtitle`: `".pdf,.xlsx,.csv"`. Si el texto y el filtro no coinciden, la persona elige un archivo que se rechaza. | propuesta |
|
|
53
|
+
| `multiple` | Varios archivos del mismo tipo (las boletas del mes). Con `multiple` cada archivo va en su `sui-file-upload-card`. | propuesta |
|
|
54
|
+
| `maxSize` | Siempre, en **bytes** (`10 * 1024 * 1024`), y el mismo número en el `subtitle`. | propuesta |
|
|
55
|
+
|
|
56
|
+
### `size`
|
|
57
|
+
|
|
58
|
+
| valor | padding | cuándo | fuente |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `small` | 24 | En mobile y dentro de un modal o una card. | propuesta |
|
|
61
|
+
| `medium` (default) | 32 | En web, en una página o un modal ancho. | guía (es el único tamaño que muestra) |
|
|
62
|
+
| `large` | 40 | Cuando subir el archivo es lo único de la pantalla (importar la carta). | propuesta |
|
|
63
|
+
| `xlarge` | 48 | No usar: más aire no ayuda a soltar el archivo. | no usar |
|
|
64
|
+
|
|
65
|
+
### Estados: `error`, `errorMessage`, `disabled`
|
|
66
|
+
|
|
67
|
+
| input | cuándo | fuente |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `error` + `errorMessage` | El archivo se subió y el servidor lo rechazó («El PDF está protegido con clave»). Lo de tamaño y tipo ya lo avisa solo. | propuesta |
|
|
70
|
+
| `disabled` | Mientras se sube, o si ya se llegó al máximo de archivos. | propuesta |
|
|
71
|
+
|
|
72
|
+
Usos de hoy que rompen la regla: **0** (no hay file-upload).
|
|
73
|
+
|
|
74
|
+
## Tamaño en mobile y en web
|
|
75
|
+
|
|
76
|
+
En mobile se toca con el dedo: lo que se toca mide **44 px o más**. Aquí **toda el área se toca**
|
|
77
|
+
(abre el selector), así que pasa en cualquier tamaño; en el celular no se arrastra, por eso va
|
|
78
|
+
más compacta. En pantallas de los dos, con el servicio de breakpoints de la app (`bp`, en
|
|
79
|
+
`services/breakpoints.service.ts`).
|
|
80
|
+
|
|
81
|
+
| uso | mobile | web | fuente |
|
|
82
|
+
|---|---|---|---|
|
|
83
|
+
| subir un documento en un formulario o modal | `small` | `medium` | propuesta |
|
|
84
|
+
| subir es lo único de la pantalla | `medium` | `large` | propuesta |
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<sui-file-upload [size]="bp.isMobile() ? 'small' : 'medium'"
|
|
88
|
+
title="Sube tu carta en PDF" subtitle="PDF, hasta 10 MB"
|
|
89
|
+
accept=".pdf" [maxSize]="10 * 1024 * 1024" (filesSelected)="subir($event)" />
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Llena el ancho del contenedor (antes 400 fijo; extensión SUI, 03-10-2026). El botón «Buscar
|
|
93
|
+
archivo» mide 32 px (`xsmall`) en todos los tamaños: solo, en mobile **no
|
|
94
|
+
llegaría**; pasa porque el área entera también abre el selector.
|
|
95
|
+
|
|
96
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
97
|
+
|
|
98
|
+
Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
|
|
99
|
+
en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
|
|
100
|
+
|
|
101
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| todo el componente (0 usos) | todo lo que se sube hoy es una imagen | la carta del local en PDF o Excel para cargarla, la ficha RUC, los documentos del repartidor escaneados en PDF |
|
|
104
|
+
| `multiple` | no hay subidas de varios archivos | las boletas del mes de un gasto, varias fotos de un reclamo |
|
|
105
|
+
| `size="xlarge"` | más aire no ayuda | ninguno |
|
|
106
|
+
| para imágenes | no muestra la vista previa ni pasa por el recortador | — |
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
<!-- api:inicio -->
|
|
111
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
112
|
+
|
|
113
|
+
| input | tipo | default |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `accept` | `string` | `''` |
|
|
116
|
+
| `multiple` | `boolean` | `false` |
|
|
117
|
+
| `maxSize` | `number` | `0` |
|
|
118
|
+
| `title` | `string \| null` | `null` |
|
|
119
|
+
| `subtitle` | `string \| null` | `null` |
|
|
120
|
+
| `browseLabel` | `string` | `'Buscar archivo'` |
|
|
121
|
+
| `disabled` | `boolean` | `false` |
|
|
122
|
+
| `error` | `boolean` | `false` |
|
|
123
|
+
| `errorMessage` | `string \| null` | `null` |
|
|
124
|
+
| `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
|
|
125
|
+
|
|
126
|
+
| output | payload |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `filesSelected` | `File[]` |
|
|
129
|
+
| `errorEvent` | `string` |
|
|
130
|
+
<!-- api:fin -->
|
|
131
|
+
|
|
132
|
+
## Trampas
|
|
133
|
+
|
|
134
|
+
- `browseLabel` dice «Buscar archivo» por defecto (antes «Browse File»).
|
|
135
|
+
- **Llena el ancho del contenedor** desde el 03-10-2026 (antes medía 400 fijo y había que forzar
|
|
136
|
+
`style="width: 100%"`). Las pantallas que lo dejaban en 400 en un contenedor ancho ahora se
|
|
137
|
+
estiran; para un ancho fijo, se lo pone el consumer al host.
|
|
138
|
+
- **`maxSize` va en bytes**, no en MB. `0` = sin límite.
|
|
139
|
+
- **Emite solo los archivos válidos**: si de tres uno pesa de más, `filesSelected` trae dos y
|
|
140
|
+
`errorEvent` avisa del tercero (con el texto ya armado: «"x.pdf" supera el tamaño máximo (10.0 MB)»).
|
|
141
|
+
- Sin `multiple`, aunque se suelten varios, **emite solo el primero**.
|
|
142
|
+
- `accept` filtra al elegir **y** al soltar, por extensión (`.pdf`) o por tipo (`image/*`).
|
|
143
|
+
- El error interno queda pegado hasta el próximo intento válido; `errorMessage` gana sobre él.
|
|
144
|
+
- **No sube nada**: entrega los `File` y la subida (y el progreso en `sui-file-upload-card`) la
|
|
145
|
+
hace quien lo usa.
|
|
146
|
+
- El atributo `title` del host se borra solo (no sale el tooltip gris del navegador).
|
|
147
|
+
|
|
148
|
+
## Ejemplo
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<sui-file-upload title="Sube tu carta en PDF o Excel" subtitle="PDF o Excel, hasta 10 MB"
|
|
152
|
+
browseLabel="Buscar archivo" accept=".pdf,.xlsx" [maxSize]="10 * 1024 * 1024"
|
|
153
|
+
(filesSelected)="subirCarta($event)" (errorEvent)="avisar($event)" />
|
|
154
|
+
```
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-file-upload-card
|
|
3
|
+
selector: sui-file-upload-card
|
|
4
|
+
resumen: La fila de un archivo que se está subiendo, con su progreso, listo o error para reintentar
|
|
5
|
+
alternativas: [sui-file-upload (el área para elegir el archivo), sui-image-upload (una imagen: muestra la vista previa en vez de la fila), sui-file-icon (un archivo en una lista, sin subida)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-file-upload-card
|
|
9
|
+
|
|
10
|
+
Story: [Molecules/Upload/File Upload Card](https://sui-design-system.web.app/?path=/docs/molecules-upload-file-upload-card--docs)
|
|
11
|
+
|
|
12
|
+
## Cuándo usarlo / cuándo no
|
|
13
|
+
|
|
14
|
+
**Úsalo** debajo de un `sui-file-upload`, una fila por archivo, para mostrar **cómo va la subida**:
|
|
15
|
+
subiendo con su barra, listo, o falló con «Reintentar».
|
|
16
|
+
|
|
17
|
+
**No lo uses** para:
|
|
18
|
+
|
|
19
|
+
- Una imagen: `sui-image-upload` muestra la vista previa, que dice más que un nombre de archivo.
|
|
20
|
+
- Una lista de archivos ya guardados (sin subida): `sui-file-icon` en una fila normal.
|
|
21
|
+
- Un progreso que no es de un archivo: `sui-progress-bar`.
|
|
22
|
+
|
|
23
|
+
## Qué variante usar
|
|
24
|
+
|
|
25
|
+
> **La guía del DS no tiene página para este componente** (su página del file upload solo muestra
|
|
26
|
+
> el área y el ícono por tipo). Todo es **propuesta, falta aprobación**.
|
|
27
|
+
>
|
|
28
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. Las subidas de hoy son de
|
|
29
|
+
> imágenes y avisan con el `subtitle` del image-upload («Procesando…») o lo deshabilitan.
|
|
30
|
+
|
|
31
|
+
### `state`
|
|
32
|
+
|
|
33
|
+
| valor | cuándo | qué muestra | fuente |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| `in-progress` (default) | Mientras sube. Va con `progress`. | barra azul, ícono de carga, X para cancelar | propuesta |
|
|
36
|
+
| `success` | Subió. | check verde, tacho para quitar | propuesta |
|
|
37
|
+
| `error` | Falló. Va con `statusText` que diga por qué. | ícono rojo, «Reintentar», tacho | propuesta |
|
|
38
|
+
|
|
39
|
+
### Textos y datos
|
|
40
|
+
|
|
41
|
+
| input | cuándo | fuente |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `file` | El nombre real del archivo (`'carta-octubre.pdf'`). La extensión da el ícono y el color. | propuesta |
|
|
44
|
+
| `description` | **Siempre** se pasa: el default es un texto de ejemplo («0 KB de 120 KB»). Subiendo: «1,2 MB de 3,4 MB»; listo: «3,4 MB». | propuesta |
|
|
45
|
+
| `progress` | 0–100, solo en `in-progress`. | propuesta |
|
|
46
|
+
| `statusText` | Los defaults ya están en español («Subiendo…», «Completado», «Falló»); en error, mejor el motivo: «Se cortó la conexión». | propuesta |
|
|
47
|
+
| `showStatus=false` | Solo en `success`, cuando el check sobra porque la lista ya dice «Archivos subidos». | propuesta |
|
|
48
|
+
| `retryLabel` | El default ya es «Reintentar». | propuesta |
|
|
49
|
+
|
|
50
|
+
Usos de hoy que rompen la regla: **0**.
|
|
51
|
+
|
|
52
|
+
## Tamaño en mobile y en web
|
|
53
|
+
|
|
54
|
+
**No tiene `size`.** Llena el ancho del contenedor (antes 400 fijo) y la X o el tacho de la derecha
|
|
55
|
+
es un `sui-compact-button` `2xlarge` de **32 px** (Figma: 24), que con el aire de la tarjeta (16 de
|
|
56
|
+
padding, 72 de alto mínimo) se toca bien con el dedo. «Reintentar» sigue siendo un link de 20 px de
|
|
57
|
+
alto: en mobile conviene que la fila entera también reintente.
|
|
58
|
+
|
|
59
|
+
| pieza | mobile | web | fuente |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| ancho | el del contenedor | el del contenedor | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
|
|
62
|
+
| X / tacho | 32 px | 32 px | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
|
|
63
|
+
| «Reintentar» | link de 20 px — **no llega** | link | medido |
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<sui-file-upload-card [file]="a.nombre" [state]="a.estado" [progress]="a.pct"
|
|
67
|
+
[description]="a.peso" (actionClicked)="quitar(a)" (retryClicked)="reintentar(a)" />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## «No usar»: por qué no hoy y cuándo sí
|
|
71
|
+
|
|
72
|
+
Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
|
|
73
|
+
en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
|
|
74
|
+
|
|
75
|
+
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| todo el componente (0 usos) | todo lo que se sube es una imagen y se ve con su vista previa | junto a `sui-file-upload`: la carta en PDF, varias boletas de un gasto, documentos del repartidor |
|
|
78
|
+
| para imágenes | la vista previa dice más que el nombre del archivo | — |
|
|
79
|
+
|
|
80
|
+
## API
|
|
81
|
+
|
|
82
|
+
<!-- api:inicio -->
|
|
83
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
84
|
+
|
|
85
|
+
| input | tipo | default |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `file` | `SuiFileUploadCardFile \| string` | `'file.pdf'` |
|
|
88
|
+
| `description` | `string` | `'0 KB de 120 KB'` |
|
|
89
|
+
| `state` | `'in-progress' \| 'success' \| 'error'` | `'in-progress'` |
|
|
90
|
+
| `progress` | `number` | `10` |
|
|
91
|
+
| `statusText` | `string \| null` | `null` |
|
|
92
|
+
| `showStatus` | `boolean` | `true` |
|
|
93
|
+
| `cancelLabel` | `string` | `'Cancelar subida'` |
|
|
94
|
+
| `removeLabel` | `string` | `'Quitar archivo'` |
|
|
95
|
+
| `progressLabel` | `string` | `'Progreso de la subida'` |
|
|
96
|
+
| `retryLabel` | `string` | `'Reintentar'` |
|
|
97
|
+
|
|
98
|
+
| output | payload |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `actionClicked` | `void` |
|
|
101
|
+
| `retryClicked` | `void` |
|
|
102
|
+
<!-- api:fin -->
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
interface SuiFileUploadCardFile { filename: string; extension?: string; }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Trampas
|
|
109
|
+
|
|
110
|
+
- Los textos de fábrica están en español desde el 03-10-2026: «0 KB de 120 KB», «Subiendo…»,
|
|
111
|
+
«Completado», «Falló», «Reintentar», y para el lector de pantalla «Cancelar subida», «Quitar
|
|
112
|
+
archivo» y «Progreso de la subida» (estos tres, con `cancelLabel`, `removeLabel` y
|
|
113
|
+
`progressLabel`).
|
|
114
|
+
- Llena el ancho del contenedor, igual que `sui-file-upload` (antes 400 fijo).
|
|
115
|
+
- **`progress` arranca en 10**, no en 0.
|
|
116
|
+
- **`actionClicked` significa dos cosas**: cancelar mientras sube y quitar cuando terminó. Quien lo
|
|
117
|
+
usa mira `state` para saber cuál.
|
|
118
|
+
- La barra de progreso es azul, no naranja.
|
|
119
|
+
- No sube nada: refleja el estado que le pasan.
|
|
120
|
+
|
|
121
|
+
## Ejemplo
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<sui-file-upload-card file="carta-octubre.pdf" state="in-progress" [progress]="45"
|
|
125
|
+
description="1,2 MB de 2,6 MB" statusText="Subiendo…" />
|
|
126
|
+
<sui-file-upload-card file="carta-octubre.pdf" state="error" description="2,6 MB"
|
|
127
|
+
statusText="Se cortó la conexión" retryLabel="Reintentar"
|
|
128
|
+
(retryClicked)="reintentar()" (actionClicked)="quitar()" />
|
|
129
|
+
```
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sui-filter
|
|
3
|
+
selector: sui-filter-bar, sui-filter-item, sui-filter-panel-header, sui-filter-panel-footer
|
|
4
|
+
resumen: Piezas de filtros de una lista o tabla del panel; la barra horizontal (buscador, vista, orden) y el panel vertical (fila, cabecera con «Limpiar», pie con «Limpiar» / «Aplicar»)
|
|
5
|
+
alternativas: [sui-segmented-control (2 a 4 vistas que se aplican al instante), sui-compact-select (un filtro suelto), sui-tab-chips (filtros rápidos con chips), sui-activity-filter (filtro del feed de actividad), sui-modal-sheet (el panel de filtros en mobile)]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# sui-filter
|
|
9
|
+
|
|
10
|
+
Story: [Organisms/Filter Bar](https://sui-design-system.web.app/?path=/docs/organisms-filter-bar--docs)
|
|
11
|
+
|
|
12
|
+
Son **cuatro componentes** en una carpeta, sin uno llamado `sui-filter`:
|
|
13
|
+
|
|
14
|
+
- `sui-filter-bar`: la **barra horizontal** arriba de una tabla. Es solo layout: un lado
|
|
15
|
+
izquierdo (`slot="start"`) y uno derecho (`slot="end"`); los controles se proyectan.
|
|
16
|
+
- `sui-filter-item`: una **fila** del panel vertical (una categoría de filtro: «Estado», «Local»).
|
|
17
|
+
- `sui-filter-panel-header`: la **cabecera** del panel, con un link «Limpiar» opcional.
|
|
18
|
+
- `sui-filter-panel-footer`: el **pie** del panel, con «Limpiar» y «Aplicar».
|
|
19
|
+
|
|
20
|
+
El panel vertical **no existe como contenedor**: se arma con header + items + footer dentro de un
|
|
21
|
+
`sui-dropdown-menu` (web) o de un `sui-modal-sheet` (mobile).
|
|
22
|
+
|
|
23
|
+
## Cuándo usarlo / cuándo no
|
|
24
|
+
|
|
25
|
+
**Úsalo** en las listas y tablas del panel del local o del super admin que necesitan filtrar
|
|
26
|
+
(pedidos, productos, repartidores): la barra arriba con el buscador, la vista y el orden; el panel
|
|
27
|
+
cuando hay varias categorías de filtro que se combinan y se aplican juntas.
|
|
28
|
+
|
|
29
|
+
**No lo uses** para:
|
|
30
|
+
|
|
31
|
+
- 2 a 4 vistas que se aplican al tocar (Hoy · Semana · Mes): `sui-segmented-control` solo, sin barra.
|
|
32
|
+
- Un único filtro: un `sui-compact-select` o `sui-select` suelto.
|
|
33
|
+
- Filtros rápidos de un toque en mobile (Todos · Pendientes · Entregados): `sui-tab-chips`.
|
|
34
|
+
- El feed de actividad: `sui-activity-filter`.
|
|
35
|
+
|
|
36
|
+
Regla corta: **barra arriba de una tabla → filter-bar · varias categorías que se aplican juntas →
|
|
37
|
+
panel (header + items + footer) · un filtro suelto → compact-select.**
|
|
38
|
+
|
|
39
|
+
## Qué variante usar
|
|
40
|
+
|
|
41
|
+
> **La guía del DS no tiene página de filtros**: estas piezas salen solo del Figma del DS
|
|
42
|
+
> («Filters»: HorizontalFilter y VerticalFilter). Todo lo de abajo es **propuesta, falta
|
|
43
|
+
> aprobación**, salvo lo marcado canon.
|
|
44
|
+
>
|
|
45
|
+
> Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-dropdown-menu`):
|
|
46
|
+
> **0 usos**. Solo aparecen en la vitrina `master-preview`.
|
|
47
|
+
|
|
48
|
+
### `sui-filter-bar`
|
|
49
|
+
|
|
50
|
+
| variant | cuándo | fuente |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `table` (default) | Arriba de una tabla: a la izquierda la vista (`sui-segmented-control`), a la derecha el buscador (`sui-input type="search"`) y el orden (`sui-select` o `sui-compact-select`). | propuesta (composición del Figma) |
|
|
53
|
+
| `calendar` | Arriba de una vista por fechas: a la izquierda «Hoy» + el rango (`sui-button-group`), a la derecha el buscador. | propuesta (composición del Figma) |
|
|
54
|
+
|
|
55
|
+
`variant` solo marca el host (`data-sui-variant`): **no cambia el layout**. Lo que se ve lo deciden
|
|
56
|
+
los controles que se proyectan.
|
|
57
|
+
|
|
58
|
+
### El panel: `sui-filter-item` + header + footer
|
|
59
|
+
|
|
60
|
+
| pieza | regla | fuente |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `sui-filter-item` `active` | La categoría abierta (la que muestra sus opciones al lado): fondo gris, texto negro, flecha a la derecha. | propuesta (estados del Figma) |
|
|
63
|
+
| `sui-filter-item` `leftIcon` | Un ícono por categoría si ayuda a ubicarla («Estado», «Local», «Repartidor»). | propuesta |
|
|
64
|
+
| `sui-filter-panel-header` `clear` | Pásale texto (`clear="Limpiar"`), no `true`: con `true` dice «Clear». | canon (CANON-SUI §5: copy en español) |
|
|
65
|
+
| `sui-filter-panel-footer` | «Limpiar» a la izquierda (`stroke neutral`), «Aplicar» a la derecha (`filled primary`), mitad y mitad. | canon (orden de `sui-modal-footer`, CLAUDE.md «Botones») |
|
|
66
|
+
| «Limpiar» en header **y** footer | Elegir uno. Con el footer, el header va sin link. | propuesta |
|
|
67
|
+
| `applyButton` deshabilitado | `{ label: 'Aplicar', disabled: !cambio() }` mientras no se toca nada. | propuesta |
|
|
68
|
+
|
|
69
|
+
## Tamaño en mobile y en web
|
|
70
|
+
|
|
71
|
+
Ninguna pieza cambia sola en mobile, salvo la barra, que apila sus dos lados por debajo de 640 px.
|
|
72
|
+
|
|
73
|
+
| pieza | mobile | web | fuente |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| `sui-filter-bar` | sin tamaño; los controles adentro van `large` (48) | sin tamaño; los controles `small` (36) | propuesta (igual que `sui-compact-select` en una barra) |
|
|
76
|
+
| `sui-filter-item` | 36 de alto, no se puede cambiar: debajo de los 44 del dedo | 36 | propuesta |
|
|
77
|
+
| `sui-filter-panel-footer` | `medium` (40) es lo más grande que tiene; en mobile, mejor `sui-modal-footer` (48) dentro de un `sui-modal-sheet` | `small` (36, default) | canon para el 48 de mobile (CLAUDE.md: footer de modal `large`); el resto, propuesta |
|
|
78
|
+
| `sui-filter-panel-header` | sin tamaño | sin tamaño | — |
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<sui-filter-bar>
|
|
82
|
+
<sui-segmented-control slot="start" … />
|
|
83
|
+
<div slot="end">
|
|
84
|
+
<sui-input type="search" [size]="bp.isMobile() ? 'large' : 'small'" placeholder="Buscar pedido…" … />
|
|
85
|
+
</div>
|
|
86
|
+
</sui-filter-bar>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## API
|
|
90
|
+
|
|
91
|
+
<!-- api:inicio -->
|
|
92
|
+
<!-- generada: no editar a mano — `npm run docs` -->
|
|
93
|
+
|
|
94
|
+
### `sui-filter-bar`
|
|
95
|
+
|
|
96
|
+
| input | tipo | default |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `variant` | `'calendar' \| 'table'` | `'table'` |
|
|
99
|
+
|
|
100
|
+
Outputs: ninguno.
|
|
101
|
+
|
|
102
|
+
### `sui-filter-item`
|
|
103
|
+
|
|
104
|
+
| input | tipo | default |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `active` | `boolean` | `false` |
|
|
107
|
+
| `disabled` | `boolean` | `false` |
|
|
108
|
+
| `leftIcon` | `string \| null` | `null` |
|
|
109
|
+
| `activeIcon` | `string` | `'arrow-right-s-line'` |
|
|
110
|
+
|
|
111
|
+
| output | payload |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `selected` | `Event` |
|
|
114
|
+
|
|
115
|
+
### `sui-filter-panel-footer`
|
|
116
|
+
|
|
117
|
+
| input | tipo | default |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `clearButton` | `SuiFooterButtonConfig \| string` | `'Clear'` |
|
|
120
|
+
| `applyButton` | `SuiFooterButtonConfig \| string` | `'Apply'` |
|
|
121
|
+
| `size` | `'small' \| 'medium'` | `'small'` |
|
|
122
|
+
|
|
123
|
+
| output | payload |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `clear` | `void` |
|
|
126
|
+
| `apply` | `void` |
|
|
127
|
+
|
|
128
|
+
### `sui-filter-panel-header`
|
|
129
|
+
|
|
130
|
+
| input | tipo | default |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `label` | `string` | `''` |
|
|
133
|
+
| `leftIcon` | `string \| null` | `null` |
|
|
134
|
+
| `clear` | `string \| boolean` | `false` |
|
|
135
|
+
|
|
136
|
+
| output | payload |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `clearClick` | `void` |
|
|
139
|
+
<!-- api:fin -->
|
|
140
|
+
|
|
141
|
+
Slots de `sui-filter-bar`: `[slot=start]`, `[slot=end]` y el contenido por defecto (fila única si no
|
|
142
|
+
se usan los slots). El label de `sui-filter-item` es su contenido proyectado. `clearButton` y
|
|
143
|
+
`applyButton` aceptan un string o `SuiFooterButtonConfig` (`{ label, disabled? }`, la misma interfaz
|
|
144
|
+
de `sui-drawer-footer`).
|
|
145
|
+
|
|
146
|
+
## Trampas
|
|
147
|
+
|
|
148
|
+
- **Los textos por defecto están en inglés**: «Clear» y «Apply» en el footer, «Clear» en el header con
|
|
149
|
+
`clear=true`. Pásalos siempre.
|
|
150
|
+
- **La barra apila a 640 px; la app cambia a mobile a 767.** Entre 641 y 767 px la app ya está en
|
|
151
|
+
mobile y la barra sigue en una fila.
|
|
152
|
+
- **Varios controles en un lado van en un contenedor.** Cada slot es una fila con 12 px de separación,
|
|
153
|
+
pero un solo elemento por `slot` queda más ordenado (`<div slot="end">`), como en el Figma.
|
|
154
|
+
- **`sui-filter-item` tiene `role="option"`**: el contenedor tiene que llevar `role="listbox"`.
|
|
155
|
+
- **`active` no es «elegido»**: marca la categoría abierta, no un valor aplicado. Para decir que una
|
|
156
|
+
categoría tiene un filtro puesto no hay prop (un `sui-badge` en el label es lo más cercano).
|
|
157
|
+
- **El footer separa sus botones 16 px** (del Figma); el canon de la app entre botones hermanos es 12
|
|
158
|
+
(CANON-SUI §0, `sui-modal-footer`).
|
|
159
|
+
- El footer no llega a `large`: en mobile queda más chico que el footer de cualquier modal.
|
|
160
|
+
- `disabled` del item usa opacidad (no está en el Figma).
|
|
161
|
+
|
|
162
|
+
## Ejemplo
|
|
163
|
+
|
|
164
|
+
```html
|
|
165
|
+
<!-- Panel de filtros en web, anclado a un botón «Filtros» -->
|
|
166
|
+
<sui-dropdown-menu #filtros="suiDropdownMenu" [minWidth]="320">
|
|
167
|
+
<sui-button trigger variant="stroke" color="neutral" size="small">Filtros</sui-button>
|
|
168
|
+
<ng-template suiDropdownPanel>
|
|
169
|
+
<sui-filter-panel-header label="Filtros" leftIcon="equalizer-line" />
|
|
170
|
+
<div role="listbox" aria-label="Categorías de filtro">
|
|
171
|
+
<sui-filter-item leftIcon="checkbox-circle-line" [active]="cat() === 'estado'"
|
|
172
|
+
(selected)="cat.set('estado')">Estado</sui-filter-item>
|
|
173
|
+
<sui-filter-item leftIcon="store-2-line" [active]="cat() === 'local'"
|
|
174
|
+
(selected)="cat.set('local')">Local</sui-filter-item>
|
|
175
|
+
</div>
|
|
176
|
+
<sui-filter-panel-footer clearButton="Limpiar"
|
|
177
|
+
[applyButton]="{ label: 'Aplicar', disabled: !cambio() }"
|
|
178
|
+
(clear)="limpiar()" (apply)="filtros.close(); aplicar()" />
|
|
179
|
+
</ng-template>
|
|
180
|
+
</sui-dropdown-menu>
|
|
181
|
+
```
|