@ajuarezso/sui-design-system 0.24.1 → 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 (120) hide show
  1. package/docs/sui-accordion/README.md +85 -11
  2. package/docs/sui-activity-feed/README.md +65 -11
  3. package/docs/sui-activity-filter/README.md +54 -5
  4. package/docs/sui-alert/README.md +54 -0
  5. package/docs/sui-app-store-badge/README.md +64 -10
  6. package/docs/sui-avatar/README.md +92 -29
  7. package/docs/sui-avatar-group/README.md +75 -9
  8. package/docs/sui-badge/README.md +85 -17
  9. package/docs/sui-banner/README.md +85 -20
  10. package/docs/sui-brand-logo/README.md +95 -31
  11. package/docs/sui-breadcrumb-item/README.md +54 -3
  12. package/docs/sui-breadcrumbs/README.md +54 -6
  13. package/docs/sui-button/README.md +76 -12
  14. package/docs/sui-button-group/README.md +91 -23
  15. package/docs/sui-button-group-item/README.md +81 -14
  16. package/docs/sui-card/README.md +105 -18
  17. package/docs/sui-chart-legend/README.md +63 -10
  18. package/docs/sui-chart-legend-dot/README.md +59 -10
  19. package/docs/sui-checkbox/README.md +109 -29
  20. package/docs/sui-checkbox-card/README.md +70 -14
  21. package/docs/sui-checkbox-label/README.md +92 -26
  22. package/docs/sui-circular-progress-bar/README.md +80 -19
  23. package/docs/sui-color-dot/README.md +72 -12
  24. package/docs/sui-color-picker/README.md +71 -13
  25. package/docs/sui-command-menu-footer/README.md +50 -1
  26. package/docs/sui-command-menu-item/README.md +74 -14
  27. package/docs/sui-command-menu-search/README.md +58 -3
  28. package/docs/sui-compact-avatar-group/README.md +73 -13
  29. package/docs/sui-compact-button/README.md +123 -34
  30. package/docs/sui-compact-select/README.md +61 -7
  31. package/docs/sui-compact-select-for-input/README.md +70 -6
  32. package/docs/sui-content-card/README.md +75 -14
  33. package/docs/sui-content-divider/README.md +67 -16
  34. package/docs/sui-content-label/README.md +99 -20
  35. package/docs/sui-counter-input/README.md +102 -18
  36. package/docs/sui-date-selector/README.md +69 -11
  37. package/docs/sui-datepicker/README.md +85 -18
  38. package/docs/sui-day-cell/README.md +75 -17
  39. package/docs/sui-day-label/README.md +56 -7
  40. package/docs/sui-divider/README.md +64 -9
  41. package/docs/sui-drawer-footer/README.md +63 -2
  42. package/docs/sui-drawer-header/README.md +69 -12
  43. package/docs/sui-dropdown-caption/README.md +58 -6
  44. package/docs/sui-dropdown-item/README.md +75 -9
  45. package/docs/sui-dropdown-menu/README.md +83 -14
  46. package/docs/sui-dropdown-search/README.md +60 -4
  47. package/docs/sui-emoji/README.md +94 -30
  48. package/docs/sui-empty-state/README.md +71 -7
  49. package/docs/sui-fancy-button/README.md +74 -14
  50. package/docs/sui-file-icon/README.md +70 -12
  51. package/docs/sui-file-upload/README.md +77 -17
  52. package/docs/sui-file-upload-card/README.md +64 -12
  53. package/docs/sui-filter/README.md +83 -14
  54. package/docs/sui-flag/README.md +73 -8
  55. package/docs/sui-form-hint/README.md +56 -7
  56. package/docs/sui-form-label/README.md +57 -5
  57. package/docs/sui-href/README.md +47 -0
  58. package/docs/sui-icon/README.md +86 -18
  59. package/docs/sui-image-upload/README.md +90 -22
  60. package/docs/sui-image-upload-profile/README.md +70 -11
  61. package/docs/sui-img-retry/README.md +50 -1
  62. package/docs/sui-inline-input/README.md +67 -9
  63. package/docs/sui-inline-select/README.md +62 -2
  64. package/docs/sui-input/README.md +90 -27
  65. package/docs/sui-integration-switch/README.md +84 -17
  66. package/docs/sui-kbd/README.md +73 -9
  67. package/docs/sui-key-icon/README.md +85 -23
  68. package/docs/sui-link-button/README.md +96 -27
  69. package/docs/sui-logo/README.md +93 -22
  70. package/docs/sui-modal/README.md +72 -13
  71. package/docs/sui-modal-footer/README.md +86 -12
  72. package/docs/sui-modal-header/README.md +57 -1
  73. package/docs/sui-modal-sheet/README.md +74 -12
  74. package/docs/sui-notification/README.md +81 -11
  75. package/docs/sui-notification-footer/README.md +55 -5
  76. package/docs/sui-notification-tab-menu/README.md +61 -5
  77. package/docs/sui-otp-input/README.md +70 -9
  78. package/docs/sui-page-header/README.md +89 -19
  79. package/docs/sui-pagination/README.md +73 -13
  80. package/docs/sui-password-strength/README.md +50 -1
  81. package/docs/sui-payment-icon/README.md +80 -18
  82. package/docs/sui-period-range/README.md +70 -11
  83. package/docs/sui-popover/README.md +81 -15
  84. package/docs/sui-product-card/README.md +89 -21
  85. package/docs/sui-progress-bar/README.md +82 -15
  86. package/docs/sui-progress-bar-label/README.md +79 -18
  87. package/docs/sui-radio/README.md +84 -7
  88. package/docs/sui-radio-card/README.md +70 -16
  89. package/docs/sui-radio-label/README.md +89 -22
  90. package/docs/sui-rating/README.md +101 -31
  91. package/docs/sui-rich-editor/README.md +47 -2
  92. package/docs/sui-segmented-control/README.md +90 -21
  93. package/docs/sui-select/README.md +80 -11
  94. package/docs/sui-sidebar/README.md +71 -16
  95. package/docs/sui-slider/README.md +75 -8
  96. package/docs/sui-social-button/README.md +71 -11
  97. package/docs/sui-status-badge/README.md +75 -14
  98. package/docs/sui-stepper/README.md +75 -18
  99. package/docs/sui-store-card/README.md +85 -22
  100. package/docs/sui-switch/README.md +82 -11
  101. package/docs/sui-switch-card/README.md +80 -16
  102. package/docs/sui-switch-label/README.md +91 -14
  103. package/docs/sui-tab-chips/README.md +93 -21
  104. package/docs/sui-tab-menu-horizontal/README.md +68 -7
  105. package/docs/sui-tab-menu-vertical/README.md +64 -11
  106. package/docs/sui-table/README.md +77 -16
  107. package/docs/sui-tag/README.md +86 -12
  108. package/docs/sui-tag-input/README.md +77 -13
  109. package/docs/sui-textarea/README.md +84 -17
  110. package/docs/sui-time-picker/README.md +96 -33
  111. package/docs/sui-toast/README.md +81 -20
  112. package/docs/sui-tooltip/README.md +80 -22
  113. package/docs/sui-topbar/README.md +64 -10
  114. package/docs/sui-topbar-button/README.md +61 -7
  115. package/docs/sui-topbar-item/README.md +68 -7
  116. package/docs/sui-topbar-user/README.md +61 -5
  117. package/fesm2022/ajuarezso-sui-design-system.mjs +15 -10
  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 +7 -3
@@ -39,8 +39,8 @@ panel (header + items + footer) · un filtro suelto → compact-select.**
39
39
  ## Qué variante usar
40
40
 
41
41
  > **La guía del DS no tiene página de filtros**: estas piezas salen solo del Figma del DS
42
- > («Filters»: HorizontalFilter y VerticalFilter). Todo lo de abajo es **propuesta, falta
43
- > aprobación**, salvo lo marcado canon.
42
+ > («Filters»: HorizontalFilter y VerticalFilter). Las reglas marcadas canon están aprobadas; lo
43
+ > que sigue **pendiente** (el área de 44 de `sui-filter-item` en mobile, P19) espera decisión.
44
44
  >
45
45
  > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-dropdown-menu`):
46
46
  > **0 usos**. Solo aparecen en la vitrina `master-preview`.
@@ -49,8 +49,8 @@ panel (header + items + footer) · un filtro suelto → compact-select.**
49
49
 
50
50
  | variant | cuándo | fuente |
51
51
  |---|---|---|
52
- | `table` (default) | Arriba de una tabla: a la izquierda la vista (`sui-segmented-control`), a la derecha el buscador (`sui-input type="search"`) y el orden (`sui-select` o `sui-compact-select`). | propuesta (composición del Figma) |
53
- | `calendar` | Arriba de una vista por fechas: a la izquierda «Hoy» + el rango (`sui-button-group`), a la derecha el buscador. | propuesta (composición del Figma) |
52
+ | `table` (default) | Arriba de una tabla: a la izquierda la vista (`sui-segmented-control`), a la derecha el buscador (`sui-input type="search"`) y el orden (`sui-select` o `sui-compact-select`). | canon (aprobado por el dueño, 05-10-2026, bloque B9), composición del Figma |
53
+ | `calendar` | Arriba de una vista por fechas: a la izquierda «Hoy» + el rango (`sui-button-group`), a la derecha el buscador. | canon (aprobado por el dueño, 05-10-2026, bloque B9), composición del Figma |
54
54
 
55
55
  `variant` solo marca el host (`data-sui-variant`): **no cambia el layout**. Lo que se ve lo deciden
56
56
  los controles que se proyectan.
@@ -59,12 +59,12 @@ los controles que se proyectan.
59
59
 
60
60
  | pieza | regla | fuente |
61
61
  |---|---|---|
62
- | `sui-filter-item` `active` | La categoría abierta (la que muestra sus opciones al lado): fondo gris, texto negro, flecha a la derecha. | propuesta (estados del Figma) |
63
- | `sui-filter-item` `leftIcon` | Un ícono por categoría si ayuda a ubicarla («Estado», «Local», «Repartidor»). | propuesta |
62
+ | `sui-filter-item` `active` | La categoría abierta (la que muestra sus opciones al lado): fondo gris, texto negro, flecha a la derecha. | según el código (estados del Figma) |
63
+ | `sui-filter-item` `leftIcon` | Un ícono por categoría si ayuda a ubicarla («Estado», «Local», «Repartidor»). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
64
64
  | `sui-filter-panel-header` `clear` | `clear=true` dice «Limpiar» (en español desde el 04-10-2026); un string lo cambia. | canon (CANON-SUI §5: copy en español) |
65
65
  | `sui-filter-panel-footer` | «Limpiar» a la izquierda (`stroke neutral`), «Aplicar» a la derecha (`filled primary`), mitad y mitad. | canon (orden de `sui-modal-footer`, CLAUDE.md «Botones») |
66
- | «Limpiar» en header **y** footer | Elegir uno. Con el footer, el header va sin link. | propuesta |
67
- | `applyButton` deshabilitado | `{ label: 'Aplicar', disabled: !cambio() }` mientras no se toca nada. | propuesta |
66
+ | «Limpiar» en header **y** footer | Elegir uno. Con el footer, el header va sin link. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
67
+ | `applyButton` deshabilitado | `{ label: 'Aplicar', disabled: !cambio() }` mientras no se toca nada. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
68
68
 
69
69
  ## Tamaño en mobile y en web
70
70
 
@@ -72,20 +72,42 @@ Ninguna pieza cambia sola en mobile, salvo la barra, que apila sus dos lados por
72
72
 
73
73
  | pieza | mobile | web | fuente |
74
74
  |---|---|---|---|
75
- | `sui-filter-bar` | sin tamaño; los controles adentro van `large` (48) | sin tamaño; los controles `small` (36) | propuesta (igual que `sui-compact-select` en una barra) |
76
- | `sui-filter-item` | 36 de alto, no se puede cambiar: debajo de los 44 del dedo | 36 | propuesta |
77
- | `sui-filter-panel-footer` | `medium` (40) es lo más grande que tiene; en mobile, mejor `sui-modal-footer` (48) dentro de un `sui-modal-sheet` | `small` (36, default) | canon para el 48 de mobile (CLAUDE.md: footer de modal `large`); el resto, propuesta |
75
+ | `sui-filter-bar` | sin tamaño; los controles adentro van `large` (48) | sin tamaño; los controles `medium` (40) | canon (D16, dueño 05-10-2026) |
76
+ | `sui-filter-item` | 36 de alto, no se puede cambiar: debajo de los 44 del dedo | 36 | pendiente (P19: área invisible de 44 o no usarlo en mobile) |
77
+ | `sui-filter-panel-footer` | `medium` (40) es lo más grande que tiene; en mobile, mejor `sui-modal-footer` (48) dentro de un `sui-modal-sheet` | `medium` (40) | canon para el 48 de mobile (CLAUDE.md: footer de modal `large`); web `medium` (40): canon (dueño, 05-10-2026, D16), reemplaza el `small` del bloque B1 (`small` es el default del componente: hay que pasarlo) |
78
78
  | `sui-filter-panel-header` | sin tamaño | sin tamaño | — |
79
79
 
80
80
  ```html
81
81
  <sui-filter-bar>
82
- <sui-segmented-control slot="start" … />
82
+ <sui-segmented-control slot="start" [size]="bp.tactil() ? '2xlarge' : 'medium'" … />
83
83
  <div slot="end">
84
- <sui-input type="search" [size]="bp.isMobile() ? 'large' : 'small'" placeholder="Buscar pedido…" … />
84
+ <sui-input type="search" [size]="bp.sizeControl()" placeholder="Buscar pedido…" … />
85
85
  </div>
86
86
  </sui-filter-bar>
87
87
  ```
88
88
 
89
+ ### Por dispositivo (D16)
90
+
91
+ Las piezas no tienen un `size` propio (salvo el pie): lo que cambia por dispositivo son los
92
+ controles que se proyectan en la barra. Fuente: D16, dueño 05-10-2026 (fila `filter`).
93
+
94
+ | dispositivo | size | nota |
95
+ |---|---|---|
96
+ | celular chico (< 380) | sin regla en la tabla (`—`) | la fila `filter` de D16 no lo define; `bp.sizeControl()` da `large`, igual que en el celular, mientras el DS no estire a 44 el área de los `medium` |
97
+ | celular (380–767) | controles `large` · segmented `2xlarge` | el panel va en un `sui-modal-sheet` con `sui-modal-footer` (48), no con este pie; el área de 44 de `sui-filter-item` está pendiente (P19) |
98
+ | tablet táctil (`pointer: coarse`) | controles `large` · segmented `2xlarge` | se toca como un celular: el panel lleva `sui-modal-footer` (48) en vez de este pie, que llega solo a `medium` (40). D16 no fija el pie en la tablet; esto sigue la columna «mobile» de arriba. El área de 44 de `sui-filter-item` está pendiente (P19), igual que en el celular |
99
+ | computadora (`pointer: fine`) | controles `medium` · `sui-filter-panel-footer` `medium` | el default del pie es `small`: hay que pasarlo |
100
+
101
+ En el ultrawide, igual que en la computadora: el espacio extra va al ancho de la tabla, no a
102
+ controles más grandes.
103
+
104
+ En master-pedidos: `[size]="bp.sizeControl()"` en el `sui-input`, `sui-select` o
105
+ `sui-compact-select` de la barra, `[size]="bp.tactil() ? '2xlarge' : 'medium'"` en el
106
+ `sui-segmented-control` (no tiene helper) y `size="medium"` fijo en `sui-filter-panel-footer`,
107
+ que solo se usa en la computadora (solo tiene `small` y `medium`: `bp.sizeControl()` le pasaría un
108
+ `large` que no existe); con `bp.tactil()` el panel lleva `sui-modal-footer` en su lugar. No uses
109
+ `bp.isMobile() ? 'large' : 'medium'`: deja la tablet táctil en `medium`.
110
+
89
111
  ## API
90
112
 
91
113
  <!-- api:inicio -->
@@ -159,12 +181,59 @@ de `sui-drawer-footer`).
159
181
  - El footer no llega a `large`: en mobile queda más chico que el footer de cualquier modal.
160
182
  - `disabled` del item usa opacidad (no está en el Figma).
161
183
 
184
+ ## Bien y mal
185
+
186
+ > Hoy no hay usos de estas piezas fuera de la vitrina `master-preview`: los pares salen de las
187
+ > trampas de este README.
188
+
189
+ Pie del panel en la computadora
190
+
191
+ ```html
192
+ <!-- ❌ mal: sin size queda en small (36), y D16 no usa small -->
193
+ <sui-filter-panel-footer (clear)="limpiar()" (apply)="aplicar()" />
194
+ ```
195
+
196
+ ```html
197
+ <!-- ✅ bien -->
198
+ <sui-filter-panel-footer size="medium" (clear)="limpiar()" (apply)="aplicar()" />
199
+ ```
200
+
201
+ «Limpiar» en dos lugares
202
+
203
+ ```html
204
+ <!-- ❌ mal: «Limpiar» en la cabecera y en el pie; se elige uno -->
205
+ <sui-filter-panel-header label="Filtros" [clear]="true" (clearClick)="limpiar()" />
206
+ <sui-filter-panel-footer size="medium" (clear)="limpiar()" (apply)="aplicar()" />
207
+ ```
208
+
209
+ ```html
210
+ <!-- ✅ bien -->
211
+ <sui-filter-panel-header label="Filtros" leftIcon="equalizer-line" />
212
+ <sui-filter-panel-footer size="medium" (clear)="limpiar()" (apply)="aplicar()" />
213
+ ```
214
+
215
+ Buscador de la barra
216
+
217
+ ```html
218
+ <!-- ❌ mal: isMobile deja la tablet táctil en medium (40), debajo de los 44 -->
219
+ <sui-filter-bar>
220
+ <sui-input slot="end" type="search" [size]="bp.isMobile() ? 'large' : 'medium'" />
221
+ </sui-filter-bar>
222
+ ```
223
+
224
+ ```html
225
+ <!-- ✅ bien -->
226
+ <sui-filter-bar>
227
+ <sui-input slot="end" type="search" [size]="bp.sizeControl()" placeholder="Buscar pedido…" />
228
+ </sui-filter-bar>
229
+ ```
230
+
162
231
  ## Ejemplo
163
232
 
164
233
  ```html
165
234
  <!-- Panel de filtros en web, anclado a un botón «Filtros» -->
166
235
  <sui-dropdown-menu #filtros="suiDropdownMenu" [minWidth]="320">
167
- <sui-button trigger variant="stroke" color="neutral" size="small">Filtros</sui-button>
236
+ <sui-button trigger variant="stroke" color="neutral" size="medium">Filtros</sui-button>
168
237
  <ng-template suiDropdownPanel>
169
238
  <sui-filter-panel-header label="Filtros" leftIcon="equalizer-line" />
170
239
  <div role="listbox" aria-label="Categorías de filtro">
@@ -19,7 +19,8 @@ nada a nadie.
19
19
 
20
20
  ## Qué variante usar
21
21
 
22
- > **La guía del DS no tiene este componente.** Todo es **propuesta, falta aprobación**.
22
+ > **La guía del DS no tiene este componente.** Las reglas marcadas canon están aprobadas y las de
23
+ > «según el código» describen el componente; lo que sigue en **propuesta** espera decisión.
23
24
  >
24
25
  > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usan por dentro
25
26
  > `sui-select`, `sui-compact-select`, `sui-compact-select-for-input`, `sui-inline-select`,
@@ -32,17 +33,17 @@ nada a nadie.
32
33
  |---|---|---|---|
33
34
  | `xs` | 16 | Dentro de un select o un tag (así lo usa el DS). | propuesta |
34
35
  | `sm` | 20 | El prefijo de un teléfono. | propuesta |
35
- | `md` (default) | 24 | Fila de una lista. | propuesta |
36
+ | `md` (default) | 24 | Fila de una lista. | canon (aprobado por el dueño, 05-10-2026, bloque B1) |
36
37
  | `lg` | 32 | Dentro de una card. | propuesta |
37
- | `xl` | 48 | No usar hoy. | propuesta |
38
- | `full` | 100 % | Llena su caja (la caja manda). | propuesta |
38
+ | `xl` | 48 | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
39
+ | `full` | 100 % | Llena su caja (la caja manda). | según el código |
39
40
 
40
41
  ### `name` y `ariaLabel`
41
42
 
42
43
  | input | cuándo | fuente |
43
44
  |---|---|---|
44
- | `name` | El slug en inglés y en kebab-case: `peru`, `venezuela`, `united-states`. Son 262. | propuesta |
45
- | `ariaLabel` | El nombre del país en español, si no está escrito al lado. Sin él, es decorativa. | propuesta |
45
+ | `name` | El slug en inglés y en kebab-case: `peru`, `venezuela`, `united-states`. Son 262. | según el código |
46
+ | `ariaLabel` | El nombre del país en español, si no está escrito al lado. Sin él, es decorativa. | canon (aprobado por el dueño, 05-10-2026, bloque B5) |
46
47
 
47
48
  Usos de hoy que rompen la regla: **0**.
48
49
 
@@ -51,7 +52,10 @@ Usos de hoy que rompen la regla: **0**.
51
52
  En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
52
53
  pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
53
54
  breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
54
- el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propuesta**.
55
+ el celular (cliente, repartidor) va directo el valor de mobile. No se toca, así que la tablet va
56
+ con el valor de web, y el celular chico (< 380 px) también (D16).
57
+ Es **canon (dueño, 05-10-2026, P1 b)**: un paso más grande en el celular que en computadora, y
58
+ se migra todo ahora, no solo al tocar cada pantalla.
55
59
 
56
60
  | uso | mobile | web |
57
61
  |---|---|---|
@@ -59,11 +63,31 @@ el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propue
59
63
  | fila de una lista | `md` (24) | `sm` (20) |
60
64
 
61
65
  ```html
62
- <sui-flag name="peru" [size]="bp.isMobile() ? 'sm' : 'xs'" ariaLabel="Perú" />
66
+ <sui-flag name="peru" [size]="bp.celular() ? 'sm' : 'xs'" ariaLabel="Perú" />
63
67
  ```
64
68
 
65
69
  La bandera no se toca: el área táctil es la del select que la contiene.
66
70
 
71
+ ### Por dispositivo (D16)
72
+
73
+ La bandera no se toca: sube un paso **solo en el celular de 380 px o más**. Fuente: D16, dueño
74
+ 05-10-2026 (P1 b).
75
+
76
+ | dispositivo | size | nota |
77
+ |---|---|---|
78
+ | celular chico (< 380) | valor «web» (`xs` en el prefijo, `sm` en una fila) | no se toca: no sube aunque sea un celular |
79
+ | celular (380–767) | valor «mobile» (`sm` en el prefijo, `md` en una fila) | un paso más que en la computadora |
80
+ | tablet táctil (`pointer: coarse`) | valor «web» (`xs` / `sm`) | no se toca: el puntero no cambia nada |
81
+ | computadora (`pointer: fine`) | valor «web» (`xs` / `sm`) | |
82
+
83
+ En el ultrawide, igual que en la computadora: el espacio extra va a más columnas, no a banderas
84
+ más grandes.
85
+
86
+ En master-pedidos no hay helper: `[size]="bp.celular() ? 'sm' : 'xs'"` en el prefijo y
87
+ `[size]="bp.celular() ? 'md' : 'sm'"` en una fila. No uses `bp.isMobile()`: incluye el celular
88
+ chico, que va con el valor de web. Dentro de un select o un compact-select no se pasa nada: el
89
+ componente elige el tamaño de su bandera.
90
+
67
91
  ## «No usar»: por qué no hoy y cuándo sí
68
92
 
69
93
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -93,6 +117,47 @@ Outputs: ninguno.
93
117
  - **El nombre va en inglés** y con las grafías del set (`slovania`, `mauritus`, `taijikistan`):
94
118
  copia el slug de `SUI_FLAG_NAMES`, no lo escribas de memoria.
95
119
 
120
+ ## Bien y mal
121
+
122
+ > Hoy no hay usos directos fuera de la vitrina `master-preview`: los pares salen de las reglas
123
+ > de este README.
124
+
125
+ Bandera de adorno
126
+
127
+ ```html
128
+ <!-- ❌ mal: la app es solo Perú; la bandera no le dice nada a nadie -->
129
+ <p><sui-flag name="peru" size="sm" /> Delivery en todo el Perú</p>
130
+ ```
131
+
132
+ ```html
133
+ <!-- ✅ bien -->
134
+ <p>Delivery en todo el Perú</p>
135
+ ```
136
+
137
+ País sin nombre al lado
138
+
139
+ ```html
140
+ <!-- ❌ mal: sin ariaLabel es decorativa y el lector de pantalla no dice el país -->
141
+ <sui-flag name="venezuela" [size]="bp.celular() ? 'md' : 'sm'" />
142
+ ```
143
+
144
+ ```html
145
+ <!-- ✅ bien -->
146
+ <sui-flag name="venezuela" [size]="bp.celular() ? 'md' : 'sm'" ariaLabel="Venezuela" />
147
+ ```
148
+
149
+ Tamaño por dispositivo
150
+
151
+ ```html
152
+ <!-- ❌ mal: isMobile sube la bandera también en el celular chico (< 380), que va con el valor de web -->
153
+ <sui-flag name="peru" [size]="bp.isMobile() ? 'sm' : 'xs'" ariaLabel="Perú" />
154
+ ```
155
+
156
+ ```html
157
+ <!-- ✅ bien -->
158
+ <sui-flag name="peru" [size]="bp.celular() ? 'sm' : 'xs'" ariaLabel="Perú" />
159
+ ```
160
+
96
161
  ## Ejemplo
97
162
 
98
163
  ```html
@@ -32,7 +32,7 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
32
32
  > y opcional. No da reglas de largo ni de copy.
33
33
  >
34
34
  > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`; las cifras
35
- > siguen iguales el 04-10-2026, las líneas de abajo están actualizadas a esa fecha):
35
+ > siguen iguales el 04-10-2026, las líneas de abajo se revisaron el 06-10-2026):
36
36
  > **36 usos en 18 archivos**: 11 `error`, 25 `neutral` (24 por default y 1 explícito), 0
37
37
  > `disabled`; 2 con `icon` propio (`information-line`). Hay además **al menos 14 hints escritos a
38
38
  > mano** con clases propias (`__form-hint`, `__hint`).
@@ -51,8 +51,8 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
51
51
  |---|---|---|
52
52
  | `message` | Hasta 8 palabras (mediana 6). Si no cabe, es un `sui-alert`. Sin punto final si es una frase corta; con punto si son dos oraciones. | canon (`docs/CANON-SUI.md` §5.4 el largo; `docs/VOZ-Y-ESCRITURA.md` el punto) |
53
53
  | `icon` sin pasar | El de la variante (ninguno en `neutral`, info en `error` y `disabled`). | según la guía del DS (ícono opcional); default de SUI |
54
- | `icon="…"` en `neutral` | Solo cuando la ayuda es una advertencia que conviene notar («No reconocimos el distrito…»). | propuesta, falta aprobación (2 usos hoy) |
55
- | `[icon]="null"` | Quita el ícono también en `error`. No usar: el error necesita algo más que el color. | propuesta, falta aprobación |
54
+ | `icon="…"` en `neutral` | Solo cuando la ayuda es una advertencia que conviene notar («No reconocimos el distrito…»). | canon (aprobado por el dueño, 05-10-2026, bloque B9) (2 usos hoy) |
55
+ | `[icon]="null"` | Quita el ícono también en `error`. No usar: el error necesita algo más que el color. | canon (aprobado por el dueño, 05-10-2026, bloque B5) |
56
56
 
57
57
  **Usos de hoy que rompen las reglas:**
58
58
 
@@ -65,11 +65,11 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
65
65
  («Pausa tu sucursal…», bajo el título de la card), `:61`, `pages/drivers/drivers.html:29`,
66
66
  `pages/driver/driver-schedule/driver-schedule.html:92`.
67
67
  - **12 de más de 8 palabras** (4 son los subtítulos de arriba) → acortar, o `sui-alert` si de
68
- verdad hace falta todo: `pages/super-admin/master-users/master-users.html:66` (26 palabras),
69
- `pages/orders/orders.html:589` (23), `pages/driver/driver-order-detail/driver-order-detail.html:868` (23),
70
- `pages/envios/envios.html:401` (15).
68
+ verdad hace falta todo: `pages/super-admin/master-users/master-users.html:68` (26 palabras),
69
+ `pages/orders/orders.html:590` (23), `pages/driver/driver-order-detail/driver-order-detail.html:898` (23),
70
+ `pages/envios/envios.html:402` (15).
71
71
  - **Al menos 14 hints a mano** con clases propias. Ejemplos: `pages/discounts/discounts.html:205`
72
- (`discounts__form-hint`), `components/settings-panel/settings-panel.html:93`,
72
+ (`discounts__form-hint`), `components/settings-panel/settings-panel.html:95`,
73
73
  `pages/promociones/promociones.html:181`.
74
74
 
75
75
  ## Tamaño en mobile y en web
@@ -80,6 +80,12 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
80
80
 
81
81
  Es texto que no se toca: el mismo tamaño en las dos plataformas está bien.
82
82
 
83
+ ### Por dispositivo (D16)
84
+
85
+ No aplica: no tiene `size` (la letra es fija de 12/16 px y no se toca), así que es la misma en el
86
+ celular chico, el celular, la tablet táctil, la computadora y el ultrawide. En master-pedidos no
87
+ lleva `bp`.
88
+
83
89
  ## «No usar»: por qué no hoy y cuándo sí
84
90
 
85
91
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -115,6 +121,49 @@ Outputs: ninguno.
115
121
  (04-10-2026). Para enlazarlo a un control propio, pon `id` en el host y apúntalo con
116
122
  `aria-describedby`; los campos del DS ya lo hacen solos.
117
123
 
124
+ ## Bien y mal
125
+
126
+ Ayuda debajo de un campo de texto
127
+
128
+ ```html
129
+ <!-- ❌ mal: sui-input ya trae su hint (pages/driver-onboarding/step-info/step-info.html:50) -->
130
+ <sui-input [size]="bp.sizeControl()" [errorMessage]="nameError() || null" … />
131
+ @if (!nameError()) { <sui-form-hint message="Como aparece en tu DNI." /> }
132
+ ```
133
+
134
+ ```html
135
+ <!-- ✅ bien -->
136
+ <sui-input [size]="bp.sizeControl()" hint="Como aparece en tu DNI"
137
+ [error]="!!nameError()" [errorMessage]="nameError() || null" … />
138
+ ```
139
+
140
+ Subtítulo de una card
141
+
142
+ ```html
143
+ <!-- ❌ mal: no es ayuda de un campo, es el texto de la sección (pages/schedule/schedule.html:17) -->
144
+ <h2 class="schedule__card-title">Estado de la sucursal</h2>
145
+ <sui-form-hint message="Pausa tu sucursal sin perder el horario que ya configuraste." />
146
+ ```
147
+
148
+ ```html
149
+ <!-- ✅ bien -->
150
+ <h2 class="schedule__card-title">Estado de la sucursal</h2>
151
+ <p class="schedule__card-subtitle">Pausa tu sucursal sin perder el horario que ya configuraste.</p>
152
+ ```
153
+
154
+ Explicación de dos oraciones
155
+
156
+ ```html
157
+ <!-- ❌ mal: 23 palabras; pasa las 8 del hint (pages/orders/orders.html:590) -->
158
+ <sui-form-hint message="Si eliges un motivo de la lista, el cliente lo verá. Si escribes uno propio, verá “El local no pudo preparar tu pedido”." />
159
+ ```
160
+
161
+ ```html
162
+ <!-- ✅ bien -->
163
+ <sui-alert variant="info"
164
+ description="Si eliges un motivo de la lista, el cliente lo verá. Si escribes uno propio, verá «El local no pudo preparar tu pedido»." />
165
+ ```
166
+
118
167
  ## Ejemplo
119
168
 
120
169
  ```html
@@ -48,8 +48,8 @@ Regla corta: **campo de texto → su propio `[label]` · grupo o control sin lab
48
48
  | `label` | Siempre. Una a tres palabras, sentence case, sin dos puntos ni punto final. | según la guía del DS (pieza); largo y forma según `docs/CANON-SUI.md` §5.4 |
49
49
  | `required` | Campo obligatorio: asterisco **rojo** (`state-error-base`). | según la guía del DS (asterisco = obligatorio); el color es canon (`docs/CANON-SUI.md` §4: excepción documentada) |
50
50
  | `sublabel` | «(Opcional)» en un formulario donde casi todo es obligatorio. Nunca el «opcional» dentro del `label`. | según la guía del DS (ejemplo «(Optional)») |
51
- | `tooltip` | Ayuda corta que no cabe en la pantalla y no hace falta para llenar el campo. Si hace falta, va visible en `sui-form-hint`. | propuesta, falta aprobación |
52
- | `link` | Una acción sobre el campo, a la derecha: «Cambiar» (el distrito). | propuesta (ya es práctica de la app: 2 usos) |
51
+ | `tooltip` | Ayuda corta que no cabe en la pantalla y no hace falta para llenar el campo. Si hace falta, va visible en `sui-form-hint`. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
52
+ | `link` | Una acción sobre el campo, a la derecha: «Cambiar» (el distrito). | canon (aprobado por el dueño, 05-10-2026, bloque B9); ya es práctica de la app: 2 usos |
53
53
  | `disabled` | El campo de abajo está deshabilitado. | según la guía del DS |
54
54
  | `for` | Siempre que el control de abajo tenga `id`. | propuesta, falta aprobación |
55
55
 
@@ -59,7 +59,7 @@ Regla corta: **campo de texto → su propio `[label]` · grupo o control sin lab
59
59
  |---|---|---|
60
60
  | `medium` (default) | Lo normal. | según la guía del DS (único tamaño) |
61
61
  | `small` | Es **idéntico** a `medium` (mismo CSS). No aporta. | — |
62
- | `xsmall` | Junto a un campo `xsmall` en una tabla o filtro denso (12 px). | propuesta, falta aprobación |
62
+ | `xsmall` | No usar: con D16 no hay campos `xsmall`; en una tabla o filtro va `medium`. | canon (dueño, 05-10-2026, D16), reemplaza el «cuándo» del bloque B1 |
63
63
 
64
64
  La regla de controles grandes del dueño (28-09-2026) no aplica aquí: el `size` del label es
65
65
  tipografía, no área táctil.
@@ -78,19 +78,26 @@ tipografía, no área táctil.
78
78
  - **1 encima de un `sui-textarea`**, que ya trae su `[label]`: `pages/promociones/promociones.html:201`
79
79
  («Descripción»).
80
80
  - **3 con un switch armado a mano al lado → `sui-switch-label`:** `pages/discounts/discounts.html:204`,
81
- `:316`; `components/add-product-modal/add-product-modal.html:204`.
81
+ `:316`; `components/add-product-modal/add-product-modal.html:206`.
82
82
 
83
83
  ## Tamaño en mobile y en web
84
84
 
85
85
  | uso | mobile | web |
86
86
  |---|---|---|
87
87
  | rótulo de un grupo o control | `medium` (14 px) | `medium` (14 px) |
88
- | junto a un campo `xsmall` en una tabla o filtro denso | no aplica | `xsmall` (12 px) |
88
+ | junto a un campo de una tabla o filtro | no aplica | `medium` (14 px): ya no hay campos `xsmall` (D16) |
89
89
 
90
90
  No necesita `bp`: es texto, no se toca. Lo único tocable es el `link` («Cambiar»), un
91
91
  `sui-link-button` de 12 px **sin tamaño para mobile**: su área táctil es la del texto. Si en
92
92
  mobile esa acción importa, conviene un botón aparte.
93
93
 
94
+ ### Por dispositivo (D16)
95
+
96
+ No aplica: el `size` es tipografía, no área táctil, y no depende del dispositivo. Va `medium`
97
+ (14 px) en el celular chico, el celular, la tablet táctil, la computadora y el ultrawide;
98
+ `small` dibuja igual y `xsmall` no se usa (D16, dueño 05-10-2026: nada en `small`/`xsmall`).
99
+ En master-pedidos: sin `[size]` (el default `medium` ya es el correcto) y sin `bp`.
100
+
94
101
  ## «No usar»: por qué no hoy y cuándo sí
95
102
 
96
103
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -131,6 +138,51 @@ mobile esa acción importa, conviene un botón aparte.
131
138
  `rel="noopener noreferrer"`). Se pinta en gris, empujado a la derecha.
132
139
  - El ícono de info es gris muy claro a propósito (baja jerarquía); se oscurece al pasar el mouse.
133
140
 
141
+ ## Bien y mal
142
+
143
+ Campo de texto con su rótulo
144
+
145
+ ```html
146
+ <!-- ❌ mal: sui-input ya dibuja su label y su asterisco (pages/driver-onboarding/step-info/step-info.html:37) -->
147
+ <sui-form-label label="Nombre completo" [required]="true" for="ob-name" />
148
+ <sui-input [size]="bp.sizeControl()" type="text" [(value)]="nombre" />
149
+ ```
150
+
151
+ ```html
152
+ <!-- ✅ bien -->
153
+ <sui-input [size]="bp.sizeControl()" type="text" label="Nombre completo" [required]="true" [(value)]="nombre" />
154
+ ```
155
+
156
+ Título de una sección
157
+
158
+ ```html
159
+ <!-- ❌ mal: «Datos personales» titula la sección, no un campo (pages/customer/checkout/checkout.html:187) -->
160
+ <section class="checkout__section">
161
+ <sui-form-label label="Datos personales" size="medium" />
162
+ ```
163
+
164
+ ```html
165
+ <!-- ✅ bien -->
166
+ <section class="checkout__section">
167
+ <h2 class="checkout__section-title">Datos personales</h2>
168
+ ```
169
+
170
+ Rótulo de un switch
171
+
172
+ ```html
173
+ <!-- ❌ mal: label, ayuda y switch armados a mano (pages/discounts/discounts.html:204) -->
174
+ <sui-form-label label="Un uso por cliente" />
175
+ <span class="discounts__form-hint">Si activas esto, cada cliente solo podrá usar el cupón…</span>
176
+ <sui-switch [size]="bp.controlSize()" [checked]="unUso()" (checkedChange)="unUso.set($event)" />
177
+ ```
178
+
179
+ ```html
180
+ <!-- ✅ bien -->
181
+ <sui-switch-label [size]="bp.controlSize()" label="Un uso por cliente"
182
+ description="Cada cliente usa el cupón una sola vez"
183
+ [active]="unUso()" (activeChange)="unUso.set($event)" />
184
+ ```
185
+
134
186
  ## Ejemplo
135
187
 
136
188
  ```html
@@ -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