@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.
Files changed (118) hide show
  1. package/docs/sui-accordion/README.md +83 -9
  2. package/docs/sui-activity-feed/README.md +55 -1
  3. package/docs/sui-activity-filter/README.md +50 -1
  4. package/docs/sui-alert/README.md +54 -0
  5. package/docs/sui-app-store-badge/README.md +57 -3
  6. package/docs/sui-avatar/README.md +66 -6
  7. package/docs/sui-avatar-group/README.md +64 -2
  8. package/docs/sui-badge/README.md +79 -11
  9. package/docs/sui-banner/README.md +70 -5
  10. package/docs/sui-brand-logo/README.md +77 -14
  11. package/docs/sui-breadcrumb-item/README.md +51 -0
  12. package/docs/sui-breadcrumbs/README.md +48 -0
  13. package/docs/sui-button/README.md +68 -6
  14. package/docs/sui-button-group/README.md +70 -5
  15. package/docs/sui-button-group-item/README.md +68 -4
  16. package/docs/sui-card/README.md +97 -10
  17. package/docs/sui-chart-legend/README.md +53 -0
  18. package/docs/sui-chart-legend-dot/README.md +49 -0
  19. package/docs/sui-checkbox/README.md +106 -26
  20. package/docs/sui-checkbox-card/README.md +58 -2
  21. package/docs/sui-checkbox-label/README.md +89 -23
  22. package/docs/sui-circular-progress-bar/README.md +63 -5
  23. package/docs/sui-color-dot/README.md +61 -5
  24. package/docs/sui-color-picker/README.md +62 -4
  25. package/docs/sui-command-menu-footer/README.md +49 -0
  26. package/docs/sui-command-menu-item/README.md +63 -4
  27. package/docs/sui-command-menu-search/README.md +58 -4
  28. package/docs/sui-compact-avatar-group/README.md +61 -4
  29. package/docs/sui-compact-button/README.md +112 -28
  30. package/docs/sui-compact-select/README.md +58 -4
  31. package/docs/sui-compact-select-for-input/README.md +69 -5
  32. package/docs/sui-content-card/README.md +63 -2
  33. package/docs/sui-content-divider/README.md +49 -1
  34. package/docs/sui-content-label/README.md +83 -4
  35. package/docs/sui-counter-input/README.md +91 -7
  36. package/docs/sui-date-selector/README.md +61 -3
  37. package/docs/sui-datepicker/README.md +72 -5
  38. package/docs/sui-day-cell/README.md +60 -3
  39. package/docs/sui-day-label/README.md +52 -3
  40. package/docs/sui-divider/README.md +57 -5
  41. package/docs/sui-drawer-footer/README.md +63 -2
  42. package/docs/sui-drawer-header/README.md +60 -3
  43. package/docs/sui-dropdown-caption/README.md +53 -1
  44. package/docs/sui-dropdown-item/README.md +72 -6
  45. package/docs/sui-dropdown-menu/README.md +74 -5
  46. package/docs/sui-dropdown-search/README.md +57 -1
  47. package/docs/sui-emoji/README.md +82 -18
  48. package/docs/sui-empty-state/README.md +68 -4
  49. package/docs/sui-fancy-button/README.md +59 -1
  50. package/docs/sui-file-icon/README.md +56 -1
  51. package/docs/sui-file-upload/README.md +69 -9
  52. package/docs/sui-file-upload-card/README.md +53 -2
  53. package/docs/sui-filter/README.md +74 -5
  54. package/docs/sui-flag/README.md +62 -1
  55. package/docs/sui-form-hint/README.md +54 -5
  56. package/docs/sui-form-label/README.md +53 -1
  57. package/docs/sui-href/README.md +47 -0
  58. package/docs/sui-icon/README.md +69 -4
  59. package/docs/sui-image-upload/README.md +70 -3
  60. package/docs/sui-image-upload-profile/README.md +58 -0
  61. package/docs/sui-img-retry/README.md +49 -0
  62. package/docs/sui-inline-input/README.md +61 -3
  63. package/docs/sui-inline-select/README.md +60 -0
  64. package/docs/sui-input/README.md +77 -14
  65. package/docs/sui-integration-switch/README.md +69 -2
  66. package/docs/sui-kbd/README.md +71 -7
  67. package/docs/sui-key-icon/README.md +65 -6
  68. package/docs/sui-link-button/README.md +79 -13
  69. package/docs/sui-logo/README.md +74 -4
  70. package/docs/sui-modal/README.md +61 -2
  71. package/docs/sui-modal-footer/README.md +83 -9
  72. package/docs/sui-modal-header/README.md +56 -0
  73. package/docs/sui-modal-sheet/README.md +72 -10
  74. package/docs/sui-notification/README.md +71 -1
  75. package/docs/sui-notification-footer/README.md +51 -1
  76. package/docs/sui-notification-tab-menu/README.md +57 -1
  77. package/docs/sui-otp-input/README.md +67 -6
  78. package/docs/sui-page-header/README.md +83 -15
  79. package/docs/sui-pagination/README.md +60 -0
  80. package/docs/sui-password-strength/README.md +50 -1
  81. package/docs/sui-payment-icon/README.md +66 -7
  82. package/docs/sui-period-range/README.md +65 -6
  83. package/docs/sui-popover/README.md +73 -7
  84. package/docs/sui-product-card/README.md +76 -8
  85. package/docs/sui-progress-bar/README.md +72 -8
  86. package/docs/sui-progress-bar-label/README.md +69 -12
  87. package/docs/sui-radio/README.md +83 -6
  88. package/docs/sui-radio-card/README.md +58 -4
  89. package/docs/sui-radio-label/README.md +86 -19
  90. package/docs/sui-rating/README.md +81 -14
  91. package/docs/sui-rich-editor/README.md +45 -0
  92. package/docs/sui-segmented-control/README.md +83 -14
  93. package/docs/sui-select/README.md +72 -3
  94. package/docs/sui-sidebar/README.md +64 -9
  95. package/docs/sui-slider/README.md +68 -1
  96. package/docs/sui-social-button/README.md +63 -3
  97. package/docs/sui-status-badge/README.md +64 -6
  98. package/docs/sui-stepper/README.md +57 -0
  99. package/docs/sui-store-card/README.md +71 -8
  100. package/docs/sui-switch/README.md +80 -9
  101. package/docs/sui-switch-card/README.md +70 -6
  102. package/docs/sui-switch-label/README.md +90 -13
  103. package/docs/sui-tab-chips/README.md +79 -9
  104. package/docs/sui-tab-menu-horizontal/README.md +62 -1
  105. package/docs/sui-tab-menu-vertical/README.md +56 -3
  106. package/docs/sui-table/README.md +68 -7
  107. package/docs/sui-tag/README.md +75 -4
  108. package/docs/sui-tag-input/README.md +71 -7
  109. package/docs/sui-textarea/README.md +78 -11
  110. package/docs/sui-time-picker/README.md +70 -7
  111. package/docs/sui-toast/README.md +65 -5
  112. package/docs/sui-tooltip/README.md +61 -4
  113. package/docs/sui-topbar/README.md +57 -3
  114. package/docs/sui-topbar-button/README.md +57 -3
  115. package/docs/sui-topbar-item/README.md +61 -0
  116. package/docs/sui-topbar-user/README.md +56 -0
  117. package/package.json +1 -1
  118. package/types/ajuarezso-sui-design-system.d.ts +19 -19
@@ -32,8 +32,9 @@ una función nueva que conviene mostrar donde está («Aquí programas tus pedid
32
32
  > La guía del DS dice para qué es, pero no cuándo va cada pie ni cada posición. Lo marcado «según la
33
33
  > guía del DS» sale de su texto; «canon» es lo ya aprobado en la app; el resto es **propuesta**.
34
34
  >
35
- > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**, y ningún recorrido de
36
- > bienvenida hecho a mano. Todo lo de abajo es para el primer flujo que lo necesite.
35
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (re-medido el 06-10-2026, sin cambios): **0
36
+ > usos** fuera de la página de guía de master-preview, y ningún recorrido de bienvenida hecho a
37
+ > mano. Todo lo de abajo es para el primer flujo que lo necesite.
37
38
 
38
39
  ### Lo que sí dice la guía del DS
39
40
 
@@ -96,19 +97,37 @@ extensión SUI 03-10-2026).
96
97
  | uso | mobile | web | fuente |
97
98
  |---|---|---|---|
98
99
  | el panel | 320 px (cabe desde 352 px de pantalla) | 320 px | según el componente |
99
- | botones del pie | `large` (48) | `medium` (40) | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web: canon (dueño, 05-10-2026, D16), antes `small` (el default del componente: hay que pasarlo) |
100
+ | botones del pie | `large` (48), también en la tablet táctil | `medium` (40) | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · tablet y web: D16, dueño 05-10-2026; antes `small` (el default del componente: hay que pasarlo) |
100
101
  | la X | se ve de 24, se toca en 40 | igual | canon (aprobado por el dueño, 03-10-2026) |
101
102
 
102
103
  ```html
103
- <sui-popover footer="stretch" [size]="bp.isMobile() ? 'large' : 'medium'" … />
104
+ <sui-popover footer="stretch" [size]="bp.sizeControl()" … />
104
105
  ```
105
106
 
106
107
  `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
+ (40) es el de la computadora, con puntero fino (D16); no llega a 44, por eso no va en lo táctil.
108
109
 
109
110
  En mobile, si el recorrido es la bienvenida de la app, conviene una pantalla o un
110
111
  `sui-modal-sheet` por paso en vez del popover (propuesta, falta aprobación).
111
112
 
113
+ ### Por dispositivo (D16)
114
+
115
+ Fila `popover` (botones del pie) de la tabla D16 (dueño, 05-10-2026). Los botones se tocan, así
116
+ que van por tipo de puntero además del ancho. El panel no cambia: 320 px en todos.
117
+
118
+ | dispositivo | size | nota |
119
+ |---|---|---|
120
+ | celular chico (< 380 px) | `large` (48) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino). El panel de 320 cabe desde 352 px |
121
+ | celular (380–767 px) | `large` (48) | |
122
+ | tablet táctil (`pointer: coarse`) | `large` (48) | se toca con el dedo: Apple pide 44 pt también en el iPad |
123
+ | computadora (`pointer: fine`) | `medium` (40) | el default es `small` (36): hay que pasarlo |
124
+
125
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`.
126
+
127
+ En master-pedidos: `[size]="bp.sizeControl()"` — el `size` del popover es el de sus `sui-button`,
128
+ así que va el mismo helper del botón (`large` con `bp.tactil()`, `medium` si no). No uses
129
+ `bp.isMobile()`: deja la tablet táctil en `medium`.
130
+
112
131
  ## «No usar»: por qué no hoy y cuándo sí
113
132
 
114
133
  Hoy el popover entero tiene **0 usos**; esto es lo que no se usaría aunque llegue un flujo nuevo.
@@ -168,6 +187,52 @@ Slot: `[data-slot=body]` reemplaza título y descripción.
168
187
  (crecen si el texto no entra). Hasta el 03-10-2026 no pasaba: el `.scss` apuntaba a
169
188
  `.sui-popover__btn` y el template pone `.sui-popover__action`.
170
189
 
190
+ ## Bien y mal
191
+
192
+ Botones del pie
193
+
194
+ ```html
195
+ <!-- ❌ mal: sin size queda en small, botones de 36. Sale de la página de guía, no de un uso real
196
+ (pages/super-admin/master-preview/_guia-moleculas/avisos.ts:224) -->
197
+ <sui-popover position="top-center" icon="wallet-3-line" title="Aquí ves lo que ganaste hoy"
198
+ [doubleButton]="false" nextLabel="Entendido" />
199
+ ```
200
+
201
+ ```html
202
+ <!-- ✅ bien -->
203
+ <sui-popover position="top-center" icon="wallet-3-line" title="Aquí ves lo que ganaste hoy"
204
+ [doubleButton]="false" nextLabel="Entendido" [size]="bp.sizeControl()" />
205
+ ```
206
+
207
+ Recorrido con puntos
208
+
209
+ ```html
210
+ <!-- ❌ mal: sin step, los puntos dicen «1 de 4» aunque el recorrido tenga 3 pasos -->
211
+ <sui-popover footer="stepper" icon="calendar-schedule-line" title="Programa tus pedidos"
212
+ [size]="bp.sizeControl()" (back)="anterior()" (next)="siguiente()" (dismissed)="saltar()" />
213
+ ```
214
+
215
+ ```html
216
+ <!-- ✅ bien -->
217
+ <sui-popover footer="stepper" [step]="{ current: 2, total: 3 }" icon="calendar-schedule-line"
218
+ title="Programa tus pedidos" [size]="bp.sizeControl()"
219
+ (back)="anterior()" (next)="siguiente()" (dismissed)="saltar()" />
220
+ ```
221
+
222
+ Ícono del tema
223
+
224
+ ```html
225
+ <!-- ❌ mal: sin icon sale una persona (user-6-line), que no dice nada de programar -->
226
+ <sui-popover title="Programa tus pedidos" description="Elige el día y la hora."
227
+ [size]="bp.sizeControl()" />
228
+ ```
229
+
230
+ ```html
231
+ <!-- ✅ bien -->
232
+ <sui-popover icon="calendar-schedule-line" title="Programa tus pedidos"
233
+ description="Elige el día y la hora." [size]="bp.sizeControl()" />
234
+ ```
235
+
171
236
  ## Ejemplo
172
237
 
173
238
  ```html
@@ -175,10 +240,11 @@ Slot: `[data-slot=body]` reemplaza título y descripción.
175
240
  <sui-popover position="top-left" icon="calendar-schedule-line"
176
241
  title="Programa tus pedidos" description="Elige el día y la hora, y el pedido entra solo a la cocina."
177
242
  footer="stepper" [step]="{ current: 2, total: 3 }"
178
- backLabel="Atrás" nextLabel="Siguiente"
243
+ backLabel="Atrás" nextLabel="Siguiente" [size]="bp.sizeControl()"
179
244
  (back)="anterior()" (next)="siguiente()" (dismissed)="saltar()" />
180
245
 
181
246
  <!-- Aviso suelto con una sola salida -->
182
247
  <sui-popover position="bottom-center" icon="wallet-3-line" title="Aquí ves lo que ganaste hoy"
183
- [doubleButton]="false" nextLabel="Entendido" (next)="cerrar()" (dismissed)="cerrar()" />
248
+ [doubleButton]="false" nextLabel="Entendido" [size]="bp.sizeControl()"
249
+ (next)="cerrar()" (dismissed)="cerrar()" />
184
250
  ```
@@ -30,10 +30,11 @@ Regla corta: **producto en la grilla de la carta → product-card · producto en
30
30
  > de la carta de la app. La card **dibuja, no decide**: el precio, si se vende ahora y la
31
31
  > etiqueta de no disponible le llegan ya resueltos.
32
32
  >
33
- > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **3
33
+ > Uso medido el 03-10-2026 y re-medido el 06-10-2026 en `master-pedidos/src/app` (misma exclusión
34
+ > que `sui-card`; las líneas son las del 06-10-2026): **3
34
35
  > product-cards en 2 archivos**: la carta del cliente
35
36
  > (`pages/customer/restaurant-menu/restaurant-menu.html:323` y `:386`) y la grilla del local
36
- > (`pages/products/products.html:145`, con `action="edit"`).
37
+ > (`pages/products/products.html:147`, con `action="edit"`).
37
38
 
38
39
  ### Las piezas
39
40
 
@@ -54,10 +55,13 @@ Regla corta: **producto en la grilla de la carta → product-card · producto en
54
55
 
55
56
  Outputs: `openDetail` (toque en la card), `add`, `increment`, `decrement`, `edit`.
56
57
 
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`.
58
+ **Usos de hoy que rompen las reglas:** 3 (medido el 06-10-2026). Las 3 cards pasan
59
+ `[size]="bp.isMobile() ? 'large' : 'small'"` (`products.html:147`, `restaurant-menu.html:323` y
60
+ `:386`): `small` en la computadora y en la tablet táctil, cuando D16 pide `medium` y `large`. Va
61
+ `bp.sizeControl()` (ver «Por dispositivo (D16)»). **Pendiente de migrar:** el precio tachado y la
62
+ chapa de descuento ya existen en el DS (`precioLista`, ver «Precio con descuento»), pero la carta
63
+ los sigue dibujando afuera (`pages/customer/restaurant-menu/restaurant-menu.scss:426`, deuda
64
+ anotada) y ninguna de las 3 cards pasa `precioLista`.
61
65
 
62
66
  ## Tamaño en mobile y en web
63
67
 
@@ -77,14 +81,33 @@ lápiz sí siguen al lado del precio.
77
81
  | uso | mobile | web | fuente |
78
82
  |---|---|---|---|
79
83
  | 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 |
80
- | botón «+», lápiz, stepper | `large` (44) | `medium` (40) | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web: canon (dueño, 05-10-2026, D16), antes `small` (el default del componente: hay que pasarlo) |
84
+ | botón «+», lápiz, stepper | `large` (44), también en la tablet táctil | `medium` (40) | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · tablet y web: D16, dueño 05-10-2026; antes `small` (el default del componente: hay que pasarlo) |
81
85
 
82
86
  ```html
83
- <sui-product-card [size]="bp.isMobile() ? 'large' : 'medium'" … />
87
+ <sui-product-card [size]="bp.sizeControl()" … />
84
88
  ```
85
89
 
86
90
  `medium` (40) es el de la computadora (D16); la tablet va como el teléfono, porque se toca.
87
91
 
92
+ ### Por dispositivo (D16)
93
+
94
+ Fila `product-card` de la tabla D16 (dueño, 05-10-2026). El «+», el lápiz y el stepper se tocan,
95
+ así que van por tipo de puntero además del ancho.
96
+
97
+ | dispositivo | size | nota |
98
+ |---|---|---|
99
+ | celular chico (< 380 px) | `large` (44) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino). El stepper baja a su propia línea |
100
+ | celular (380–767 px) | `large` (44) | grilla de 2 columnas: el stepper baja a su propia línea |
101
+ | tablet táctil (`pointer: coarse`) | `large` (44) | se toca con el dedo: Apple pide 44 pt también en el iPad |
102
+ | computadora (`pointer: fine`) | `medium` (40) | el default es `small` (36): hay que pasarlo |
103
+
104
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`; el espacio extra va a más columnas de
105
+ la grilla, no a botones más grandes.
106
+
107
+ En master-pedidos: `[size]="bp.sizeControl()"` — el «+» y el lápiz son la escala del `sui-button`,
108
+ así que va el mismo helper (`large` con `bp.tactil()`, `medium` si no). No uses
109
+ `bp.isMobile() ? 'large' : 'small'`: deja la tablet táctil y la computadora en `small`.
110
+
88
111
  ## Precio con descuento
89
112
 
90
113
  `precioLista` es el precio de referencia. Si es **mayor** que `price`, la card pinta el precio en
@@ -158,10 +181,55 @@ interface SuiProductCardFallback { variant?: 'name' | 'icon'; color?: string | n
158
181
  - Cada url nueva vuelve a mostrar el barrido de carga; si la miniatura falla, intenta con
159
182
  `fallbackUrl` antes de apagarlo.
160
183
 
184
+ ## Bien y mal
185
+
186
+ Tamaño de los botones del pie
187
+
188
+ ```html
189
+ <!-- ❌ mal: small (36) en la computadora y en la tablet táctil (pages/customer/restaurant-menu/restaurant-menu.html:323) -->
190
+ <sui-product-card [size]="bp.isMobile() ? 'large' : 'small'"
191
+ [name]="product.name" [price]="product.price" (add)="onCardAdd(product)" />
192
+ ```
193
+
194
+ ```html
195
+ <!-- ✅ bien -->
196
+ <sui-product-card [size]="bp.sizeControl()"
197
+ [name]="product.name" [price]="product.price" (add)="onCardAdd(product)" />
198
+ ```
199
+
200
+ La grilla del dueño del local
201
+
202
+ ```html
203
+ <!-- ❌ mal: sin action="edit" el dueño ve el «+» del cliente, y en agotado ni eso -->
204
+ <sui-product-card [size]="bp.sizeControl()" [name]="p.name" [price]="p.priceNum"
205
+ [available]="seVendeAhora(p)" (openDetail)="editProduct(p)" />
206
+ ```
207
+
208
+ ```html
209
+ <!-- ✅ bien -->
210
+ <sui-product-card [size]="bp.sizeControl()" action="edit" [name]="p.name" [price]="p.priceNum"
211
+ [available]="seVendeAhora(p)" (openDetail)="editProduct(p)" (edit)="editProduct(p)" />
212
+ ```
213
+
214
+ Foto del producto
215
+
216
+ ```html
217
+ <!-- ❌ mal: como string no hay respaldo si la miniatura falla, ni encuadre guardado -->
218
+ <sui-product-card [size]="bp.sizeControl()" [name]="p.name" [price]="p.price"
219
+ [image]="p.thumbnailUrl" />
220
+ ```
221
+
222
+ ```html
223
+ <!-- ✅ bien -->
224
+ <sui-product-card [size]="bp.sizeControl()" [name]="p.name" [price]="p.price"
225
+ [image]="p.thumbnailUrl ? { url: p.thumbnailUrl, fallbackUrl: p.imageUrl, position: p.imagePosition ?? 50 } : null" />
226
+ ```
227
+
161
228
  ## Ejemplo
162
229
 
163
230
  ```html
164
231
  <sui-product-card
232
+ [size]="bp.sizeControl()"
165
233
  [name]="p.name"
166
234
  [description]="p.description ?? ''"
167
235
  [price]="p.price"
@@ -55,9 +55,9 @@ como «atención».
55
55
 
56
56
  | size | alto | cuándo | fuente |
57
57
  |---|---|---|---|
58
- | `small` | 4 px | Web: dentro de una card o una fila densa. | propuesta, falta aprobación |
59
- | `medium` (default) | 6 px | Web: lo normal y la barra principal. Mobile: dentro de una fila densa. Es la única altura de la guía. | según la guía del DS |
60
- | `large` | 8 px | Mobile: lo normal y la barra principal (descarga, meta del día). | propuesta, falta aprobación |
58
+ | `small` | 4 px | Pendiente (P10). Era la barra de web en una card densa; D16 no deja nada en `small`, pero la opción recomendada de P10 (a) deja el saldo del repartidor en `small` como excepción escrita (decidido el 20-09-2026). | propuesta, espera P10 |
59
+ | `medium` (default) | 6 px | Computadora, tablet y celular chico. Es la única altura de la guía. | según la guía del DS · D16, dueño 05-10-2026 (cuándo) |
60
+ | `large` | 8 px | Celular de 380 px o más: lo normal y la barra principal (descarga, meta del día). | propuesta (P10 a), pendiente |
61
61
  | `xlarge` | 10 px | **No usar** (ver abajo). | propuesta, falta aprobación |
62
62
 
63
63
  ### `value` y `ariaLabel`
@@ -86,22 +86,47 @@ Criterio de la app: **D16, tamaño por dispositivo** (canon, dueño, 05-10-2026)
86
86
  380 px o más y, en lo que se toca, también la tablet (`pointer: coarse`). La columna «web» es la
87
87
  computadora (`pointer: fine`) y, en lo que no se toca, también la tablet. En el celular chico
88
88
  (< 380 px) va `medium` a la vista, sin achicar el área de 44 de lo que se toca. **Nada en `small` ni
89
- `xsmall`**, salvo lo que el componente solo tiene en chico. Hoy la app corta con
90
- `BreakpointsService.isMobile()` (≤ 767 px), que todavía no mira el puntero ni los 380 px.
89
+ `xsmall`**, salvo lo que el componente solo tiene en chico. En la app, `BreakpointsService` ya
90
+ tiene las señales de D16: `celular()` (380–767 px), `celularChico()`, `toque()` y `tactil()`.
91
91
 
92
92
  | uso | mobile | web | fuente |
93
93
  |---|---|---|---|
94
- | Dentro de una fila o card densa | `medium` (6) | `small` (4) | propuesta, falta aprobación |
95
- | Lo normal, y la barra que es lo principal (descarga, meta del día) | `large` (8) | `medium` (6) | propuesta, falta aprobación |
94
+ | Dentro de una fila o card densa | pendiente (P10) | `medium` (6) | web: D16, dueño 05-10-2026 · mobile: espera P10 (la excepción del saldo en `small` vive en `sui-progress-bar-label`) |
95
+ | Lo normal, y la barra que es lo principal (descarga, meta del día) | `large` (8): propuesta (P10 a), pendiente | `medium` (6) | web: D16, dueño 05-10-2026 · mobile: espera P10 |
96
96
 
97
97
  ```ts
98
98
  readonly bp = inject(BreakpointsService); // master-pedidos: src/app/services/breakpoints.service.ts
99
99
  ```
100
100
 
101
+ Si P10 se cierra en (a) o (c):
102
+
101
103
  ```html
102
- <sui-progress-bar [value]="progreso()" [size]="bp.isMobile() ? 'large' : 'medium'" ariaLabel="Subiendo la foto" />
104
+ <sui-progress-bar [value]="progreso()" [size]="bp.celular() ? 'large' : 'medium'" ariaLabel="Subiendo la foto" />
103
105
  ```
104
106
 
107
+ Va `bp.celular()` y no `bp.isMobile()`: `isMobile()` también incluye el celular chico, que en lo que
108
+ no se toca lleva el valor de web (D16, dueño 05-10-2026).
109
+
110
+ ### Por dispositivo (D16)
111
+
112
+ No se toca: sube un paso solo en el celular de 380 px o más (P1 b). El celular chico y la tablet
113
+ van con el valor de la computadora.
114
+
115
+ | dispositivo | size | nota |
116
+ |---|---|---|
117
+ | celular chico (< 380 px) | `medium` (6) | valor «web» |
118
+ | celular (380–767 px) | `large` (8): propuesta (P10 a), pendiente | valor «mobile»: un paso más que la computadora, si P10 lo confirma |
119
+ | tablet táctil (`pointer: coarse`) | `medium` (6) | no se toca, no necesita crecer |
120
+ | computadora (`pointer: fine`) | `medium` (6) | |
121
+
122
+ Ultrawide (≥ 1920 px): igual que la computadora; el espacio extra va a ancho, no a una barra más gruesa.
123
+
124
+ **Pendiente (P10):** el valor del celular y si `small` queda como excepción del saldo del
125
+ repartidor (20-09-2026). Decide el dueño.
126
+
127
+ En master-pedidos: no hay helper. Si P10 confirma `large` en el celular,
128
+ `[size]="bp.celular() ? 'large' : 'medium'"`.
129
+
105
130
  ## API
106
131
 
107
132
  <!-- api:inicio -->
@@ -129,6 +154,45 @@ Outputs: ninguno.
129
154
  `prefers-reduced-motion`. Nombre: `ariaLabel`, o `ariaLabelledby` (id de un texto visible), y si
130
155
  no hay ninguno se llama «Progreso» (04-10-2026: antes quedaba sin nombre).
131
156
 
157
+ ## Bien y mal
158
+
159
+ Barra pelada sin nombre
160
+
161
+ ```html
162
+ <!-- ❌ mal: sin ariaLabel el lector anuncia «Progreso» y no qué mide (pages/overview/components/overview-visitors/overview-visitors.html:22) -->
163
+ <sui-progress-bar [value]="device.percentage" color="orange" />
164
+ ```
165
+
166
+ ```html
167
+ <!-- ✅ bien: el color sigue igual; si pasa a blue espera P9 -->
168
+ <sui-progress-bar [value]="device.percentage" color="orange" [ariaLabel]="'Visitas desde ' + device.name" />
169
+ ```
170
+
171
+ El valor como fracción
172
+
173
+ ```html
174
+ <!-- ❌ mal: value es de 0 a 100; 0.6 pinta casi vacía -->
175
+ <sui-progress-bar [value]="b.progreso" ariaLabel="Meta del día" />
176
+ ```
177
+
178
+ ```html
179
+ <!-- ✅ bien -->
180
+ <sui-progress-bar [value]="b.progreso * 100" ariaLabel="Meta del día" />
181
+ ```
182
+
183
+ Título y número armados a mano
184
+
185
+ ```html
186
+ <!-- ❌ mal: el texto va suelto, con otra tipografía y otro espaciado -->
187
+ <p class="subida__texto">Subiendo la foto · {{ progreso() }} %</p>
188
+ <sui-progress-bar [value]="progreso()" />
189
+ ```
190
+
191
+ ```html
192
+ <!-- ✅ bien -->
193
+ <sui-progress-bar-label title="Subiendo la foto" [value]="progreso()" />
194
+ ```
195
+
132
196
  ## Ejemplo
133
197
 
134
198
  ```html
@@ -45,17 +45,17 @@ que mide** (blue neutro, green cumplido, orange pide atención, red perdido o ag
45
45
  | `type` | `on-right` | Sin título: barra y número en una línea, dentro de una fila que ya dice qué mide a la izquierda. | Pedidos por distrito en una tabla | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
46
46
  | `title` | texto | Qué mide, en sentence case, sin punto: «Saldo restante», «Meta del día». | `pages/driver/driver-wallet/driver-wallet.html:43` | según la guía del DS |
47
47
  | `percentage` | `true` (default) | El porcentaje es la unidad que importa (una descarga). | `components/ota-update/ota-update.html:132` | según la guía del DS («80%») |
48
- | `percentage` | texto | Hay una unidad real: entregas, soles. «3 de 5 entregas», «S/ 12.40 de S/ 20.00». | `pages/driver/driver-dashboard/driver-dashboard.html:512` | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
48
+ | `percentage` | texto | Hay una unidad real: entregas, soles. «3 de 5 entregas», «S/ 12.40 de S/ 20.00». | `pages/driver/driver-dashboard/driver-dashboard.html:539` | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
49
49
  | `percentage` | `false` | El número ya está escrito al lado, o no significa nada. | — | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
50
50
  | `showBottom` + `description` | texto | Qué está pasando o qué hacer mientras avanza: «No cierres la app, estamos dejando todo listo.» | `components/ota-update/ota-update.html:132` | según la guía del DS («Advanced») |
51
51
  | `link` | texto o `{ label, href }` | La acción que resuelve lo que la barra avisa: «Recargar» cuando el saldo está en rojo. Va con `showBottom`. | — (sin usos) | según la guía del DS («Upgrade») · canon (aprobado por el dueño, 05-10-2026, bloque B9) (cuándo) |
52
- | `ariaLabel` | texto | Lo que mide, si el título no alcanza («Saldo restante sobre el saldo de cortesía»). | `pages/driver/driver-dashboard/driver-dashboard.html:240` | canon (aprobado por el dueño, 05-10-2026, bloque B5) |
52
+ | `ariaLabel` | texto | Lo que mide, si el título no alcanza («Saldo restante sobre el saldo de cortesía»). | `pages/driver/driver-dashboard/driver-dashboard.html:282` | canon (aprobado por el dueño, 05-10-2026, bloque B5) |
53
53
 
54
54
  **Usos de hoy que rompen la regla — a discutir, 1:**
55
55
  `components/ota-update/ota-update.html:132` pinta la descarga en `orange`. Una descarga es avance
56
56
  neutro: con la regla de color va `blue`. En la app el naranja se lee como la marca, así que puede
57
57
  ser una decisión de marca y no un error: decide el dueño. Las de saldo y meta (`driver-wallet:43`,
58
- `driver-dashboard:240` y `:512`) ya pintan verde, naranja y rojo según el estado: cumplen.
58
+ `driver-dashboard:282` y `:539`) ya pintan verde, naranja y rojo según el estado: cumplen.
59
59
 
60
60
  ## No usar: por qué no hoy y cuándo sí
61
61
 
@@ -71,26 +71,52 @@ Criterio de la app: **D16, tamaño por dispositivo** (canon, dueño, 05-10-2026)
71
71
  380 px o más y, en lo que se toca, también la tablet (`pointer: coarse`). La columna «web» es la
72
72
  computadora (`pointer: fine`) y, en lo que no se toca, también la tablet. En el celular chico
73
73
  (< 380 px) va `medium` a la vista, sin achicar el área de 44 de lo que se toca. **Nada en `small` ni
74
- `xsmall`**, salvo lo que el componente solo tiene en chico. Hoy la app corta con
75
- `BreakpointsService.isMobile()` (≤ 767 px), que todavía no mira el puntero ni los 380 px.
74
+ `xsmall`**, salvo lo que el componente solo tiene en chico. En la app, `BreakpointsService` ya
75
+ tiene las señales de D16: `celular()` (380–767 px), `celularChico()`, `toque()` y `tactil()`.
76
76
 
77
77
  El `size` solo cambia la barra; el título y el número no cambian de tamaño.
78
78
 
79
79
  | uso | mobile | web | fuente |
80
80
  |---|---|---|---|
81
- | Dentro de una card o fila densa (saldo en el dashboard) | `medium` (6) | `small` (4) | propuesta, falta aprobación |
82
- | Lo normal, y la barra que es lo principal (descarga, meta del día) | `large` (8) | `medium` (6) | propuesta, falta aprobación |
81
+ | Dentro de una card o fila densa (saldo en el dashboard) | pendiente (P10) | pendiente (P10) | P10 sigue abierta. D16 no deja nada en `small`, pero la opción recomendada de P10 (a) deja el saldo del repartidor en `small` como excepción escrita (decidido el 20-09-2026, ver el comentario de `pages/driver/driver-dashboard/driver-dashboard.html:279`). Decide el dueño |
82
+ | Lo normal, y la barra que es lo principal (descarga, meta del día) | `large` (8): propuesta (P10 a), pendiente | `medium` (6) | web: D16, dueño 05-10-2026 · mobile: espera P10 |
83
83
 
84
84
  ```ts
85
85
  readonly bp = inject(BreakpointsService); // master-pedidos: src/app/services/breakpoints.service.ts
86
86
  ```
87
87
 
88
+ Si P10 se cierra en (a) o (c), la barra normal va así (la meta del día, no el saldo):
89
+
88
90
  ```html
89
- <sui-progress-bar-label title="Saldo restante" [value]="balancePercent()"
90
- [size]="bp.isMobile() ? 'large' : 'medium'" [color]="balanceColor()" />
91
+ <sui-progress-bar-label title="Meta del día" [value]="metaPercent()"
92
+ [size]="bp.celular() ? 'large' : 'medium'" [color]="metaColor()" />
91
93
  ```
92
94
 
93
- Hoy las 4 de la app tienen un size fijo para las dos plataformas.
95
+ Hoy las 4 de la app tienen un size fijo para todos los dispositivos, y una va en `small`
96
+ (`pages/driver/driver-dashboard/driver-dashboard.html:284`, el saldo, desde el 20-09-2026). Si se
97
+ queda como excepción o sube a `medium` / `large` espera P10.
98
+
99
+ ### Por dispositivo (D16)
100
+
101
+ No se toca: sube un paso solo en el celular de 380 px o más (P1 b). El celular chico y la tablet
102
+ van con el valor de la computadora. El size solo cambia la barra; el título y el número no se mueven.
103
+
104
+ | dispositivo | size | nota |
105
+ |---|---|---|
106
+ | celular chico (< 380 px) | `medium` (barra de 6) | valor «web» |
107
+ | celular (380–767 px) | `large` (barra de 8): propuesta (P10 a), pendiente | valor «mobile»: un paso más que la computadora, si P10 lo confirma |
108
+ | tablet táctil (`pointer: coarse`) | `medium` (barra de 6) | no se toca, no necesita crecer |
109
+ | computadora (`pointer: fine`) | `medium` (barra de 6) | |
110
+
111
+ Ultrawide (≥ 1920 px): igual que la computadora.
112
+
113
+ **Pendiente (P10): el saldo del repartidor.** Va en `small` en todos los dispositivos desde el
114
+ 20-09-2026. La opción recomendada de P10 (a) lo deja así como excepción escrita; la (c) lo sube.
115
+ Hasta que el dueño decida, esta tabla no se le aplica.
116
+
117
+ En master-pedidos: no hay helper. Si P10 confirma `large` en el celular,
118
+ `[size]="bp.celular() ? 'large' : 'medium'"` (y no `bp.isMobile()`, que también agranda la barra en
119
+ el celular chico).
94
120
 
95
121
  ## API
96
122
 
@@ -130,6 +156,37 @@ Output: `(linkClick)`. Con `link` de texto el `<a>` no navega y solo emite; con
130
156
  - El `title` visible nombra la barra (`aria-labelledby`, 04-10-2026); sin título (`on-right`) y sin
131
157
  `ariaLabel` se anuncia «Progreso».
132
158
 
159
+ ## Bien y mal
160
+
161
+ El saldo en `small` de `pages/driver/driver-dashboard/driver-dashboard.html:284` no va aquí como
162
+ ❌: es la excepción del 20-09-2026 que P10 (a) propone escribir, y decide el dueño.
163
+
164
+ La acción que no aparece
165
+
166
+ ```html
167
+ <!-- ❌ mal: sin showBottom no se dibujan ni la descripción ni el link -->
168
+ <sui-progress-bar-label title="Saldo restante" [value]="18" color="red"
169
+ link="Recargar" description="para seguir recibiendo pedidos" (linkClick)="abrirRecarga()" />
170
+ ```
171
+
172
+ ```html
173
+ <!-- ✅ bien -->
174
+ <sui-progress-bar-label title="Saldo restante" [value]="18" color="red" [showBottom]="true"
175
+ link="Recargar" description="para seguir recibiendo pedidos" (linkClick)="abrirRecarga()" />
176
+ ```
177
+
178
+ Título en una barra `on-right`
179
+
180
+ ```html
181
+ <!-- ❌ mal: on-right ignora title; el lector anuncia «Progreso» -->
182
+ <sui-progress-bar-label type="on-right" title="Pedidos en Lince" [value]="72" />
183
+ ```
184
+
185
+ ```html
186
+ <!-- ✅ bien: el nombre lo pone la fila; la barra lo recibe en ariaLabel -->
187
+ <sui-progress-bar-label type="on-right" [value]="72" ariaLabel="Pedidos en Lince" />
188
+ ```
189
+
133
190
  ## Ejemplo
134
191
 
135
192
  ```html
@@ -138,8 +195,8 @@ Output: `(linkClick)`. Con `link` de texto el `<a>` no navega y solo emite; con
138
195
  title="Meta del día"
139
196
  [value]="hechas / meta * 100"
140
197
  [percentage]="hechas + ' de ' + meta + ' entregas'"
141
- [color]="perdida ? 'red' : cumplida ? 'green' : 'orange'"
142
- size="large" />
198
+ [color]="perdida ? 'red' : cumplida ? 'green' : 'orange'" />
199
+ <!-- size: medium (default); el valor del celular espera P10 -->
143
200
 
144
201
  <!-- Saldo en rojo, con la acción que lo resuelve -->
145
202
  <sui-progress-bar-label
@@ -52,18 +52,17 @@ Regla corta: **lista densa de texto → radio-label · con peso o en el teléfon
52
52
  |---|---|---|---|
53
53
  | `xlarge` | 28 | Mobile, vía `bp.controlSize()`. | canon (aprobado por el dueño, 28-09-2026: «componentes grandes») |
54
54
  | `large` | 24 | Desktop, vía `bp.controlSize()`. | canon (aprobado por el dueño, 28-09-2026) |
55
- | `medium` (default) | 20 | Solo dentro de un componente que fija su escala (detalle de producto). Es el único tamaño de la guía. | según la guía del DS (único tamaño); el «cuándo» es canon (aprobado por el dueño, 05-10-2026, bloque B1) |
55
+ | `medium` (default) | 20 | Solo dentro de un componente que fija su escala en chico; hoy ningún padre lo hace (el detalle de producto recibe `xlarge` / `large`, ver «Por dispositivo»). Es el único tamaño de la guía. | según la guía del DS (único tamaño); el «cuándo» es canon (aprobado por el dueño, 05-10-2026, bloque B1) |
56
56
 
57
57
  **Usos de hoy que rompen la regla:**
58
58
 
59
59
  - **1 radio nativo → `sui-radio-card type="basic"`:**
60
- `pages/driver/driver-order-detail/driver-order-detail.html:844` (motivos de cancelación del
60
+ `pages/driver/driver-order-detail/driver-order-detail.html:874` (motivos de cancelación del
61
61
  repartidor, el mismo caso del ejemplo de la guía). La pantalla hermana del local ya lo resolvió
62
62
  así: `pages/orders/orders.html:567`.
63
- - **1 suelto que se puede desincronizar:** `pages/super-admin/master-settings/master-settings.html:107`
64
- (categoría por defecto). Usa `[standaloneChecked]` + `$event && …`: al tocar el que ya está
65
- elegido, el círculo se apaga por dentro pero el padre sigue diciendo que es el elegido. Va en
66
- un `sui-radio-group` con `[ngModel]`.
63
+ - **Resuelto el 04-10-2026:** el suelto que se podía desincronizar en `master-settings.html`
64
+ (categoría por defecto, con `[standaloneChecked]` + `$event && …`) se quitó junto con el «por
65
+ defecto», que nadie leía (commit `62ee5d60` de master-pedidos). El error queda como par en «Bien y mal».
67
66
 
68
67
  ## Tamaño en mobile y en web
69
68
 
@@ -78,6 +77,27 @@ Regla corta: **lista densa de texto → radio-label · con peso o en el teléfon
78
77
 
79
78
  El más grande mide 28 px: el área táctil de 44 px la tiene que dar la fila.
80
79
 
80
+ ### Por dispositivo (D16)
81
+
82
+ Fila de `radio` en la tabla de D16 (dueño, 05-10-2026; computadora resuelta el 06-10-2026): se
83
+ toca, y en la computadora va **un paso menos que en el celular**, sin bajar a `medium`.
84
+
85
+ | dispositivo | size | nota |
86
+ |---|---|---|
87
+ | celular chico (< 380 px) | `xlarge` (28) | la fila que lo contiene da los 44 de alto |
88
+ | celular (380–767 px) | `xlarge` (28) | |
89
+ | tablet táctil (`pointer: coarse`) | `xlarge` (28) | `bp.controlSize()` hoy mira solo el ancho (≤ 767): en un iPad de 768 o más da `large`. Pendiente que el helper mire el puntero |
90
+ | computadora (`pointer: fine`) | `large` (24) | un paso menos que el celular (dueño, 06-10-2026) |
91
+
92
+ Ultrawide (≥ 1920 px): igual que la computadora, `large`. `medium` solo cuando un padre fija la
93
+ escala en chico, y hoy ninguna pantalla lo hace: el detalle de producto
94
+ (`components/product-detail-view/product-detail-view.html:202`) recibe el `size` de quien lo
95
+ monta, y los dos que lo montan le pasan `xlarge` / `large` (`pages/customer/restaurant-menu/restaurant-menu.html:457`
96
+ con `bp.controlSize()` y `components/add-product-modal/add-product-modal.html:360` con
97
+ `ctrlSize()`, el mismo corte).
98
+
99
+ En master-pedidos: `[size]="bp.controlSize()"`.
100
+
81
101
  ## «No usar»: por qué no hoy y cuándo sí
82
102
 
83
103
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -130,6 +150,63 @@ y proyecta los radios (`sui-radio`, `sui-radio-label`, `sui-radio-card`).
130
150
  - Sin marcar, en foco, el círculo se pinta del color de marca: viene del Figma, no es un error.
131
151
  - No dibuja texto ni `aria-label`: pelado, pon el texto en un `<label>` o usa `sui-radio-label`.
132
152
 
153
+ ## Bien y mal
154
+
155
+ Motivos de cancelación
156
+
157
+ ```html
158
+ <!-- ❌ mal: radio nativo con <label> a mano (pages/driver/driver-order-detail/driver-order-detail.html:874) -->
159
+ <label class="ts__modal-reason">
160
+ <input type="radio" name="driverCancelReason" [value]="reason" (change)="cancelReasonSelected.set(reason)" />
161
+ <span>{{ reason }}</span>
162
+ </label>
163
+ ```
164
+
165
+ ```html
166
+ <!-- ✅ bien: opción que se toca en el teléfono → radio-card en una columna, como la pantalla
167
+ hermana del local (pages/orders/orders.html:567). Dentro de sui-radio-group sin más, las
168
+ tarjetas quedan en fila (su host es inline-flex): si se usa el grupo, darle
169
+ flex-direction: column desde afuera (ver Trampas) -->
170
+ <div class="motivos" role="radiogroup" aria-label="Motivo de cancelación">
171
+ @for (reason of CANCEL_REASONS; track reason) {
172
+ <sui-radio-card [size]="bp.controlSize()" type="basic" [value]="reason" [label]="reason"
173
+ [checked]="cancelReasonSelected() === reason" (selected)="cancelReasonSelected.set(reason)" />
174
+ }
175
+ </div>
176
+ <!-- .motivos { display: flex; flex-direction: column; gap: 8px; } -->
177
+ ```
178
+
179
+ Elegir uno de una lista
180
+
181
+ ```html
182
+ <!-- ❌ mal: sueltos con standaloneChecked; al tocar el elegido se apaga y el padre no se entera (se quitó de master-settings.html el 04-10-2026) -->
183
+ @for (cat of categorias; track cat.id) {
184
+ <sui-radio [size]="bp.controlSize()" [standaloneChecked]="cat.id === porDefecto()"
185
+ (standaloneCheckedChange)="$event && porDefecto.set(cat.id)" />
186
+ }
187
+ ```
188
+
189
+ ```html
190
+ <!-- ✅ bien: el grupo hace la exclusión -->
191
+ <sui-radio-group [ngModel]="porDefecto()" (ngModelChange)="porDefecto.set($event)">
192
+ @for (cat of categorias; track cat.id) {
193
+ <sui-radio [size]="bp.controlSize()" [value]="cat.id" [attr.aria-label]="cat.nombre" />
194
+ }
195
+ </sui-radio-group>
196
+ ```
197
+
198
+ Círculo pelado en una tabla
199
+
200
+ ```html
201
+ <!-- ❌ mal: el radio no dibuja texto ni aria-label; el lector solo dice «botón de opción» -->
202
+ <sui-radio [size]="bp.controlSize()" [value]="cat.id" />
203
+ ```
204
+
205
+ ```html
206
+ <!-- ✅ bien -->
207
+ <sui-radio [size]="bp.controlSize()" [value]="cat.id" [attr.aria-label]="'Por defecto: ' + cat.nombre" />
208
+ ```
209
+
133
210
  ## Ejemplo
134
211
 
135
212
  ```html