@ajuarezso/sui-design-system 0.20.0 → 0.22.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 (85) hide show
  1. package/docs/INDEX.md +75 -80
  2. package/docs/sui-accordion/README.md +171 -0
  3. package/docs/sui-activity-feed/README.md +155 -0
  4. package/docs/sui-activity-filter/README.md +100 -0
  5. package/docs/sui-alert/README.md +13 -0
  6. package/docs/sui-badge/README.md +17 -0
  7. package/docs/sui-banner/README.md +190 -0
  8. package/docs/sui-breadcrumb-item/README.md +96 -0
  9. package/docs/sui-breadcrumbs/README.md +122 -0
  10. package/docs/sui-button/README.md +36 -0
  11. package/docs/sui-card/README.md +168 -0
  12. package/docs/sui-chart-legend/README.md +140 -0
  13. package/docs/sui-chart-legend-dot/README.md +118 -0
  14. package/docs/sui-checkbox-card/README.md +150 -0
  15. package/docs/sui-command-menu-footer/README.md +100 -0
  16. package/docs/sui-command-menu-item/README.md +140 -0
  17. package/docs/sui-command-menu-search/README.md +105 -0
  18. package/docs/sui-compact-select/README.md +130 -0
  19. package/docs/sui-compact-select-for-input/README.md +120 -0
  20. package/docs/sui-content-card/README.md +147 -0
  21. package/docs/sui-content-label/README.md +148 -0
  22. package/docs/sui-counter-input/README.md +148 -0
  23. package/docs/sui-date-selector/README.md +98 -0
  24. package/docs/sui-datepicker/README.md +197 -0
  25. package/docs/sui-day-cell/README.md +118 -0
  26. package/docs/sui-day-label/README.md +81 -0
  27. package/docs/sui-drawer-footer/README.md +127 -0
  28. package/docs/sui-drawer-header/README.md +140 -0
  29. package/docs/sui-dropdown-caption/README.md +92 -0
  30. package/docs/sui-dropdown-item/README.md +163 -0
  31. package/docs/sui-dropdown-menu/README.md +196 -0
  32. package/docs/sui-dropdown-search/README.md +113 -0
  33. package/docs/sui-empty-state/README.md +145 -0
  34. package/docs/sui-file-upload/README.md +154 -0
  35. package/docs/sui-file-upload-card/README.md +129 -0
  36. package/docs/sui-filter/README.md +181 -0
  37. package/docs/sui-href/README.md +85 -0
  38. package/docs/sui-image-upload/README.md +200 -0
  39. package/docs/sui-image-upload-profile/README.md +145 -0
  40. package/docs/sui-img-retry/README.md +107 -0
  41. package/docs/sui-inline-input/README.md +104 -0
  42. package/docs/sui-inline-select/README.md +101 -0
  43. package/docs/sui-input/README.md +247 -0
  44. package/docs/sui-integration-switch/README.md +142 -0
  45. package/docs/sui-modal/README.md +238 -0
  46. package/docs/sui-modal-footer/README.md +178 -0
  47. package/docs/sui-modal-header/README.md +115 -0
  48. package/docs/sui-modal-sheet/README.md +170 -0
  49. package/docs/sui-notification/README.md +179 -0
  50. package/docs/sui-notification-footer/README.md +98 -0
  51. package/docs/sui-notification-tab-menu/README.md +112 -0
  52. package/docs/sui-otp-input/README.md +116 -0
  53. package/docs/sui-page-header/README.md +123 -0
  54. package/docs/sui-pagination/README.md +146 -0
  55. package/docs/sui-password-strength/README.md +99 -0
  56. package/docs/sui-period-range/README.md +93 -0
  57. package/docs/sui-popover/README.md +178 -0
  58. package/docs/sui-product-card/README.md +173 -0
  59. package/docs/sui-radio-card/README.md +160 -0
  60. package/docs/sui-rating/README.md +7 -6
  61. package/docs/sui-rich-editor/README.md +114 -0
  62. package/docs/sui-segmented-control/README.md +3 -0
  63. package/docs/sui-select/README.md +183 -0
  64. package/docs/sui-sidebar/README.md +217 -0
  65. package/docs/sui-stepper/README.md +166 -0
  66. package/docs/sui-store-card/README.md +147 -0
  67. package/docs/sui-switch-card/README.md +149 -0
  68. package/docs/sui-switch-label/README.md +3 -0
  69. package/docs/sui-tab-chips/README.md +188 -0
  70. package/docs/sui-tab-menu-horizontal/README.md +142 -0
  71. package/docs/sui-tab-menu-vertical/README.md +136 -0
  72. package/docs/sui-table/README.md +264 -0
  73. package/docs/sui-tag-input/README.md +123 -0
  74. package/docs/sui-textarea/README.md +160 -0
  75. package/docs/sui-time-picker/README.md +240 -0
  76. package/docs/sui-toast/README.md +190 -0
  77. package/docs/sui-tooltip/README.md +201 -0
  78. package/docs/sui-topbar/README.md +153 -0
  79. package/docs/sui-topbar-button/README.md +95 -0
  80. package/docs/sui-topbar-item/README.md +97 -0
  81. package/docs/sui-topbar-user/README.md +83 -0
  82. package/fesm2022/ajuarezso-sui-design-system.mjs +291 -246
  83. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  84. package/package.json +1 -1
  85. package/types/ajuarezso-sui-design-system.d.ts +208 -50
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: sui-content-card
3
+ selector: sui-content-card
4
+ resumen: Fila «cara + nombre + detalle» dentro de su propia cajita, con badge y una X opcional para quitarla
5
+ alternativas: [sui-content-label (la misma fila sin caja, dentro de una card que ya existe), sui-card (contenido libre), sui-radio-card / sui-checkbox-card (la fila se elige)]
6
+ ---
7
+
8
+ # sui-content-card
9
+
10
+ Story: [Molecules/Card/Content Card](https://sui-design-system.web.app/?path=/docs/molecules-card-content-card--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para una fila suelta que representa a alguien o algo, con su propia caja: el top de
15
+ locales, clientes y repartidores del resumen del super admin, una persona del equipo que se puede
16
+ quitar, un método de pago guardado.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Filas dentro de una card que ya pone el borde: `sui-content-label` (si no, queda caja dentro de
21
+ caja).
22
+ - Una fila que se elige: `sui-radio-card` o `sui-checkbox-card`.
23
+ - Una fila que se toca para abrir un detalle: hoy no tiene `interactive`; usa `sui-card
24
+ [interactive]` con un `sui-content-label` adentro.
25
+
26
+ Regla corta: **fila suelta con caja → content-card · filas dentro de una card → content-label ·
27
+ se elige → card de selección.**
28
+
29
+ ## Qué variante usar
30
+
31
+ > **La guía del DS no tiene página de la content card.** Es un `sui-content-label size="medium"`
32
+ > envuelto en una card con la X. Lo que sigue es práctica de la app («propuesta») salvo lo
33
+ > aprobado («canon»).
34
+ >
35
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **4
36
+ > content-cards, todas en `pages/super-admin/master-overview/master-overview.html`**. Tipos:
37
+ > `avatar` (o `left-icon` cuando el local no tiene logo). Las 4 con `[dismissible]="false"`; 1 con
38
+ > `badge` (la nota del local).
39
+
40
+ ### `type` (el leading)
41
+
42
+ | type | cuándo | fuente |
43
+ |---|---|---|
44
+ | `avatar` (`avatar`) | Una persona o un local con foto. El color de las iniciales va por rol: local `orange`, repartidor `green`, cliente `blue`. | canon (avatar por rol); el uso es propuesta |
45
+ | `left-icon` (`icon`) | La misma fila cuando no hay foto: `store-2-line` para el local sin logo. | propuesta (precedente `master-overview.html:224`) |
46
+ | `basic` | Ver «No usar». | propuesta |
47
+ | `company` (`avatar` + `companyLogoSrc`) | Ver «No usar». | propuesta |
48
+ | `brand` (`brand`) | Ver «No usar». | propuesta |
49
+ | `card-provider` (`brand`) | Ver «No usar». | propuesta |
50
+
51
+ ### Las piezas
52
+
53
+ | prop | cuándo | fuente |
54
+ |---|---|---|
55
+ | `title` | Siempre. El nombre, nunca un id (regla de la pasada de UX). | canon (CLAUDE.md, «un identificador nunca es el título») |
56
+ | `subtitle` | El dato que se compara entre filas: «214 pedidos este mes», «38 calificaciones». | propuesta |
57
+ | `badge` | Un dato chico que se compara de un vistazo (la nota). El color sigue el significado del badge: `red` si está mal. | propuesta (badge: canon de colores) |
58
+ | `dismissible` | La X solo cuando quitar la fila ES la acción (sacar a alguien del equipo, borrar una tarjeta). **El default es `true`**: pasa `false` siempre que no. | propuesta |
59
+ | `dismissAriaLabel` | Siempre que haya X: «Quitar a Rosa del equipo», no el default «Descartar». | propuesta |
60
+ | `sublabel` | Ver «No usar». | propuesta |
61
+ | `disabled` | Ver «No usar». | propuesta |
62
+
63
+ **Usos de hoy que rompen las reglas:** 0. Las 4 apagan la X a mano: el default de `dismissible`
64
+ no le sirve a ningún uso de hoy.
65
+
66
+ ## Tamaño en mobile y en web
67
+
68
+ La fila mide 72 (leading de 40 + padding 16) en las dos. El `size` cambia **solo la X de quitar**:
69
+
70
+ | size | X visible | área táctil | glyph | fuente |
71
+ |---|---|---|---|---|
72
+ | `medium` (default) | 20 × 20 | 20 × 20 | 20 | Figma |
73
+ | `large` | 32 × 32 (radius 8 al hover) | 40 × 40 (`::before` invisible) | 20 | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
74
+
75
+ En `large` el glyph queda en el mismo lugar que en `medium` (la caja grande se come el aire del
76
+ gap con margen negativo), así que la fila se ve igual: lo que crece es dónde se puede tocar.
77
+
78
+ | uso | mobile | web | fuente |
79
+ |---|---|---|---|
80
+ | fila | 72, sin cambio | 72, sin cambio | Figma |
81
+ | X para quitar | `large` (32, área 40) | `medium` (20) | propuesta: el tamaño es extensión SUI aprobada (03-10-2026); el «cuándo» falta aprobarlo |
82
+
83
+ ```html
84
+ <sui-content-card … [size]="bp.isMobile() ? 'large' : 'medium'" (dismiss)="quitar(item)" />
85
+ ```
86
+
87
+ ## «No usar»: por qué no hoy y cuándo sí
88
+
89
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
90
+ |---|---|---|
91
+ | `type="basic"` (0 usos) | las 4 filas tienen cara | un dato sin cara: una dirección guardada |
92
+ | `type="company"` (0 usos) | no se listan empleados | un empleado con el logo de su local en la esquina |
93
+ | `type="brand"` (0 usos) | no hay servicios conectados | WhatsApp o Mapbox conectado, con su logo |
94
+ | `type="card-provider"` (0 usos) | no hay pago con tarjeta guardada | una tarjeta guardada, cuando entre Culqi / Niubiz |
95
+ | `sublabel` (0 usos) | ninguna fila lo pide | «(tú)» en la lista del equipo |
96
+ | `disabled` (0 usos) | ninguna fila está apagada | un repartidor suspendido en la lista de su local |
97
+ | `dismissible` en mobile con `size="medium"` | la X mide 20 | nunca: en mobile va `size="large"` |
98
+
99
+ ## API
100
+
101
+ <!-- api:inicio -->
102
+ <!-- generada: no editar a mano — `npm run docs` -->
103
+
104
+ | input | tipo | default |
105
+ |---|---|---|
106
+ | `type` | `'basic' \| 'left-icon' \| 'avatar' \| 'card-provider' \| 'brand' \| 'company'` | `'basic'` |
107
+ | `title` | `string` | `''` |
108
+ | `sublabel` | `string` | `''` |
109
+ | `subtitle` | `string` | `''` |
110
+ | `badge` | `SuiBadgeConfig \| string \| null` | `null` |
111
+ | `icon` | `string \| null` | `null` |
112
+ | `avatar` | `SuiAvatarConfig \| string \| null` | `null` |
113
+ | `companyLogoSrc` | `string \| null` | `null` |
114
+ | `brand` | `SuiBrandLogoCompany \| null` | `null` |
115
+ | `dismissible` | `boolean` | `true` |
116
+ | `dismissAriaLabel` | `string` | `'Descartar'` |
117
+ | `size` | `'medium' \| 'large'` | `'medium'` |
118
+ | `disabled` | `boolean` | `false` |
119
+
120
+ | output | payload |
121
+ |---|---|
122
+ | `dismiss` | `MouseEvent` |
123
+ <!-- api:fin -->
124
+
125
+ ## Trampas
126
+
127
+ - **`dismissible` arranca en `true`**: sin `[dismissible]="false"` aparece una X que no hace nada.
128
+ - **Aquí se llama `title` / `subtitle`**; en `sui-content-label` la misma fila es `label` /
129
+ `description`.
130
+ - **`badge` con string sale naranja `lighter` `small`** (en MAYÚSCULAS); en el content-label el
131
+ mismo string sale `medium`.
132
+ - `card-provider` toma el logo de `brand` y lo pone en una cajita de 32 × 24 (no hay assets de
133
+ tarjetas en el DS).
134
+ - No tiene `interactive` ni output de toque: la fila no se puede tocar entera.
135
+ - El host borra el atributo `title` del DOM y lleva `role="group"` con `aria-label` = `title`.
136
+
137
+ ## Ejemplo
138
+
139
+ ```html
140
+ <sui-content-card
141
+ type="avatar"
142
+ [avatar]="{ src: local.logo, initials: 'SA', color: 'orange' }"
143
+ [title]="local.nombre"
144
+ [subtitle]="local.pedidos + ' pedidos este mes'"
145
+ [badge]="{ label: '4.6 ★', color: 'orange', variant: 'lighter', size: 'small' }"
146
+ [dismissible]="false" />
147
+ ```
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: sui-content-label
3
+ selector: sui-content-label
4
+ resumen: Fila sin caja con ícono, foto o logo a la izquierda, título, descripción y un badge opcional
5
+ alternativas: [sui-content-card (la misma fila dentro de su propia cajita, con X), sui-switch-label (un ajuste que se prende o apaga), sui-alert (un aviso con color), sui-card (para agrupar las filas)]
6
+ ---
7
+
8
+ # sui-content-label
9
+
10
+ Story: [Molecules/Card/Content Label](https://sui-design-system.web.app/?path=/docs/molecules-card-content-label--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para una fila de lectura dentro de una superficie que ya pone el borde (una card, un
15
+ sheet): los consejos del perfil del repartidor y de mi-negocio, el resumen «dato → estado» al
16
+ terminar un registro, un negocio en una lista, «Contactar soporte».
17
+
18
+ **No lo uses** para:
19
+
20
+ - Una fila que necesita su propia caja o una X para quitarla: `sui-content-card`.
21
+ - Un ajuste que se prende o se apaga: `sui-switch-label` con `flip` (no el `toggle` de este).
22
+ - Un aviso que tiene que llamar la atención: `sui-alert`.
23
+ - Una opción que se elige: las cards de selección.
24
+
25
+ Regla corta: **fila de lectura dentro de una card → content-label · fila suelta con caja →
26
+ content-card · ajuste → switch-label.**
27
+
28
+ ## Qué variante usar
29
+
30
+ > **La guía del DS no tiene página del content label.** Lo que sigue es práctica de la app
31
+ > («propuesta») salvo lo que ya está aprobado («canon»).
32
+ >
33
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **18
34
+ > content-labels en 4 archivos**. Tipos: 14 `left-icon`, 3 `basic`, 1 `avatar`. Tamaños: 13
35
+ > `large` (los consejos), 1 `medium` explícito, 4 sin `size`. 4 con `badge` (3 a la derecha, 1 en
36
+ > el título). 0 con `toggle`, `sublabel` o `disabled`.
37
+
38
+ ### `type` (el leading)
39
+
40
+ | type | cuándo | fuente |
41
+ |---|---|---|
42
+ | `left-icon` (`icon`) | El ícono dice de qué va la fila: los consejos («Revisa tu zona de cobertura»), «Contactar soporte». Sale en un círculo con borde (`sui-key-icon` stroke). | propuesta (14 de 18) |
43
+ | `basic` | Fila de dato sin cara, casi siempre con badge: «Datos personales → Completados». | propuesta |
44
+ | `avatar` (`avatar`) | Una persona o un local. El color de las iniciales va por rol: local `orange`, repartidor `green`, cliente `blue`. | canon (avatar por rol) |
45
+ | `company` (`avatar` + `companyLogoSrc`) | Ver «No usar». | propuesta |
46
+ | `brand` (`brand`) | Ver «No usar». | propuesta |
47
+
48
+ ### `size`
49
+
50
+ | size | cuándo | fuente |
51
+ |---|---|---|
52
+ | `large` (leading 48, título 16) | Consejos y pasos que se leen, con descripción larga (los 13 de hoy). | propuesta |
53
+ | `medium` (leading 40, título 14, default) | Filas de dato en una lista: el negocio del repartidor, el resumen del registro. | propuesta |
54
+
55
+ ### Las piezas
56
+
57
+ | prop | cuándo | fuente |
58
+ |---|---|---|
59
+ | `label` | Siempre. En los consejos, una instrucción («Ponle foto a tus productos»); en los datos, el nombre del dato. | propuesta |
60
+ | `description` | La explicación o el detalle. En los consejos, el porqué. | propuesta |
61
+ | `badge` trailing (default) | El estado del dato a la derecha. Pasa el objeto con el color del badge: con string sale naranja. | propuesta |
62
+ | `badgePlacement="title"` | El badge pegado al nombre, cuando la derecha queda libre o es angosta («Sabores Andinos · Propio»). | propuesta |
63
+ | `sublabel` | Ver «No usar». | propuesta |
64
+ | `toggle` / `toggleChecked` | Ver «No usar». | propuesta |
65
+ | `disabled` | Ver «No usar». | propuesta |
66
+
67
+ **Usos de hoy que rompen las reglas:** 0. A mirar: los 3 badges de
68
+ `pages/driver-onboarding/step-complete/step-complete.html:48`–`:58` dicen estados de ciclo
69
+ («Completados», «Esperando vinculación»); el README de `sui-badge` deja esos en
70
+ `sui-status-badge`, pero el content-label solo recibe la config del badge.
71
+
72
+ ## Tamaño en mobile y en web
73
+
74
+ No se toca, así que no tiene que llegar a 44. El `size` es de lectura, no de dedo.
75
+
76
+ | uso | mobile | web |
77
+ |---|---|---|
78
+ | consejos y pasos | `large` | `large` |
79
+ | filas de dato | `medium` | `medium` |
80
+ | fila que se toca (soporte) | `large`, o dale a la fila un alto mínimo de 44 | `medium` |
81
+
82
+ ```html
83
+ <sui-content-label [size]="bp.isMobile() ? 'large' : 'medium'" … /> <!-- solo si la fila se toca -->
84
+ ```
85
+
86
+ ## «No usar»: por qué no hoy y cuándo sí
87
+
88
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
89
+ |---|---|---|
90
+ | `toggle` (0 usos) | el switch es `medium` fijo (32 × 20) y la fila no se toca entera | nunca para un ajuste (es `sui-switch-label` con `flip`); un resumen de solo lectura en web |
91
+ | `sublabel` (0 usos) | ninguna fila lo pide | una precisión corta junto al nombre: «(opcional)», «(9 a. m. a 9 p. m.)» |
92
+ | `disabled` (0 usos) | ninguna fila está apagada | un paso del onboarding que todavía no aplica |
93
+ | `type="company"` (0 usos) | no se muestran empleados con su local | la fila de un empleado con el logo de su local |
94
+ | `type="brand"` (0 usos) | no hay servicios externos | un canal de contacto externo con su logo (WhatsApp) |
95
+
96
+ ## API
97
+
98
+ <!-- api:inicio -->
99
+ <!-- generada: no editar a mano — `npm run docs` -->
100
+
101
+ | input | tipo | default |
102
+ |---|---|---|
103
+ | `type` | `'basic' \| 'left-icon' \| 'avatar' \| 'brand' \| 'company'` | `'basic'` |
104
+ | `size` | `'medium' \| 'large'` | `'medium'` |
105
+ | `label` | `string` | `''` |
106
+ | `sublabel` | `string` | `''` |
107
+ | `description` | `string` | `''` |
108
+ | `icon` | `string \| null` | `null` |
109
+ | `avatar` | `SuiAvatarConfig \| string \| null` | `null` |
110
+ | `companyLogoSrc` | `string \| null` | `null` |
111
+ | `brand` | `SuiBrandLogoCompany \| null` | `null` |
112
+ | `badge` | `SuiBadgeConfig \| string \| null` | `null` |
113
+ | `badgePlacement` | `'trailing' \| 'title'` | `'trailing'` |
114
+ | `toggle` | `boolean` | `false` |
115
+ | `toggleChecked` | `boolean` | `false` |
116
+ | `disabled` | `boolean` | `false` |
117
+
118
+ | output | payload |
119
+ |---|---|
120
+ | `toggleCheckedChange` | `boolean` |
121
+ <!-- api:fin -->
122
+
123
+ ## Trampas
124
+
125
+ - **Aquí se llama `label` / `description`**; en `sui-content-card` la misma fila se llama
126
+ `title` / `subtitle`.
127
+ - **`badge` con string sale naranja `lighter` `medium`** (sin mayúsculas). En la content-card el
128
+ mismo string sale `small` (en MAYÚSCULAS).
129
+ - `avatar` acepta string (es el `src`) o `{ src, initials, color }`; sin `color` las iniciales
130
+ salen `slate`, no el color del rol.
131
+ - `left-icon` sin `icon` no dibuja nada a la izquierda.
132
+ - El `toggle` es un `sui-switch` `medium` fijo y solo el interruptor se toca, no la fila.
133
+ - El host lleva `role="group"` y `aria-label` = `label`.
134
+
135
+ ## Ejemplo
136
+
137
+ ```html
138
+ <!-- Consejo -->
139
+ <sui-content-label
140
+ type="left-icon"
141
+ size="large"
142
+ icon="camera-line"
143
+ label="Ponle foto a tus productos"
144
+ description="Desde dos productos con foto tu negocio sube en la lista. Las cargas en Productos." />
145
+
146
+ <!-- Dato con estado -->
147
+ <sui-content-label label="Datos personales" [badge]="{ label: 'Completados', color: 'green', variant: 'lighter' }" />
148
+ ```
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: sui-counter-input
3
+ selector: sui-counter-input
4
+ resumen: Cantidad con − y + a los lados, con mínimo y máximo (unidades en el carrito, pasajeros)
5
+ alternativas: [sui-input type="number" (un número que se tipea, sin pasos de a uno), sui-slider (un valor de un rango continuo), sui-select (elegir una cantidad de una lista corta)]
6
+ ---
7
+
8
+ # sui-counter-input
9
+
10
+ Story: [Molecules/Input/Counter Input](https://sui-design-system.web.app/?path=/docs/molecules-input-counter-input--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para una cantidad chica que se ajusta de a uno y tiene tope: unidades de un producto
15
+ (carrito, detalle del producto), pasajeros de un viaje. Los botones se apagan solos al llegar al
16
+ mínimo o al máximo.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Un número que se tipea entero (minutos, kilómetros, un monto): `sui-input` (`number` o `amount`).
21
+ - Una cantidad que arranca en cero y aparece al tocar «+» (los extras de un producto): hoy es un
22
+ armado propio con dos `sui-compact-button` en `components/product-detail-view/product-detail-view.html:169`,
23
+ y está bien así; el contador del DS siempre muestra los dos botones y el número.
24
+ - Quitar el producto: el contador baja hasta `min` y para. Borrar es otro botón (el tacho).
25
+
26
+ Regla corta: **se ajusta de a uno y tiene tope → counter · se tipea → input.**
27
+
28
+ ## Qué variante usar
29
+
30
+ > **La guía del DS lo muestra como un ejemplo de su página del input** (un campo «Counter Input*»
31
+ > con − y + a los lados) y no dice cuándo usarlo. Todo lo de abajo es **propuesta, falta
32
+ > aprobación**, salvo lo que se indica.
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`, más
35
+ > `master-ejercicios`): **4 usos en 4 archivos**, todos con `min=1`. Tamaños: 2 `large`, 2 `medium`.
36
+ > 1 con `label`, 2 con `ariaLabel`, 2 sin ninguno de los dos.
37
+
38
+ | prop | cuándo | fuente |
39
+ |---|---|---|
40
+ | `min` | `1` en cantidades de compra: en 1 el − se apaga y quitar queda en el tacho (evita borrar por error). | propuesta (ya es práctica en los 4 usos: `pages/customer/cart/cart.html:82`) |
41
+ | `max` | Siempre el tope real: stock, tope por pedido, cupo del viaje. Sin dato, 99. | propuesta (ya es práctica: `pages/customer/restaurant-menu/restaurant-menu.html:480`) |
42
+ | `step` | `1`. Otro paso no tiene caso hoy. | propuesta, falta aprobación |
43
+ | `label` | Cuando es un campo de un formulario («Pasajeros»). | según la guía del DS (su ejemplo lleva label) |
44
+ | `hint` | El tope dicho en palabras: «Hasta 4 pasajeros». | propuesta (ya es práctica: `components/cambiar-pasajeros/cambiar-pasajeros.html:7`) |
45
+ | `ariaLabel` | **Obligatorio si no hay `label`**: en el carrito o en una fila donde el texto está al lado. «Cantidad de Pollo a la brasa 1/4». | propuesta, falta aprobación |
46
+ | `decrementLabel` / `incrementLabel` | Los defaults («Disminuir», «Aumentar») sirven. Cambiarlos solo si el contexto pide otro verbo («Quitar un pasajero»). | propuesta, falta aprobación |
47
+ | `disabled` | El producto se agotó mientras estaba en el carrito. | propuesta, falta aprobación |
48
+ | `error` + `errorMessage` | No usar hoy: el contador no deja salir del rango. | — |
49
+ | `required` · `sublabel` · `tooltip` | No usar hoy: una cantidad siempre tiene valor. | — |
50
+
51
+ **Usos de hoy que rompen la regla:**
52
+
53
+ - **2 sin `label` ni `ariaLabel`** (el lector de pantalla dice solo «grupo»):
54
+ `pages/customer/cart/cart.html:82`, `pages/customer/restaurant-menu/restaurant-menu.html:480`.
55
+ - **2 en `medium` en pantallas del teléfono** → `large`: `pages/customer/cart/cart.html:82`,
56
+ `pages/customer/viaje/viaje.html:190`.
57
+
58
+ ## Tamaño en mobile y en web
59
+
60
+ El campo llega a la escala completa del botón (2xsmall 28 · xsmall 32 · small 36 · medium 40 ·
61
+ large 48 · xlarge 52; la guía solo tiene 40, 36 y 32). **Los botones − y + crecen con el campo en
62
+ los tamaños de mobile**: 24 × 24 de `2xsmall` a `medium` (como la guía, el default no cambia), **40
63
+ × 40 en `large`** y **44 × 44 en `xlarge`**, ocupando todo el alto útil del campo (3 px de aire
64
+ dentro de la píldora). El ícono es de 20 hasta `large` y de 24 en `xlarge`.
65
+
66
+ | size | campo | botón − / + | fuente |
67
+ |---|---|---|---|
68
+ | `xlarge` | 52 | 44 | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
69
+ | `large` | 48 | 40 | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
70
+ | `medium` (default) · `small` · `xsmall` | 40 · 36 · 32 | 24 | según la guía del DS |
71
+ | `2xsmall` | 28 | 24 | extensión SUI |
72
+
73
+ En large y xlarge el texto sube a 16 px (regla del 03-10-2026): el número va en 16/24; el alto del
74
+ campo no cambia (lo ponen los botones).
75
+
76
+ | uso | mobile | web | fuente |
77
+ |---|---|---|---|
78
+ | cantidad junto al CTA (detalle del producto) | `large` (48), igual que el botón | `large` | propuesta (ya es práctica en `restaurant-menu.html:480`) |
79
+ | cantidad en una fila (carrito, pasajeros) | `large` (48) | `medium` (40) | propuesta, falta aprobación |
80
+
81
+ ```html
82
+ <sui-counter-input [size]="bp.isMobile() ? 'large' : 'medium'" … /> <!-- bp = BreakpointsService -->
83
+ ```
84
+
85
+ ## «No usar»: por qué no hoy y cuándo sí
86
+
87
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
88
+ |---|---|---|
89
+ | `size` `2xsmall`, `xsmall`, `small` | en la app la cantidad se toca con el dedo | una tabla del panel donde se ajusta el stock de varios productos |
90
+ | `size="xlarge"` | el CTA de al lado es `large` | si el CTA del detalle pasa a `xlarge` |
91
+ | `step` distinto de 1 | no hay productos que se vendan de a varios | huevos por media docena, gaseosas por pack de 6 |
92
+ | `error` | el contador no deja salir del rango | el stock bajó con el carrito abierto y la cantidad ya no alcanza |
93
+ | `tooltip` · `sublabel` · `required` | una cantidad siempre tiene valor | — |
94
+
95
+ ## API
96
+
97
+ <!-- api:inicio -->
98
+ <!-- generada: no editar a mano — `npm run docs` -->
99
+
100
+ | input | tipo | default |
101
+ |---|---|---|
102
+ | `size` | `'2xsmall' \| 'xsmall' \| 'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
103
+ | `label` | `string \| null` | `null` |
104
+ | `sublabel` | `string \| null` | `null` |
105
+ | `required` | `boolean` | `false` |
106
+ | `tooltip` | `string \| null` | `null` |
107
+ | `hint` | `string \| null` | `null` |
108
+ | `error` | `boolean` | `false` |
109
+ | `errorMessage` | `string \| null` | `null` |
110
+ | `value` | `number` | `0` |
111
+ | `min` | `number` | `Number.NEGATIVE_INFINITY` |
112
+ | `max` | `number` | `Number.POSITIVE_INFINITY` |
113
+ | `step` | `number` | `1` |
114
+ | `disabled` | `boolean` | `false` |
115
+ | `ariaLabel` | `string \| null` | `null` |
116
+ | `decrementLabel` | `string` | `'Disminuir'` |
117
+ | `incrementLabel` | `string` | `'Aumentar'` |
118
+
119
+ | output | payload |
120
+ |---|---|
121
+ | `valueChange` | `number` |
122
+ <!-- api:fin -->
123
+
124
+ `value` es un `input` y `valueChange` un `output`: `[(value)]` funciona. Implementa
125
+ `ControlValueAccessor`.
126
+
127
+ ## Trampas
128
+
129
+ - **Es controlado**: al tocar − o + no cambia su número; emite `valueChange` con el valor nuevo
130
+ (ya recortado a `min`/`max`) y el padre lo aplica. Con solo `[value]` y sin `(valueChange)` el
131
+ número no se mueve.
132
+ - `min` y `max` arrancan en −∞ y +∞: sin pasarlos, el contador baja a negativos.
133
+ - Los botones de 24 px de `medium` para abajo no llegan a los 40 de un dedo: en mobile, `large`
134
+ o `xlarge` (ver «Tamaño en mobile y en web»).
135
+ - Sin `label` ni `ariaLabel` el grupo no tiene nombre para el lector de pantalla.
136
+ - El campo es una píldora (radio completo), decisión de SUI; el Figma de origen usa 10/8 px.
137
+
138
+ ## Ejemplo
139
+
140
+ ```html
141
+ <!-- En el detalle del producto, al lado del CTA -->
142
+ <sui-counter-input size="large" [min]="1" [max]="pdv.topeCantidad()"
143
+ ariaLabel="Cantidad" [value]="pdv.qty()" (valueChange)="pdv.setQty($event)" />
144
+
145
+ <!-- Campo de formulario -->
146
+ <sui-counter-input label="Pasajeros" hint="Hasta 4 pasajeros" [min]="1" [max]="4"
147
+ [size]="bp.isMobile() ? 'large' : 'medium'" [(value)]="pasajeros" />
148
+ ```
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: sui-date-selector
3
+ selector: sui-date-selector
4
+ resumen: La cabecera de un calendario con el mes y las flechas de anterior y siguiente
5
+ alternativas: [sui-datepicker (el calendario completo, que ya la trae), sui-tab-chips (elegir entre pocos días: hoy, mañana, sábado)]
6
+ ---
7
+
8
+ # sui-date-selector
9
+
10
+ Story: [Molecules/Date & Time/Date Selector](https://sui-design-system.web.app/?path=/docs/molecules-date-time-date-selector--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** como cabecera de un **calendario armado a mano** o de una vista que se recorre por
15
+ mes o por semana: «Octubre 2026» con flechas para ir al mes anterior o al siguiente (los gastos
16
+ del mes, las ganancias del repartidor por mes).
17
+
18
+ **No lo uses** para:
19
+
20
+ - Un calendario completo: `sui-datepicker` ya lo trae adentro.
21
+ - Elegir entre pocos días: `sui-tab-chips` (como la hoja de pedido programado).
22
+ - Cambiar entre períodos fijos («Hoy», «Esta semana», «Este mes»): `sui-tab-chips`, como el super admin.
23
+
24
+ ## Qué variante usar
25
+
26
+ > **La guía del DS no tiene página para este componente** (vive dentro del datepicker). Todo es
27
+ > **propuesta, falta aprobación**.
28
+ >
29
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usa por dentro
30
+ > `sui-datepicker`.
31
+
32
+ | input | valor | cuándo | fuente |
33
+ |---|---|---|---|
34
+ | `label` | texto | El período visible, con mayúscula inicial y sin abreviar: «Octubre 2026», «Semana del 6 al 12 de octubre». | propuesta |
35
+ | `leftIcon` + `rightIcon` | `true` / `true` (default) | Lo normal: se puede ir atrás y adelante. | propuesta |
36
+ | `rightIcon` | `false` | Ya se está en el período actual y no hay futuro que mirar (ganancias, gastos). Mejor que dejar la flecha y que no haga nada. | propuesta |
37
+ | `leftIcon` | `false` | Ya se está en el primer período con datos (el mes en que se abrió el local). | propuesta |
38
+ | los dos en `false` | — | No usar: sin flechas es un título; va un texto. | no usar |
39
+ | `disabled` | `true` | Mientras carga el período nuevo, para que no se encadenen toques. | propuesta |
40
+
41
+ Usos de hoy que rompen la regla: **0**.
42
+
43
+ ## Tamaño en mobile y en web
44
+
45
+ **No tiene `size`.** Mide 288 × 36 y las flechas son `sui-compact-button` `large` de **24 px**:
46
+ en mobile **no llegan** a los 44 px.
47
+
48
+ | uso | mobile | web | fuente |
49
+ |---|---|---|---|
50
+ | cabecera de un período | — **no hay tamaño** | 288 × 36, flechas de 24 | medido |
51
+
52
+ ```html
53
+ <!-- Web -->
54
+ <sui-date-selector label="Octubre 2026" [rightIcon]="!esMesActual()" (prev)="mesAnterior()" (next)="mesSiguiente()" />
55
+ ```
56
+
57
+ **Sin tamaño suficiente para mobile.** En el celular, hasta que el DS le sume un `size`, se arma
58
+ con `sui-compact-button` `xlarge` (o `sui-button` `onlyIcon` `large`) a los lados de un título.
59
+
60
+ ## «No usar»: por qué no hoy y cuándo sí
61
+
62
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
63
+ |---|---|---|
64
+ | todo el componente suelto (0 usos) | no hay vistas que se recorran mes a mes | ganancias del repartidor o gastos del super admin «por mes», en web |
65
+ | los dos íconos apagados | sin flechas es un título | ninguno |
66
+
67
+ ## API
68
+
69
+ <!-- api:inicio -->
70
+ <!-- generada: no editar a mano — `npm run docs` -->
71
+
72
+ | input | tipo | default |
73
+ |---|---|---|
74
+ | `label` | `string` | — (requerido) |
75
+ | `leftIcon` | `boolean` | `true` |
76
+ | `rightIcon` | `boolean` | `true` |
77
+ | `disabled` | `boolean` | `false` |
78
+
79
+ | output | payload |
80
+ |---|---|
81
+ | `prev` | `void` |
82
+ | `next` | `void` |
83
+ <!-- api:fin -->
84
+
85
+ ## Trampas
86
+
87
+ - **`leftIcon` y `rightIcon` son booleanos**, no nombres de ícono: prenden o apagan las flechas.
88
+ - **Ancho fijo de 288 px** (`max-width` incluido): no se estira con el contenedor.
89
+ - Con una flecha apagada queda un hueco de 24 px para que el texto siga centrado.
90
+ - El componente **no sabe de fechas**: el texto lo arma quien lo usa y las flechas solo emiten.
91
+ - Los `aria-label` de las flechas dicen «Mes anterior» y «Mes siguiente» aunque el período sea
92
+ una semana.
93
+
94
+ ## Ejemplo
95
+
96
+ ```html
97
+ <sui-date-selector label="Octubre 2026" [rightIcon]="false" (prev)="mesAnterior()" />
98
+ ```