@ajuarezso/sui-design-system 0.25.0 → 0.25.2

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 (120) 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/fesm2022/ajuarezso-sui-design-system.mjs +216 -227
  118. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  119. package/package.json +1 -1
  120. package/types/ajuarezso-sui-design-system.d.ts +68 -45
@@ -56,7 +56,7 @@ type="date"` · día + franja de entrega → la hoja del checkout.**
56
56
  | `showFooter` | `true` (default) | Cancelar/Aplicar: la elección no se guarda hasta confirmar. Úsalo cuando cambiar la fecha recalcula algo caro (un reporte). | guía (ejemplo Approval) |
57
57
  | `showFooter` | `false` | Se aplica al tocar el día. Fecha única y nada que recalcular. En `range` no tiene efecto: el rango siempre trae footer. | guía (ejemplo Popover) |
58
58
  | `calendars` | `2` (default) | Rango en web: dos meses lado a lado (936 px). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
59
- | `calendars` | `1` | Rango en un espacio angosto (columna, modal `medium`). En mobile se fuerza a 1 solo. | guía (Range con un mes) |
59
+ | `calendars` | `1` | Rango en un espacio angosto (columna, modal `medium`, tablet en vertical: los 936 px necesitan ≥ 968 de ancho). En mobile (≤ 767) se fuerza a 1 solo; en tablet hay que pasarlo. | guía (Range con un mes) |
60
60
 
61
61
  ### `min`, `max`, `markedDates`, `presets`, `placeholder`, `disabled`
62
62
 
@@ -93,7 +93,7 @@ Tiene `size` para el campo: `small` (36), `medium` (40, default, el de siempre),
93
93
  el mismo alto que `sui-input` y `sui-select` `large`, y **`xlarge` (52)**, el de `sui-input` `xlarge`.
94
94
  Con `large` **y siempre en mobile (≤ 767 px)** el panel también crece: **flechas de mes de 40** y
95
95
  **Cancelar / Aplicar en `large` (48)**. Con **`xlarge`** todo lo que se toca llega a 44: **días de
96
- 44 × 44** (`sui-day-cell` `large`, gap 4: 7 × 44 + 6 × 4 = 332, entra en 390), **flechas de mes de
96
+ 44 × 44** (`sui-day-cell` `large`, gap 4: grilla de 7 × 44 + 6 × 4 = 332, panel de 358 con padding y borde: entra en una pantalla de 390, y dentro de un modal fullscreen solo con `[fullBody]`, ver «Por dispositivo»), **flechas de mes de
97
97
  44** (`sui-date-selector` `large`, barra de 52) y **rangos predefinidos de 44** (`sui-period-range`
98
98
  `large`). En el teléfono el footer del rango pone el resumen «Rango: …» arriba y los dos botones
99
99
  abajo, 50/50.
@@ -112,18 +112,42 @@ campo (y su placeholder) va en 16/24. Con `large` el calendario no cambia (días
112
112
  `large`). El resumen del rango sigue en 14.
113
113
 
114
114
  ```html
115
- <!-- Web: popover. Mobile: en línea dentro de un sui-modal fullscreen. -->
115
+ <!-- Web: popover. Mobile: en línea dentro de un sui-modal fullscreen con [fullBody]="true"
116
+ (sin él el body deja ancho − 56 y el panel de 358 no entra; ver «Por dispositivo»). -->
116
117
  @if (bp.isMobile()) {
117
118
  <sui-datepicker mode="range" size="xlarge" [inline]="true" [calendars]="1" [(value)]="rango" />
118
119
  } @else {
119
- <sui-datepicker mode="range" placeholder="Elige el período" [(value)]="rango" />
120
+ <sui-datepicker mode="range" [size]="bp.tactil() ? 'xlarge' : 'medium'"
121
+ [calendars]="bp.isTablet() ? 1 : 2"
122
+ placeholder="Elige el período" [(value)]="rango" />
120
123
  }
121
124
  ```
122
125
 
123
126
  | uso | mobile | web | fuente |
124
127
  |---|---|---|---|
125
128
  | fecha en un formulario | `xlarge` (días de 44) | `medium` | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web: canon (aprobado por el dueño, 05-10-2026, bloque B1) |
126
- | filtro de período de un reporte | `xlarge`, en línea dentro de un modal | `medium`, popover | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web: canon (aprobado por el dueño, 05-10-2026, bloque B1) |
129
+ | filtro de período de un reporte | `xlarge`, en línea dentro de un modal con `[fullBody]` | `medium`, popover | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web: canon (aprobado por el dueño, 05-10-2026, bloque B1) |
130
+
131
+ ### Por dispositivo (D16)
132
+
133
+ El datepicker tiene fila propia en D16: los días solo llegan a 44 en `xlarge`, así que todo
134
+ dispositivo táctil va en `xlarge`, también el celular chico.
135
+
136
+ | dispositivo | size | nota |
137
+ |---|---|---|
138
+ | celular chico (< 380) | `xlarge` | **no entra en 360 hoy** (en 375 solo `mode="date"` con `[fullBody]`, por 1 px). La grilla de días mide 332 (7 × 44 + 6 × 4), pero el panel mide **358** (332 + 2 × 12 de padding + borde). Dentro de un `sui-modal` fullscreen el body deja `ancho − 56` (8 de inset y 20 de padding por lado): 304 en 360. Con `[fullBody]="true"` deja `ancho − 16`: 344 en 360, 359 en 375. En `range` además el panel se fija en `ancho − 32` (328 en 360, 343 en 375) y recorta el domingo. Pendiente: que quepa en 360 es código del DS (gap o padding del calendario), no del README |
139
+ | celular (380–767) | `xlarge` | en línea dentro de un `sui-modal` fullscreen **con `[fullBody]="true"`**: sin él el body deja 334 en 390 y el panel de 358 se sale. Con él quedan 374 en 390. Se fuerza a 1 calendario |
140
+ | tablet táctil (`pointer: coarse`) | `xlarge` | popover. En `mode="date"` el panel mide 368 y entra desde 768. En `range` con 2 calendarios mide 936 (200 + 2 × 368) y necesita ≥ 968 de ancho: un iPad en vertical (820–834) lo recorta, así que va con `[calendars]="1"` (200 + 368 = 568). Los días, flechas y rangos llegan a 44 por el `size`, no por el ancho |
141
+ | computadora (`pointer: fine`) | `medium` | popover. Ojo: con `medium` el componente pinta Cancelar / Aplicar en `small` (36) por dentro (`footerButtonSize()`); D16 no deja nada en `small`, pero cambiarlo es código del DS, no del README |
142
+
143
+ Ultrawide: igual que la computadora; el rango ya ocupa sus dos meses (936 px) y el espacio extra no
144
+ agranda nada. Fuente: D16, dueño 05-10-2026.
145
+
146
+ En master-pedidos: `[size]="bp.tactil() ? 'xlarge' : 'medium'"` (no hay helper que dé
147
+ `xlarge`/`medium`). `bp.isMobile()` decide solo si va en línea o en popover, que es cuestión de
148
+ ancho, no de puntero. En `range` fuera del celular, `[calendars]="bp.isTablet() ? 1 : 2"`: el
149
+ componente solo baja a 1 calendario por su cuenta hasta 767. `isTablet()` es hasta 1024, un poco
150
+ conservador (en 1024 los dos meses sí entran), pero es la señal que tiene el servicio.
127
151
 
128
152
  ## «No usar»: por qué no hoy y cuándo sí
129
153
 
@@ -198,6 +222,49 @@ interface DatepickerPreset { id: DatepickerPresetId; label: string; resolve: (ho
198
222
  - Las piezas internas son `sui-date-selector`, `sui-day-label`, `sui-day-cell` y
199
223
  `sui-period-range`: no se arman a mano.
200
224
 
225
+ ## Bien y mal
226
+
227
+ Una fecha suelta en un formulario
228
+
229
+ ```html
230
+ <!-- ❌ mal: un popover de 368 px para un campo «Válido hasta» (Cuándo no) -->
231
+ <sui-form-label label="Válido hasta" />
232
+ <sui-datepicker [min]="hoy" [(value)]="venceEl" />
233
+ ```
234
+
235
+ ```html
236
+ <!-- ✅ bien -->
237
+ <sui-input type="date" label="Válido hasta" [size]="bp.sizeControl()" [(value)]="venceEl" />
238
+ ```
239
+
240
+ Período en el celular
241
+
242
+ ```html
243
+ <!-- ❌ mal: en el celular el popover no es hoja (Trampas), y en medium los días miden 40
244
+ (Tamaño en mobile y en web) -->
245
+ <sui-datepicker mode="range" [(value)]="rango" />
246
+ ```
247
+
248
+ ```html
249
+ <!-- ✅ bien: [fullBody] porque el panel xlarge mide 358 y el body con padding deja 334 en 390.
250
+ En < 380 todavía no entra (pendiente del DS, ver «Por dispositivo») -->
251
+ <sui-modal [(open)]="eligiendo" [fullscreen]="true" [fullBody]="true" title="Elige el período">
252
+ <sui-datepicker mode="range" size="xlarge" [inline]="true" [calendars]="1" [(value)]="rango" />
253
+ </sui-modal>
254
+ ```
255
+
256
+ Rango que se aplica al tocar
257
+
258
+ ```html
259
+ <!-- ❌ mal: en range el footer sale igual; showFooter no tiene efecto (Trampas) -->
260
+ <sui-datepicker mode="range" [showFooter]="false" [(value)]="rango" />
261
+ ```
262
+
263
+ ```html
264
+ <!-- ✅ bien: el rango siempre confirma con Aplicar; [showFooter]="false" es solo para mode="date" -->
265
+ <sui-datepicker mode="range" [max]="hoy" [(value)]="rango" />
266
+ ```
267
+
201
268
  ## Ejemplo
202
269
 
203
270
  ```html
@@ -61,8 +61,8 @@ de 44 px en mobile (gap 4) y 48 en web (gap 8) con `medium`, y 48 (gap 4) con `l
61
61
 
62
62
  | size | celda | texto | uso | fuente |
63
63
  |---|---|---|---|---|
64
- | `large` | **44 × 44** | 16/24 | mobile: lo que se toca llega a 44 (en 390 entran 7 × 44 con gap 4 = 332) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
65
- | `medium` (default) | 40 × 40 | 14/20 | web | medido (Figma 437:174) |
64
+ | `large` | **44 × 44** | 16/24 | celular y tablet táctil: lo que se toca llega a 44 (en 390 entran 7 × 44 con gap 4 = 332) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · tablet: D16, dueño 05-10-2026 |
65
+ | `medium` (default) | 40 × 40 | 14/20 | computadora | medido (Figma 437:174) |
66
66
 
67
67
  Los puntos de hoy y de marcado no cambian con el size.
68
68
 
@@ -70,12 +70,31 @@ Los puntos de hoy y de marcado no cambian con el size.
70
70
  <!-- La grilla da el paso: gap 4 -->
71
71
  <div class="semana" [style.gap.px]="4">
72
72
  @for (d of dias(); track d.fecha) {
73
- <sui-day-cell [size]="bp.isMobile() ? 'large' : 'medium'" [day]="d.numero" [today]="d.esHoy"
73
+ <sui-day-cell [size]="bp.tactil() ? 'large' : 'medium'" [day]="d.numero" [today]="d.esHoy"
74
74
  [marked]="d.conTurno" (clicked)="elegir(d)" />
75
75
  }
76
76
  </div>
77
77
  ```
78
78
 
79
+ ### Por dispositivo (D16)
80
+
81
+ La celda se toca: sigue «lo que se toca» de D16. Su size grande es `large` (44), el único que llega
82
+ al piso del dedo.
83
+
84
+ | dispositivo | size | nota |
85
+ |---|---|---|
86
+ | celular chico (< 380) | `large` | interino: D16 pide `medium` con área de 44, pero el DS todavía no la estira; 7 × 44 + 6 × 4 = 332 entra en 360 |
87
+ | celular (380–767) | `large` | gap 4 en la grilla |
88
+ | tablet táctil (`pointer: coarse`) | `large` | Apple pide 44 también en iPad |
89
+ | computadora (`pointer: fine`) | `medium` | 40 × 40, el de Figma |
90
+
91
+ Ultrawide: igual que la computadora. Fuente: D16, dueño 05-10-2026.
92
+
93
+ En master-pedidos: `[size]="bp.tactil() ? 'large' : 'medium'"`. `bp.sizeControl()` devuelve lo
94
+ mismo (`'large' | 'medium'`), pero está documentado para botón y campo; la expresión deja claro de
95
+ dónde sale. Si la grilla va con `sui-day-label`, la cabecera también tiene que medir 44 en `large`
96
+ (ver su README).
97
+
79
98
  ## «No usar»: por qué no hoy y cuándo sí
80
99
 
81
100
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -119,6 +138,44 @@ Los puntos de hoy y de marcado no cambian con el size.
119
138
  completa. Hoy lleva `aria-current="date"` y, en `type="range"`, `start`/`end` salen
120
139
  `aria-selected` (04-10-2026).
121
140
 
141
+ ## Bien y mal
142
+
143
+ El día de la grilla
144
+
145
+ ```html
146
+ <!-- ❌ mal: day es el número, no una fecha; la celda no sabe qué día es (Trampas) -->
147
+ <sui-day-cell [day]="d.fecha" [today]="true" />
148
+ ```
149
+
150
+ ```html
151
+ <!-- ✅ bien -->
152
+ <sui-day-cell [day]="d.fecha.getDate()" [today]="d.esHoy" [size]="bp.tactil() ? 'large' : 'medium'" />
153
+ ```
154
+
155
+ Días del mes vecino que no se eligen
156
+
157
+ ```html
158
+ <!-- ❌ mal: outOfMonth solo los apaga; se pueden tocar igual (Trampas) -->
159
+ <sui-day-cell [day]="d.numero" [outOfMonth]="true" (clicked)="elegir(d)" />
160
+ ```
161
+
162
+ ```html
163
+ <!-- ✅ bien -->
164
+ <sui-day-cell [day]="d.numero" [outOfMonth]="true" [disabled]="true" (clicked)="elegir(d)" />
165
+ ```
166
+
167
+ Un día con algo
168
+
169
+ ```html
170
+ <!-- ❌ mal: el lector de pantalla dice «Día 12», sin mes ni qué tiene (canon B5) -->
171
+ <sui-day-cell day="12" [marked]="true" />
172
+ ```
173
+
174
+ ```html
175
+ <!-- ✅ bien -->
176
+ <sui-day-cell day="12" [marked]="true" ariaLabel="Domingo 12 de octubre, con pedidos" />
177
+ ```
178
+
122
179
  ## Ejemplo
123
180
 
124
181
  ```html
@@ -38,17 +38,28 @@ Usos de hoy que rompen la regla: **0**.
38
38
 
39
39
  ## Tamaño en mobile y en web
40
40
 
41
- **No tiene `size`.** Mide 40 × 40, igual que `sui-day-cell`, para que las columnas calcen. No se
42
- toca: el tamaño solo importa para alinear.
41
+ **No tiene `size`.** Mide 40 × 40, igual que `sui-day-cell` `medium`, para que las columnas calcen.
42
+ No se toca: el tamaño solo importa para alinear. Con `sui-day-cell` `large` (44) la columna ya no
43
+ calza sola: el `sui-datepicker` `xlarge` le pone `width: 44px` desde afuera, y un calendario armado a
44
+ mano tiene que hacer lo mismo.
43
45
 
44
46
  | uso | mobile | web | fuente |
45
47
  |---|---|---|---|
46
- | cabecera de columna | 40 × 40 | 40 × 40 | medido |
48
+ | cabecera de columna | 40 × 40 (44 de ancho, desde afuera, si las celdas van en `large`) | 40 × 40 | medido · 44: `sui-datepicker.scss`, size `xlarge` |
47
49
 
48
50
  ```html
49
51
  @for (d of ['LU','MA','MI','JU','VI','SÁ','DO']; track d) { <sui-day-label [label]="d" /> }
50
52
  ```
51
53
 
54
+ ### Por dispositivo (D16)
55
+
56
+ No aplica: **no tiene `size`** y no se toca, así que no sube en ningún dispositivo. Lo único que
57
+ cambia es su ancho, que sigue al de la celda: 44 donde `sui-day-cell` va en `large` (celular chico,
58
+ celular y tablet táctil), 40 en la computadora. Fuente: D16, dueño 05-10-2026.
59
+
60
+ En master-pedidos: sin `[size]`; el ancho de 44 sale de la misma señal que la celda,
61
+ `bp.tactil()`.
62
+
52
63
  ## «No usar»: por qué no hoy y cuándo sí
53
64
 
54
65
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -74,6 +85,44 @@ Outputs: ninguno.
74
85
  al lector de pantalla.
75
86
  - Acepta cualquier texto, pero el ancho es fijo de 40 px: lo que no entra se corta.
76
87
 
88
+ ## Bien y mal
89
+
90
+ La cabecera de la semana
91
+
92
+ ```html
93
+ <!-- ❌ mal: «M» es martes y miércoles a la vez (canon B4) -->
94
+ @for (d of ['L','M','M','J','V','S','D']; track $index) { <sui-day-label [label]="d" /> }
95
+ ```
96
+
97
+ ```html
98
+ <!-- ✅ bien -->
99
+ @for (d of ['LU','MA','MI','JU','VI','SÁ','DO']; track d) { <sui-day-label [label]="d" /> }
100
+ ```
101
+
102
+ Elegir los días que abre el local
103
+
104
+ ```html
105
+ <!-- ❌ mal: es solo texto (columnheader); no se toca ni se marca -->
106
+ @for (d of dias; track d.value) { <sui-day-label [label]="d.label" (click)="alternar(d)" /> }
107
+ ```
108
+
109
+ ```html
110
+ <!-- ✅ bien: size por D16 (celular `large`, o `medium` si los 7 no entran: P18, pendiente) -->
111
+ <sui-button-group [multi]="true" [items]="dias" [size]="bp.sizeControl()" [(value)]="diasAbiertos" />
112
+ ```
113
+
114
+ Cabecera sobre celdas de 44
115
+
116
+ ```html
117
+ <!-- ❌ mal: la etiqueta mide 40 y la celda large 44; las columnas se corren -->
118
+ <sui-day-label label="LU" />
119
+ ```
120
+
121
+ ```html
122
+ <!-- ✅ bien: el mismo ancho que la celda, como hace el datepicker xlarge -->
123
+ <sui-day-label label="LU" [style.width.px]="bp.tactil() ? 44 : 40" [style.max-width.px]="bp.tactil() ? 44 : 40" />
124
+ ```
125
+
77
126
  ## Ejemplo
78
127
 
79
128
  ```html
@@ -45,7 +45,9 @@ Story: [Atoms/Divider/Divider](https://sui-design-system.web.app/?path=/docs/ato
45
45
  | `horizontal` (default) | Separa bloques o filas. El espacio arriba y abajo lo pone el `gap` del padre, no el divider. | `pages/driver/driver-dashboard/driver-dashboard.html:1127` (entre filas, `@if (!last)`) | según la guía del DS («Line») |
46
46
  | `vertical` | Separa datos cortos en una sola fila. El padre necesita alto (si no, mide 16 px). | — (sin usos) | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
47
47
 
48
- **Corregido el 03-10-2026:** las 26 líneas hechas a mano (mi-negocio, checkout, carrito, billetera y movimientos) ya son `sui-divider`. Seis conservan un `margin` propio porque sus vecinos se separan con margen y no con el `gap` del padre; pasarlo al `gap` es un cambio aparte.
48
+ **Corregido el 03-10-2026:** las 26 líneas hechas a mano (mi-negocio, checkout, carrito, billetera y movimientos) ya son `sui-divider`. Seis conservan un `margin` propio porque sus vecinos se separan con margen y no con el `gap` del padre; pasarlo al `gap` es un cambio aparte. Quedan **dos líneas a mano** (medido el 06-10-2026):
49
+ `pages/driver/driver-dashboard/driver-dashboard.html:410` (`.dashboard__votaciones-sep`) y
50
+ `pages/customer/viaje/viaje.html:111` (`.vj__ruta-divisor`).
49
51
 
50
52
  El «o» del login y del registro también pasó a `sui-content-divider type="text-line"`.
51
53
 
@@ -61,11 +63,17 @@ Criterio de la app: **D16, tamaño por dispositivo** (canon, dueño, 05-10-2026)
61
63
  380 px o más y, en lo que se toca, también la tablet (`pointer: coarse`). La columna «web» es la
62
64
  computadora (`pointer: fine`) y, en lo que no se toca, también la tablet. En el celular chico
63
65
  (< 380 px) va `medium` a la vista, sin achicar el área de 44 de lo que se toca. **Nada en `small` ni
64
- `xsmall`**, salvo lo que el componente solo tiene en chico. Hoy la app corta con
65
- `BreakpointsService.isMobile()` (≤ 767 px), que todavía no mira el puntero ni los 380 px.
66
+ `xsmall`**, salvo lo que el componente solo tiene en chico. En la app, `BreakpointsService` ya
67
+ mira el puntero y los 380 px: `bp.tactil()` (celular o pantalla táctil), `bp.celular()` (380–767) y
68
+ `bp.celularChico()` (< 380).
66
69
 
67
- **No aplica**: es 1 px en las dos plataformas. Lo que cambia por plataforma es el `gap` del padre,
68
- que separa los bloques (la regla de spacing de la app: 20/16/12 según el breakpoint).
70
+ ### Por dispositivo (D16)
71
+
72
+ **No aplica**: no tiene `size` y es 1 px en todos los dispositivos (celular chico, celular, tablet
73
+ táctil, computadora y ultrawide). Lo que cambia es el `gap` del padre, que separa los bloques (la
74
+ regla de spacing de la app: 20/16/12 según el breakpoint). Fuente: D16, dueño 05-10-2026.
75
+
76
+ En master-pedidos: sin `[size]`.
69
77
 
70
78
  ## API
71
79
 
@@ -89,6 +97,50 @@ Outputs: ninguno.
89
97
  - Lleva `role="separator"` y `aria-orientation`. Va **entre** filas (`@if (!last)`), no uno por
90
98
  fila: el último sobra.
91
99
 
100
+ ## Bien y mal
101
+
102
+ Separar dos bloques dentro de una card
103
+
104
+ ```html
105
+ <!-- ❌ mal: línea hecha a mano (pages/driver/driver-dashboard/driver-dashboard.html:410, .scss:1527) -->
106
+ <div class="dashboard__votaciones-sep"></div>
107
+ ```
108
+
109
+ ```html
110
+ <!-- ✅ bien: la línea la pone el divider; la clase se queda solo con el margin, como en checkout y carrito -->
111
+ <sui-divider class="dashboard__votaciones-sep" />
112
+ ```
113
+
114
+ Una línea entre las filas de una lista
115
+
116
+ ```html
117
+ <!-- ❌ mal: uno por fila; el último sobra y queda pegado al borde (Trampas) -->
118
+ @for (f of filas; track f.id) {
119
+ <app-fila [fila]="f" />
120
+ <sui-divider />
121
+ }
122
+ ```
123
+
124
+ ```html
125
+ <!-- ✅ bien -->
126
+ @for (f of filas; track f.id; let last = $last) {
127
+ <app-fila [fila]="f" />
128
+ @if (!last) { <sui-divider /> }
129
+ }
130
+ ```
131
+
132
+ Datos en una fila
133
+
134
+ ```html
135
+ <!-- ❌ mal: el padre no tiene alto ni centra; la línea queda de 16 px y descolgada (Trampas) -->
136
+ <div><span>4.7</span><sui-divider orientation="vertical" /><span>25–35 min</span></div>
137
+ ```
138
+
139
+ ```html
140
+ <!-- ✅ bien: .meta { display: flex; align-items: center; height: 20px; gap: 8px } -->
141
+ <div class="meta"><span>4.7</span><sui-divider orientation="vertical" /><span>25–35 min</span></div>
142
+ ```
143
+
92
144
  ## Ejemplo
93
145
 
94
146
  ```html
@@ -69,14 +69,32 @@ El `size` cambia **los botones** (escala del `sui-button`):
69
69
 
70
70
  | uso | mobile | web | fuente |
71
71
  |---|---|---|---|
72
- | pie de un drawer | `large` (48) | `medium` (40) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
72
+ | pie de un drawer | `large` (48), también en la tablet táctil | `medium` (40) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · tablet: D16, dueño 05-10-2026 |
73
73
  | par de botones de un modal | `sui-modal-footer` (botones `large`, 48) | `sui-modal-footer` | canon (CLAUDE.md, botones: size `large` en todos los modales) |
74
74
 
75
75
  ```html
76
- <sui-drawer-footer type="stretch" [size]="bp.isMobile() ? 'large' : 'medium'"
76
+ <sui-drawer-footer type="stretch" [size]="bp.sizeControl()"
77
77
  (primaryClick)="guardar()" (secondaryClick)="cancelar()" />
78
78
  ```
79
79
 
80
+ ### Por dispositivo (D16)
81
+
82
+ No está en la tabla por componente de D16: son botones, así que va con **lo que se toca** (la fila
83
+ de `button`). El `size` del pie es el de sus dos botones.
84
+
85
+ | dispositivo | size | nota |
86
+ |---|---|---|
87
+ | celular chico (< 380) | `large` (48) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino) |
88
+ | celular (380–767) | `large` (48) | |
89
+ | tablet táctil (`pointer: coarse`) | `large` (48) | se toca con el dedo: Apple pide 44 pt también en el iPad |
90
+ | computadora (`pointer: fine`) | `medium` (40) | |
91
+
92
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`; el espacio extra va a ancho, no a botones
93
+ más grandes.
94
+
95
+ En master-pedidos: `[size]="bp.sizeControl()"` (da `large` o `medium`, los dos sizes que tiene el pie).
96
+ Igual, el par de botones va en `sui-modal-footer` (ver arriba), cuyo canon es `large` siempre (D2).
97
+
80
98
  ## «No usar»: por qué no hoy y cuándo sí
81
99
 
82
100
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -130,6 +148,49 @@ interface SuiFooterButtonConfig { label: string; disabled?: boolean; color?: 'pr
130
148
  - `checkboxActive` y `toggleActive` son `model`: `[(checkboxActive)]`.
131
149
  - El borde de arriba ya viene puesto: no le sumes otro.
132
150
 
151
+ ## Bien y mal
152
+
153
+ **Pie de un modal**
154
+
155
+ ```html
156
+ <!-- ❌ mal: el par de botones de un modal es de sui-modal-footer (canon de botones, 27-07-2026) -->
157
+ <sui-drawer-footer type="basic" primaryButton="Guardar"
158
+ (primaryClick)="guardar()" (secondaryClick)="cerrar()" />
159
+ ```
160
+
161
+ ```html
162
+ <!-- ✅ bien -->
163
+ <sui-modal-footer secondaryButton="Cancelar" [primaryButton]="{ label: 'Guardar' }"
164
+ (secondaryClick)="cerrar()" (primaryClick)="guardar()" />
165
+ ```
166
+
167
+ **Confirmar algo destructivo**
168
+
169
+ ```html
170
+ <!-- ❌ mal: el drawer-footer ignora `color: 'error'`; el «Eliminar» sale naranja -->
171
+ <sui-drawer-footer type="basic" [primaryButton]="{ label: 'Eliminar', color: 'error' }"
172
+ (primaryClick)="eliminar()" (secondaryClick)="cerrar()" />
173
+ ```
174
+
175
+ ```html
176
+ <!-- ✅ bien -->
177
+ <sui-modal-footer secondaryButton="Cancelar" [primaryButton]="{ label: 'Eliminar', color: 'error' }"
178
+ (secondaryClick)="cerrar()" (primaryClick)="eliminar()" />
179
+ ```
180
+
181
+ **Un solo botón**
182
+
183
+ ```html
184
+ <!-- ❌ mal: sin `secondaryButton` aparece un «Cancelar» que nadie pidió (es el default) -->
185
+ <sui-drawer-footer type="basic" primaryButton="Entendido" (primaryClick)="cerrar()" />
186
+ ```
187
+
188
+ ```html
189
+ <!-- ✅ bien -->
190
+ <sui-drawer-footer type="basic" primaryButton="Entendido" [secondaryButton]="null"
191
+ [size]="bp.sizeControl()" (primaryClick)="cerrar()" />
192
+ ```
193
+
133
194
  ## Ejemplo
134
195
 
135
196
  ```html
@@ -56,7 +56,7 @@ Regla corta: **modal o sheet → sui-modal con title · panel lateral de web →
56
56
  | `showDismiss` | `false` | Solo si el panel no se puede cerrar sin decidir (y entonces es un modal, no un drawer). | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
57
57
  | `showDivider` | `true` | Cuando el cuerpo scrollea por debajo de la cabecera. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
58
58
  | `badge` | número | Pendientes dentro del panel (círculo rojo). | propuesta, falta aprobación |
59
- | `badge` | texto o `SuiBadgeConfig` | Un estado o etiqueta al lado del título. Pasa `variant: 'lighter'`: el default de aquí es `light` (ver Trampas). | canon (README de `sui-badge`: `lighter` en cabeceras) |
59
+ | `badge` | texto o `SuiBadgeConfig` | Un estado o etiqueta al lado del título. Pasa `variant: 'lighter'` y `size: 'medium'`: los defaults de aquí son `light` y `small` (ver Trampas). | canon (README de `sui-badge`: `lighter` en cabeceras) |
60
60
  | `link` | texto | Una acción menor en la cabecera («Ver todo»). Solo en `small`. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
61
61
  | `dismissAriaLabel` | «Cerrar» (default) | Ya está en español. | según el código |
62
62
 
@@ -77,6 +77,18 @@ los 40-44 del dedo. Es una pieza de web.
77
77
  }
78
78
  ```
79
79
 
80
+ ### Por dispositivo (D16)
81
+
82
+ No aplica: su `size` no depende del dispositivo sino del contenido (`large` cuando hay `description`,
83
+ `small` cuando el título se explica solo), y la X de cerrar es un `sui-compact-button` `large` fijo
84
+ (24 px) que el `size` de la cabecera no mueve. En el celular chico y en el celular no se usa (el
85
+ panel es un `sui-modal` fullscreen); en la computadora y el ultrawide va `small` o `large` según el
86
+ contenido. En la tablet táctil con 768 px o más el panel sí se mostraría y la X de 24 no llega al
87
+ piso de 44: ningún size lo arregla y queda **sin decidir**.
88
+
89
+ En master-pedidos: sin helper; `@if (!bp.isMobile())` alrededor y `size="large"` solo si lleva
90
+ `description`.
91
+
80
92
  ## «No usar»: por qué no hoy y cuándo sí
81
93
 
82
94
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -119,13 +131,58 @@ type SuiDrawerHeaderSize = 'small' | 'large' | 'xlarge';
119
131
 
120
132
  - **`description` no se ve en `small`** y **`link` no se ve en `large`/`xlarge`**: los dos se pasan
121
133
  sin error y no aparecen.
122
- - **El badge de texto sale `orange` + `light` por default**, que va contra el canon del badge
123
- (`lighter` en cabeceras, naranja solo si pide atención). Pasa un `SuiBadgeConfig` completo.
134
+ - **El badge de texto sale `orange` + `light` + `small` por default**, que va contra el canon del badge
135
+ (`lighter` en cabeceras, naranja solo si pide atención) y contra D16 (`medium` en la computadora;
136
+ `small` no se usa). Pasa un `SuiBadgeConfig` completo, con `size: 'medium'`. Un `SuiBadgeConfig`
137
+ sin `size` también cae en `small` (`bcfg.size ?? 'small'` en el template).
124
138
  - **`badge` en `0` sí se dibuja** (un círculo rojo con «0»). Pasa `null` para no mostrarlo.
125
139
  - **`left-icon` sin `icon` no dibuja nada.**
126
140
  - El título es un `<h2>`: si la página ya tiene un `h2` al mismo nivel, revisa el orden de títulos.
127
141
  - No hay contenedor: el fondo, el ancho y la animación del panel los pones tú.
128
142
 
143
+ ## Bien y mal
144
+
145
+ **Cabecera de un modal**
146
+
147
+ ```html
148
+ <!-- ❌ mal: el modal ya trae su cabecera; el drawer-header es para un panel lateral de web -->
149
+ <sui-modal [(open)]="abierto" [fullscreen]="true">
150
+ <sui-drawer-header title="Editar producto" (dismiss)="abierto.set(false)" />
151
+ </sui-modal>
152
+ ```
153
+
154
+ ```html
155
+ <!-- ✅ bien -->
156
+ <sui-modal [(open)]="abierto" [fullscreen]="true" title="Editar producto"
157
+ description="Los cambios se ven en la carta" />
158
+ ```
159
+
160
+ **Estado al lado del título**
161
+
162
+ ```html
163
+ <!-- ❌ mal: el texto suelto sale `orange` + `light`, contra el canon del badge (ver Trampas) -->
164
+ <sui-drawer-header title="Sabores Andinos" badge="Abierto" (dismiss)="cerrar()" />
165
+ ```
166
+
167
+ ```html
168
+ <!-- ✅ bien: config completa; sin `size` el badge cae en `small` y D16 pide `medium` en la computadora -->
169
+ <sui-drawer-header title="Sabores Andinos" (dismiss)="cerrar()"
170
+ [badge]="{ label: 'Abierto', color: 'green', variant: 'lighter', size: 'medium' }" />
171
+ ```
172
+
173
+ **Línea de contexto**
174
+
175
+ ```html
176
+ <!-- ❌ mal: con el `small` del default la `description` no se ve, y no avisa -->
177
+ <sui-drawer-header title="Historial de pedidos" description="Últimos 30 días" (dismiss)="cerrar()" />
178
+ ```
179
+
180
+ ```html
181
+ <!-- ✅ bien -->
182
+ <sui-drawer-header size="large" title="Historial de pedidos" description="Últimos 30 días"
183
+ (dismiss)="cerrar()" />
184
+ ```
185
+
129
186
  ## Ejemplo
130
187
 
131
188
  ```html
@@ -59,6 +59,14 @@ de 44 px del dedo.
59
59
  |---|---|---|---|
60
60
  | pie de un menú | igual (14/20) | igual (14/20) | canon (aprobado por el dueño, 05-10-2026, bloque B1) |
61
61
 
62
+ ### Por dispositivo (D16)
63
+
64
+ No aplica: no tiene input `size` y no se toca, así que mide 14/20 con 8 px de padding en todo
65
+ dispositivo (celular chico, celular, tablet táctil, computadora y ultrawide). El que crece en lo
66
+ táctil es el `sui-dropdown-item` de al lado, no la caption.
67
+
68
+ En master-pedidos: sin `[size]` ni helper.
69
+
62
70
  ## API
63
71
 
64
72
  <!-- api:inicio -->
@@ -79,13 +87,57 @@ Slot: el contenido por defecto (`<ng-content />`) es el texto.
79
87
  la caja.
80
88
  - No lleva `role`: el lector de pantalla lo lee como texto suelto dentro del menú.
81
89
 
90
+ ## Bien y mal
91
+
92
+ **Cabecera de un grupo**
93
+
94
+ ```html
95
+ <!-- ❌ mal: la caption es gris claro y va al pie; no titula un grupo -->
96
+ <sui-dropdown-caption>Negocios</sui-dropdown-caption>
97
+ @for (t of negocios(); track t.id) { <sui-dropdown-item [label]="t.name" mode="option" size="large" /> }
98
+ ```
99
+
100
+ ```html
101
+ <!-- ✅ bien (lo mismo para los <span> a mano de sidebar.html:67, :88 y :104) -->
102
+ <sui-content-divider type="text" text="Negocios" />
103
+ @for (t of negocios(); track t.id) { <sui-dropdown-item [label]="t.name" mode="option" size="large" /> }
104
+ ```
105
+
106
+ **Un dato que ayuda a elegir**
107
+
108
+ ```html
109
+ <!-- ❌ mal: `soft-400` es el gris de los metadatos; lo que decide la elección no va aquí -->
110
+ <sui-dropdown-item label="Recojo en tienda" size="large" />
111
+ <sui-dropdown-caption>El recojo está listo en 20 min</sui-dropdown-caption>
112
+ ```
113
+
114
+ ```html
115
+ <!-- ✅ bien -->
116
+ <sui-dropdown-item label="Recojo en tienda" description="Listo en 20 min" size="large" />
117
+ ```
118
+
119
+ **Dónde va**
120
+
121
+ ```html
122
+ <!-- ❌ mal: arriba del todo, empuja los items y se lee antes que ellos -->
123
+ <sui-dropdown-caption>Presiona Enter para agregar</sui-dropdown-caption>
124
+ <sui-dropdown-search [(value)]="busqueda" placeholder="Buscar etiqueta…" />
125
+ ```
126
+
127
+ ```html
128
+ <!-- ✅ bien: al final del panel, después del último item -->
129
+ <sui-dropdown-search [(value)]="busqueda" placeholder="Buscar etiqueta…" />
130
+ @for (e of etiquetas(); track e) { <sui-dropdown-item [label]="e" size="large" /> }
131
+ <sui-dropdown-caption>Presiona Enter para agregar</sui-dropdown-caption>
132
+ ```
133
+
82
134
  ## Ejemplo
83
135
 
84
136
  ```html
85
137
  <ng-template suiDropdownPanel>
86
138
  <sui-dropdown-search [(value)]="busqueda" placeholder="Buscar etiqueta…" />
87
139
  @for (e of etiquetasFiltradas(); track e) {
88
- <sui-dropdown-item [label]="e" (clicked)="menu.close(); elegir(e)" />
140
+ <sui-dropdown-item [label]="e" size="large" (clicked)="menu.close(); elegir(e)" />
89
141
  }
90
142
  <sui-dropdown-caption>Presiona Enter para crear «{{ busqueda() }}»</sui-dropdown-caption>
91
143
  </ng-template>