@ajuarezso/sui-design-system 0.25.0 → 0.25.1
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/sui-accordion/README.md +83 -9
- package/docs/sui-activity-feed/README.md +55 -1
- package/docs/sui-activity-filter/README.md +50 -1
- package/docs/sui-alert/README.md +54 -0
- package/docs/sui-app-store-badge/README.md +57 -3
- package/docs/sui-avatar/README.md +66 -6
- package/docs/sui-avatar-group/README.md +64 -2
- package/docs/sui-badge/README.md +79 -11
- package/docs/sui-banner/README.md +70 -5
- package/docs/sui-brand-logo/README.md +77 -14
- package/docs/sui-breadcrumb-item/README.md +51 -0
- package/docs/sui-breadcrumbs/README.md +48 -0
- package/docs/sui-button/README.md +68 -6
- package/docs/sui-button-group/README.md +70 -5
- package/docs/sui-button-group-item/README.md +68 -4
- package/docs/sui-card/README.md +97 -10
- package/docs/sui-chart-legend/README.md +53 -0
- package/docs/sui-chart-legend-dot/README.md +49 -0
- package/docs/sui-checkbox/README.md +106 -26
- package/docs/sui-checkbox-card/README.md +58 -2
- package/docs/sui-checkbox-label/README.md +89 -23
- package/docs/sui-circular-progress-bar/README.md +63 -5
- package/docs/sui-color-dot/README.md +61 -5
- package/docs/sui-color-picker/README.md +62 -4
- package/docs/sui-command-menu-footer/README.md +49 -0
- package/docs/sui-command-menu-item/README.md +63 -4
- package/docs/sui-command-menu-search/README.md +58 -4
- package/docs/sui-compact-avatar-group/README.md +61 -4
- package/docs/sui-compact-button/README.md +112 -28
- package/docs/sui-compact-select/README.md +58 -4
- package/docs/sui-compact-select-for-input/README.md +69 -5
- package/docs/sui-content-card/README.md +63 -2
- package/docs/sui-content-divider/README.md +49 -1
- package/docs/sui-content-label/README.md +83 -4
- package/docs/sui-counter-input/README.md +91 -7
- package/docs/sui-date-selector/README.md +61 -3
- package/docs/sui-datepicker/README.md +72 -5
- package/docs/sui-day-cell/README.md +60 -3
- package/docs/sui-day-label/README.md +52 -3
- package/docs/sui-divider/README.md +57 -5
- package/docs/sui-drawer-footer/README.md +63 -2
- package/docs/sui-drawer-header/README.md +60 -3
- package/docs/sui-dropdown-caption/README.md +53 -1
- package/docs/sui-dropdown-item/README.md +72 -6
- package/docs/sui-dropdown-menu/README.md +74 -5
- package/docs/sui-dropdown-search/README.md +57 -1
- package/docs/sui-emoji/README.md +82 -18
- package/docs/sui-empty-state/README.md +68 -4
- package/docs/sui-fancy-button/README.md +59 -1
- package/docs/sui-file-icon/README.md +56 -1
- package/docs/sui-file-upload/README.md +69 -9
- package/docs/sui-file-upload-card/README.md +53 -2
- package/docs/sui-filter/README.md +74 -5
- package/docs/sui-flag/README.md +62 -1
- package/docs/sui-form-hint/README.md +54 -5
- package/docs/sui-form-label/README.md +53 -1
- package/docs/sui-href/README.md +47 -0
- package/docs/sui-icon/README.md +69 -4
- package/docs/sui-image-upload/README.md +70 -3
- package/docs/sui-image-upload-profile/README.md +58 -0
- package/docs/sui-img-retry/README.md +49 -0
- package/docs/sui-inline-input/README.md +61 -3
- package/docs/sui-inline-select/README.md +60 -0
- package/docs/sui-input/README.md +77 -14
- package/docs/sui-integration-switch/README.md +69 -2
- package/docs/sui-kbd/README.md +71 -7
- package/docs/sui-key-icon/README.md +65 -6
- package/docs/sui-link-button/README.md +79 -13
- package/docs/sui-logo/README.md +74 -4
- package/docs/sui-modal/README.md +61 -2
- package/docs/sui-modal-footer/README.md +83 -9
- package/docs/sui-modal-header/README.md +56 -0
- package/docs/sui-modal-sheet/README.md +72 -10
- package/docs/sui-notification/README.md +71 -1
- package/docs/sui-notification-footer/README.md +51 -1
- package/docs/sui-notification-tab-menu/README.md +57 -1
- package/docs/sui-otp-input/README.md +67 -6
- package/docs/sui-page-header/README.md +83 -15
- package/docs/sui-pagination/README.md +60 -0
- package/docs/sui-password-strength/README.md +50 -1
- package/docs/sui-payment-icon/README.md +66 -7
- package/docs/sui-period-range/README.md +65 -6
- package/docs/sui-popover/README.md +73 -7
- package/docs/sui-product-card/README.md +76 -8
- package/docs/sui-progress-bar/README.md +72 -8
- package/docs/sui-progress-bar-label/README.md +69 -12
- package/docs/sui-radio/README.md +83 -6
- package/docs/sui-radio-card/README.md +58 -4
- package/docs/sui-radio-label/README.md +86 -19
- package/docs/sui-rating/README.md +81 -14
- package/docs/sui-rich-editor/README.md +45 -0
- package/docs/sui-segmented-control/README.md +83 -14
- package/docs/sui-select/README.md +72 -3
- package/docs/sui-sidebar/README.md +64 -9
- package/docs/sui-slider/README.md +68 -1
- package/docs/sui-social-button/README.md +63 -3
- package/docs/sui-status-badge/README.md +64 -6
- package/docs/sui-stepper/README.md +57 -0
- package/docs/sui-store-card/README.md +71 -8
- package/docs/sui-switch/README.md +80 -9
- package/docs/sui-switch-card/README.md +70 -6
- package/docs/sui-switch-label/README.md +90 -13
- package/docs/sui-tab-chips/README.md +79 -9
- package/docs/sui-tab-menu-horizontal/README.md +62 -1
- package/docs/sui-tab-menu-vertical/README.md +56 -3
- package/docs/sui-table/README.md +68 -7
- package/docs/sui-tag/README.md +75 -4
- package/docs/sui-tag-input/README.md +71 -7
- package/docs/sui-textarea/README.md +78 -11
- package/docs/sui-time-picker/README.md +70 -7
- package/docs/sui-toast/README.md +65 -5
- package/docs/sui-tooltip/README.md +61 -4
- package/docs/sui-topbar/README.md +57 -3
- package/docs/sui-topbar-button/README.md +57 -3
- package/docs/sui-topbar-item/README.md +61 -0
- package/docs/sui-topbar-user/README.md +56 -0
- package/package.json +1 -1
- package/types/ajuarezso-sui-design-system.d.ts +19 -19
package/docs/sui-href/README.md
CHANGED
|
@@ -44,6 +44,15 @@ No tiene variantes. Lo que decide qué hace es la URL:
|
|
|
44
44
|
|
|
45
45
|
No aplica: es una directiva, no dibuja nada. El tamaño es el del componente que la usa.
|
|
46
46
|
|
|
47
|
+
### Por dispositivo (D16)
|
|
48
|
+
|
|
49
|
+
No aplica: es una directiva sobre un `<a>` y **no tiene `size`** ni dibuja nada. El tamaño por
|
|
50
|
+
dispositivo lo pone el componente que la usa (`sui-link-button`, `sui-compact-button`,
|
|
51
|
+
`sui-fancy-button`…), cada uno con su fila de D16 (dueño, 05-10-2026). Lo mismo en el ultrawide.
|
|
52
|
+
|
|
53
|
+
En master-pedidos: nada que pasar a `suiHref`; el `[size]` va en el componente que la lleva
|
|
54
|
+
(p. ej. `<sui-fancy-button [size]="bp.sizeControl()" href="/cliente/pedidos">`).
|
|
55
|
+
|
|
47
56
|
## API
|
|
48
57
|
|
|
49
58
|
<!-- api:inicio -->
|
|
@@ -70,6 +79,44 @@ Solo se aplica a `<a>` (`selector: a[suiHref]`).
|
|
|
70
79
|
- Un `href` relativo sin `/` inicial (`pedidos/123`) **no** se intercepta: lo resuelve el
|
|
71
80
|
navegador contra la URL actual y recarga. Pasa rutas absolutas.
|
|
72
81
|
|
|
82
|
+
## Bien y mal
|
|
83
|
+
|
|
84
|
+
Link interno en una plantilla de la app
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<!-- ❌ mal: no marca el link activo y la app usa routerLink (98 usos, 0 de suiHref) -->
|
|
88
|
+
<a suiHref="/cliente/pedidos">Mis pedidos</a>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<!-- ✅ bien -->
|
|
93
|
+
<a routerLink="/cliente/pedidos" routerLinkActive="activo">Mis pedidos</a>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Ruta sin `/` inicial (el `href` que la app le pasa a un componente del DS)
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<!-- ❌ mal: sui-link-button lo pinta con suiHref, pero un href relativo no se intercepta; el navegador lo resuelve y recarga el WebView -->
|
|
100
|
+
<sui-link-button [href]="'pedidos/' + id()">Ver pedido</sui-link-button>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<!-- ✅ bien -->
|
|
105
|
+
<sui-link-button [href]="'/cliente/pedidos/' + id()">Ver pedido</sui-link-button>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`href` configurable dentro de un componente del DS
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<!-- ❌ mal: con [attr.href] un link interno recarga la app entera (en Capacitor pierde el estado) -->
|
|
112
|
+
<a class="sui-link-button" [attr.href]="href()" [attr.target]="target()"><ng-content /></a>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<!-- ✅ bien -->
|
|
117
|
+
<a class="sui-link-button" [suiHref]="href()" [attr.target]="target()"><ng-content /></a>
|
|
118
|
+
```
|
|
119
|
+
|
|
73
120
|
## Ejemplo
|
|
74
121
|
|
|
75
122
|
```html
|
package/docs/sui-icon/README.md
CHANGED
|
@@ -76,8 +76,8 @@ propios del DS (`info-custom-fill`, `heart-half-fill`…) también pasan por aqu
|
|
|
76
76
|
En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
|
|
77
77
|
pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
|
|
78
78
|
breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
|
|
79
|
-
el celular (cliente, repartidor)
|
|
80
|
-
con el valor de web, y el celular chico (< 380 px) también (D16).
|
|
79
|
+
el celular (cliente, repartidor) también se usa `bp`, porque el celular chico va con el valor de
|
|
80
|
+
web. No se toca, así que la tablet va con el valor de web, y el celular chico (< 380 px) también (D16).
|
|
81
81
|
Es **canon (dueño, 05-10-2026, P1 b)**: un paso más grande en el celular que en computadora, y
|
|
82
82
|
se migra todo ahora, no solo al tocar cada pantalla.
|
|
83
83
|
|
|
@@ -89,12 +89,36 @@ se migra todo ahora, no solo al tocar cada pantalla.
|
|
|
89
89
|
| dentro de un botón o un input | lo decide el componente | igual |
|
|
90
90
|
|
|
91
91
|
```html
|
|
92
|
-
<sui-icon name="store-2-line" [size]="bp.
|
|
92
|
+
<sui-icon name="store-2-line" [size]="bp.celular() ? 20 : 16" />
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
Un ícono suelto **nunca** es el área táctil: si se toca, va en `sui-compact-button` o
|
|
96
96
|
`sui-button` `onlyIcon`, que dan los 44 px. Hoy solo 2 íconos cambian por breakpoint
|
|
97
|
-
(`pages/discounts/discounts.html:103` y `:108`, con `bp.isTablet() ? 20 : 16`)
|
|
97
|
+
(`pages/discounts/discounts.html:103` y `:108`, con `bp.isTablet() ? 20 : 16`), y los dos están
|
|
98
|
+
mal: van dentro de un `sui-button`, que ya le da al ícono una caja de 20, así que no llevan
|
|
99
|
+
`size`. Hasta 1024 px dibujan 20 y llenan la caja (no se nota); en una computadora de más de
|
|
100
|
+
1024 px dibujan 16 y el glifo queda chico dentro de esa caja. Además `isTablet` no es un corte
|
|
101
|
+
de D16 (ver «Bien y mal»).
|
|
102
|
+
|
|
103
|
+
### Por dispositivo (D16)
|
|
104
|
+
|
|
105
|
+
El ícono no se toca: sube un paso **solo en el celular de 380 px o más**. Fuente: D16, dueño
|
|
106
|
+
05-10-2026 (P1 b).
|
|
107
|
+
|
|
108
|
+
| dispositivo | size | nota |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| celular chico (< 380) | valor «web» (`16` en una fila, `24` protagonista) | no se toca: no sube aunque sea un celular |
|
|
111
|
+
| celular (380–767) | valor «mobile» (`20` junto al texto de una fila, `32` protagonista) | un paso más que en la computadora |
|
|
112
|
+
| tablet táctil (`pointer: coarse`) | valor «web» (`16` en una fila, `24` protagonista) | no se toca: el puntero no cambia nada |
|
|
113
|
+
| computadora (`pointer: fine`) | valor «web» (`16` en una fila, `24` protagonista) | |
|
|
114
|
+
|
|
115
|
+
En el ultrawide, igual que en la computadora: el espacio extra va a más columnas, no a íconos
|
|
116
|
+
más grandes. Dentro de un botón o un input no se pasa `size`: lo decide el componente.
|
|
117
|
+
|
|
118
|
+
En master-pedidos no hay helper: `[size]="bp.celular() ? 20 : 16"` (fila) o
|
|
119
|
+
`[size]="bp.celular() ? 32 : 24"` (protagonista). No uses `bp.isMobile()` (incluye el celular
|
|
120
|
+
chico) ni `bp.isTablet()` (incluye la tablet y la laptop de hasta 1024 px): los dos van con el
|
|
121
|
+
valor de web.
|
|
98
122
|
|
|
99
123
|
## «No usar»: por qué no hoy y cuándo sí
|
|
100
124
|
|
|
@@ -131,6 +155,47 @@ Outputs: ninguno.
|
|
|
131
155
|
el paquete del DS no la trae.
|
|
132
156
|
- Dentro de un `sui-kbd`, el kbd le fuerza el color `text-sub-600`.
|
|
133
157
|
|
|
158
|
+
## Bien y mal
|
|
159
|
+
|
|
160
|
+
Ícono de una acción en una tabla
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<!-- ❌ mal: el botón ya le da al ícono su caja de 20 y no hace falta size; en la computadora de más de 1024 px isTablet dibuja el glifo en 16 dentro de ella (pages/discounts/discounts.html:103) -->
|
|
164
|
+
<sui-button variant="ghost" color="neutral" [size]="bp.sizeControl()" [onlyIcon]="true" aria-label="Editar">
|
|
165
|
+
<sui-icon data-slot="start" name="edit-2-line" [size]="bp.isTablet() ? 20 : 16" />
|
|
166
|
+
</sui-button>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```html
|
|
170
|
+
<!-- ✅ bien -->
|
|
171
|
+
<sui-button variant="ghost" color="neutral" [size]="bp.sizeControl()" [onlyIcon]="true"
|
|
172
|
+
leftIcon="edit-2-line" aria-label="Editar" />
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Ícono protagonista
|
|
176
|
+
|
|
177
|
+
```html
|
|
178
|
+
<!-- ❌ mal: 28 está fuera de la escala y no cambia por dispositivo (pages/envios/envios.html:712) -->
|
|
179
|
+
<sui-icon class="seg__buscando-icono" name="e-bike-2-line" [size]="28" />
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<!-- ✅ bien -->
|
|
184
|
+
<sui-icon class="seg__buscando-icono" name="e-bike-2-line" [size]="bp.celular() ? 32 : 24" />
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Tamaño como texto
|
|
188
|
+
|
|
189
|
+
```html
|
|
190
|
+
<!-- ❌ mal: un string sin unidad no es un tamaño CSS válido; el ícono no toma tamaño (Trampas) -->
|
|
191
|
+
<sui-icon name="time-line" size="20" />
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```html
|
|
195
|
+
<!-- ✅ bien -->
|
|
196
|
+
<sui-icon name="time-line" [size]="20" />
|
|
197
|
+
```
|
|
198
|
+
|
|
134
199
|
## Ejemplo
|
|
135
200
|
|
|
136
201
|
```html
|
|
@@ -100,8 +100,8 @@ El archivo que entrega **no se sube tal cual**: pasa por `ImageCompressorService
|
|
|
100
100
|
En mobile se toca con el dedo: lo que se toca mide **44 px o más** (canon (dueño, 04-10-2026): piso táctil 44 en el teléfono). El área vacía se
|
|
101
101
|
toca entera (80 a 200 px), así que pasa. Los botones con imagen se **ven** de 40 (lápiz y tacho) y
|
|
102
102
|
32 («Quitar»), pero en el teléfono (≤ 767 px) **se tocan en 44 de alto** con un `::before`
|
|
103
|
-
invisible (04-10-2026).
|
|
104
|
-
(
|
|
103
|
+
invisible (04-10-2026). Aquí `bp` no elige nada: `size` va por la forma de la imagen y lo que se
|
|
104
|
+
toca ya tiene su área sola (ver «Por dispositivo (D16)»).
|
|
105
105
|
|
|
106
106
|
**Por qué no hay un size nuevo**: aquí `size` (`sm`/`md`/`lg`/`xl`) es el tamaño de la **foto**, no
|
|
107
107
|
el de los botones. Un `2xl` agrandaría la imagen sin que nadie lo pida; el área invisible lleva lo
|
|
@@ -115,7 +115,7 @@ que se toca a 44 sin cambiar el dibujo ni los sizes de hoy.
|
|
|
115
115
|
| «Quitar» (sin `editable`) | se ve de 32 (`sui-button` `xsmall`), se toca en 44 de alto: crece 4 hacia la foto (la mitad del gap de 8) y 8 hacia abajo | 32 px | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono (área) · canon (aprobado por el dueño, 03-10-2026) |
|
|
116
116
|
|
|
117
117
|
```html
|
|
118
|
-
<sui-image-upload shape="rect"
|
|
118
|
+
<sui-image-upload shape="rect" size="xl" [editable]="true"
|
|
119
119
|
[src]="logo()" [maxSize]="50 * 1024 * 1024" title="Sube tu logo"
|
|
120
120
|
subtitle="JPG, PNG o WebP — máx 50 MB"
|
|
121
121
|
(imageSelected)="alElegirLogo($event)" (editRequested)="abrirRecortador()"
|
|
@@ -127,6 +127,27 @@ de 40 y quedan en 32) y el «Quitar» es un `sui-button` `xsmall` de **32** (ant
|
|
|
127
127
|
los dos botones van centrados abajo, dentro del círculo. Lo que haya justo debajo del «Quitar»
|
|
128
128
|
pierde 8 px de toque en el teléfono: no pegarle otro control sin margen.
|
|
129
129
|
|
|
130
|
+
### Por dispositivo (D16)
|
|
131
|
+
|
|
132
|
+
D16 (dueño, 05-10-2026) no mueve `size`: aquí `size` es el tamaño de la **foto**, no el de lo que
|
|
133
|
+
se toca, así que no sigue la escala «lo que se toca / lo que no se toca». Se elige por la forma de
|
|
134
|
+
la imagen (`xl` para lo cuadrado, `fluid` para capturas y apaisadas) y por el layout, igual que en
|
|
135
|
+
la tabla de arriba: `xl` en una columna, que es lo que hay en el celular, el celular chico y la
|
|
136
|
+
tablet; `lg` solo cuando la foto comparte la fila con el nombre (hoy ninguna pantalla lo hace:
|
|
137
|
+
los 3 `lg` medidos son el logo del onboarding y el banner y el comprobante de promociones, que
|
|
138
|
+
además van `fluid`; ninguno está en una fila).
|
|
139
|
+
Lo que decide entre `xl` y `lg` es si hay fila, no el dispositivo: cuando una pantalla arme esa
|
|
140
|
+
fila según el ancho, la condición es el mismo corte del layout de la pantalla, no
|
|
141
|
+
`bp.celular()` ni `bp.tactil()`.
|
|
142
|
+
|
|
143
|
+
Lo que se toca (lápiz, tacho, «Quitar») ya llega a 44 de alto en el celular y en el celular chico
|
|
144
|
+
con el área invisible (`@media (max-width: 767px)`). En la **tablet táctil** (`pointer: coarse`,
|
|
145
|
+
más de 767 px) esa área no se prende y quedan en 40 y 32: **pendiente**, espera el mixin
|
|
146
|
+
`sui-tactil` del DS que propone §0 de las decisiones (sin el sí del dueño todavía).
|
|
147
|
+
|
|
148
|
+
En master-pedidos: no hay helper de D16; `size="xl"` para lo cuadrado y `[fluid]="true"` para
|
|
149
|
+
capturas y apaisadas. `lg` solo en la fila del nombre, con la condición del layout de esa pantalla.
|
|
150
|
+
|
|
130
151
|
## «No usar»: por qué no hoy y cuándo sí
|
|
131
152
|
|
|
132
153
|
Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
|
|
@@ -195,6 +216,52 @@ recortador; se llama con una referencia: `#qr` → `qr.abrirSelector()`).
|
|
|
195
216
|
- El atributo `title` del host se borra solo (no sale el tooltip gris del navegador).
|
|
196
217
|
- Ya trae el arreglo de iOS para el `:active` pegado.
|
|
197
218
|
|
|
219
|
+
## Bien y mal
|
|
220
|
+
|
|
221
|
+
Logo del local
|
|
222
|
+
|
|
223
|
+
```html
|
|
224
|
+
<!-- ❌ mal: el logo se ve cuadrado en el home, no en círculo; en 160 (lg) en una columna, donde va xl; y sin lápiz (pages/business-onboarding/step-info/step-info.html:42) -->
|
|
225
|
+
<sui-image-upload shape="circle" size="lg" [(src)]="logoPreview" title="Subir logo"
|
|
226
|
+
(imageSelected)="onLogoSelected($event)" />
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```html
|
|
230
|
+
<!-- ✅ bien -->
|
|
231
|
+
<sui-image-upload shape="rect" size="xl" [editable]="true" [(src)]="logoPreview" title="Sube tu logo"
|
|
232
|
+
(imageSelected)="onLogoSelected($event)" (editRequested)="abrirRecortador()" />
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Comprobante de pago
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<!-- ❌ mal: una captura vertical se recorta en el cuadrado de 200 y el «Quitar» queda en 32 (pages/central/central-gastos/central-gastos.html:118) -->
|
|
239
|
+
<sui-image-upload shape="rect" size="xl" [src]="vistaComprobante()" [maxSize]="10 * 1024 * 1024"
|
|
240
|
+
title="Subir comprobante" (imageSelected)="onComprobante($event)" (removed)="quitarComprobante()" />
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<!-- ✅ bien -->
|
|
245
|
+
<sui-image-upload #comprobante shape="rect" [fluid]="true" [editable]="true" [src]="vistaComprobante()"
|
|
246
|
+
[maxSize]="10 * 1024 * 1024" title="Sube el comprobante" (imageSelected)="onComprobante($event)"
|
|
247
|
+
(editRequested)="comprobante.abrirSelector()" (removed)="quitarComprobante()" />
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Banner apaisado
|
|
251
|
+
|
|
252
|
+
```html
|
|
253
|
+
<!-- ❌ mal: con fluid, size no hace nada; y sin editable (pages/promociones/promociones.html:186) -->
|
|
254
|
+
<sui-image-upload shape="rect" size="lg" [fluid]="true" [src]="campaignBannerPreview()"
|
|
255
|
+
title="Subir banner" (imageSelected)="onBannerImage($event)" />
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```html
|
|
259
|
+
<!-- ✅ bien -->
|
|
260
|
+
<sui-image-upload #banner shape="rect" [fluid]="true" [editable]="true" [src]="campaignBannerPreview()"
|
|
261
|
+
title="Sube el banner" (imageSelected)="onBannerImage($event)"
|
|
262
|
+
(editRequested)="banner.abrirSelector()" (removed)="onBannerRemoved()" />
|
|
263
|
+
```
|
|
264
|
+
|
|
198
265
|
## Ejemplo
|
|
199
266
|
|
|
200
267
|
```html
|
|
@@ -81,6 +81,22 @@ Usos de hoy que rompen la regla: **0**.
|
|
|
81
81
|
**Sin tamaño suficiente para mobile.** Hace falta en el DS un `size` que lleve los botones a
|
|
82
82
|
`large` (48 px). Mientras tanto, en el celular va `sui-image-upload` `circle` `xl`.
|
|
83
83
|
|
|
84
|
+
### Por dispositivo (D16)
|
|
85
|
+
|
|
86
|
+
No aplica: **no tiene `size`** y nada cambia por dispositivo (avatar de 64/56 y botones `xsmall`
|
|
87
|
+
de 32 fijos). Con D16 (dueño, 05-10-2026) lo que se toca va `large` en el celular y en la tablet
|
|
88
|
+
táctil, y esos botones no llegan a 44, así que en una pantalla táctil no se usa:
|
|
89
|
+
|
|
90
|
+
| dispositivo | qué va | ¿llega a 44? |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| celular y celular chico (≤ 767) | `sui-image-upload` `circle` `xl` con `[editable]="true"` | sí: su lápiz y su tacho se tocan en 44 con el área invisible |
|
|
93
|
+
| tablet táctil (`pointer: coarse`, > 767) | `sui-image-upload` `circle` `xl` con `[editable]="true"` (40 contra 32, el que más se acerca) | **no, pendiente**: el área de 44 de `sui-image-upload` se prende solo hasta 767 px y en la tablet quedan en 40; espera el mixin `sui-tactil` del DS (§0 de las decisiones, sin el sí del dueño todavía) |
|
|
94
|
+
| computadora y ultrawide | este componente, botones de 32 | no hace falta 44; se queda en 32 porque solo tiene ese tamaño de botón. Subirlo a `medium` es código del DS (un `size`), **pendiente** |
|
|
95
|
+
|
|
96
|
+
En master-pedidos: no lleva `[size]`; si la pantalla se usa en un dispositivo táctil,
|
|
97
|
+
`@if (!bp.tactil())` para este componente y `sui-image-upload` en el otro caso (con la tablet
|
|
98
|
+
todavía en 40, ver la tabla).
|
|
99
|
+
|
|
84
100
|
## «No usar»: por qué no hoy y cuándo sí
|
|
85
101
|
|
|
86
102
|
Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
|
|
@@ -137,6 +153,48 @@ interface SuiImageUploadProfileLabels { upload?: string; remove?: string; change
|
|
|
137
153
|
- El atributo `title` del host se borra solo (no sale el tooltip gris del navegador); el `title`
|
|
138
154
|
sí se usa como `alt` de la foto.
|
|
139
155
|
|
|
156
|
+
## Bien y mal
|
|
157
|
+
|
|
158
|
+
Logo del local
|
|
159
|
+
|
|
160
|
+
```html
|
|
161
|
+
<!-- ❌ mal: company lo muestra en círculo y el logo se ve cuadrado en el home (vitrina: pages/super-admin/master-preview/_guia-moleculas/fechas.ts:233) -->
|
|
162
|
+
<sui-image-upload-profile type="company" title="Logo del local" subtitle="JPG o PNG, cuadrado" />
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```html
|
|
166
|
+
<!-- ✅ bien -->
|
|
167
|
+
<sui-image-upload shape="rect" size="xl" [editable]="true" [src]="logo()" title="Sube tu logo"
|
|
168
|
+
(imageSelected)="alElegirLogo($event)" (editRequested)="abrirRecortador()" />
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Subir la foto
|
|
172
|
+
|
|
173
|
+
```html
|
|
174
|
+
<!-- ❌ mal: no tiene input de archivo; «Subir» y «Cambiar» solo emiten y no abren nada (Trampas) -->
|
|
175
|
+
<sui-image-upload-profile title="Foto de perfil" [imageUrl]="foto()" (upload)="subir()" />
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<!-- ✅ bien -->
|
|
180
|
+
<sui-image-upload-profile title="Foto de perfil" [imageUrl]="foto()" [loading]="subiendo()"
|
|
181
|
+
(upload)="input.click()" (change)="input.click()" (remove)="quitar()" />
|
|
182
|
+
<input #input type="file" accept="image/jpeg,image/png,image/webp" hidden (change)="alElegir($event)" />
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Foto de perfil en el celular
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<!-- ❌ mal: los botones miden 32 y en una pantalla táctil no llegan a 44 (D16) -->
|
|
189
|
+
<sui-image-upload-profile title="Tu foto" [imageUrl]="foto()" (upload)="input.click()" />
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```html
|
|
193
|
+
<!-- ✅ bien -->
|
|
194
|
+
<sui-image-upload shape="circle" size="xl" [editable]="true" [src]="foto()" title="Sube tu foto"
|
|
195
|
+
(imageSelected)="alElegir($event)" (editRequested)="abrirRecortador()" />
|
|
196
|
+
```
|
|
197
|
+
|
|
140
198
|
## Ejemplo
|
|
141
199
|
|
|
142
200
|
```html
|
|
@@ -52,6 +52,12 @@ No tiene variantes ni inputs. Lo que hace:
|
|
|
52
52
|
|
|
53
53
|
No aplica: es una directiva, no dibuja nada. El tamaño es el del `<img>`.
|
|
54
54
|
|
|
55
|
+
### Por dispositivo (D16)
|
|
56
|
+
|
|
57
|
+
No aplica: no tiene `size` ni escala que repartir por dispositivo (D16, dueño 05-10-2026). El
|
|
58
|
+
`<img>` mide lo que diga el CSS de la pantalla o el componente que lo contiene (`sui-avatar` con
|
|
59
|
+
`bp.sizeAvatar()`, la tarjeta del local), y la directiva se pone igual en todos los dispositivos.
|
|
60
|
+
|
|
55
61
|
## API
|
|
56
62
|
|
|
57
63
|
<!-- api:inicio -->
|
|
@@ -89,6 +95,49 @@ Solo se aplica a `<img>` (`selector: img[suiImgRetry]`). El `src` se pone como s
|
|
|
89
95
|
- **No borra el cache completo** a propósito: solo la entrada de esa URL. Borrarlo todo mataría
|
|
90
96
|
la ventaja de no volver a bajar nada.
|
|
91
97
|
- Funciona igual con `loading="lazy"` y `decoding="async"`.
|
|
98
|
+
- **Con `srcset` no**: el reintento y el `fetch` van sobre `img.src`, no sobre la candidata que el
|
|
99
|
+
navegador eligió (`currentSrc`), así que purgaría la URL equivocada. Va un `src` único (en el home,
|
|
100
|
+
la portada chica de 800 px; ver `master-pedidos/src/app/core/services/state.service.ts:45`).
|
|
101
|
+
|
|
102
|
+
## Bien y mal
|
|
103
|
+
|
|
104
|
+
Logo en las sugerencias de búsqueda
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<!-- ❌ mal: listado del cliente sin la directiva; tras un corte el logo queda roto (pages/customer/favorites/favorites.html:32; la misma sugerencia del home sí la lleva) -->
|
|
108
|
+
<img class="favorites__suggestion-img" [src]="s.logoUrl" [alt]="s.name" loading="lazy" />
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<!-- ✅ bien (con las reglas de sui-img-loaded y data-sui-img-dead en el scss) -->
|
|
113
|
+
<img class="favorites__suggestion-img" suiImgRetry [src]="s.logoUrl" [alt]="s.name"
|
|
114
|
+
loading="lazy" decoding="async" />
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Logo del local con inicial de respaldo
|
|
118
|
+
|
|
119
|
+
```html
|
|
120
|
+
<!-- ❌ mal: el (error) a mano esconde la imagen al primer fallo, sin reintento ni inicial (pages/customer/order-history/order-history.html:168) -->
|
|
121
|
+
<img [src]="logo" [alt]="order.tenantName ?? 'Local'" (error)="$any($event).target.style.display='none'" />
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<!-- ✅ bien: logo con iniciales de respaldo → sui-avatar, no la directiva -->
|
|
126
|
+
<sui-avatar [size]="bp.sizeAvatar('md')" [src]="logo" [initials]="storeInitial(order)"
|
|
127
|
+
[alt]="order.tenantName ?? 'Local'" />
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Portada con varias resoluciones
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<!-- ❌ mal: la directiva reintenta sobre img.src; con srcset purga la candidata equivocada (lo documenta pages/customer/store-browser/store-browser.html:332) -->
|
|
134
|
+
<img class="fila__img" suiImgRetry [src]="store.coverThumbUrl" [srcset]="portadaSrcset(store)" [alt]="store.name" />
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<!-- ✅ bien: src único, del tamaño que pide la tarjeta -->
|
|
139
|
+
<img class="fila__img" suiImgRetry [src]="store.coverThumbUrl" [alt]="store.name" decoding="async" />
|
|
140
|
+
```
|
|
92
141
|
|
|
93
142
|
## Ejemplo
|
|
94
143
|
|
|
@@ -51,13 +51,25 @@ Regla corta: **un dato, en su lugar, que se corrige rápido → inline · varios
|
|
|
51
51
|
**No tiene `size`**: mide 38 px de alto (8 + 20 + 8 de padding y línea, más 1 + 1 de borde) y sus
|
|
52
52
|
botones (lápiz, ✓, ✕) son de 24 × 24 (ícono de 20 + 2 de padding). En edición el texto sube a 16 px
|
|
53
53
|
en mobile (sin zoom de iOS). **No tiene tamaño suficiente para mobile**: los botones
|
|
54
|
-
de 24 px quedan lejos de los 44 que pide un dedo. Usarlo en el panel web; en el teléfono
|
|
55
|
-
con un `sui-input` `large`.
|
|
54
|
+
de 24 px quedan lejos de los 44 que pide un dedo. Usarlo en el panel web; en el teléfono y en la
|
|
55
|
+
tablet táctil, editar con un `sui-input` `large`.
|
|
56
56
|
|
|
57
57
|
| uso | mobile | web |
|
|
58
58
|
|---|---|---|
|
|
59
59
|
| renombrar en una lista | `sui-input` `large` en un modal | este, 38 px |
|
|
60
60
|
|
|
61
|
+
### Por dispositivo (D16)
|
|
62
|
+
|
|
63
|
+
**No tiene `size`**: mide 38 px fijos y sus botones son de 24, así que no hay escala que repartir
|
|
64
|
+
por dispositivo. Lo que sí aplica es la regla de lo que se toca (D16, dueño 05-10-2026): en toda
|
|
65
|
+
pantalla táctil (celular chico, celular y tablet con `pointer: coarse`) los botones de 24 no llegan
|
|
66
|
+
a 44, y ahí se edita con un `sui-input` en un modal. Este queda para la computadora (y el
|
|
67
|
+
ultrawide, igual que ella). La condición es `bp.tactil()` y no `bp.isMobile()`: con `isMobile` el
|
|
68
|
+
iPad se queda con los botones de 24.
|
|
69
|
+
|
|
70
|
+
En master-pedidos: `@if (bp.tactil())` → `sui-input` con `[size]="bp.sizeControl()"` en un modal;
|
|
71
|
+
si no, `sui-inline-input`.
|
|
72
|
+
|
|
61
73
|
## «No usar»: por qué no hoy y cuándo sí
|
|
62
74
|
|
|
63
75
|
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
@@ -90,12 +102,58 @@ Implementa `ControlValueAccessor`.
|
|
|
90
102
|
|
|
91
103
|
## Trampas
|
|
92
104
|
|
|
93
|
-
- **Los defaults están pensados para la story**: `placeholder` «
|
|
105
|
+
- **Los defaults están pensados para la story**: `placeholder` «Escribe aquí…» y
|
|
94
106
|
`leftIcon` `user-3-line`. Pasa los dos siempre.
|
|
95
107
|
- `error` no trae mensaje: decir qué falta en otro lado (toast o hint cercano).
|
|
96
108
|
- Cancelar restaura el texto de antes; `(confirm)` es el único momento de guardar.
|
|
97
109
|
- Ocupa todo el ancho de su contenedor.
|
|
98
110
|
|
|
111
|
+
## Bien y mal
|
|
112
|
+
|
|
113
|
+
Alias de una dirección
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<!-- ❌ mal: con los defaults, vacío dice «Escribe aquí…» y el ícono es una persona (user-3-line) -->
|
|
117
|
+
<sui-inline-input [(value)]="alias" (confirm)="guardarAlias($event)" />
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```html
|
|
121
|
+
<!-- ✅ bien -->
|
|
122
|
+
<sui-inline-input [(value)]="alias" placeholder="Sin alias" leftIcon="map-pin-line"
|
|
123
|
+
editLabel="Editar alias" (confirm)="guardarAlias($event)" />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Formulario reactivo
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<!-- ❌ mal: dos dueños del mismo valor; [(value)] y formControlName se pisan -->
|
|
130
|
+
<sui-inline-input formControlName="nombre" [(value)]="nombre" placeholder="Sin nombre" />
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```html
|
|
134
|
+
<!-- ✅ bien -->
|
|
135
|
+
<sui-inline-input formControlName="nombre" placeholder="Sin nombre" leftIcon="price-tag-3-line"
|
|
136
|
+
editLabel="Editar nombre" (confirm)="renombrar($event)" />
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Renombrar en una pantalla táctil
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<!-- ❌ mal: con bp.isMobile() la tablet táctil se queda con el lápiz, el ✓ y el ✕ de 24 px -->
|
|
143
|
+
@if (!bp.isMobile()) {
|
|
144
|
+
<sui-inline-input [(value)]="nombreCategoria" placeholder="Sin nombre" leftIcon="price-tag-3-line" />
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<!-- ✅ bien (el sui-input va dentro de un sui-modal) -->
|
|
150
|
+
@if (bp.tactil()) {
|
|
151
|
+
<sui-input label="Nombre de la categoría" [size]="bp.sizeControl()" [(value)]="nombreCategoria" />
|
|
152
|
+
} @else {
|
|
153
|
+
<sui-inline-input [(value)]="nombreCategoria" placeholder="Sin nombre" leftIcon="price-tag-3-line" />
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
99
157
|
## Ejemplo
|
|
100
158
|
|
|
101
159
|
```html
|
|
@@ -56,6 +56,20 @@ entera.
|
|
|
56
56
|
Las opciones del menú miden **36 px también en mobile**: a diferencia de `sui-select` y de los
|
|
57
57
|
compactos, este no tiene la regla de 44 en ≤ 767 px (`sui-inline-select.scss` no la trae).
|
|
58
58
|
|
|
59
|
+
### Por dispositivo (D16)
|
|
60
|
+
|
|
61
|
+
**No tiene `size`**: mide 20 px (la línea del texto) en cualquier pantalla, así que no hay escala
|
|
62
|
+
que repartir por dispositivo. D16 (dueño, 05-10-2026) se aplica según dónde va:
|
|
63
|
+
|
|
64
|
+
- **Al final de un `sui-input`**: el alto lo pone el input, que sigue su fila D16 (`large` en el
|
|
65
|
+
celular chico, el celular y la tablet táctil; `medium` en la computadora y el ultrawide).
|
|
66
|
+
- **Dentro de una frase**: solo en la computadora (y el ultrawide). En toda pantalla táctil
|
|
67
|
+
(celular chico, celular y tablet con `pointer: coarse`) la palabra de 20 px no llega a 44: va un
|
|
68
|
+
`sui-select`. La condición es `bp.tactil()`, no `bp.isMobile()`, para que el iPad también cambie.
|
|
69
|
+
|
|
70
|
+
En master-pedidos: el `sui-input` que lo contiene con `[size]="bp.sizeControl()"`; en una frase,
|
|
71
|
+
`@if (bp.tactil())` → `sui-select` con `[size]="bp.sizeControl()"`.
|
|
72
|
+
|
|
59
73
|
## «No usar»: por qué no hoy y cuándo sí
|
|
60
74
|
|
|
61
75
|
| qué | por qué no hoy | cuándo sí, en un flujo nuevo |
|
|
@@ -95,6 +109,52 @@ Implementa `ControlValueAccessor`.
|
|
|
95
109
|
- No mezclar `[(selected)]` con `formControlName`.
|
|
96
110
|
- El menú mide al menos 200 px aunque el texto sea corto.
|
|
97
111
|
|
|
112
|
+
## Bien y mal
|
|
113
|
+
|
|
114
|
+
Unidad al final de un campo
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<!-- ❌ mal: sin [trailingControl] el slot es un ícono de 20 × 20 con pointer-events: none y el selector no responde -->
|
|
118
|
+
<sui-input label="Peso" type="number" [size]="bp.sizeControl()" [(value)]="peso">
|
|
119
|
+
<sui-inline-select data-slot="end" icon="ruler-line" [items]="unidades" [(selected)]="unidad" />
|
|
120
|
+
</sui-input>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<!-- ✅ bien -->
|
|
125
|
+
<sui-input label="Peso" type="number" [size]="bp.sizeControl()" [trailingControl]="true" [(value)]="peso">
|
|
126
|
+
<sui-inline-select data-slot="end" icon="ruler-line" [items]="unidades" [(selected)]="unidad" />
|
|
127
|
+
</sui-input>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Formulario reactivo
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<!-- ❌ mal: dos dueños del mismo valor; [(selected)] y formControlName se pisan -->
|
|
134
|
+
<sui-inline-select formControlName="periodo" [items]="periodos" [(selected)]="periodo" />
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<!-- ✅ bien -->
|
|
139
|
+
<sui-inline-select formControlName="periodo" icon="calendar-line" [items]="periodos" />
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Frase en una pantalla táctil
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<!-- ❌ mal: en el celular y la tablet táctil se toca una palabra de 20 px de alto -->
|
|
146
|
+
<p>Mostrar ventas de <sui-inline-select icon="calendar-line" [items]="periodos" [(selected)]="periodo" /></p>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<!-- ✅ bien -->
|
|
151
|
+
@if (bp.tactil()) {
|
|
152
|
+
<sui-select label="Periodo" [options]="opcionesPeriodo" [size]="bp.sizeControl()" [(value)]="periodoId" />
|
|
153
|
+
} @else {
|
|
154
|
+
<p>Mostrar ventas de <sui-inline-select icon="calendar-line" [items]="periodos" [(selected)]="periodo" /></p>
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
98
158
|
## Ejemplo
|
|
99
159
|
|
|
100
160
|
```html
|