@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
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: sui-dropdown-caption
3
+ selector: sui-dropdown-caption
4
+ resumen: Texto gris de pie dentro de un menú flotante (una pista, la versión, cuándo se actualizó)
5
+ alternativas: [sui-content-divider (cabecera de un grupo de items), sui-form-hint (ayuda debajo de un campo), sui-empty-state (el menú no tiene resultados)]
6
+ ---
7
+
8
+ # sui-dropdown-caption
9
+
10
+ Story: [Organisms/Dropdown/Dropdown Caption](https://sui-design-system.web.app/?path=/docs/organisms-dropdown-dropdown-caption--docs)
11
+
12
+ Una línea de texto `soft-400` 14/20 con 8 px de aire, pensada para el **pie** del panel de un
13
+ `sui-dropdown-menu`. No tiene inputs: el texto se proyecta.
14
+
15
+ ## Cuándo usarlo / cuándo no
16
+
17
+ **Úsalo** para un dato accesorio al final del menú, que nadie tiene que leer para usarlo: una
18
+ pista («Presiona Enter para agregar»), la versión, «Actualizado hace 5 min».
19
+
20
+ **No lo uses** para:
21
+
22
+ - La cabecera de un grupo de items («Negocios», «Sucursales»): `sui-content-divider` `text`.
23
+ - Algo que la persona necesita para decidir: el gris `soft-400` es el de los metadatos y
24
+ placeholders (CANON-SUI §0); lo importante va en el `description` del item.
25
+ - Decir que la búsqueda no encontró nada: un texto de vacío con la voz del CANON («No encontramos
26
+ nada con ese filtro»), sin CTA.
27
+ - Fuera de un menú: en una pantalla, el metadato es texto con `paragraph-xs` + `soft-400`.
28
+
29
+ Regla corta: **pie del menú → caption · cabecera de grupo → content-divider · ayuda de un campo →
30
+ form-hint.**
31
+
32
+ ## Qué variante usar
33
+
34
+ > **La guía del DS no tiene una pieza «caption»** en su dropdown: tiene etiqueta de grupo y
35
+ > separador. La caption sale del Figma del DS («Dropdown Misc Items»). Todo lo de abajo es
36
+ > **propuesta, falta aprobación**.
37
+ >
38
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-dropdown-menu`):
39
+ > **0 usos**.
40
+
41
+ No tiene variantes. Lo único que se decide es el texto:
42
+
43
+ | qué | regla | fuente |
44
+ |---|---|---|
45
+ | largo | Una línea; si no entra, corta palabra y salta de línea (`word-break: break-word`). | propuesta |
46
+ | copy | Sentence case, con punto solo si son dos frases. Tuteo: «Presiona Enter para agregar». | canon (CANON-SUI §5, `docs/VOZ-Y-ESCRITURA.md`) |
47
+ | posición | Al final del panel, después del último item. | propuesta |
48
+
49
+ **Candidatos de hoy:** las cabeceras de grupo a mano del switcher del sidebar
50
+ (`components/sidebar/sidebar.html:67`, `:88`, `:104`) **no** son caption: son cabeceras de grupo y van
51
+ con `sui-content-divider`.
52
+
53
+ ## Tamaño en mobile y en web
54
+
55
+ No tiene tamaños: 14/20 con 8 px de padding en los dos. No se toca, así que no le aplica el mínimo
56
+ de 44 px del dedo.
57
+
58
+ | uso | mobile | web | fuente |
59
+ |---|---|---|---|
60
+ | pie de un menú | igual (14/20) | igual (14/20) | propuesta |
61
+
62
+ ## API
63
+
64
+ <!-- api:inicio -->
65
+ <!-- generada: no editar a mano — `npm run docs` -->
66
+
67
+ Inputs: ninguno.
68
+
69
+ Outputs: ninguno.
70
+ <!-- api:fin -->
71
+
72
+ Slot: el contenido por defecto (`<ng-content />`) es el texto.
73
+
74
+ ## Trampas
75
+
76
+ - **No es una cabecera de grupo.** Es gris claro y va al pie; para «Negocios» / «Sucursales» se usa
77
+ `sui-content-divider`.
78
+ - Tiene fondo blanco propio (`bg-white-0`) y ocupa todo el ancho: sobre un panel de otro color se nota
79
+ la caja.
80
+ - No lleva `role`: el lector de pantalla lo lee como texto suelto dentro del menú.
81
+
82
+ ## Ejemplo
83
+
84
+ ```html
85
+ <ng-template suiDropdownPanel>
86
+ <sui-dropdown-search [(value)]="busqueda" placeholder="Buscar etiqueta…" />
87
+ @for (e of etiquetasFiltradas(); track e) {
88
+ <sui-dropdown-item [label]="e" (clicked)="menu.close(); elegir(e)" />
89
+ }
90
+ <sui-dropdown-caption>Presiona Enter para crear «{{ busqueda() }}»</sui-dropdown-caption>
91
+ </ng-template>
92
+ ```
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: sui-dropdown-item
3
+ selector: sui-dropdown-item
4
+ resumen: Fila de un menú flotante o de una lista de opciones, con ícono, bandera, avatar o logo a la izquierda y badge o atajo a la derecha
5
+ alternativas: [sui-command-menu-item (fila del buscador ⌘K), sui-filter-item (fila de un panel de filtros), sui-sidebar (navegación lateral, con sus items), sui-radio-label (opciones fijas a la vista en un formulario)]
6
+ ---
7
+
8
+ # sui-dropdown-item
9
+
10
+ Story: [Organisms/Dropdown/Dropdown Item](https://sui-design-system.web.app/?path=/docs/organisms-dropdown-dropdown-item--docs)
11
+
12
+ Va **dentro** de algo que lo contiene: el panel de un `sui-dropdown-menu`, la lista de un
13
+ `sui-select` (que lo arma solo) o el panel del header de `sui-sidebar`. Suelto en una pantalla no
14
+ tiene sentido: para una lista a la vista hay otros componentes.
15
+
16
+ ## Cuándo usarlo / cuándo no
17
+
18
+ **Úsalo** para cada fila de un menú de acciones (`mode="menuitem"`, el default) o de una lista
19
+ donde se elige un valor y el elegido queda marcado (`mode="option"`): el ⋮ de una sección, el
20
+ switcher de negocio y sucursal del sidebar.
21
+
22
+ **No lo uses** para:
23
+
24
+ - Las opciones de un `sui-select` o `sui-compact-select`: el select ya las pinta con este mismo
25
+ componente; se le pasan `options`, no items.
26
+ - Una lista de navegación lateral: `sui-sidebar` y sus items (`SuiSidebarItem`).
27
+ - Las filas del buscador ⌘K: `sui-command-menu-item` (otra altura y otro marcado).
28
+ - Opciones fijas que deberían verse todas en un formulario: `sui-radio-label` / `sui-radio-card`.
29
+
30
+ Regla corta: **hace algo → `menuitem` · elige y queda marcado → `option`.** Ver la relación entre
31
+ dropdown, select y command menu en el README de `sui-dropdown-menu`.
32
+
33
+ ## Qué variante usar
34
+
35
+ > **La guía del DS lo arma por partes** (item + ícono, y adentro bandera, avatar, badge o atajo),
36
+ > con una prop `inset` para alinear los que no llevan ícono. No dice cuándo va cada tamaño ni cada
37
+ > modo. Lo que sigue es **propuesta, falta aprobación**, salvo lo marcado.
38
+ >
39
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-dropdown-menu`):
40
+ > **10 usos, los 10 en `size="large"`**. 7 `mode="option"` en los switchers del sidebar
41
+ > (`components/sidebar/sidebar.html:69`, `:89`, `:96`, `:106`, `layouts/customer/customer-layout.html:27`,
42
+ > `layouts/driver/driver-layout.html:25`, `layouts/master/master-layout.html:27`) y 3 `menuitem` con
43
+ > `leadingFramed` en el ⋮ de `components/option-sections-manager/option-sections-manager.html:40`, `:43`, `:46`.
44
+
45
+ ### `mode` — qué es la fila
46
+
47
+ | mode | cuándo | ejemplo real de la app | fuente |
48
+ |---|---|---|---|
49
+ | `menuitem` (default) | La fila **hace algo**: editar, archivar, ir a otra pantalla. `selected` no pinta nada. | `option-sections-manager.html:40` («Editar») | propuesta |
50
+ | `option` | La fila **es un valor** y el elegido queda marcado (fondo `primary-alpha-10` + check a la derecha). El contenedor lleva `role="listbox"`. | `sidebar.html:69` (el negocio actual) | propuesta (ya es práctica) |
51
+
52
+ ### `size`
53
+
54
+ | size | alto | cuándo | fuente |
55
+ |---|---|---|---|
56
+ | `small` (default) | 36 | Menú de acciones en web, una línea (label + `sublabel` en la misma línea). | según la guía del DS (Figma: Small 36) |
57
+ | `large` | 56 | Toda fila en mobile; en web, cuando hay segunda línea (`description`) o el ícono va enmarcado. | según la guía del DS (Figma: Large 56); el cuándo es propuesta |
58
+ | `xlarge` | 76 | Extensión SUI. Sin uso hoy. | — |
59
+
60
+ ### Las piezas
61
+
62
+ | prop / slot | cuándo | fuente |
63
+ |---|---|---|
64
+ | `slot="leading"` | `sui-icon` (20), `sui-flag`, `sui-avatar` (`xs`), `sui-brand-logo` o `sui-checkbox`. El tipo de la fila sale de lo que se proyecta. | según la guía del DS (se arma por partes) |
65
+ | `leadingFramed` | Solo con un `sui-icon` en `large`/`xlarge`: lo mete en un círculo de 40 con borde. Nunca con avatar, bandera o logo (ya traen forma). | según la guía del DS (Figma Large, tipo basic) |
66
+ | `sublabel` | Dato corto al lado del label en `small` («(es)», «@juan»). | según la guía del DS |
67
+ | `description` | Segunda línea en `large`: la aclaración que ayuda a elegir. **En `small` no se ve.** | según la guía del DS |
68
+ | `shortcut` | Solo web (en mobile no hay teclado físico, ver README de `sui-kbd`). | canon (README de `sui-kbd`) |
69
+ | `slot="trailing"` | Badge primero, después el atajo (lo pone el componente), al final un switch o botón. | según la guía del DS (orden del Figma) |
70
+ | `disabled` | Existe pero hoy no se puede: queda gris claro y no recibe toques. | según la guía del DS |
71
+ | `highlighted` | Lo usa el select para la navegación con flechas. A mano no hace falta. | propuesta |
72
+
73
+ **Usos de hoy que romperían la propuesta:**
74
+
75
+ - **4 filas de «Cambiar de rol» en `mode="option"` que nunca marcan `selected`**:
76
+ `customer-layout.html:27`, `driver-layout.html:25`, `master-layout.html:27` (y `sidebar.html:106`).
77
+ Cambiar de rol es una acción, no un valor elegido: o se marca el rol actual con `selected`, o
78
+ pasan a `menuitem` con el contenedor en `role="menu"`. **A discutir.**
79
+ - **`sublabel` en `large`** en esos mismos switchers: en `large` el sublabel cae abajo en 12/16
80
+ `soft-400` (gris claro). Para la segunda línea de `large` el componente tiene `description`
81
+ (`sub-600`, se lee mejor).
82
+ - **Íconos de 18 dentro de `leadingFramed`**: `option-sections-manager.html:41`, `:44`, `:47`. El
83
+ círculo está medido para un ícono de 20 (20 + 10 + 10 = 40); con 18 queda de 38.
84
+
85
+ ## Tamaño en mobile y en web
86
+
87
+ El item **no cambia solo en mobile**: no tiene `@media`. El 44 de mobile que tienen las opciones de
88
+ `sui-select` lo pone el panel del select, no el item. Suelto, un `small` mide 36 también en el
89
+ celular: queda debajo de los 44 del dedo.
90
+
91
+ | uso | mobile | web | fuente |
92
+ |---|---|---|---|
93
+ | menú de acciones (⋮) | `large` (56) | `small` (36) | propuesta, falta aprobación |
94
+ | switcher con segunda línea (negocio + dirección) | `large` (56) | `large` (56) | propuesta (ya es práctica en el sidebar) |
95
+ | opciones de un select | las pone el select (44) | las pone el select (36–48) | canon (README de `sui-select`, aprobado 03-10-2026) |
96
+
97
+ ```html
98
+ <sui-dropdown-item label="Editar" [size]="bp.isMobile() ? 'large' : 'small'" … /> <!-- bp = BreakpointsService -->
99
+ ```
100
+
101
+ En large y xlarge el texto sube a 16 px (regla del 03-10-2026). El label va en Label/Medium 16/24
102
+ (el nodo de Figma del large lo dibuja en 14); la description no cambia en large (12) y el alto
103
+ sigue en 56: el padding-y bajó de 8 a 6.
104
+
105
+ ## API
106
+
107
+ <!-- api:inicio -->
108
+ <!-- generada: no editar a mano — `npm run docs` -->
109
+
110
+ | input | tipo | default |
111
+ |---|---|---|
112
+ | `label` | `string` | — (requerido) |
113
+ | `sublabel` | `string \| null` | `null` |
114
+ | `description` | `string \| null` | `null` |
115
+ | `size` | `'small' \| 'large' \| 'xlarge'` | `'small'` |
116
+ | `leadingFramed` | `boolean` | `false` |
117
+ | `mode` | `'menuitem' \| 'option'` | `'menuitem'` |
118
+ | `selected` | `boolean` | `false` |
119
+ | `highlighted` | `boolean` | `false` |
120
+ | `disabled` | `boolean` | `false` |
121
+ | `shortcut` | `string \| null` | `null` |
122
+
123
+ | output | payload |
124
+ |---|---|
125
+ | `clicked` | `Event` |
126
+ <!-- api:fin -->
127
+
128
+ Slots: `[slot=leading]` y `[slot=trailing]`. `clicked` sale con clic, Enter y Espacio, y no sale si
129
+ está `disabled`.
130
+
131
+ ## Trampas
132
+
133
+ - **No cierra el menú.** Dentro de un `sui-dropdown-menu` hay que cerrarlo en el handler:
134
+ `(clicked)="menu.close(); editar()"`.
135
+ - **`selected` en `menuitem` no se ve.** El set del Figma no le da fondo al seleccionado de un menú;
136
+ solo `mode="option"` pinta fondo naranja suave + check. Si la fila tiene que verse marcada, es
137
+ `option`.
138
+ - **CANON-SUI §4.2 mezcla los dos modos**: dice que la opción de lista «no lleva fondo de selección»
139
+ y a la vez que se marca con `primary-alpha-10`. Lo que hace el código: `menuitem` seleccionado =
140
+ sin fondo; `option` seleccionado = `primary-alpha-10` + check (hover `primary-alpha-16`).
141
+ - **`description` solo existe en `large`/`xlarge`.** En `small` se descarta sin avisar.
142
+ - **`leadingFramed` solo hace algo en `large`/`xlarge`.**
143
+ - `role="option"` necesita un padre con `role="listbox"` (los switchers lo ponen a mano).
144
+ - `disabled` no usa opacidad: baja el texto y el ícono a `disabled-300`; un avatar o una bandera
145
+ quedan al 48 %.
146
+ - El label corta con `…` en una línea: no hace salto de línea.
147
+ - Ya trae los listeners `touchstart`/`touchend` para el `:active` pegado de iOS.
148
+
149
+ ## Ejemplo
150
+
151
+ ```html
152
+ <!-- Acción en un menú -->
153
+ <sui-dropdown-item label="Archivar" [size]="bp.isMobile() ? 'large' : 'small'"
154
+ (clicked)="menu.close(); archivar()">
155
+ <sui-icon slot="leading" name="archive-line" [size]="20" />
156
+ </sui-dropdown-item>
157
+
158
+ <!-- Valor elegido en un switcher (el contenedor lleva role="listbox") -->
159
+ <sui-dropdown-item [label]="local.name" [description]="local.address" mode="option" size="large"
160
+ [selected]="local.id === localActual()" (clicked)="cambiarLocal(local.id)">
161
+ <sui-avatar slot="leading" size="xs" [src]="local.imageUrl" [initials]="local.name.charAt(0)" />
162
+ </sui-dropdown-item>
163
+ ```
@@ -0,0 +1,196 @@
1
+ ---
2
+ name: sui-dropdown-menu
3
+ selector: sui-dropdown-menu, ng-template[suiDropdownPanel]
4
+ resumen: Menú flotante anclado a un botón (el kebab ⋮ de una card, un avatar) con acciones sobre eso; también es el overlay que usan por dentro los selects
5
+ alternativas: [sui-select (elegir un valor de un formulario), sui-modal-sheet (más de 5 acciones o una lista larga en mobile), sui-popover (explicar algo con una flecha, sin anclaje propio), sui-tooltip (ayuda corta al pasar el mouse), sui-command-menu-item (buscar y saltar con ⌘K en desktop)]
6
+ ---
7
+
8
+ # sui-dropdown-menu
9
+
10
+ Story: [Organisms/Dropdown/Dropdown Menu](https://sui-design-system.web.app/?path=/docs/organisms-dropdown-dropdown-menu--docs)
11
+
12
+ Es **solo el contenedor**: abre y cierra el panel, lo ancla al trigger (CDK Overlay), lo cierra al
13
+ tocar afuera o con Escape y lo hace seguir al scroll. Lo que va adentro se arma con las piezas
14
+ hermanas: `sui-dropdown-item` (las filas), `sui-dropdown-search` (el buscador de arriba) y
15
+ `sui-dropdown-caption` (el texto de pie).
16
+
17
+ ## Cuándo usarlo / cuándo no
18
+
19
+ **Úsalo** para un puñado de **acciones sobre algo concreto** que no merecen estar siempre a la
20
+ vista: el ⋮ de una card («Editar», «Aplicar a productos», «Archivar»), el menú de una fila, un
21
+ cambio de cuenta. También para anclar un panel chico a un botón cuando `sui-popover` no sirve
22
+ (no se ancla solo).
23
+
24
+ **No lo uses** para:
25
+
26
+ - Elegir un valor de un formulario (distrito, categoría): `sui-select`, que ya es un
27
+ `sui-dropdown-menu` por dentro con su campo, su teclado y su `ControlValueAccessor`. Armar un
28
+ select a mano con este componente es rehacer lo que el select ya resuelve.
29
+ - Una sola acción: un botón con su ícono (lápiz, tacho). Un ⋮ que abre un menú de un solo item es
30
+ un toque de más.
31
+ - Acciones que la persona usa todo el rato: van a la vista, como botones.
32
+ - Buscar en toda la app: el command menu (`sui-command-menu-search` + `-item` + `-footer`).
33
+ - Explicar algo: `sui-tooltip` (web) o `sui-popover`.
34
+
35
+ Regla corta: **acciones sobre algo → dropdown-menu · elegir un valor → select · buscar y saltar →
36
+ command menu · explicar → tooltip/popover.**
37
+
38
+ ## Dropdown, select y command menu: cuál va
39
+
40
+ Los tres muestran una lista flotante, pero responden a preguntas distintas.
41
+
42
+ | pregunta de la persona | componente | items | rol ARIA | fuente |
43
+ |---|---|---|---|---|
44
+ | «¿qué hago con esto?» (editar, archivar, compartir) | `sui-dropdown-menu` | `sui-dropdown-item` (default `mode="menuitem"`) | `menu` (default) | según la guía del DS («un menú con un conjunto de acciones, abierto desde un botón») |
45
+ | «¿cuál de estos valores elijo?» | `sui-select` / `sui-compact-select` | los arma el select: `sui-dropdown-item mode="option"` | `listbox` | según la guía del DS (el select es el control de una opción) |
46
+ | «¿dónde está X?» (buscar y saltar a cualquier lado) | command menu: `sui-command-menu-search` + `sui-command-menu-item` + `sui-command-menu-footer` dentro de un `sui-modal` | `sui-command-menu-item` | lo arma quien lo usa | según la guía del DS (el command menu vive dentro de un diálogo) |
47
+
48
+ Por dentro, `sui-select`, `sui-compact-select`, `sui-compact-select-for-input`, `sui-inline-select`,
49
+ `sui-time-picker` y `sui-color-picker` usan este mismo componente con `[origin]` (el trigger es su
50
+ propio campo, que ya lleva su `aria-haspopup`: `listbox` en los selects, `dialog` en los pickers). Por
51
+ eso un arreglo del overlay los toca a todos. Con `[origin]`, `popupRole` no se usa: el wrapper del
52
+ trigger no se dibuja.
53
+
54
+ ## Qué variante usar
55
+
56
+ > **La guía del DS lo define como el menú de acciones que abre un botón** y lo arma por partes:
57
+ > item con ícono, grupo con su etiqueta, separador, items con casilla o radio y submenús. No trae
58
+ > variantes ni do/don't; el panel arranca en 300 px de ancho y 8 px separado del trigger. Lo
59
+ > demás es **propuesta, falta aprobación**, salvo lo marcado canon.
60
+ >
61
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (sin `master-preview`, `master-prototipos`,
62
+ > `mockup-sheets-*`, `dx/*`, `master-rutina`, `master-medico`, `master-ejercicios`, `dev-index` ni las
63
+ > copias de `components/sui/`): **2 usos**. `components/option-sections-manager/option-sections-manager.html:37`
64
+ > (el ⋮ de una sección de opciones, con 3 acciones) y `components/option-image/option-image.ts:52`
65
+ > (panel con un campo para pegar un link, `popupRole="true"`).
66
+
67
+ ### Lo que sí dice la guía del DS
68
+
69
+ - **Para qué es**: mostrar un menú de acciones o funciones, abierto desde un botón.
70
+ - **Se arma por partes**, no por tipos: el ícono, la bandera, el avatar, el badge o el atajo van
71
+ dentro del item. En SUI eso es el slot `leading` / `trailing` de `sui-dropdown-item`.
72
+ - **Grupos**: la guía tiene etiqueta de grupo y separador. SUI no trae una pieza propia para la
73
+ etiqueta: se usa `sui-content-divider` (`text`) para la cabecera y `sui-divider` para el separador.
74
+ - **Submenús, items con casilla y con radio**: existen en la guía; SUI no los tiene armados.
75
+
76
+ ### Las props que importan
77
+
78
+ | prop | cuándo | fuente |
79
+ |---|---|---|
80
+ | sin props (default) | El caso normal: un ⋮ o un botón con 2 a 5 acciones. El panel se ajusta al contenido. | propuesta |
81
+ | `matchWidth` | El panel debe medir lo mismo que el trigger (un botón ancho que abre opciones). | propuesta |
82
+ | `minWidth` | El trigger es un ícono chico y el panel quedaría angosto: 200 a 240 px. | propuesta |
83
+ | `position="above"` | El trigger vive pegado al borde de abajo (una barra inferior). Con `auto` ya cae arriba si no entra. | propuesta |
84
+ | `popupRole="listbox"` | **Solo** si los items son `mode="option"`. El rol tiene que coincidir con el de los items. | según ARIA (documentado en el `.ts`) |
85
+ | `popupRole="true"` | El panel no es un menú: un campo, un formulario chico (`option-image.ts:52`). | propuesta (ya es práctica) |
86
+ | `origin` | El trigger lo maneja el padre (los selects del DS). En la app no hace falta. | propuesta |
87
+ | `push` | No usar: un panel empujado queda fijo y **se despega del trigger al scrollear**. | canon (comentario del `.ts`, bug real del color picker 21-07-2026) |
88
+ | `flexibleDimensions=false` | Solo paneles de tamaño fijo que no pueden encogerse (el color picker). | propuesta |
89
+
90
+ **Usos de hoy que rompen la propuesta:**
91
+
92
+ - **Un ⋮ que no abre menú**: `pages/products/products.html:229` pinta `more-2-fill` («Opciones») y al
93
+ tocarlo abre la edición directo. O se cambia el ícono por el lápiz, o se abre un menú con las
94
+ acciones del producto.
95
+ - **Cabeceras de grupo a mano** en el switcher del sidebar: `components/sidebar/sidebar.html:67`,
96
+ `:88` y `:104` usan `<span class="sidebar-switcher__label">` («Negocios», «Sucursales», «Cambiar
97
+ de rol») → `sui-content-divider` `text`.
98
+
99
+ ## Tamaño en mobile y en web
100
+
101
+ El menú **no tiene `size`**: el alto lo ponen los items. El panel mide lo que su contenido, con
102
+ 8 px de padding, 4 px entre items y hasta 400 px de alto (después scrollea).
103
+
104
+ | uso | mobile | web | fuente |
105
+ |---|---|---|---|
106
+ | items de un menú de acciones | `sui-dropdown-item size="large"` (56) | `size="small"` (36) | propuesta; hoy los 3 items del ⋮ van en `large` en las dos |
107
+ | trigger ⋮ | `sui-compact-button` de 40 o más | `sui-compact-button` `large` | propuesta (ver README de `sui-compact-button`) |
108
+ | más de 5 acciones, o alguna destructiva que pide confirmar | `sui-modal-sheet` | `sui-dropdown-menu` | propuesta, falta aprobación |
109
+
110
+ ```html
111
+ <sui-dropdown-item [size]="bp.isMobile() ? 'large' : 'small'" … /> <!-- bp = BreakpointsService -->
112
+ ```
113
+
114
+ ## API
115
+
116
+ <!-- api:inicio -->
117
+ <!-- generada: no editar a mano — `npm run docs` -->
118
+
119
+ ### `sui-dropdown-menu`
120
+
121
+ | input | tipo | default |
122
+ |---|---|---|
123
+ | `matchWidth` | `boolean` | `false` |
124
+ | `flexibleDimensions` | `boolean` | `true` |
125
+ | `push` | `boolean` | `false` |
126
+ | `minWidth` | `number \| null` | `null` |
127
+ | `position` | `'auto' \| 'below' \| 'above'` | `'auto'` |
128
+ | `viewportMargin` | `number` | `8` |
129
+ | `panelClass` | `string` | `''` |
130
+ | `disabled` | `boolean` | `false` |
131
+ | `popupRole` | `'menu' \| 'listbox' \| 'true'` | `'menu'` |
132
+ | `origin` | `ElementRef<HTMLElement> \| HTMLElement \| null` | `null` |
133
+
134
+ | output | payload |
135
+ |---|---|
136
+ | `openedChange` | `boolean` |
137
+
138
+ ### `ng-template[suiDropdownPanel]`
139
+
140
+ Inputs: ninguno.
141
+
142
+ Outputs: ninguno.
143
+ <!-- api:fin -->
144
+
145
+ `exportAs: 'suiDropdownMenu'`. Métodos públicos: `open()`, `close()`, `toggle()`. Signal pública:
146
+ `isOpen` (`signal(false)`).
147
+
148
+ Slots: el trigger se proyecta con el atributo `trigger` (`<sui-compact-button trigger … />`); el
149
+ panel va en un `<ng-template suiDropdownPanel>` (hay que importar `SuiDropdownPanel` junto con
150
+ `SuiDropdownMenu`).
151
+
152
+ ## Trampas
153
+
154
+ - **El paquete npm no envía estilos.** La caja del panel (fondo, borde, radio, sombra, padding,
155
+ `max-height`) vive en `src/styles/_sui-dropdown-menu-overlay.scss` del DS, y la app tiene que
156
+ importar su propia copia (`master-pedidos/src/styles.scss:13`). **La copia de la app está
157
+ desfasada**: usa `radius-16` + `regular-shadow-medium`; el DS ya va en `radius-10` + `x-small`
158
+ (alineado al Figma del dropdown).
159
+ - **El item no cierra el menú.** Hay que cerrarlo en el handler:
160
+ `#menu="suiDropdownMenu"` y `(clicked)="menu.close(); editar()"`.
161
+ - **El panel tiene que ir en `<ng-template suiDropdownPanel>`.** Si los items se ponen directo
162
+ dentro del `sui-dropdown-menu`, no se proyectan en ningún lado y el menú abre vacío (o no abre:
163
+ `open()` sale sin panel).
164
+ - **El trigger necesita el atributo `trigger`.** Sin él no se proyecta.
165
+ - **El primer toque afuera solo cierra**: el backdrop es transparente y se come ese toque; no le
166
+ llega al elemento de abajo.
167
+ - **No hay flechas entre items.** Enter, Espacio y Flecha abajo abren el menú desde el trigger,
168
+ pero adentro se navega con Tab. Y al abrir, el foco **se queda en el trigger**.
169
+ - `disabled` no abre el menú pero **no pinta nada**: deshabilita también el trigger.
170
+ - El lado (arriba o abajo) se decide al abrir y queda fijo mientras está abierto; si el trigger
171
+ está pegado al borde derecho, el panel abre hacia la izquierda.
172
+ - Se cierra solo al cambiar de ruta (`disposeOnNavigation`).
173
+ - **El `z-index` del overlay también es de esa hoja.** El DS sube `.cdk-overlay-container` a 1100
174
+ (encima de `sui-modal`, 1000/1001, y debajo de los toasts); con el 1000 del CDK, un menú abierto
175
+ dentro de un modal queda detrás. La copia de la app no trae ese bloque: no se verificó en la
176
+ app, pero es lo primero que hay que mirar si un menú «no abre» dentro de un modal.
177
+ - El host es `display: contents`: no ocupa caja. Para alinearlo, se alinea el trigger.
178
+
179
+ ## Ejemplo
180
+
181
+ ```html
182
+ <sui-dropdown-menu #menu="suiDropdownMenu">
183
+ <sui-compact-button trigger icon="more-2-line" variantStyle="ghost" size="large"
184
+ ariaLabel="Opciones de la sección" />
185
+ <ng-template suiDropdownPanel>
186
+ <sui-dropdown-item label="Editar" [size]="bp.isMobile() ? 'large' : 'small'"
187
+ (clicked)="menu.close(); editar()">
188
+ <sui-icon slot="leading" name="pencil-line" [size]="20" />
189
+ </sui-dropdown-item>
190
+ <sui-dropdown-item label="Archivar" [size]="bp.isMobile() ? 'large' : 'small'"
191
+ (clicked)="menu.close(); archivar()">
192
+ <sui-icon slot="leading" name="archive-line" [size]="20" />
193
+ </sui-dropdown-item>
194
+ </ng-template>
195
+ </sui-dropdown-menu>
196
+ ```
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: sui-dropdown-search
3
+ selector: sui-dropdown-search
4
+ resumen: Buscador sin caja que va arriba del panel de un menú flotante para filtrar sus items
5
+ alternativas: [sui-input type="search" (buscador de una pantalla o una lista a la vista), sui-command-menu-search (buscador del ⌘K), sui-select (elegir de una lista corta, sin buscar)]
6
+ ---
7
+
8
+ # sui-dropdown-search
9
+
10
+ Story: [Organisms/Dropdown/Dropdown Search](https://sui-design-system.web.app/?path=/docs/organisms-dropdown-dropdown-search--docs)
11
+
12
+ Es solo el campo: **no filtra nada**. Quien lo usa recibe el texto (`[(value)]`) y decide qué items
13
+ pinta debajo.
14
+
15
+ ## Cuándo usarlo / cuándo no
16
+
17
+ **Úsalo** arriba del panel de un `sui-dropdown-menu` cuando la lista es larga para scrollear y la
18
+ persona sabe lo que busca: más de ~10 opciones (un repartidor entre 40, un país, una etiqueta).
19
+
20
+ **No lo uses** para:
21
+
22
+ - El buscador de una pantalla o de una lista que ya está a la vista: `sui-input type="search"`
23
+ (con caja, label y tamaños).
24
+ - El ⌘K que busca en toda la app: `sui-command-menu-search`.
25
+ - Una lista corta: con 6 opciones el buscador estorba.
26
+ - Fuera de un panel: no tiene borde ni radio, se pierde en la pantalla.
27
+
28
+ Regla corta: **filtrar los items de un menú → dropdown-search · buscar en una pantalla → sui-input
29
+ search · buscar en toda la app → command-menu-search.**
30
+
31
+ `sui-select` **no tiene buscador**. Si un select necesita buscar, hoy se arma con
32
+ `sui-dropdown-menu` + este buscador + `sui-dropdown-item mode="option"` (es lo que muestra su story
33
+ «En contexto»), sabiendo que se pierde el `ControlValueAccessor` del select. Propuesta, falta
34
+ aprobación.
35
+
36
+ ## Qué variante usar
37
+
38
+ > **La guía del DS no tiene buscador en su dropdown**; el buscador de lista vive en su command
39
+ > menu. Este sale del Figma del DS («Dropdown Misc Items», estados Default / Hover / Active). Todo lo
40
+ > de abajo es **propuesta, falta aprobación**, salvo lo marcado canon.
41
+ >
42
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-dropdown-menu`):
43
+ > **0 usos**.
44
+
45
+ No tiene variantes. Los estados salen solos: sin texto, lupa gris; con texto, lupa oscura y una X
46
+ para limpiar.
47
+
48
+ | prop | regla | fuente |
49
+ |---|---|---|
50
+ | `placeholder` | **Siempre**, en español y con elipsis: «Buscar repartidor…». El default genérico es `'Buscar…'`. | canon (CANON-SUI §5: copy en español, elipsis `…`) |
51
+ | `[(value)]` | El texto; con él se filtra la lista. | API |
52
+ | `disabled` | Extensión SUI, no está en el Figma. Sin caso hoy. | — |
53
+
54
+ ## Tamaño en mobile y en web
55
+
56
+ No tiene tamaños: 36 px de alto (8 + 20 + 8), texto 14/20, en los dos.
57
+
58
+ | uso | mobile | web | fuente |
59
+ |---|---|---|---|
60
+ | buscador del menú | igual (36) | igual (36) | propuesta |
61
+
62
+ En mobile tiene dos problemas que el componente no resuelve (ver «Trampas»): el texto de 14 px hace
63
+ que iOS haga zoom al enfocarlo, y el teclado no muestra la lupa. Para buscar en una lista larga en
64
+ mobile, mejor un `sui-modal-sheet` con `sui-input type="search"` arriba. Propuesta, falta aprobación.
65
+
66
+ ## API
67
+
68
+ <!-- api:inicio -->
69
+ <!-- generada: no editar a mano — `npm run docs` -->
70
+
71
+ | input | tipo | default |
72
+ |---|---|---|
73
+ | `value` · model, `[(value)]` | `string` | `''` |
74
+ | `placeholder` | `string` | `'Buscar…'` |
75
+ | `disabled` | `boolean` | `false` |
76
+
77
+ | output | payload |
78
+ |---|---|
79
+ | `cleared` | `void` |
80
+ | `valueChanged` | `string` |
81
+ <!-- api:fin -->
82
+
83
+ `valueChanged` sale con cada tecla (lo mismo que `value`, como evento). `cleared` sale al tocar la X,
84
+ que además deja `value` en `''`.
85
+
86
+ ## Trampas
87
+
88
+ - **No filtra.** Hay que filtrar la lista con el `value` (un `computed` sobre las opciones).
89
+ - **El default del placeholder es genérico** (`'Buscar…'`, en español desde el 04-10-2026): pásalo siempre diciendo qué se busca.
90
+ - **iOS hace zoom al enfocarlo**: el campo está en 14 px y la regla de la app pide 16 px en los
91
+ inputs de mobile (CLAUDE.md, «Responsive mobile»). Hoy no hay forma de cambiarlo desde afuera.
92
+ - **El teclado no trae la lupa**: el `<input>` es `type="text"` sin `enterkeyhint="search"` (la regla
93
+ de la app para buscadores, CLAUDE.md «La lupa del teclado»).
94
+ - **El campo no tiene nombre accesible**: solo placeholder, sin `aria-label`.
95
+ - **Al abrir el menú el foco no entra al buscador**: quien quiera escribir de una tiene que enfocarlo
96
+ a mano.
97
+ - El `<input>` no tiene `(keydown)`: Enter no hace nada salvo que quien lo usa lo escuche.
98
+
99
+ ## Ejemplo
100
+
101
+ ```html
102
+ <sui-dropdown-menu #menu="suiDropdownMenu" [minWidth]="280">
103
+ <sui-button trigger variant="stroke" color="neutral">Asignar repartidor</sui-button>
104
+ <ng-template suiDropdownPanel>
105
+ <sui-dropdown-search [(value)]="busqueda" placeholder="Buscar repartidor…" />
106
+ @for (r of repartidoresFiltrados(); track r.uid) {
107
+ <sui-dropdown-item [label]="r.nombre" (clicked)="menu.close(); asignar(r.uid)">
108
+ <sui-avatar slot="leading" size="xs" [src]="r.avatarUrl" [initials]="r.nombre.charAt(0)" />
109
+ </sui-dropdown-item>
110
+ }
111
+ </ng-template>
112
+ </sui-dropdown-menu>
113
+ ```
@@ -11,8 +11,8 @@ Story: [Atoms/Emoji](https://sui-design-system.web.app/?path=/docs/atoms-emoji--
11
11
 
12
12
  ## Cuándo usarlo / cuándo no
13
13
 
14
- **Úsalo** donde la pantalla tiene que **sentirse**, no solo funcionar: un estado vacío, «¡Pedido
15
- confirmado!», los pasos de una landing, la barra de calificación.
14
+ **Úsalo** donde la pantalla tiene que **sentirse**, no solo funcionar: un estado vacío, «Pedido
15
+ confirmado», los pasos de una landing, la barra de calificación.
16
16
 
17
17
  **No lo uses** para:
18
18
 
@@ -32,10 +32,10 @@ confirmado!», los pasos de una landing, la barra de calificación.
32
32
 
33
33
  | caso | cómo | fuente |
34
34
  |---|---|---|
35
- | Estados vacíos y celebraciones | Emoji animado, uno solo, en `xl`. Nada de íconos genéricos en un estado vacío. | canon (preferencia del dueño: emojis animados en los estados vacíos) |
35
+ | Estados vacíos y celebraciones | Emoji animado, uno solo, en `xl`. Nada de íconos genéricos en un estado vacío. | canon (CANON-SUI §5.6) para los estados vacíos · propuesta, falta aprobación para celebraciones y el `xl` |
36
36
  | Pasos de una landing | `lg`, uno por paso. | propuesta |
37
37
  | Junto a un título o dentro de un texto | `md` o `sm`, como acento. | propuesta |
38
- | Como ícono de un botón | No: el botón lleva `leftIcon`. | propuesta |
38
+ | Como ícono de un botón | No: el botón lleva `leftIcon`. | derivado de CANON-SUI §5.7 (emojis solo en contenido escrito por un usuario; botones con `leftIcon`), falta confirmación |
39
39
 
40
40
  ### `size`
41
41
 
@@ -59,12 +59,12 @@ confirmado!», los pasos de una landing, la barra de calificación.
59
59
 
60
60
  **Usos de hoy que romperían la propuesta:**
61
61
 
62
- - **2 emojis como ícono de botón**: «Encargarme yo» en `pages/orders/orders.html:322` y `:353` → `leftIcon`.
62
+ - **2 emojis como ícono de botón**: «Encargarme yo» en `pages/orders/orders.html:323` y `:354` → `leftIcon`.
63
63
  - **5 animados a la vez** en `pages/public/landing-customers/landing-customers.html:160`–`:184`
64
64
  (más otro en `:56`). No tienen copia estática: o se acepta el peso en la landing o se generan
65
65
  las copias.
66
66
  - **Un catálogo paralelo**: `core/fluent-emoji.ts` arma sus propias URLs (otro CDN incluido) y lo
67
- importan 8 archivos (`components/permission-prime-modal/permission-prime-modal.ts`,
67
+ importan 11 archivos (medido el 04-10-2026) (`components/permission-prime-modal/permission-prime-modal.ts`,
68
68
  `pages/role-selector/role-selector.ts`, `pages/customer/order-tracking/order-tracking.ts`…).
69
69
  - **10 `<img>` con un emoji**, fuera del componente: `pages/products/add-product/add-product.html:122`
70
70
  (la URL del paquete escrita a mano, y 3 más en el mismo archivo),