@ajuarezso/sui-design-system 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/docs/INDEX.md +30 -35
  2. package/docs/sui-accordion/README.md +171 -0
  3. package/docs/sui-activity-feed/README.md +154 -0
  4. package/docs/sui-activity-filter/README.md +100 -0
  5. package/docs/sui-alert/README.md +28 -19
  6. package/docs/sui-app-store-badge/README.md +5 -4
  7. package/docs/sui-avatar/README.md +16 -16
  8. package/docs/sui-avatar-group/README.md +4 -4
  9. package/docs/sui-badge/README.md +27 -9
  10. package/docs/sui-banner/README.md +10 -9
  11. package/docs/sui-brand-logo/README.md +3 -3
  12. package/docs/sui-breadcrumbs/README.md +1 -1
  13. package/docs/sui-button/README.md +64 -21
  14. package/docs/sui-button-group/README.md +6 -4
  15. package/docs/sui-button-group-item/README.md +3 -3
  16. package/docs/sui-card/README.md +17 -19
  17. package/docs/sui-chart-legend/README.md +8 -7
  18. package/docs/sui-checkbox/README.md +11 -6
  19. package/docs/sui-checkbox-card/README.md +24 -19
  20. package/docs/sui-checkbox-label/README.md +32 -10
  21. package/docs/sui-circular-progress-bar/README.md +2 -0
  22. package/docs/sui-color-dot/README.md +1 -1
  23. package/docs/sui-color-picker/README.md +22 -7
  24. package/docs/sui-command-menu-footer/README.md +100 -0
  25. package/docs/sui-command-menu-item/README.md +140 -0
  26. package/docs/sui-command-menu-search/README.md +105 -0
  27. package/docs/sui-compact-avatar-group/README.md +4 -3
  28. package/docs/sui-compact-button/README.md +41 -44
  29. package/docs/sui-compact-select/README.md +12 -5
  30. package/docs/sui-compact-select-for-input/README.md +5 -2
  31. package/docs/sui-content-card/README.md +6 -5
  32. package/docs/sui-content-divider/README.md +4 -4
  33. package/docs/sui-content-label/README.md +11 -6
  34. package/docs/sui-counter-input/README.md +21 -17
  35. package/docs/sui-date-selector/README.md +16 -12
  36. package/docs/sui-datepicker/README.md +46 -28
  37. package/docs/sui-day-cell/README.md +17 -8
  38. package/docs/sui-day-label/README.md +2 -2
  39. package/docs/sui-divider/README.md +5 -5
  40. package/docs/sui-drawer-footer/README.md +19 -5
  41. package/docs/sui-dropdown-caption/README.md +92 -0
  42. package/docs/sui-dropdown-item/README.md +163 -0
  43. package/docs/sui-dropdown-menu/README.md +196 -0
  44. package/docs/sui-dropdown-search/README.md +113 -0
  45. package/docs/sui-emoji/README.md +6 -6
  46. package/docs/sui-empty-state/README.md +13 -23
  47. package/docs/sui-fancy-button/README.md +24 -18
  48. package/docs/sui-file-icon/README.md +1 -1
  49. package/docs/sui-file-upload/README.md +3 -0
  50. package/docs/sui-file-upload-card/README.md +8 -7
  51. package/docs/sui-filter/README.md +181 -0
  52. package/docs/sui-flag/README.md +3 -2
  53. package/docs/sui-form-hint/README.md +12 -8
  54. package/docs/sui-form-label/README.md +11 -16
  55. package/docs/sui-href/README.md +85 -0
  56. package/docs/sui-icon/README.md +4 -3
  57. package/docs/sui-image-upload/README.md +28 -16
  58. package/docs/sui-img-retry/README.md +107 -0
  59. package/docs/sui-inline-input/README.md +7 -6
  60. package/docs/sui-inline-select/README.md +8 -5
  61. package/docs/sui-input/README.md +27 -33
  62. package/docs/sui-integration-switch/README.md +14 -7
  63. package/docs/sui-kbd/README.md +4 -4
  64. package/docs/sui-key-icon/README.md +6 -2
  65. package/docs/sui-link-button/README.md +21 -17
  66. package/docs/sui-modal/README.md +238 -0
  67. package/docs/sui-modal-footer/README.md +178 -0
  68. package/docs/sui-modal-header/README.md +115 -0
  69. package/docs/sui-modal-sheet/README.md +170 -0
  70. package/docs/sui-notification/README.md +8 -6
  71. package/docs/sui-notification-footer/README.md +2 -2
  72. package/docs/sui-notification-tab-menu/README.md +5 -3
  73. package/docs/sui-page-header/README.md +123 -0
  74. package/docs/sui-pagination/README.md +8 -5
  75. package/docs/sui-password-strength/README.md +1 -1
  76. package/docs/sui-period-range/README.md +18 -14
  77. package/docs/sui-popover/README.md +13 -7
  78. package/docs/sui-product-card/README.md +14 -10
  79. package/docs/sui-progress-bar/README.md +4 -2
  80. package/docs/sui-progress-bar-label/README.md +2 -0
  81. package/docs/sui-radio/README.md +14 -7
  82. package/docs/sui-radio-card/README.md +12 -12
  83. package/docs/sui-radio-label/README.md +36 -11
  84. package/docs/sui-rating/README.md +28 -9
  85. package/docs/sui-rich-editor/README.md +3 -3
  86. package/docs/sui-segmented-control/README.md +33 -19
  87. package/docs/sui-select/README.md +40 -33
  88. package/docs/sui-sidebar/README.md +216 -0
  89. package/docs/sui-slider/README.md +7 -0
  90. package/docs/sui-social-button/README.md +24 -11
  91. package/docs/sui-status-badge/README.md +7 -3
  92. package/docs/sui-stepper/README.md +30 -17
  93. package/docs/sui-store-card/README.md +9 -4
  94. package/docs/sui-switch/README.md +16 -11
  95. package/docs/sui-switch-card/README.md +18 -16
  96. package/docs/sui-switch-label/README.md +25 -11
  97. package/docs/sui-tab-chips/README.md +56 -39
  98. package/docs/sui-tab-menu-horizontal/README.md +19 -11
  99. package/docs/sui-tab-menu-vertical/README.md +10 -5
  100. package/docs/sui-table/README.md +264 -0
  101. package/docs/sui-tag/README.md +25 -11
  102. package/docs/sui-tag-input/README.md +25 -12
  103. package/docs/sui-textarea/README.md +23 -20
  104. package/docs/sui-time-picker/README.md +39 -30
  105. package/docs/sui-toast/README.md +27 -22
  106. package/docs/sui-tooltip/README.md +14 -17
  107. package/docs/sui-topbar/README.md +153 -0
  108. package/docs/sui-topbar-button/README.md +95 -0
  109. package/docs/sui-topbar-item/README.md +97 -0
  110. package/docs/sui-topbar-user/README.md +83 -0
  111. package/fesm2022/ajuarezso-sui-design-system.mjs +1076 -242
  112. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  113. package/package.json +1 -1
  114. package/types/ajuarezso-sui-design-system.d.ts +616 -280
@@ -28,40 +28,30 @@ algo que avisar → alert.**
28
28
  ## Qué variante usar
29
29
 
30
30
  > **La guía del DS no tiene página del empty state.** El componente de SUI se construyó a
31
- > propósito con Fluent Emoji animados en vez de ilustraciones: es una decisión del proyecto
32
- > (memoria «emojis animados en empty states», 17-04-2026).
31
+ > propósito con Fluent Emoji animados en vez de ilustraciones: es una decisión del proyecto, escrita
32
+ > en CANON-SUI §5.6 (ilustración = Fluent Emoji animado, default el zorro).
33
33
  >
34
- > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **66
35
- > empty-states en 40 archivos**. 25 con `action` (10 con `route`). 4 con `emoji` propio, 22 con la
36
- > URL del zorro pegada a mano (que ya es el default) y 40 sin `emoji`. 29 con un atributo `icon`
37
- > que el componente no tiene.
34
+ > Uso medido el 04-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **66
35
+ > empty-states en 40 archivos**. 29 con `action` (10 con `route`). 8 con `emoji` propio y 58 sin
36
+ > `emoji` (sale el zorro). 0 con `icon`, 0 con la URL del zorro pegada, 0 con `size`.
38
37
 
39
38
  ### Las piezas
40
39
 
41
40
  | prop | cuándo | fuente |
42
41
  |---|---|---|
43
- | `emoji` vacío (default: el zorro) | Lo normal. El zorro es la mascota de los empty states y sale solo: **no pegues su URL**. | canon (memoria del proyecto) |
44
- | `emoji` propio | Cuando el emoji dice algo del caso: el reloj de arena en «Aún no tienes facturas» (se está esperando algo), el chef en los avisos del local. Siempre de `FLUENT_EMOJI_ANIM` (`core/fluent-emoji.ts`) o de `assets/emoji-anim/`. | canon (memoria del proyecto) |
45
- | `title` (obligatorio) | Qué pasa, en corto y sin punto: «Tu carrito está vacío», «Sin pedidos aún». En una búsqueda, repite lo buscado: «Nada con “pollo broaster”». | propuesta (práctica de la app) |
46
- | `subtitle` | Qué va a pasar o qué puede hacer la persona: «Cuando hagas tu primer pedido, aparecerá aquí.» | propuesta |
42
+ | `emoji` vacío (default: el zorro) | Lo normal. El zorro es la mascota de los empty states y sale solo: **no pegues su URL**. | canon (CANON-SUI §5.6) |
43
+ | `emoji` propio | Cuando el emoji dice algo del caso: el reloj de arena en «Aún no tienes facturas» (se está esperando algo), el chef en los avisos del local. Siempre de `FLUENT_EMOJI_ANIM` (`core/fluent-emoji.ts`) o de `assets/emoji-anim/`. | canon (CANON-SUI §5.6: Fluent Emoji animado) |
44
+ | `title` (obligatorio) | Qué pasa, sin punto y en 2 a 4 palabras, con uno de tres patrones: «Todavía no hay <cosa>», «Sin <cosa>», «Tu <cosa> está vacío» («Tu carrito está vacío», «Sin pedidos aún»). En una búsqueda, repetir lo buscado («Nada con “pollo broaster”») queda fuera de esos patrones. | canon (CANON-SUI §5.6) · lo de la búsqueda: propuesta, falta aprobación |
45
+ | `subtitle` | Una oración con punto, en futuro tranquilizador: «Cuando hagas tu primer pedido, aparecerá aquí.» | canon (CANON-SUI §5.6) |
47
46
  | `action` como string + `(actionClicked)` | La salida es algo de esta misma pantalla: «Reintentar», «Ver todo el catálogo», «Activar captura». | propuesta |
48
47
  | `action` como `{ label, route }` | La salida es otra pantalla: «Ver negocios» → `/cliente/inicio`. | propuesta |
49
48
  | sin `action` | No hay un paso obvio, o la pantalla ya tiene el botón para llenarla (el «Nuevo local» de arriba). | propuesta |
50
49
  | error de carga | Siempre con `action="Reintentar"`. Excepción: la pantalla reintenta sola y lo dice («Seguimos intentando»). | propuesta |
51
50
 
52
- **Usos de hoy que rompen las reglas:**
53
-
54
- - **29 con `icon="…"`**: `icon` no es un input, el atributo no hace nada. Ejemplos:
55
- `pages/customer/cart/cart.html:18`, `pages/drivers/drivers.html:87`,
56
- `pages/customer/order-history/order-history.html:20`. Se borra.
57
- - **22 con la URL del zorro pegada** (`emoji="…/Animals/Fox.png"`), que ya es el default:
58
- `pages/customers/customers.html:65`, `pages/products/products.html:113`,
59
- `pages/locations/locations.html:16`. Se borra.
60
- - **4 errores de carga sin «Reintentar»**:
61
- `pages/driver/driver-dashboard/driver-dashboard.html:1071`,
62
- `pages/customer/order-history/order-history.html:20`,
63
- `pages/super-admin/master-drivers/master-drivers.html:524` y `:754`.
64
- (`pages/public/pedido-en-vivo/pedido-en-vivo.html:50` no cuenta: reintenta solo.)
51
+ **Usos de hoy que rompen las reglas:** 0. Los 29 `icon="…"` (que no es un input), las 22 URL del
52
+ zorro pegadas a mano y los 4 errores de carga sin «Reintentar» se corrigieron el 03-10-2026 (commit
53
+ `461efbec` de la app). `pages/public/pedido-en-vivo/pedido-en-vivo.html:50` sigue sin «Reintentar»
54
+ a propósito: reintenta solo y lo dice.
65
55
 
66
56
  ## Tamaño en mobile y en web
67
57
 
@@ -38,7 +38,7 @@ marketing: brillo arriba, borde interior claro y un anillo del color del botón.
38
38
 
39
39
  - **Para qué es**: un botón normal con un acabado más vistoso.
40
40
  - **Default**: `neutral` (negro) en la guía; **`primary` en SUI**.
41
- - **Tamaños**: `medium` (40), `small` (36) y `xsmall` (32). No hay más grandes.
41
+ - **Tamaños**: `medium` (40), `small` (36) y `xsmall` (32). SUI agrega `large` (48) para el teléfono (04-10-2026).
42
42
  - **Hover**: el brillo se aclara, no se oscurece. `basic` pasa a fondo gris plano.
43
43
  - **Deshabilitado**: fondo gris plano, sin brillo, sin anillo ni sombra, igual en los cuatro tipos.
44
44
 
@@ -55,6 +55,7 @@ marketing: brillo arriba, borde interior claro y un anillo del color del botón.
55
55
 
56
56
  | size | cuándo | fuente |
57
57
  |---|---|---|
58
+ | `large` (48) | El CTA en el teléfono. Texto 16. | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono; extensión de SUI, la guía no lo tiene |
58
59
  | `medium` (40, default) | El CTA de la landing en desktop. | escala y default según la guía del DS · cuándo: propuesta |
59
60
  | `small` (36) | Un CTA dentro de una card de la landing (la card de un plan). | escala según la guía del DS · cuándo: propuesta |
60
61
  | `xsmall` (32) | Sin caso: en una landing el CTA nunca es tan chico. | escala según la guía del DS · cuándo: propuesta |
@@ -70,27 +71,32 @@ marketing: brillo arriba, borde interior claro y un anillo del color del botón.
70
71
 
71
72
  ## Tamaño en mobile y en web
72
73
 
73
- En mobile se toca con el dedo: el área táctil tiene que medir **44 px o más**. En web, con mouse,
74
- va un tamaño más chico. La app ya lo resuelve con `BreakpointsService`
75
- (`src/app/services/breakpoints.service.ts`, mobile = hasta 767 px):
76
- `[size]="bp.isMobile() ? 'large' : 'small'"`, 27 usos hoy en `master-pedidos` (16 `large`/`small`,
77
- 9 `large`/`medium`, 2 `medium`/`xsmall`). Regla del dueño, 03-10-2026.
74
+ En mobile se toca con el dedo: el área táctil tiene que medir **44 px o más** (canon (dueño, 04-10-2026): piso táctil 44 en el teléfono). En web,
75
+ con mouse, va un tamaño más chico. La app ya lo resuelve con `BreakpointsService`
76
+ (`src/app/services/breakpoints.service.ts`, mobile = hasta 767 px).
77
+
78
+ | size | alto | texto | cuándo | fuente |
79
+ |---|---|---|---|---|
80
+ | `large` | 48 | 16 (Label/Medium) | CTA en el teléfono | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono. Size nuevo del 04-10-2026 |
81
+ | `medium` (default) | 40 | 14 | CTA en web | Figma |
82
+ | `small` | 36 | 14 | CTA dentro de una card en web | Figma |
83
+ | `xsmall` | 32 | 14 | — | Figma |
84
+
85
+ **Por qué `large` = 48 y no 44**: el fancy es «el mismo botón con otro acabado» que `sui-button` y su
86
+ escala lo espeja tal cual (medium 40 / small 36 / xsmall 32). El siguiente es `large`, y el
87
+ `large` de sui-button mide 48: el fancy en el teléfono queda del mismo alto que el botón normal
88
+ que va al lado. El texto sube a 16 (regla de tamaños del 03-10-2026); los íconos siguen en 20.
78
89
 
79
90
  | uso | mobile | web | fuente |
80
91
  |---|---|---|---|
81
- | CTA principal de una landing | no usar fancy: `sui-button` `large` (48) | `medium` (40) | propuesta |
82
- | CTA dentro de la card de un plan | no usar fancy: `sui-button` `large` | `small` (36) | propuesta |
92
+ | CTA principal de una landing | `large` (48) | `medium` (40) | propuesta |
93
+ | CTA dentro de la card de un plan | `large` (48) | `small` (36) | propuesta |
83
94
 
84
95
  ```html
85
- @if (bp.isMobile()) {
86
- <sui-button size="large">Empieza gratis</sui-button>
87
- } @else {
88
- <sui-fancy-button type="primary" size="medium">Empieza gratis</sui-fancy-button>
89
- }
96
+ <sui-fancy-button type="primary" [size]="bp.isMobile() ? 'large' : 'medium'">Empieza gratis</sui-fancy-button>
90
97
  ```
91
98
 
92
- **El fancy no tiene un tamaño táctil**: el más grande mide 40, por debajo de 44. En mobile el CTA
93
- va con `sui-button` `large`. Hoy no hay usos (todo el componente está en «no usar»).
99
+ Hoy no hay usos (todo el componente está en «no usar»).
94
100
 
95
101
  ## «No usar»: por qué no hoy y cuándo sí
96
102
 
@@ -110,7 +116,7 @@ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
110
116
  | input | tipo | default |
111
117
  |---|---|---|
112
118
  | `type` | `'primary' \| 'neutral' \| 'basic' \| 'destructive'` | `'primary'` |
113
- | `size` | `'medium' \| 'small' \| 'xsmall'` | `'medium'` |
119
+ | `size` | `'large' \| 'medium' \| 'small' \| 'xsmall'` | `'medium'` |
114
120
  | `leftIcon` | `string \| null` | `null` |
115
121
  | `rightIcon` | `string \| null` | `null` |
116
122
  | `disabled` | `boolean` | `false` |
@@ -132,8 +138,8 @@ El clic se escucha con `(clicked)`. Slots: `<ng-content>` (el texto).
132
138
  - **`type` es el relleno**, no el `type` HTML: ese se llama **`htmlType`**. `type="submit"` no
133
139
  compila (no es un tipo válido) y no hace un submit.
134
140
  - **El radio es 10 px, no pill.** Al lado de un `sui-button` (pill en SUI) se ven de dos familias.
135
- - **No hay `large` ni `xlarge`**: el más grande mide 40. En mobile, donde el CTA de la app es de
136
- 48, un fancy queda más bajo.
141
+ - **`large` (48) es de SUI** (04-10-2026), no de la guía: en el teléfono va ese, del mismo alto que
142
+ el `large` de `sui-button`. No hay `xlarge`.
137
143
  - **El default es `primary`**; en la guía es `neutral`.
138
144
  - El anillo del `neutral` es un hex crudo (`#242628`): no hay token para ese gris.
139
145
  - Ya trae el arreglo de iOS para el `:active` pegado: no lo agregues.
@@ -92,7 +92,7 @@ Outputs: ninguno.
92
92
 
93
93
  - **La extensión se corta a 4 letras** y va en mayúsculas: `.jpeg` → `JPEG`, `.numbers` → `NUMB`.
94
94
  - **`extension` gana sobre `filename`.**
95
- - **El nombre para el lector de pantalla está en inglés** («File: PDF») y no se puede cambiar.
95
+ - El nombre para el lector de pantalla es «Archivo PDF» (en español desde el 04-10-2026) y no se puede cambiar.
96
96
  - `size` es `xsmall` o `medium`: no hay `small` ni `large`.
97
97
 
98
98
  ## Ejemplo
@@ -132,6 +132,9 @@ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
132
132
  ## Trampas
133
133
 
134
134
  - `browseLabel` dice «Buscar archivo» por defecto (antes «Browse File»).
135
+ - **Con teclado el control es «Buscar archivo»**, no el área. Desde el 04-10-2026 el host ya no
136
+ es `role="button"` ni entra en el Tab (era un control con otro adentro y Enter pedía el selector
137
+ dos veces). Con el mouse o el dedo, tocar cualquier parte del área sigue abriendo el selector.
135
138
  - **Llena el ancho del contenedor** desde el 03-10-2026 (antes medía 400 fijo y había que forzar
136
139
  `style="width: 100%"`). Las pantallas que lo dejaban en 400 en un contenedor ancho ahora se
137
140
  estiran; para un ancho fijo, se lo pone el consumer al host.
@@ -41,7 +41,7 @@ subiendo con su barra, listo, o falló con «Reintentar».
41
41
  | input | cuándo | fuente |
42
42
  |---|---|---|
43
43
  | `file` | El nombre real del archivo (`'carta-octubre.pdf'`). La extensión da el ícono y el color. | propuesta |
44
- | `description` | **Siempre** se pasa: el default es un texto de ejemplo («0 KB de 120 KB»). Subiendo: «1,2 MB de 3,4 MB»; listo: «3,4 MB». | propuesta |
44
+ | `description` | **Siempre** se pasa: el default es un texto de ejemplo («0 KB de 120 KB»). Subiendo: «1.2 MB de 3.4 MB»; listo: «3.4 MB» (punto decimal, como el «10.0 MB» que arma `sui-file-upload`). | propuesta |
45
45
  | `progress` | 0–100, solo en `in-progress`. | propuesta |
46
46
  | `statusText` | Los defaults ya están en español («Subiendo…», «Completado», «Falló»); en error, mejor el motivo: «Se cortó la conexión». | propuesta |
47
47
  | `showStatus=false` | Solo en `success`, cuando el check sobra porque la lista ya dice «Archivos subidos». | propuesta |
@@ -52,14 +52,15 @@ Usos de hoy que rompen la regla: **0**.
52
52
  ## Tamaño en mobile y en web
53
53
 
54
54
  **No tiene `size`.** Llena el ancho del contenedor (antes 400 fijo) y la X o el tacho de la derecha
55
- es un `sui-compact-button` `2xlarge` de **32 px** (Figma: 24), que con el aire de la tarjeta (16 de
56
- padding, 72 de alto mínimo) se toca bien con el dedo. «Reintentar» sigue siendo un link de 20 px de
57
- alto: en mobile conviene que la fila entera también reintente.
55
+ es un `sui-compact-button` `2xlarge` de **32 px** (Figma: 24): queda debajo de los 44 del dedo. La
56
+ fila mide 74 sin barra (ícono de 40 + padding 16 × 2 + borde 1 × 2; no hay `min-height`).
57
+ «Reintentar» sigue siendo un link de 20 px de alto: en mobile conviene que la fila entera también
58
+ reintente.
58
59
 
59
60
  | pieza | mobile | web | fuente |
60
61
  |---|---|---|---|
61
62
  | ancho | el del contenedor | el del contenedor | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
62
- | X / tacho | 32 px | 32 px | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
63
+ | X / tacho | 32 px — **no llega** a 44 | 32 px | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
63
64
  | «Reintentar» | link de 20 px — **no llega** | link | medido |
64
65
 
65
66
  ```html
@@ -122,8 +123,8 @@ interface SuiFileUploadCardFile { filename: string; extension?: string; }
122
123
 
123
124
  ```html
124
125
  <sui-file-upload-card file="carta-octubre.pdf" state="in-progress" [progress]="45"
125
- description="1,2 MB de 2,6 MB" statusText="Subiendo…" />
126
- <sui-file-upload-card file="carta-octubre.pdf" state="error" description="2,6 MB"
126
+ description="1.2 MB de 2.6 MB" statusText="Subiendo…" />
127
+ <sui-file-upload-card file="carta-octubre.pdf" state="error" description="2.6 MB"
127
128
  statusText="Se cortó la conexión" retryLabel="Reintentar"
128
129
  (retryClicked)="reintentar()" (actionClicked)="quitar()" />
129
130
  ```
@@ -0,0 +1,181 @@
1
+ ---
2
+ name: sui-filter
3
+ selector: sui-filter-bar, sui-filter-item, sui-filter-panel-header, sui-filter-panel-footer
4
+ resumen: Piezas de filtros de una lista o tabla del panel; la barra horizontal (buscador, vista, orden) y el panel vertical (fila, cabecera con «Limpiar», pie con «Limpiar» / «Aplicar»)
5
+ alternativas: [sui-segmented-control (2 a 4 vistas que se aplican al instante), sui-compact-select (un filtro suelto), sui-tab-chips (filtros rápidos con chips), sui-activity-filter (filtro del feed de actividad), sui-modal-sheet (el panel de filtros en mobile)]
6
+ ---
7
+
8
+ # sui-filter
9
+
10
+ Story: [Organisms/Filter Bar](https://sui-design-system.web.app/?path=/docs/organisms-filter-bar--docs)
11
+
12
+ Son **cuatro componentes** en una carpeta, sin uno llamado `sui-filter`:
13
+
14
+ - `sui-filter-bar`: la **barra horizontal** arriba de una tabla. Es solo layout: un lado
15
+ izquierdo (`slot="start"`) y uno derecho (`slot="end"`); los controles se proyectan.
16
+ - `sui-filter-item`: una **fila** del panel vertical (una categoría de filtro: «Estado», «Local»).
17
+ - `sui-filter-panel-header`: la **cabecera** del panel, con un link «Limpiar» opcional.
18
+ - `sui-filter-panel-footer`: el **pie** del panel, con «Limpiar» y «Aplicar».
19
+
20
+ El panel vertical **no existe como contenedor**: se arma con header + items + footer dentro de un
21
+ `sui-dropdown-menu` (web) o de un `sui-modal-sheet` (mobile).
22
+
23
+ ## Cuándo usarlo / cuándo no
24
+
25
+ **Úsalo** en las listas y tablas del panel del local o del super admin que necesitan filtrar
26
+ (pedidos, productos, repartidores): la barra arriba con el buscador, la vista y el orden; el panel
27
+ cuando hay varias categorías de filtro que se combinan y se aplican juntas.
28
+
29
+ **No lo uses** para:
30
+
31
+ - 2 a 4 vistas que se aplican al tocar (Hoy · Semana · Mes): `sui-segmented-control` solo, sin barra.
32
+ - Un único filtro: un `sui-compact-select` o `sui-select` suelto.
33
+ - Filtros rápidos de un toque en mobile (Todos · Pendientes · Entregados): `sui-tab-chips`.
34
+ - El feed de actividad: `sui-activity-filter`.
35
+
36
+ Regla corta: **barra arriba de una tabla → filter-bar · varias categorías que se aplican juntas →
37
+ panel (header + items + footer) · un filtro suelto → compact-select.**
38
+
39
+ ## Qué variante usar
40
+
41
+ > **La guía del DS no tiene página de filtros**: estas piezas salen solo del Figma del DS
42
+ > («Filters»: HorizontalFilter y VerticalFilter). Todo lo de abajo es **propuesta, falta
43
+ > aprobación**, salvo lo marcado canon.
44
+ >
45
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-dropdown-menu`):
46
+ > **0 usos**. Solo aparecen en la vitrina `master-preview`.
47
+
48
+ ### `sui-filter-bar`
49
+
50
+ | variant | cuándo | fuente |
51
+ |---|---|---|
52
+ | `table` (default) | Arriba de una tabla: a la izquierda la vista (`sui-segmented-control`), a la derecha el buscador (`sui-input type="search"`) y el orden (`sui-select` o `sui-compact-select`). | propuesta (composición del Figma) |
53
+ | `calendar` | Arriba de una vista por fechas: a la izquierda «Hoy» + el rango (`sui-button-group`), a la derecha el buscador. | propuesta (composición del Figma) |
54
+
55
+ `variant` solo marca el host (`data-sui-variant`): **no cambia el layout**. Lo que se ve lo deciden
56
+ los controles que se proyectan.
57
+
58
+ ### El panel: `sui-filter-item` + header + footer
59
+
60
+ | pieza | regla | fuente |
61
+ |---|---|---|
62
+ | `sui-filter-item` `active` | La categoría abierta (la que muestra sus opciones al lado): fondo gris, texto negro, flecha a la derecha. | propuesta (estados del Figma) |
63
+ | `sui-filter-item` `leftIcon` | Un ícono por categoría si ayuda a ubicarla («Estado», «Local», «Repartidor»). | propuesta |
64
+ | `sui-filter-panel-header` `clear` | `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
+ | `sui-filter-panel-footer` | «Limpiar» a la izquierda (`stroke neutral`), «Aplicar» a la derecha (`filled primary`), mitad y mitad. | canon (orden de `sui-modal-footer`, CLAUDE.md «Botones») |
66
+ | «Limpiar» en header **y** footer | Elegir uno. Con el footer, el header va sin link. | propuesta |
67
+ | `applyButton` deshabilitado | `{ label: 'Aplicar', disabled: !cambio() }` mientras no se toca nada. | propuesta |
68
+
69
+ ## Tamaño en mobile y en web
70
+
71
+ Ninguna pieza cambia sola en mobile, salvo la barra, que apila sus dos lados por debajo de 640 px.
72
+
73
+ | pieza | mobile | web | fuente |
74
+ |---|---|---|---|
75
+ | `sui-filter-bar` | sin tamaño; los controles adentro van `large` (48) | sin tamaño; los controles `small` (36) | propuesta (igual que `sui-compact-select` en una barra) |
76
+ | `sui-filter-item` | 36 de alto, no se puede cambiar: debajo de los 44 del dedo | 36 | propuesta |
77
+ | `sui-filter-panel-footer` | `medium` (40) es lo más grande que tiene; en mobile, mejor `sui-modal-footer` (48) dentro de un `sui-modal-sheet` | `small` (36, default) | canon para el 48 de mobile (CLAUDE.md: footer de modal `large`); el resto, propuesta |
78
+ | `sui-filter-panel-header` | sin tamaño | sin tamaño | — |
79
+
80
+ ```html
81
+ <sui-filter-bar>
82
+ <sui-segmented-control slot="start" … />
83
+ <div slot="end">
84
+ <sui-input type="search" [size]="bp.isMobile() ? 'large' : 'small'" placeholder="Buscar pedido…" … />
85
+ </div>
86
+ </sui-filter-bar>
87
+ ```
88
+
89
+ ## API
90
+
91
+ <!-- api:inicio -->
92
+ <!-- generada: no editar a mano — `npm run docs` -->
93
+
94
+ ### `sui-filter-bar`
95
+
96
+ | input | tipo | default |
97
+ |---|---|---|
98
+ | `variant` | `'calendar' \| 'table'` | `'table'` |
99
+
100
+ Outputs: ninguno.
101
+
102
+ ### `sui-filter-item`
103
+
104
+ | input | tipo | default |
105
+ |---|---|---|
106
+ | `active` | `boolean` | `false` |
107
+ | `disabled` | `boolean` | `false` |
108
+ | `leftIcon` | `string \| null` | `null` |
109
+ | `activeIcon` | `string` | `'arrow-right-s-line'` |
110
+
111
+ | output | payload |
112
+ |---|---|
113
+ | `selected` | `Event` |
114
+
115
+ ### `sui-filter-panel-footer`
116
+
117
+ | input | tipo | default |
118
+ |---|---|---|
119
+ | `clearButton` | `SuiFooterButtonConfig \| string` | `'Limpiar'` |
120
+ | `applyButton` | `SuiFooterButtonConfig \| string` | `'Aplicar'` |
121
+ | `size` | `'small' \| 'medium'` | `'small'` |
122
+
123
+ | output | payload |
124
+ |---|---|
125
+ | `clear` | `void` |
126
+ | `apply` | `void` |
127
+
128
+ ### `sui-filter-panel-header`
129
+
130
+ | input | tipo | default |
131
+ |---|---|---|
132
+ | `label` | `string` | `''` |
133
+ | `leftIcon` | `string \| null` | `null` |
134
+ | `clear` | `string \| boolean` | `false` |
135
+
136
+ | output | payload |
137
+ |---|---|
138
+ | `clearClick` | `void` |
139
+ <!-- api:fin -->
140
+
141
+ Slots de `sui-filter-bar`: `[slot=start]`, `[slot=end]` y el contenido por defecto (fila única si no
142
+ se usan los slots). El label de `sui-filter-item` es su contenido proyectado. `clearButton` y
143
+ `applyButton` aceptan un string o `SuiFooterButtonConfig` (`{ label, disabled? }`, la misma interfaz
144
+ de `sui-drawer-footer`).
145
+
146
+ ## Trampas
147
+
148
+ - Los textos por defecto son «Limpiar» y «Aplicar» en el footer y «Limpiar» en el header con
149
+ `clear=true` (en español desde el 04-10-2026).
150
+ - **La barra apila a 640 px; la app cambia a mobile a 767.** Entre 641 y 767 px la app ya está en
151
+ mobile y la barra sigue en una fila.
152
+ - **Varios controles en un lado van en un contenedor.** Cada slot es una fila con 12 px de separación,
153
+ pero un solo elemento por `slot` queda más ordenado (`<div slot="end">`), como en el Figma.
154
+ - **`sui-filter-item` tiene `role="option"`**: el contenedor tiene que llevar `role="listbox"`.
155
+ - **`active` no es «elegido»**: marca la categoría abierta, no un valor aplicado. Para decir que una
156
+ categoría tiene un filtro puesto no hay prop (un `sui-badge` en el label es lo más cercano).
157
+ - **El footer separa sus botones 16 px** (del Figma); el canon de la app entre botones hermanos es 12
158
+ (CANON-SUI §0, `sui-modal-footer`).
159
+ - El footer no llega a `large`: en mobile queda más chico que el footer de cualquier modal.
160
+ - `disabled` del item usa opacidad (no está en el Figma).
161
+
162
+ ## Ejemplo
163
+
164
+ ```html
165
+ <!-- Panel de filtros en web, anclado a un botón «Filtros» -->
166
+ <sui-dropdown-menu #filtros="suiDropdownMenu" [minWidth]="320">
167
+ <sui-button trigger variant="stroke" color="neutral" size="small">Filtros</sui-button>
168
+ <ng-template suiDropdownPanel>
169
+ <sui-filter-panel-header label="Filtros" leftIcon="equalizer-line" />
170
+ <div role="listbox" aria-label="Categorías de filtro">
171
+ <sui-filter-item leftIcon="checkbox-circle-line" [active]="cat() === 'estado'"
172
+ (selected)="cat.set('estado')">Estado</sui-filter-item>
173
+ <sui-filter-item leftIcon="store-2-line" [active]="cat() === 'local'"
174
+ (selected)="cat.set('local')">Local</sui-filter-item>
175
+ </div>
176
+ <sui-filter-panel-footer clearButton="Limpiar"
177
+ [applyButton]="{ label: 'Aplicar', disabled: !cambio() }"
178
+ (clear)="limpiar()" (apply)="filtros.close(); aplicar()" />
179
+ </ng-template>
180
+ </sui-dropdown-menu>
181
+ ```
@@ -22,8 +22,9 @@ nada a nadie.
22
22
  > **La guía del DS no tiene este componente.** Todo es **propuesta, falta aprobación**.
23
23
  >
24
24
  > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usan por dentro
25
- > `sui-select`, `sui-compact-select`, `sui-inline-select`, `sui-dropdown-item`, `sui-tag` y
26
- > `sui-command-menu-item`.
25
+ > `sui-select`, `sui-compact-select`, `sui-compact-select-for-input`, `sui-inline-select`,
26
+ > `sui-dropdown-item` y `sui-command-menu-item`. `sui-tag` no la trae: la recibe proyectada en
27
+ > `[data-slot=start]`.
27
28
 
28
29
  ### `size`
29
30
 
@@ -12,7 +12,7 @@ Story: [Atoms/Form/Form Hint](https://sui-design-system.web.app/?path=/docs/atom
12
12
  ## Cuándo usarlo / cuándo no
13
13
 
14
14
  **Úsalo** para una línea debajo de un campo o grupo **que no trae la suya**: cómo se llena
15
- («Como aparece en tu DNI.»), un contador («120/200»), o qué falló («Selecciona un método de
15
+ («Como aparece en tu DNI»), un contador («120/200»), o qué falló («Selecciona un método de
16
16
  pago»). Va pegado al control que explica.
17
17
 
18
18
  **No lo uses** para:
@@ -31,7 +31,8 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
31
31
  > trae tres estados: normal, deshabilitado y con error (`hasError`). El ícono es una pieza aparte
32
32
  > y opcional. No da reglas de largo ni de copy.
33
33
  >
34
- > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`):
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
36
  > **36 usos en 18 archivos**: 11 `error`, 25 `neutral` (24 por default y 1 explícito), 0
36
37
  > `disabled`; 2 con `icon` propio (`information-line`). Hay además **al menos 14 hints escritos a
37
38
  > mano** con clases propias (`__form-hint`, `__hint`).
@@ -48,7 +49,7 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
48
49
 
49
50
  | qué | regla | fuente |
50
51
  |---|---|---|
51
- | `message` | Hasta 8 palabras (mediana 6). Si no cabe, es un `sui-alert`. Con punto final si es una oración. | canon (`docs/CANON-SUI.md` §5.4) |
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) |
52
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 |
53
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) |
54
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 |
@@ -62,14 +63,14 @@ Regla corta: **ayuda o error de un control sin hint propio → form-hint · camp
62
63
  Bien usado, en cambio, `step-vehicle.html:43`: el error de un grupo de `sui-radio-card`.
63
64
  - **4 como subtítulo de una sección, no de un campo:** `pages/schedule/schedule.html:17`
64
65
  («Pausa tu sucursal…», bajo el título de la card), `:61`, `pages/drivers/drivers.html:29`,
65
- `pages/driver/driver-schedule/driver-schedule.html:94`.
66
+ `pages/driver/driver-schedule/driver-schedule.html:92`.
66
67
  - **12 de más de 8 palabras** (4 son los subtítulos de arriba) → acortar, o `sui-alert` si de
67
68
  verdad hace falta todo: `pages/super-admin/master-users/master-users.html:66` (26 palabras),
68
- `pages/orders/orders.html:587` (23), `pages/driver/driver-order-detail/driver-order-detail.html:834` (23),
69
- `pages/envios/envios.html:399` (15).
70
- - **Al menos 14 hints a mano** con clases propias. Ejemplos: `pages/discounts/discounts.html:196`
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).
71
+ - **Al menos 14 hints a mano** con clases propias. Ejemplos: `pages/discounts/discounts.html:205`
71
72
  (`discounts__form-hint`), `components/settings-panel/settings-panel.html:93`,
72
- `pages/promociones/promociones.html:180`.
73
+ `pages/promociones/promociones.html:181`.
73
74
 
74
75
  ## Tamaño en mobile y en web
75
76
 
@@ -110,6 +111,9 @@ Outputs: ninguno.
110
111
  - **Sin `message` no ocupa lugar**: no hace falta envolverlo en `@if`.
111
112
  - En `error` el ícono es `information-fill` en rojo, no `error-warning-line`.
112
113
  - Letra fija de 12/16 px; el ícono mide 16 px y se alinea con la primera línea.
114
+ - `variant="error"` con mensaje lleva `role="alert"`: el lector lo anuncia al aparecer
115
+ (04-10-2026). Para enlazarlo a un control propio, pon `id` en el host y apúntalo con
116
+ `aria-describedby`; los campos del DS ya lo hacen solos.
113
117
 
114
118
  ## Ejemplo
115
119
 
@@ -19,7 +19,8 @@ Story: [Atoms/Form/Form Label](https://sui-design-system.web.app/?path=/docs/ato
19
19
 
20
20
  - **Encima de un `sui-input`, `sui-select` o `sui-textarea`**: esos ya dibujan su label, asterisco,
21
21
  sublabel y tooltip con `[label]`, `[required]`, `[sublabel]`, `[tooltip]`. Ponerle uno afuera
22
- duplica la pieza y pierde el `for`.
22
+ duplica la pieza y deja el `required` y el error separados del campo. El label interno sí
23
+ lleva `for` al `id` del control (desde el 04-10-2026); uno puesto afuera no lo conoce.
23
24
  - El texto de un solo checkbox, radio o switch: `sui-checkbox-label`, `sui-radio-label`,
24
25
  `sui-switch-label`.
25
26
  - Un título de sección o de card («Datos personales»): `sui-page-header`, `sui-content-label` o
@@ -35,8 +36,8 @@ Regla corta: **campo de texto → su propio `[label]` · grupo o control sin lab
35
36
  > es «Last Name*(Optional)»: el opcional va **entre paréntesis** en el sub. Tiene un solo tamaño y
36
37
  > un estado deshabilitado. Info (tooltip) y el link de la derecha vienen del Figma del componente.
37
38
  >
38
- > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`):
39
- > **37 usos en 13 archivos**: 13 con `required`, 5 con `sublabel="Opcional"`, 2 con `link`
39
+ > Uso medido el 04-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`):
40
+ > **37 usos en 13 archivos**: 13 con `required`, 7 con `sublabel="(Opcional)"`, 2 con `link`
40
41
  > («Cambiar»), 0 con `tooltip`, 0 con `disabled`; 6 con `size="medium"` explícito, el resto en el
41
42
  > default (`medium`).
42
43
 
@@ -63,27 +64,21 @@ Regla corta: **campo de texto → su propio `[label]` · grupo o control sin lab
63
64
  La regla de controles grandes del dueño (28-09-2026) no aplica aquí: el `size` del label es
64
65
  tipografía, no área táctil.
65
66
 
66
- **Usos de hoy que rompen las reglas:**
67
+ **Usos de hoy que rompen las reglas** (medido el 04-10-2026; los sublabels sin paréntesis, el
68
+ «(opcional)» en el label, el número de paso en los labels de promociones y el Title Case de
69
+ `drivers.html:28` ya se corrigieron en la app, commits `ce4a2d12` y `8128dc03`):
67
70
 
68
71
  - **8 encima de un campo que ya trae su label → pasar a `[label]` del campo:**
69
72
  `pages/driver-onboarding/step-info/step-info.html:37` («Nombre completo»), `:56`, `:77`;
70
73
  `pages/customer-onboarding/step-address/step-address.html:70` («Departamento», sobre
71
74
  `sui-select`), `:87`, `:106`; `pages/driver-onboarding/step-vehicle/step-vehicle.html:49`, `:62`.
72
75
  En esos mismos campos el `sui-form-hint` de abajo también es el `[hint]` del input.
73
- - **5 con `sublabel="Opcional"` sin paréntesis** → se lee «ImagenOpcional» (1 px de separación).
74
- Pasar a «(Opcional)»: `components/add-product-modal/add-product-modal.html:42`, `:195`;
75
- `pages/promociones/promociones.html:200`; `pages/business-onboarding/step-info/step-info.html:41`, `:54`.
76
- - **2 con «(opcional)» dentro del label → `sublabel`:** `pages/driver-onboarding/step-vehicle/step-vehicle.html:49`
77
- («Placa del vehículo (opcional)») y `:62`.
78
76
  - **2 como título de sección → heading o `sui-content-label`:** `pages/customer/checkout/checkout.html:187`
79
77
  («Datos personales») y `:35` («Recoges en el local»).
80
- - **5 con el número de paso dentro del label** («1. Imagen del banner»…«5. Comprobante de pago»):
81
- `pages/promociones/promociones.html:179`, `:200`, `:210`, `:230`, `:264`. Los pasos van en un
82
- `sui-stepper` o en el título de la sección; el label queda «Imagen del banner». Además `:200`
83
- («2. Descripción») está encima de un `sui-textarea`, que ya trae su `[label]`.
84
- - **1 en Title Case:** `pages/drivers/drivers.html:28` («Modo de Asignación» → «Modo de asignación»).
85
- - **3 con un switch armado a mano al lado → `sui-switch-label`:** `pages/discounts/discounts.html:195`,
86
- `:299`; `components/add-product-modal/add-product-modal.html:195`.
78
+ - **1 encima de un `sui-textarea`**, que ya trae su `[label]`: `pages/promociones/promociones.html:201`
79
+ («Descripción»).
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`.
87
82
 
88
83
  ## Tamaño en mobile y en web
89
84
 
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: sui-href
3
+ selector: a[suiHref]
4
+ resumen: Directiva para los <a> del DS que reciben un href configurable; los links internos navegan con el Router sin recargar la app
5
+ alternativas: [routerLink (link interno escrito en la plantilla de la app), sui-link-button (acción con forma de link, ya usa suiHref por dentro)]
6
+ ---
7
+
8
+ # sui-href
9
+
10
+ Story: [Utilities/Href](https://sui-design-system.web.app/?path=/docs/utilities-href--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** dentro de un componente del DS que recibe un `href` por input y lo pinta en un `<a>`:
15
+ en vez de `[attr.href]="href()"`, `[suiHref]="href()"`. Así un `href="/cliente/pedidos"` que
16
+ viene de la app navega **sin recargar el WebView** (en Capacitor, una recarga pierde el estado y
17
+ tarda segundos) y uno externo se abre normal.
18
+
19
+ Ya lo usan `sui-link-button`, `sui-compact-button`, `sui-fancy-button`, `sui-social-button`,
20
+ `sui-breadcrumb-item`, `sui-topbar-item`, `sui-brand-logo`, `sui-app-store-badge`, `sui-rating` y
21
+ `sui-progress-bar-label`.
22
+
23
+ **No lo uses** para:
24
+
25
+ - Un link interno que escribes en una plantilla de la app: `routerLink`. Es lo que usa la app
26
+ (98 usos, 0 de `suiHref` el 03-10-2026) y además marca el link activo.
27
+ - Un botón que ejecuta algo: `sui-button` o `sui-link-button` con `(clicked)`.
28
+
29
+ ## Qué variante usar
30
+
31
+ > **No está en la guía del DS: es una utilidad de SUI**, sin Figma ni variantes.
32
+
33
+ No tiene variantes. Lo que decide qué hace es la URL:
34
+
35
+ | `suiHref` | qué hace al tocarlo | fuente |
36
+ |---|---|---|
37
+ | empieza con `/` (no `//`) | `router.navigateByUrl()`: navegación dentro de la app, conserva query y `#` | componente |
38
+ | `https://…`, `mailto:`, `tel:`, `#…`, `//host` | lo que haga el navegador | componente |
39
+ | cualquiera, con `target` distinto de `_self` | lo que haga el navegador (nueva pestaña) | componente |
40
+ | cualquiera, con cmd/ctrl/shift/alt o botón del medio | lo que haga el navegador | componente |
41
+ | `null` o `''` | el `<a>` queda **sin** `href` (no navegable) | componente |
42
+
43
+ ## Tamaño en mobile y en web
44
+
45
+ No aplica: es una directiva, no dibuja nada. El tamaño es el del componente que la usa.
46
+
47
+ ## API
48
+
49
+ <!-- api:inicio -->
50
+ <!-- generada: no editar a mano — `npm run docs` -->
51
+
52
+ | input | tipo | default |
53
+ |---|---|---|
54
+ | `suiHref` | `string \| null` | `null` |
55
+
56
+ Outputs: ninguno.
57
+ <!-- api:fin -->
58
+
59
+ Solo se aplica a `<a>` (`selector: a[suiHref]`).
60
+
61
+ ## Trampas
62
+
63
+ - **El atributo `href` real queda puesto**: el clic del medio, «copiar enlace» y «abrir en
64
+ pestaña nueva» siguen funcionando. Solo el clic normal se intercepta.
65
+ - **Sin Router no intercepta nada**: en Storybook o en una app sin `provideRouter` es un `href`
66
+ común y corriente (recarga la página).
67
+ - **Si el componente ya hizo `preventDefault()`** en su propio `(click)`, la directiva no navega.
68
+ Útil para un link que a veces solo emite un evento.
69
+ - **No marca el link activo** (`routerLinkActive` no lo ve). Para menús de la app, `routerLink`.
70
+ - Un `href` relativo sin `/` inicial (`pedidos/123`) **no** se intercepta: lo resuelve el
71
+ navegador contra la URL actual y recarga. Pasa rutas absolutas.
72
+
73
+ ## Ejemplo
74
+
75
+ ```html
76
+ <!-- Dentro del template de un componente del DS -->
77
+ <a class="sui-link-button" [suiHref]="href()" [attr.target]="target()">
78
+ <ng-content />
79
+ </a>
80
+ ```
81
+
82
+ ```html
83
+ <!-- Desde la app: el componente del DS ya lo resuelve -->
84
+ <sui-link-button href="/cliente/pedidos">Ver mis pedidos</sui-link-button>
85
+ ```
@@ -91,7 +91,7 @@ el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propue
91
91
 
92
92
  Un ícono suelto **nunca** es el área táctil: si se toca, va en `sui-compact-button` o
93
93
  `sui-button` `onlyIcon`, que dan los 44 px. Hoy solo 2 íconos cambian por breakpoint
94
- (`pages/discounts/discounts.html:101` y `:106`, con `bp.isTablet() ? 20 : 16`).
94
+ (`pages/discounts/discounts.html:103` y `:108`, con `bp.isTablet() ? 20 : 16`).
95
95
 
96
96
  ## «No usar»: por qué no hoy y cuándo sí
97
97
 
@@ -121,8 +121,9 @@ Outputs: ninguno.
121
121
  - **`size` acepta número o string**: `[size]="20"` son px; `size="1.25em"` es CSS. Con
122
122
  `size="20"` (string sin unidad) el ícono no toma tamaño.
123
123
  - **El nombre no se valida**: si no existe en RemixIcon, sale vacío sin error.
124
- - **No tiene `aria-label`**: los propios del DS llevan `aria-hidden`; los de RemixIcon son un
125
- `<i>` vacío. Si el ícono es lo único que dice algo, el texto va al lado o en el contenedor.
124
+ - **No tiene `aria-label` y es decorativo siempre**: el SVG propio y el `<i>` de RemixIcon llevan
125
+ `aria-hidden="true"` (el `<i>` desde el 04-10-2026; antes el lector podía leer el glifo como un
126
+ símbolo raro). Si el ícono es lo único que dice algo, el texto va al lado o en el contenedor.
126
127
  - **La app necesita la fuente de RemixIcon** (`remixicon/fonts/remixicon.css` en `styles.scss`):
127
128
  el paquete del DS no la trae.
128
129
  - Dentro de un `sui-kbd`, el kbd le fuerza el color `text-sub-600`.