@ajuarezso/sui-design-system 0.18.10 → 0.20.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 (47) hide show
  1. package/docs/INDEX.md +136 -0
  2. package/docs/sui-alert/README.md +216 -0
  3. package/docs/sui-app-store-badge/README.md +137 -0
  4. package/docs/sui-avatar/README.md +263 -0
  5. package/docs/sui-avatar-group/README.md +115 -0
  6. package/docs/sui-badge/README.md +212 -0
  7. package/docs/sui-brand-logo/README.md +143 -0
  8. package/docs/sui-button/README.md +192 -0
  9. package/docs/sui-button-group/README.md +178 -0
  10. package/docs/sui-button-group-item/README.md +102 -0
  11. package/docs/sui-checkbox/README.md +147 -0
  12. package/docs/sui-checkbox-label/README.md +143 -0
  13. package/docs/sui-circular-progress-bar/README.md +131 -0
  14. package/docs/sui-color-dot/README.md +112 -0
  15. package/docs/sui-color-picker/README.md +124 -0
  16. package/docs/sui-compact-avatar-group/README.md +103 -0
  17. package/docs/sui-compact-button/README.md +190 -0
  18. package/docs/sui-content-divider/README.md +124 -0
  19. package/docs/sui-divider/README.md +102 -0
  20. package/docs/sui-emoji/README.md +138 -0
  21. package/docs/sui-fancy-button/README.md +148 -0
  22. package/docs/sui-file-icon/README.md +103 -0
  23. package/docs/sui-flag/README.md +99 -0
  24. package/docs/sui-form-hint/README.md +124 -0
  25. package/docs/sui-form-label/README.md +148 -0
  26. package/docs/sui-icon/README.md +135 -0
  27. package/docs/sui-kbd/README.md +97 -0
  28. package/docs/sui-key-icon/README.md +125 -0
  29. package/docs/sui-link-button/README.md +221 -0
  30. package/docs/sui-logo/README.md +152 -0
  31. package/docs/sui-payment-icon/README.md +98 -0
  32. package/docs/sui-progress-bar/README.md +132 -0
  33. package/docs/sui-progress-bar-label/README.md +143 -0
  34. package/docs/sui-radio/README.md +134 -0
  35. package/docs/sui-radio-label/README.md +137 -0
  36. package/docs/sui-rating/README.md +198 -0
  37. package/docs/sui-segmented-control/README.md +144 -0
  38. package/docs/sui-slider/README.md +143 -0
  39. package/docs/sui-social-button/README.md +158 -0
  40. package/docs/sui-status-badge/README.md +164 -0
  41. package/docs/sui-switch/README.md +146 -0
  42. package/docs/sui-switch-label/README.md +139 -0
  43. package/docs/sui-tag/README.md +145 -0
  44. package/fesm2022/ajuarezso-sui-design-system.mjs +207 -52
  45. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/types/ajuarezso-sui-design-system.d.ts +177 -28
@@ -0,0 +1,143 @@
1
+ ---
2
+ name: sui-brand-logo
3
+ selector: sui-brand-logo
4
+ resumen: El logo oficial de otra marca (WhatsApp, Google, Apple, Instagram…) en su color, sin tocarlo
5
+ alternativas: [sui-icon (el mismo logo como ícono monocromo de una línea), sui-logo (el logo de Master Pedidos), sui-social-button (botón de entrar con Google o Apple)]
6
+ ---
7
+
8
+ # sui-brand-logo
9
+
10
+ Story: [Atoms/Brand Logo](https://sui-design-system.web.app/?path=/docs/atoms-brand-logo--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** cuando **la marca es el contenido**: «Escríbenos por WhatsApp», los logos de redes de
15
+ un negocio, una tarjeta de contacto. Va con su color oficial y no se tiñe.
16
+
17
+ **No lo uses** para:
18
+
19
+ - Un ícono más dentro de un botón o de una fila de íconos monocromos: ahí va `sui-icon`
20
+ (`whatsapp-line`, `apple-fill`), que toma el color del texto.
21
+ - El botón de entrar con Google o Apple: `sui-social-button`, que ya lo trae adentro.
22
+ - El logo de Master Pedidos: `sui-logo`.
23
+
24
+ Regla corta: **la marca es lo que se muestra → brand-logo · es un ícono más → sui-icon.**
25
+
26
+ ## Qué variante usar
27
+
28
+ > **La guía del DS no tiene página para este componente.** Todo es **propuesta, falta
29
+ > aprobación**.
30
+ >
31
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usan por dentro
32
+ > `sui-content-card` (`type="brand"`), `sui-social-button`, `sui-content-label`,
33
+ > `sui-dropdown-item` y `sui-radio-card`. Además hay 9 logos de marca hechos con `sui-icon`
34
+ > (`whatsapp-line`, `apple-fill`), que están bien donde son un ícono más.
35
+
36
+ ### `company`
37
+
38
+ | valor | cuándo | fuente |
39
+ |---|---|---|
40
+ | `whatsapp` | Soporte y contacto con el negocio. | propuesta |
41
+ | `google`, `apple` | Entrar con esa cuenta (vía `sui-social-button`). | propuesta |
42
+ | `instagram`, `facebook` | Las redes del negocio o de la app. | propuesta |
43
+ | las otras 23 (`adobe`, `notion`, `slack`, `stripe`…) | No usar hoy. | propuesta |
44
+
45
+ **No hay TikTok** en el catálogo (son 28 marcas), aunque la app hace publicidad ahí.
46
+
47
+ ### `variant`
48
+
49
+ | valor | cuándo | fuente |
50
+ |---|---|---|
51
+ | `original` (default) | El normal: sobre fondo claro, con su color oficial. | propuesta |
52
+ | `white` | Sobre fondo oscuro o sobre foto. | propuesta |
53
+ | `black` | No usar hoy. | propuesta |
54
+
55
+ ### `size`
56
+
57
+ | valor | px | cuándo | fuente |
58
+ |---|---|---|---|
59
+ | `xs` | 16 | Dentro de un texto o de un tag. | propuesta |
60
+ | `sm` | 20 | Dentro de un botón (lo usa `sui-social-button`). | propuesta |
61
+ | `md` (default) | 24 | Fila de una lista. | propuesta |
62
+ | `lg` | 32 | Tarjeta de contacto (el tamaño del Figma). | propuesta |
63
+ | `xl` | 40 | Tarjeta grande. | propuesta |
64
+ | `2xl` | 48 | Lo pide `sui-content-label` en tamaño grande. | propuesta |
65
+
66
+ ### `href`, `target`, `rel`, `disabled`, `ariaLabel`
67
+
68
+ | input | cuándo | fuente |
69
+ |---|---|---|
70
+ | `href` + `target="_blank"` | El logo lleva a la red social. `rel` ya viene en `noopener noreferrer`. | propuesta |
71
+ | `ariaLabel` | Con `href`, siempre: «Síguenos en Instagram». Sin `href`, el default («Instagram logo») alcanza. | propuesta |
72
+ | `disabled` | No usar hoy. | propuesta |
73
+
74
+ Usos de hoy que rompen la regla: **0**.
75
+
76
+ ## Tamaño en mobile y en web
77
+
78
+ En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
79
+ pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
80
+ breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
81
+ el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propuesta**.
82
+
83
+ | uso | mobile | web |
84
+ |---|---|---|
85
+ | tarjeta de contacto, fila | `lg` (32) | `md` (24) |
86
+ | como link (con `href`, se toca) | `2xl` (48) | `lg` (32) |
87
+
88
+ ```html
89
+ <sui-brand-logo company="instagram" [size]="bp.isMobile() ? '2xl' : 'lg'" [href]="url" target="_blank"
90
+ ariaLabel="Síguenos en Instagram" />
91
+ ```
92
+
93
+ Con `href` el logo **es** el área táctil: en mobile tiene que medir 44 px o más, y el único
94
+ tamaño que llega es `2xl` (48). Si se quiere un logo de 32 px tocable, el link va en un
95
+ contenedor de 44 px.
96
+
97
+ ## «No usar»: por qué no hoy y cuándo sí
98
+
99
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
100
+ |---|---|---|
101
+ | las 23 marcas ajenas | la app no se relaciona con Adobe, Notion, Slack… | una integración real (pagos con Stripe o PayPal) |
102
+ | `variant` `black` | no hay un fondo donde vaya | una fila de «nos encuentras en» o de aliados donde el color distrae |
103
+ | `disabled` | un logo apagado no explica nada | una integración que el local todavía no conectó, con el motivo al lado |
104
+
105
+ ## API
106
+
107
+ <!-- api:inicio -->
108
+ <!-- generada: no editar a mano — `npm run docs` -->
109
+
110
+ | input | tipo | default |
111
+ |---|---|---|
112
+ | `company` | `SuiBrandLogoCompany` | — (requerido) |
113
+ | `variant` | `'original' \| 'black' \| 'white'` | `'original'` |
114
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | `'md'` |
115
+ | `href` | `string \| null` | `null` |
116
+ | `target` | `string \| null` | `null` |
117
+ | `rel` | `string \| null` | `'noopener noreferrer'` |
118
+ | `disabled` | `boolean` | `false` |
119
+ | `ariaLabel` | `string \| null` | `null` |
120
+
121
+ Outputs: ninguno.
122
+ <!-- api:fin -->
123
+
124
+ ## Trampas
125
+
126
+ - **Los SVG no vienen en el paquete npm.** Se piden a `/assets/brand/brand-logos/<marca>-<variant>.svg`:
127
+ la app tiene que tener la carpeta copiada en `src/assets/brand/brand-logos/` (hoy la tiene, 84
128
+ archivos). Si falta, sale una imagen rota.
129
+ - **No se tiñe**: es un `<img>`. Si necesitas otro color, es `sui-icon`.
130
+ - **`variant` es el color**, no el tamaño ni la forma.
131
+ - Con `href` y `disabled` a la vez, no se vuelve link.
132
+ - El `aria-label` por defecto está en inglés («WhatsApp logo»): pasa `ariaLabel` en español.
133
+
134
+ ## Ejemplo
135
+
136
+ ```html
137
+ <!-- Tarjeta de soporte -->
138
+ <sui-brand-logo company="whatsapp" size="lg" />
139
+
140
+ <!-- Red del negocio, como link -->
141
+ <sui-brand-logo company="instagram" size="md" [href]="tenant.instagramUrl" target="_blank"
142
+ ariaLabel="Síguenos en Instagram" />
143
+ ```
@@ -0,0 +1,192 @@
1
+ ---
2
+ name: sui-button
3
+ selector: sui-button
4
+ resumen: Botón base para que la persona dispare una acción
5
+ alternativas: [sui-link-button (acción que se lee como texto), sui-compact-button (ícono de 20-28 px en filas y barras), sui-fancy-button (el CTA héroe), sui-social-button (entrar con Google/Apple), sui-button-group (opciones que se ven como un solo control)]
6
+ ---
7
+
8
+ # sui-button
9
+
10
+ Story: [Atoms/Button/Button](https://sui-design-system.web.app/?path=/docs/atoms-button-button--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** por defecto para cualquier acción. Se cambia a otro componente solo por una razón
15
+ concreta: se lee como texto dentro de un párrafo (`sui-link-button`), es un ícono suelto en
16
+ una fila o barra apretada (`sui-compact-button`), es login con una marca (`sui-social-button`).
17
+
18
+ **No lo uses** para:
19
+
20
+ - Navegar sin acción: un `<a>` o `sui-link-button` con `href`.
21
+ - Prender/apagar algo: `sui-switch` o `sui-button-group`.
22
+ - Mostrar carga: **no tiene `loading`**. Pon un spinner en `[data-slot=start]` y `disabled`.
23
+
24
+ ## Qué variante usar
25
+
26
+ El botón tiene dos ejes: `variant` (el peso: cuánto llama la atención) y `color` (qué hace:
27
+ `primary` naranja de marca, `neutral`, `error` destructivo). Las combinaciones se eligen juntas.
28
+
29
+ > **La guía del DS no dice cuándo usar cada variante ni cada color.** Su página del botón
30
+ > muestra las 12 combinaciones, los tamaños, el estado deshabilitado y la API; no trae
31
+ > do/don't ni jerarquía. Así que la tabla de variantes sigue siendo **propuesta, falta
32
+ > aprobación**, salvo lo que ya es canon de SUI por `sui-modal-footer`.
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: 397 botones, sin contar prototipos ni
35
+ > vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`, `dx/*`, `master-rutina`,
36
+ > `master-medico`, `dev-index`). Combinaciones: 127 `stroke neutral`, 123 `filled primary`,
37
+ > 31 `stroke error`, 26 `ghost neutral`, 21 `filled neutral`, 15 `ghost error`, 13 `lighter`,
38
+ > 7 `ghost primary`, 7 `stroke primary`, 7 `filled error`, 20 con variante o color dinámico.
39
+
40
+ ### Lo que sí dice la guía del DS
41
+
42
+ - **Defaults**: `filled` + `primary` + `medium`. Igual que SUI.
43
+ - **Tamaños**: `medium` (40), `small` (36), `xsmall` (32) y el más chico de 28 (`2xsmall` en SUI).
44
+ `large` y `xlarge` **no están en la guía**: son extensión de SUI.
45
+ - **Hermanos**: `sui-link-button` es la acción que se integra en un texto; `sui-compact-button`,
46
+ la de cuando falta espacio; `sui-button-group`, botones pegados en una sola línea;
47
+ `sui-fancy-button`, el mismo botón con un acabado más vistoso.
48
+ - **Dentro de un alert la acción es un link, no un `sui-button`** (ver `sui-alert`). Hoy hay 5
49
+ `sui-button` proyectados en alerts.
50
+
51
+ La base de la jerarquía no se inventa: la fija **`sui-modal-footer`**, que ya está en el DS y la
52
+ usa toda la app. Ahí el secundario está fijo en `stroke` + `neutral`, el primario es `filled`, y
53
+ el destructivo es el primario con `color: 'error'`. Las reglas de abajo extienden eso a
54
+ cualquier grupo de botones.
55
+
56
+ | variant + color | cuándo | ejemplo real de la app | fuente |
57
+ |---|---|---|---|
58
+ | `filled` `primary` (default) | **La** acción principal del grupo. Una sola por grupo visible: dos `filled` juntos = ninguno es principal. | `pages/orders/orders.html:236` («Aceptar pedido») · `pages/customer/cart/cart.html:204` («Continuar») | ya es canon (sui-modal-footer) |
59
+ | `stroke` `neutral` | Toda acción secundaria: Cancelar, Volver, Editar, Ver detalle. Va a la izquierda del primario. | `pages/orders/orders.html:320` («Encargarme yo») · `pages/envios/envios.html:175` («Ver seguimiento») | ya es canon (sui-modal-footer) |
60
+ | `filled` `error` | **Confirmar** algo destructivo: el último paso, dentro de la confirmación. Nunca el botón que abre la confirmación. | `pages/customer/order-history/order-history.html:132` («Sí», confirma cancelar) | canon (aprobado por el dueño, 03-10-2026) |
61
+ | `stroke` `error` | **Abrir** una acción destructiva (lleva a la confirmación) o el «Rechazar» de un par Aprobar/Rechazar. | `pages/customer/about/about.html:76` («Eliminar cuenta») · `pages/super-admin/master-approvals/master-approvals.html:99` («Rechazar») | canon (aprobado por el dueño, 03-10-2026) |
62
+ | `ghost` `neutral` / `ghost` `error` | Acción terciaria sin caja: íconos de editar/borrar en filas, «Cerrar», acciones de baja jerarquía en zonas densas. | `pages/super-admin/master-gastos/master-gastos.html:80` (editar) · `pages/customer/cart/cart.html:107` («Vaciar carrito») | canon (aprobado por el dueño, 03-10-2026) |
63
+ | `filled` `neutral` | Salir a otra app: WhatsApp, abrir el mapa. Es la práctica de hoy (21 usos, 13 de WhatsApp), no un principio: **falta criterio**. | `pages/driver/driver-order-detail/driver-order-detail.html:515` («WhatsApp») · `:567` («Abrir mapa») | canon (aprobado por el dueño, 03-10-2026) |
64
+ | `ghost` `primary` | «Ver todas», «Reporte», «Detalles» en la cabecera de una card. **A discutir**: se pisa con `sui-link-button`, que según la guía es la acción que se lee como texto. | `pages/overview/components/overview-sales/overview-sales.html:5` | a discutir |
65
+ | `stroke` `primary` | No usar. El secundario siempre es neutral. | — | canon (aprobado por el dueño, 03-10-2026) |
66
+ | `lighter` (cualquier color) | No usar en botones nuevos. En `neutral` su fondo (`bg-weak-50`) es **el mismo que el de `disabled`**: se lee como apagado. Lo existente pasa a `stroke` (secundaria) o `ghost` (terciaria). | — | canon (aprobado por el dueño, 03-10-2026) |
67
+
68
+ **Usos de hoy que romperían la propuesta** (sin prototipos):
69
+
70
+ - **13 `lighter` → `stroke` o `ghost`** (7 `neutral`, 5 `error`, 1 `primary`). Ejemplos:
71
+ `pages/mi-negocio/mi-negocio.html:133` («Cambiar plan»), `pages/customer/cart/cart.html:33`
72
+ («Quitar no disponibles»), `pages/customer/order-tracking/order-tracking.html:737` («Cancelar
73
+ pedido», `lighter error` → `stroke error`). 4 de los 13 son los que viven dentro de un alert
74
+ (`pages/overview/overview.html:41`, `pages/mi-negocio/mi-negocio.html:381`, `cart.html:33`,
75
+ `pages/role-selector/role-selector.html:59`): ahí la salida correcta es `actions[]` del alert.
76
+ - **7 `stroke primary` → `stroke neutral`.** Ejemplos: `pages/customer/checkout/checkout.html:117`
77
+ («Agregar dirección de entrega»), `pages/customer/profile/profile.html:131`,
78
+ `pages/super-admin/master-drivers/master-drivers.html:462`.
79
+ - **4 `filled error` que no confirman nada destructivo (+1 a discutir):**
80
+ `pages/empresa/about/about.html:46` y `pages/repartidor/about/about.html:46` («Eliminar mi cuenta»
81
+ abre un modal → `stroke error`, como ya lo hace `pages/customer/about/about.html:76`);
82
+ `pages/driver/driver-dashboard/driver-dashboard.html:139` («Recargar S/ X para pagar»: urgente,
83
+ no destructivo → `filled primary`); `pages/super-admin/master-settings/master-settings.html:714`
84
+ («Salir» → `stroke neutral`). A discutir: `driver-dashboard.html:144` («Acepto y pago S/ X» de una
85
+ multa) — es dinero que sale, pero no borra nada.
86
+ - **7 `ghost primary` a discutir** (si se decide que son links): `components/product-categories/product-categories.html:17`,
87
+ `pages/overview/components/overview-visitors/overview-visitors.html:5`, `pages/customer/profile/profile.html:90`.
88
+ - **2 `filled primary` en la misma vista:** `pages/products/add-product/add-product.html:276`
89
+ («Aplicar») y `:281` («Continuar»). No se recalculó: la búsqueda fue por cercanía de líneas y
90
+ puede haber más.
91
+
92
+ ### `size`
93
+
94
+ Uso de hoy: 123 `large`, 91 `small`, 60 `medium`, 50 `xsmall`, 29 `2xsmall`, 44 dinámicos.
95
+
96
+ | size | cuándo | fuente |
97
+ |---|---|---|
98
+ | `large` (48 px) | Footers de modal y CTA táctiles en mobile. | ya es canon (default de sui-modal-footer); extensión de SUI, la guía no lo tiene |
99
+ | `medium` (40 px, default) | CTA en desktop y formularios. | default según la guía del DS; el «cuándo» es propuesta |
100
+ | `small` (36) / `xsmall` (32) | Acciones dentro de cards, filas y cabeceras de sección. | escala según la guía del DS; el «cuándo» es propuesta |
101
+ | `2xsmall` (28) | Acciones de ícono en tablas y filas densas. Si el espacio es de verdad chico, mirar antes `sui-compact-button`. | escala según la guía del DS; el «cuándo» es propuesta |
102
+ | `xlarge` (52) | Extensión de SUI. Sin uso hoy. | canon (aprobado por el dueño, 03-10-2026) |
103
+
104
+ En la app el patrón responsive ya es `[size]="bp.isMobile() ? 'large' : 'medium'"` (o
105
+ `bp.controlSize()`).
106
+
107
+ ## «No usar»: por qué no hoy y cuándo sí
108
+
109
+ Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un
110
+ flujo nuevo cae en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
111
+
112
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
113
+ |---|---|---|
114
+ | `stroke` `primary` | el secundario es neutral; dos naranjas compiten por ser el principal | landings con dos CTA de marca sobre fondo oscuro |
115
+ | `lighter` (los 3 colores) | en `neutral` tiene el mismo fondo que `disabled`: parece apagado | botones dentro de un alert o banner teñido, donde `stroke` se ve pesado |
116
+ | `ghost` `primary` | lo hace mejor `sui-link-button` `primary` («Ver todas») | una acción con ícono en una barra de herramientas donde todo va sin caja |
117
+ | `sui-social-button` Facebook, X, LinkedIn, GitHub, Dropbox | no hay login con esas cuentas | «Continuar con Facebook» o botones de compartir en redes |
118
+ | `sui-social-button` `onlyIcon` | Apple exige el texto en su botón de login | una fila de «compartir en» fuera del login |
119
+ | `sui-app-store-badge` `alternative` | el `preferred` es el oficial de cada tienda | landings o piezas sobre fondo oscuro o de color |
120
+ | `sui-app-store-badge` otras tiendas | la app no está publicada ahí | Huawei AppGallery o Galaxy Store si se publica ahí |
121
+ | `sui-fancy-button` | estilo de marketing (brillo, degradé) | el CTA principal de una landing, «Mejorar plan» o una campaña |
122
+ | `sui-button-group` (0 usos) | hoy no hay opciones combinables pegadas | días del horario del local o filtros que se suman |
123
+ | `sui-topbar-button` (0 usos) | las barras de la app tienen sus íconos propios | si se unifica la barra superior del admin con la del DS |
124
+
125
+ ## API
126
+
127
+ <!-- api:inicio -->
128
+ <!-- generada: no editar a mano — `npm run docs` -->
129
+
130
+ | input | tipo | default |
131
+ |---|---|---|
132
+ | `variant` | `'filled' \| 'stroke' \| 'lighter' \| 'ghost'` | `'filled'` |
133
+ | `color` | `'primary' \| 'neutral' \| 'error'` | `'primary'` |
134
+ | `size` | `'2xsmall' \| 'xsmall' \| 'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
135
+ | `onlyIcon` | `boolean` | `false` |
136
+ | `disabled` | `boolean` | `false` |
137
+ | `leftIcon` | `string \| null` | `null` |
138
+ | `rightIcon` | `string \| null` | `null` |
139
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` |
140
+
141
+ Outputs: ninguno.
142
+ <!-- api:fin -->
143
+
144
+ El clic se escucha con `(click)` nativo sobre el host. `leftIcon` y `rightIcon` reciben el nombre
145
+ RemixIcon, sin el prefijo `ri-`.
146
+
147
+ Slots: `<ng-content>` (el texto), `[data-slot=start]`, `[data-slot=end]` (íconos que no son RemixIcon, spinner).
148
+
149
+ ```ts
150
+ // Exportado desde sui-button.ts; lo usan sui-modal-footer, sui-drawer-footer y el footer de filtros.
151
+ interface SuiFooterButtonConfig {
152
+ label: string;
153
+ disabled?: boolean;
154
+ color?: 'primary' | 'error'; // solo lo lee el botón primario
155
+ }
156
+ ```
157
+
158
+ ## Trampas
159
+
160
+ - **No es un `<button>` nativo.** El host es `<sui-button role="button">`. `type="submit"`
161
+ funciona porque intercepta el clic y llama a `form.requestSubmit()` del `<form>` más cercano;
162
+ fuera de un `<form>` no hace nada.
163
+ - **El output no existe**: aquí es `(click)`. En `sui-link-button`, `sui-compact-button`,
164
+ `sui-fancy-button` y `sui-social-button` es `(clicked)`.
165
+ - **La prop de peso se llama distinto en cada hermano:** `variant` aquí, `variantStyle` en
166
+ compact-button y social-button, `type` en fancy-button (donde el `type` HTML es `htmlType`).
167
+ - **`primary` es naranja (`#fa7319`)**, no el azul del Figma de origen.
168
+ - `onlyIcon` no define el ícono: va con `leftIcon` (o el slot `start`). Solo con `onlyIcon` el
169
+ botón sale vacío. Y **no hay input `ariaLabel`**: un botón de solo ícono queda sin nombre para
170
+ el lector de pantalla salvo que pongas `aria-label="…"` en el host a mano.
171
+ - El ícono mide 20 px en todos los tamaños.
172
+ - El radio es pill (999 px) en todos los tamaños, decisión del proyecto; el Figma de origen usa 8/10 px.
173
+ - `disabled` usa `pointer-events: none` y colores con `!important`: no se puede pintar un
174
+ disabled propio desde afuera.
175
+ - Ya trae el arreglo de iOS para el `:active` pegado (`touchstart`/`touchend`): no lo agregues.
176
+
177
+ ## Ejemplo
178
+
179
+ ```html
180
+ <!-- Par de acciones: secundario a la izquierda, primario a la derecha -->
181
+ <sui-button variant="stroke" color="neutral" (click)="cancelar()">Cancelar</sui-button>
182
+ <sui-button (click)="guardar()">Guardar</sui-button>
183
+
184
+ <!-- Abre una acción destructiva (la confirmación usa filled error) -->
185
+ <sui-button variant="stroke" color="error" leftIcon="delete-bin-line" (click)="abrirConfirmacion()">
186
+ Eliminar cuenta
187
+ </sui-button>
188
+
189
+ <!-- Solo ícono -->
190
+ <sui-button variant="ghost" color="neutral" size="2xsmall" leftIcon="pencil-line" [onlyIcon]="true"
191
+ aria-label="Editar" (click)="editar()" />
192
+ ```
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: sui-button-group
3
+ selector: sui-button-group
4
+ resumen: Opciones pegadas en una fila que se prenden y se apagan, varias a la vez
5
+ alternativas: [sui-segmented-control (cambiar de vista o elegir una sola opción), sui-checkbox (opciones que se suman dentro de un formulario largo), sui-tab-chips (filtros en chips que se pueden desplazar)]
6
+ ---
7
+
8
+ # sui-button-group
9
+
10
+ Story: [Atoms/Button/Button Group](https://sui-design-system.web.app/?path=/docs/atoms-button-button-group--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Hoy no se usa** (0 usos en la app).
15
+
16
+ **Úsalo** para elegir **varias** opciones cortas que se combinan y se ven juntas: los días de
17
+ atención de un local (L M M J V S D), filtros que se suman en una barra.
18
+
19
+ **No lo uses** para:
20
+
21
+ - **Cambiar de vista** (lista / mapa, día / semana / mes) o elegir **una sola** opción:
22
+ `sui-segmented-control`.
23
+ - **Acciones** (guardar, exportar): son `sui-button` sueltos; el grupo marca qué está prendido,
24
+ no dispara acciones.
25
+ - **Opciones largas** o que no entran en una fila del teléfono: `sui-checkbox` en lista.
26
+
27
+ ## Qué variante usar
28
+
29
+ > **La guía del DS no dice cuándo usarlo**: lo define como «botones pegados en una línea
30
+ > horizontal». **Su ejemplo es «Grid view / List view / Gallery view», o sea cambiar de vista, y
31
+ > el dueño decidió lo contrario el 03-10-2026: cambiar de vista va con `sui-segmented-control`.**
32
+ > El button-group queda para elegir varias opciones a la vez. Las reglas de abajo son **canon
33
+ > (aprobado por el dueño, 03-10-2026)** salvo donde dice otra fuente.
34
+ >
35
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0** button-groups, sin contar
36
+ > prototipos ni vitrinas.
37
+
38
+ ### Lo que sí dice la guía del DS
39
+
40
+ - **Para qué es**: un conjunto de botones pegados en una línea horizontal.
41
+ - **Tamaños**: `small` (default), `xsmall` y el más chico (`xxsmall` en la guía, `2xsmall` en SUI).
42
+ - **La selección no es del componente**: la guía la arma con un toggle group aparte. En SUI viene
43
+ incluida (`multi`, `[(value)]`, `change`) y es extensión de SUI.
44
+
45
+ ### `multi`
46
+
47
+ | multi | cuándo | ejemplo de copy | fuente |
48
+ |---|---|---|---|
49
+ | `true` | Elegir días u opciones que se combinan. | L M M J V S D (días de atención) | canon (aprobado por el dueño, 03-10-2026) |
50
+ | `false` (default) | No: elegir una sola o cambiar de vista va con `sui-segmented-control`. | — | cambiar de vista: canon (aprobado por el dueño, 03-10-2026) · elegir una sola en general: propuesta |
51
+
52
+ ### `size`
53
+
54
+ | size | alto | cuándo | fuente |
55
+ |---|---|---|---|
56
+ | `large` | 48 | Mobile: los días del horario y las opciones de un formulario, para tocar con el dedo. Label/Medium (16/24), ícono 20, radius 12. | canon (aprobado por el dueño, 03-10-2026) · extensión SUI |
57
+ | `medium` | 40 | Mobile cuando la fila es larga (los 7 días) y `large` no entra en 360 px. Label/Small (14/20), ícono 20, radius 10. | alto y tipografía: canon (aprobado por el dueño, 03-10-2026), extensión SUI · cuándo: propuesta |
58
+ | `small` (default) | 36 | Web: los días del horario, formularios. | escala según la guía del DS · cuándo: propuesta |
59
+ | `xsmall` | 32 | Barras de filtros en desktop. | escala según la guía del DS · cuándo: propuesta |
60
+ | `2xsmall` | 24 | Solo desktop, dentro de una tabla o una card densa. Muy chico para el dedo. | escala según la guía del DS · cuándo: propuesta |
61
+
62
+ ### `items` (lo que lleva cada opción)
63
+
64
+ | contenido | cuándo | fuente |
65
+ |---|---|---|
66
+ | solo `label` | Lo normal: textos de una a tres letras o una palabra («L», «Delivery»). | propuesta |
67
+ | `leftIcon` + `label` | Cuando el ícono ayuda a distinguir opciones parecidas (moto / bici / auto). | propuesta |
68
+ | solo ícono (`leftIcon`, sin `label`) | Desktop, opciones universales; **`ariaLabel` obligatorio** en cada una. | propuesta |
69
+ | `disabled: true` en una opción | La opción existe pero hoy no se puede elegir (un día que el local no atiende por regla). | propuesta |
70
+ | cuántas | De 2 a 7. Con más, no entra en el ancho del teléfono: lista de `sui-checkbox`. | propuesta (el Figma dibuja de 2 a 6; los días son 7) |
71
+
72
+ ### `value`, `ariaLabel`, `change`
73
+
74
+ | prop | cuándo | fuente |
75
+ |---|---|---|
76
+ | `[(value)]` | Con `multi`, un `string[]` con los `value` prendidos. | propuesta |
77
+ | `ariaLabel` | Siempre: dice qué se elige («Días de atención»). El host es `role="group"`. | propuesta |
78
+ | `(change)` | Cuando hay que reaccionar al cambio (guardar, filtrar); si alcanza con el `model`, no hace falta. | propuesta |
79
+
80
+ ## Tamaño en mobile y en web
81
+
82
+ En mobile se toca con el dedo: el área táctil tiene que medir **44 px o más**. En web, con mouse,
83
+ va un tamaño más chico. La app ya lo resuelve con `BreakpointsService`
84
+ (`src/app/services/breakpoints.service.ts`, mobile = hasta 767 px):
85
+ `[size]="bp.isMobile() ? 'large' : 'small'"`, 27 usos hoy en `master-pedidos` (16 `large`/`small`,
86
+ 9 `large`/`medium`, 2 `medium`/`xsmall`). Regla del dueño, 03-10-2026.
87
+
88
+ Desde el 03-10-2026 el grupo tiene `large` (48) y `medium` (40), la misma escala de `sui-button`,
89
+ así que el par es el de toda la app.
90
+
91
+ | uso | mobile | web | fuente |
92
+ |---|---|---|---|
93
+ | días del horario, opciones en un formulario | `large` (48) | `small` (36) | canon (aprobado por el dueño, 03-10-2026) |
94
+ | fila larga que no entra a 48 en 360 px (los 7 días con texto) | `medium` (40) | `small` (36) | propuesta, falta aprobación |
95
+ | barra de filtros | `large` | `xsmall` (32) | propuesta, falta aprobación |
96
+ | dentro de una tabla o una card densa | no va en mobile | `2xsmall` (24) | propuesta |
97
+
98
+ ```html
99
+ <sui-button-group [items]="dias" [multi]="true" [(value)]="diasAbiertos" ariaLabel="Días de atención"
100
+ [size]="bp.isMobile() ? 'large' : 'small'" />
101
+ ```
102
+
103
+ En mobile, cada opción tiene que ser ancha (los 7 días repartidos en todo el ancho, no apretados a
104
+ la izquierda). Si las opciones no entran ni en `medium`, va una lista de `sui-checkbox`.
105
+
106
+ ## «No usar»: por qué no hoy y cuándo sí
107
+
108
+ Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
109
+ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
110
+
111
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
112
+ |---|---|---|
113
+ | `sui-button-group` (0 usos) | hoy no hay opciones combinables pegadas | días del horario del local (L M M J V S D) o filtros que se suman |
114
+ | `multi` en `false` (una sola opción) | cambiar de vista y elegir una sola van con `sui-segmented-control` | una barra de herramientas de desktop donde el resto ya son button-groups y una opción es excluyente |
115
+
116
+ ## API
117
+
118
+ <!-- api:inicio -->
119
+ <!-- generada: no editar a mano — `npm run docs` -->
120
+
121
+ | input | tipo | default |
122
+ |---|---|---|
123
+ | `items` | `readonly SuiButtonGroupEntry[]` | — (requerido) |
124
+ | `size` | `'small' \| 'xsmall' \| '2xsmall' \| 'medium' \| 'large'` | `'small'` |
125
+ | `multi` | `boolean` | `false` |
126
+ | `value` · model, `[(value)]` | `string \| string[]` | `''` |
127
+ | `ariaLabel` | `string` | `''` |
128
+
129
+ | output | payload |
130
+ |---|---|
131
+ | `change` | `string \| string[]` |
132
+ <!-- api:fin -->
133
+
134
+ ```ts
135
+ interface SuiButtonGroupEntry {
136
+ value: string; // único: es lo que se guarda en value
137
+ label?: string;
138
+ leftIcon?: string; // RemixIcon, sin el prefijo ri-
139
+ rightIcon?: string;
140
+ disabled?: boolean;
141
+ ariaLabel?: string; // obligatorio en la práctica si no hay label
142
+ }
143
+ ```
144
+
145
+ ## Trampas
146
+
147
+ - **En una sola opción (`multi` en `false`) no se puede apagar** la que está prendida: tocarla otra
148
+ vez no hace nada. Es el comportamiento de un segmented control, otra razón para usar ese.
149
+ - **`value` cambia de tipo con `multi`**: `string` en una sola, `string[]` en varias, y el
150
+ `model` es `string | string[]`. El signal que se enlaza con `[(value)]` tiene que ser
151
+ `signal<string | string[]>` (con `signal<string[]>` no compila); al leerlo, estrecha con
152
+ `Array.isArray`. El default es `''`: con `multi`, arráncalo en `[]` o en un arreglo.
153
+ - **Dos opciones con el mismo texto** (los dos «M» de martes y miércoles) se distinguen solo por
154
+ `value`; ponles `ariaLabel` con el nombre completo.
155
+ - **El output es `(change)`**, no `(clicked)` ni `(valueChange)` a mano: `[(value)]` ya usa el
156
+ `valueChange` del `model`.
157
+ - Las opciones van por `items`, no proyectando `sui-button-group-item` adentro: el grupo es quien
158
+ pone las puntas redondeadas y junta los bordes.
159
+ - El estado prendido es sutil (fondo gris y texto más oscuro), no naranja. En un formulario,
160
+ acompáñalo con un texto que diga cuántas hay elegidas.
161
+ - Ya trae el arreglo de iOS para el `:active` pegado: no lo agregues.
162
+
163
+ ## Ejemplo
164
+
165
+ ```html
166
+ <!-- Días de atención del local -->
167
+ <sui-button-group [items]="dias" [multi]="true" [(value)]="diasAbiertos" ariaLabel="Días de atención" />
168
+ ```
169
+
170
+ ```ts
171
+ readonly dias: SuiButtonGroupEntry[] = [
172
+ { value: 'lu', label: 'L', ariaLabel: 'Lunes' }, { value: 'ma', label: 'M', ariaLabel: 'Martes' },
173
+ { value: 'mi', label: 'M', ariaLabel: 'Miércoles' }, { value: 'ju', label: 'J', ariaLabel: 'Jueves' },
174
+ { value: 'vi', label: 'V', ariaLabel: 'Viernes' }, { value: 'sa', label: 'S', ariaLabel: 'Sábado' },
175
+ { value: 'do', label: 'D', ariaLabel: 'Domingo' },
176
+ ];
177
+ readonly diasAbiertos = signal<string | string[]>(['lu', 'ma', 'mi', 'ju', 'vi']);
178
+ ```
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: sui-button-group-item
3
+ selector: sui-button-group-item
4
+ resumen: Cada opción de un sui-button-group; no se usa suelto
5
+ alternativas: [sui-button-group (el grupo, que ya pinta sus ítems desde items[]), sui-segmented-control (elegir una sola opción), sui-switch (prender o apagar algo suelto)]
6
+ ---
7
+
8
+ # sui-button-group-item
9
+
10
+ Story: [Atoms/Button/Button Group Item](https://sui-design-system.web.app/?path=/docs/atoms-button-button-group-item--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **No lo uses directo.** `sui-button-group` lo pinta solo a partir de su `items[]`: el grupo le pasa
15
+ `size`, `active` y `disabled`, y es quien le redondea las puntas y le junta los bordes. Las reglas de
16
+ uso (cuándo un button-group, qué tamaño, qué lleva cada opción) están en el README de
17
+ `sui-button-group`.
18
+
19
+ **Suelto** mantiene su propio borde y se ve como un botón de alternar aislado. Para prender o
20
+ apagar algo suelto está `sui-switch`; para una acción, `sui-button`.
21
+
22
+ ## Qué variante usar
23
+
24
+ > **La guía del DS lo trata como parte del grupo** («ButtonGroup.Item»), sin props propias más
25
+ > que la de componer. Hoy hay **0** usos directos en la app, ni del grupo.
26
+
27
+ | prop | valor | cuándo | fuente |
28
+ |---|---|---|---|
29
+ | `size` | `large` · `medium` · `small` · `xsmall` · `2xsmall` | El mismo del grupo; lo pone el grupo. Altos 48 · 40 · 36 · 32 · 24. | `small` a `2xsmall`: escala según la guía del DS · `large` y `medium`: canon (aprobado por el dueño, 03-10-2026), extensión SUI |
30
+ | `active` | `true` | La opción está elegida; lo calcula el grupo desde `value`. | propuesta |
31
+ | `disabled` | `true` | La opción existe pero hoy no se puede elegir; viene de `disabled` en la entrada de `items`. | propuesta |
32
+ | `label` | texto | Una a tres letras o una palabra. | propuesta |
33
+ | `leftIcon` / `rightIcon` | RemixIcon | Ícono a la izquierda si ayuda a distinguir; a la derecha, sin caso. Sin `label` queda cuadrado. | propuesta |
34
+ | `ariaLabel` | texto | Obligatorio si no hay `label`, o si dos opciones tienen el mismo texto. | propuesta |
35
+
36
+ ## Tamaño en mobile y en web
37
+
38
+ En mobile se toca con el dedo: el área táctil tiene que medir **44 px o más**. En web, con mouse,
39
+ va un tamaño más chico. La app ya lo resuelve con `BreakpointsService`
40
+ (`src/app/services/breakpoints.service.ts`, mobile = hasta 767 px):
41
+ `[size]="bp.isMobile() ? 'large' : 'small'"`, 27 usos hoy en `master-pedidos` (16 `large`/`small`,
42
+ 9 `large`/`medium`, 2 `medium`/`xsmall`). Regla del dueño, 03-10-2026.
43
+
44
+ El tamaño lo pone el grupo: es el mismo `size` de `sui-button-group` (ver su README).
45
+
46
+ | uso | mobile | web | fuente |
47
+ |---|---|---|---|
48
+ | dentro de un grupo | `large` (48) · `medium` (40) si la fila no entra | `small` (36) | canon (aprobado por el dueño, 03-10-2026) |
49
+ | suelto (barra de herramientas) | no va en mobile | `xsmall` o `2xsmall` | propuesta |
50
+
51
+ ## «No usar»: por qué no hoy y cuándo sí
52
+
53
+ Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
54
+ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
55
+
56
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
57
+ |---|---|---|
58
+ | `sui-button-group-item` suelto | el grupo ya lo pinta desde `items[]`, y suelto se lee como un switch mal dibujado | un botón de alternar en una barra de herramientas de desktop (negrita en un editor de texto) |
59
+ | `rightIcon` | en un grupo de opciones cortas, un ícono a la derecha no agrega nada | una opción que abre un menú (con `arrow-down-s-line`) |
60
+
61
+ ## API
62
+
63
+ <!-- api:inicio -->
64
+ <!-- generada: no editar a mano — `npm run docs` -->
65
+
66
+ | input | tipo | default |
67
+ |---|---|---|
68
+ | `label` | `string` | `''` |
69
+ | `leftIcon` | `string` | `''` |
70
+ | `rightIcon` | `string` | `''` |
71
+ | `size` | `'small' \| 'xsmall' \| '2xsmall' \| 'medium' \| 'large'` | `'small'` |
72
+ | `active` | `boolean` | `false` |
73
+ | `disabled` | `boolean` | `false` |
74
+ | `ariaLabel` | `string` | `''` |
75
+
76
+ | output | payload |
77
+ |---|---|
78
+ | `clicked` | `void` |
79
+ <!-- api:fin -->
80
+
81
+ ## Trampas
82
+
83
+ - **El output es `(clicked)` y no lleva payload** (`void`), a diferencia de los otros botones, que
84
+ mandan el `MouseEvent`.
85
+ - **`active` no se prende solo al tocarlo**: el ítem solo avisa; quien lo usa (normalmente el grupo)
86
+ tiene que cambiar `active`.
87
+ - Los íconos miden 20 en `small` y `xsmall`, y 16 en `2xsmall`.
88
+ - Suelto no recibe las puntas redondeadas del grupo: esas reglas dependen de los atributos
89
+ `data-sui-first` y `data-sui-last` que pone `sui-button-group`.
90
+ - Es un `<button type="button">` con `aria-pressed`: el lector de pantalla lo anuncia como botón de
91
+ alternar.
92
+
93
+ ## Ejemplo
94
+
95
+ ```html
96
+ <!-- Lo normal: no se escribe a mano, lo arma el grupo -->
97
+ <sui-button-group [items]="dias" [multi]="true" [(value)]="diasAbiertos" ariaLabel="Días de atención" />
98
+
99
+ <!-- Suelto, solo en el caso de «cuándo sí» -->
100
+ <sui-button-group-item leftIcon="bold" ariaLabel="Negrita" size="xsmall"
101
+ [active]="negrita()" (clicked)="negrita.set(!negrita())" />
102
+ ```