@ajuarezso/sui-design-system 0.24.1 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/docs/sui-accordion/README.md +85 -11
  2. package/docs/sui-activity-feed/README.md +65 -11
  3. package/docs/sui-activity-filter/README.md +54 -5
  4. package/docs/sui-alert/README.md +54 -0
  5. package/docs/sui-app-store-badge/README.md +64 -10
  6. package/docs/sui-avatar/README.md +92 -29
  7. package/docs/sui-avatar-group/README.md +75 -9
  8. package/docs/sui-badge/README.md +85 -17
  9. package/docs/sui-banner/README.md +85 -20
  10. package/docs/sui-brand-logo/README.md +95 -31
  11. package/docs/sui-breadcrumb-item/README.md +54 -3
  12. package/docs/sui-breadcrumbs/README.md +54 -6
  13. package/docs/sui-button/README.md +76 -12
  14. package/docs/sui-button-group/README.md +91 -23
  15. package/docs/sui-button-group-item/README.md +81 -14
  16. package/docs/sui-card/README.md +105 -18
  17. package/docs/sui-chart-legend/README.md +63 -10
  18. package/docs/sui-chart-legend-dot/README.md +59 -10
  19. package/docs/sui-checkbox/README.md +109 -29
  20. package/docs/sui-checkbox-card/README.md +70 -14
  21. package/docs/sui-checkbox-label/README.md +92 -26
  22. package/docs/sui-circular-progress-bar/README.md +80 -19
  23. package/docs/sui-color-dot/README.md +72 -12
  24. package/docs/sui-color-picker/README.md +71 -13
  25. package/docs/sui-command-menu-footer/README.md +50 -1
  26. package/docs/sui-command-menu-item/README.md +74 -14
  27. package/docs/sui-command-menu-search/README.md +58 -3
  28. package/docs/sui-compact-avatar-group/README.md +73 -13
  29. package/docs/sui-compact-button/README.md +123 -34
  30. package/docs/sui-compact-select/README.md +61 -7
  31. package/docs/sui-compact-select-for-input/README.md +70 -6
  32. package/docs/sui-content-card/README.md +75 -14
  33. package/docs/sui-content-divider/README.md +67 -16
  34. package/docs/sui-content-label/README.md +99 -20
  35. package/docs/sui-counter-input/README.md +102 -18
  36. package/docs/sui-date-selector/README.md +69 -11
  37. package/docs/sui-datepicker/README.md +85 -18
  38. package/docs/sui-day-cell/README.md +75 -17
  39. package/docs/sui-day-label/README.md +56 -7
  40. package/docs/sui-divider/README.md +64 -9
  41. package/docs/sui-drawer-footer/README.md +63 -2
  42. package/docs/sui-drawer-header/README.md +69 -12
  43. package/docs/sui-dropdown-caption/README.md +58 -6
  44. package/docs/sui-dropdown-item/README.md +75 -9
  45. package/docs/sui-dropdown-menu/README.md +83 -14
  46. package/docs/sui-dropdown-search/README.md +60 -4
  47. package/docs/sui-emoji/README.md +94 -30
  48. package/docs/sui-empty-state/README.md +71 -7
  49. package/docs/sui-fancy-button/README.md +74 -14
  50. package/docs/sui-file-icon/README.md +70 -12
  51. package/docs/sui-file-upload/README.md +77 -17
  52. package/docs/sui-file-upload-card/README.md +64 -12
  53. package/docs/sui-filter/README.md +83 -14
  54. package/docs/sui-flag/README.md +73 -8
  55. package/docs/sui-form-hint/README.md +56 -7
  56. package/docs/sui-form-label/README.md +57 -5
  57. package/docs/sui-href/README.md +47 -0
  58. package/docs/sui-icon/README.md +86 -18
  59. package/docs/sui-image-upload/README.md +90 -22
  60. package/docs/sui-image-upload-profile/README.md +70 -11
  61. package/docs/sui-img-retry/README.md +50 -1
  62. package/docs/sui-inline-input/README.md +67 -9
  63. package/docs/sui-inline-select/README.md +62 -2
  64. package/docs/sui-input/README.md +90 -27
  65. package/docs/sui-integration-switch/README.md +84 -17
  66. package/docs/sui-kbd/README.md +73 -9
  67. package/docs/sui-key-icon/README.md +85 -23
  68. package/docs/sui-link-button/README.md +96 -27
  69. package/docs/sui-logo/README.md +93 -22
  70. package/docs/sui-modal/README.md +72 -13
  71. package/docs/sui-modal-footer/README.md +86 -12
  72. package/docs/sui-modal-header/README.md +57 -1
  73. package/docs/sui-modal-sheet/README.md +74 -12
  74. package/docs/sui-notification/README.md +81 -11
  75. package/docs/sui-notification-footer/README.md +55 -5
  76. package/docs/sui-notification-tab-menu/README.md +61 -5
  77. package/docs/sui-otp-input/README.md +70 -9
  78. package/docs/sui-page-header/README.md +89 -19
  79. package/docs/sui-pagination/README.md +73 -13
  80. package/docs/sui-password-strength/README.md +50 -1
  81. package/docs/sui-payment-icon/README.md +80 -18
  82. package/docs/sui-period-range/README.md +70 -11
  83. package/docs/sui-popover/README.md +81 -15
  84. package/docs/sui-product-card/README.md +89 -21
  85. package/docs/sui-progress-bar/README.md +82 -15
  86. package/docs/sui-progress-bar-label/README.md +79 -18
  87. package/docs/sui-radio/README.md +84 -7
  88. package/docs/sui-radio-card/README.md +70 -16
  89. package/docs/sui-radio-label/README.md +89 -22
  90. package/docs/sui-rating/README.md +101 -31
  91. package/docs/sui-rich-editor/README.md +47 -2
  92. package/docs/sui-segmented-control/README.md +90 -21
  93. package/docs/sui-select/README.md +80 -11
  94. package/docs/sui-sidebar/README.md +71 -16
  95. package/docs/sui-slider/README.md +75 -8
  96. package/docs/sui-social-button/README.md +71 -11
  97. package/docs/sui-status-badge/README.md +75 -14
  98. package/docs/sui-stepper/README.md +75 -18
  99. package/docs/sui-store-card/README.md +85 -22
  100. package/docs/sui-switch/README.md +82 -11
  101. package/docs/sui-switch-card/README.md +80 -16
  102. package/docs/sui-switch-label/README.md +91 -14
  103. package/docs/sui-tab-chips/README.md +93 -21
  104. package/docs/sui-tab-menu-horizontal/README.md +68 -7
  105. package/docs/sui-tab-menu-vertical/README.md +64 -11
  106. package/docs/sui-table/README.md +77 -16
  107. package/docs/sui-tag/README.md +86 -12
  108. package/docs/sui-tag-input/README.md +77 -13
  109. package/docs/sui-textarea/README.md +84 -17
  110. package/docs/sui-time-picker/README.md +96 -33
  111. package/docs/sui-toast/README.md +81 -20
  112. package/docs/sui-tooltip/README.md +80 -22
  113. package/docs/sui-topbar/README.md +64 -10
  114. package/docs/sui-topbar-button/README.md +61 -7
  115. package/docs/sui-topbar-item/README.md +68 -7
  116. package/docs/sui-topbar-user/README.md +61 -5
  117. package/fesm2022/ajuarezso-sui-design-system.mjs +15 -10
  118. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  119. package/package.json +1 -1
  120. package/types/ajuarezso-sui-design-system.d.ts +7 -3
@@ -28,18 +28,19 @@ Regla corta: **varios valores libres → tag-input · varias opciones fijas →
28
28
  > **En la guía del DS es un ejemplo de su página del input** («With Tags»: un campo con los chips
29
29
  > Berlin, London, Paris debajo). No dice cuándo usarlo.
30
30
  >
31
- > Uso medido el 04-10-2026 en `master-pedidos/src/app`: **0 usos**. Candidato: «Rubros que entran»
32
- > en `pages/super-admin/master-settings/master-settings.html:136`, un `sui-input` donde se escriben
33
- > palabras separadas por coma («ferreteria, ferretería, construcción») y la pantalla las parte a mano.
31
+ > Uso medido el 06-10-2026 en `master-pedidos/src/app`: **1 uso**, «Rubros que entran» de una
32
+ > categoría propia del home (`pages/super-admin/master-categorias/master-categorias.html:179`), con
33
+ > `commaSeparator` y `addOnBlur`. Antes eran palabras separadas por coma en un `sui-input` que la
34
+ > pantalla partía a mano.
34
35
 
35
36
  | prop / evento | cuándo | fuente |
36
37
  |---|---|---|
37
38
  | `label` · `required` · `sublabel` · `tooltip` · `hint` | Igual que `sui-input`. El hint dice cómo se agrega: «Escribe y presiona Enter». | según la guía del DS (ejemplo con label «Tag Input») |
38
- | `placeholder` | **Siempre** que el default genérico («Agrega una etiqueta…», 04-10-2026) no diga qué se agrega: «Agrega una palabra…». | propuesta, falta aprobación |
39
- | `commaSeparator` | `true` cuando la gente ya escribe con comas (rubros, sinónimos). | propuesta, falta aprobación |
40
- | `addOnBlur` | `true` en mobile: si sale del campo sin Enter, lo escrito no se pierde. | propuesta, falta aprobación |
41
- | `maxTags` | Cuando hay un tope real. Hoy no hay. | propuesta, falta aprobación |
42
- | `allowDuplicates` | `false` (default). | propuesta, falta aprobación |
39
+ | `placeholder` | **Siempre** que el default genérico («Agrega una etiqueta…», 04-10-2026) no diga qué se agrega: «Agrega una palabra…». | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
40
+ | `commaSeparator` | `true` cuando la gente ya escribe con comas (rubros, sinónimos). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
41
+ | `addOnBlur` | `true` siempre, en mobile y en web: si sale del campo sin Enter, lo escrito no se pierde. | canon (aprobado por el dueño, 05-10-2026, bloque B13) |
42
+ | `maxTags` | Cuando hay un tope real. Hoy no hay. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
43
+ | `allowDuplicates` | `false` (default). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
43
44
  | `rightIcon` | No usar hoy (ícono de info a la derecha). | — |
44
45
  | `error` + `errorMessage` | Falta al menos un valor en un campo obligatorio. | según la guía del DS (estado de error del Figma) |
45
46
  | `disabled` | Mientras se guarda. | API |
@@ -65,21 +66,42 @@ en web; el alto sigue en 48/52.
65
66
 
66
67
  | uso | mobile | web | fuente |
67
68
  |---|---|---|---|
68
- | campo de formulario | `xlarge` (52, chips de 40 con X tocable en 44) | `medium` (40) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono (el 44 lo da la X del chip `xlarge`) |
69
+ | campo de formulario | `large` (48, chips de 32 con X tocable en 32) | `medium` (40) | D16, dueño 05-10-2026 (fila `input`/`tag-input`); reemplaza el `xlarge` del 04-10-2026 · la X de 32 no llega a 44: ver «Por dispositivo» |
69
70
 
70
71
  ```html
71
- <sui-tag-input [size]="bp.isMobile() ? 'xlarge' : 'medium'" … /> <!-- bp = BreakpointsService -->
72
+ <sui-tag-input [size]="bp.sizeControl()" … /> <!-- bp = BreakpointsService -->
72
73
  ```
73
74
 
75
+ ### Por dispositivo (D16)
76
+
77
+ Fila `input`/`tag-input` de la tabla D16 (dueño, 05-10-2026). Se toca, así que va por tipo de
78
+ puntero además del ancho:
79
+
80
+ | dispositivo | size | nota |
81
+ |---|---|---|
82
+ | celular chico (< 380) | `large` (48) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino) |
83
+ | celular (380–767) | `large` (48) | los chips salen en `large`: la X mide 20 con área de 32, no llega a 44 |
84
+ | tablet táctil (`pointer: coarse`) | `large` (48) | igual que el celular |
85
+ | computadora (`pointer: fine`) | `medium` (40) | también en filtros del panel; `xsmall` y `small` no se usan |
86
+
87
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`.
88
+
89
+ **Choque entre dos filas de D16 (a confirmar con el dueño):** con el campo en `large` la X del
90
+ chip queda en 32, y la fila `tag` dice que la X solo llega a 44 en `xlarge`. Hasta el 04-10-2026 el
91
+ campo iba `xlarge` en el teléfono justo por eso. Mientras no se diga otra cosa, manda la fila
92
+ `tag-input` (`large`).
93
+
94
+ En master-pedidos: `[size]="bp.sizeControl()"`.
95
+
74
96
  ## «No usar»: por qué no hoy y cuándo sí
75
97
 
76
98
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
77
99
  |---|---|---|
78
- | el componente entero (0 usos) | nadie carga listas de palabras | «Rubros que entran» de una categoría del home (`master-settings.html:136`), o sinónimos de un producto para el buscador |
100
+ | otros usos (hoy solo los rubros de una categoría) | nadie más carga listas de palabras | sinónimos de un producto para el buscador |
79
101
  | `rightIcon` | el hint explica mejor | — |
80
102
  | `maxTags` | no hay topes | un máximo de 5 palabras clave por producto |
81
103
  | `allowDuplicates` | repetir no sirve | — |
82
- | `size` `xsmall` / `small` | no hay tag-inputs en tablas | un filtro denso del panel |
104
+ | `size` `xsmall` / `small` | son chicos (D16, 05-10-2026) | nunca: un filtro denso del panel también va `medium` |
83
105
 
84
106
  ## API
85
107
 
@@ -124,10 +146,52 @@ no es parte del valor. Slot `[slot=right]` para un contenido propio a la derecha
124
146
  - **Accesibilidad (04-10-2026)**: el control trae su `id`; el `label` interno apunta a él con `for`,
125
147
  el hint o el error se enlazan con `aria-describedby` y `error` pone `aria-invalid`.
126
148
 
127
- ## Ejemplo
149
+ ## Bien y mal
150
+
151
+ Tamaño en el celular
152
+
153
+ ```html
154
+ <!-- ❌ mal: sin size queda en medium en el celular y la X de los chips mide 16 (master-categorias.html:179) -->
155
+ <sui-tag-input label="Rubros que entran" [commaSeparator]="true" [addOnBlur]="true"
156
+ [value]="e.match" (valueChange)="editar('match', $event)" />
157
+ ```
158
+
159
+ ```html
160
+ <!-- ✅ bien -->
161
+ <sui-tag-input [size]="bp.sizeControl()" label="Rubros que entran" [commaSeparator]="true"
162
+ [addOnBlur]="true" [value]="e.match" (valueChange)="editar('match', $event)" />
163
+ ```
164
+
165
+ Placeholder y hint
128
166
 
129
167
  ```html
168
+ <!-- ❌ mal: el placeholder dice cómo se agrega, no qué se agrega (master-categorias.html:179) -->
169
+ <sui-tag-input label="Rubros que entran" placeholder="Escribe y pulsa coma"
170
+ hint="Un local entra si su rubro contiene alguna de estas palabras" />
171
+ ```
172
+
173
+ ```html
174
+ <!-- ✅ bien: el placeholder dice qué; el hint, cómo -->
130
175
  <sui-tag-input label="Rubros que entran" placeholder="Agrega una palabra…"
176
+ hint="Separa con coma. Un local entra si su rubro contiene alguna" />
177
+ ```
178
+
179
+ Salir del campo sin Enter
180
+
181
+ ```html
182
+ <!-- ❌ mal: sin addOnBlur, lo escrito y no confirmado se pierde al salir -->
183
+ <sui-tag-input label="Sinónimos" [commaSeparator]="true" [(value)]="sinonimos" />
184
+ ```
185
+
186
+ ```html
187
+ <!-- ✅ bien -->
188
+ <sui-tag-input label="Sinónimos" [commaSeparator]="true" [addOnBlur]="true" [(value)]="sinonimos" />
189
+ ```
190
+
191
+ ## Ejemplo
192
+
193
+ ```html
194
+ <sui-tag-input [size]="bp.sizeControl()" label="Rubros que entran" placeholder="Agrega una palabra…"
131
195
  hint="Un local entra si su rubro contiene alguna" [commaSeparator]="true"
132
196
  [addOnBlur]="true" [(value)]="rubros" />
133
197
  ```
@@ -18,8 +18,8 @@ comentario al calificar.
18
18
  **No lo uses** para:
19
19
 
20
20
  - Un dato de una línea (nombre, referencia corta, URL, un slug): `sui-input`. Hoy hay 4 así:
21
- «Personaliza tu url» en `pages/mi-negocio/mi-negocio.html:713` (a propósito, para que envuelva en
22
- mobile, según su comentario) y 3 URL de imagen: `pages/mi-negocio/mi-negocio.html:534`, `:588` y
21
+ «Personaliza tu url» en `pages/mi-negocio/mi-negocio.html:714` (a propósito, para que envuelva en
22
+ mobile, según su comentario) y 3 URL de imagen: `pages/mi-negocio/mi-negocio.html:533`, `:588` y
23
23
  `components/add-product-modal/add-product-modal.html:72`.
24
24
  - Un motivo que se puede elegir de una lista cerrada: radios o `sui-select`, y la opción «Otro»
25
25
  abre el textarea (como ya hace `pages/envios/envios.html:822`, con `[maxLength]="200"`; el
@@ -47,13 +47,13 @@ Regla corta: **se redacta y puede pasar de una línea → textarea · una línea
47
47
  | `hint` | Para quién es el texto: «Lo va a leer el cliente», «Solo lo ve tu equipo». | según la guía del DS (ejemplo con hint) |
48
48
  | `error` + `errorMessage` | Motivo obligatorio vacío. El mensaje reemplaza al hint y el contador se pone rojo. | según la guía del DS (`Has Error`) |
49
49
  | `placeholder` | Un ejemplo de lo que se espera: «Ej. frágil, tocar el timbre, entregar en recepción». Elipsis `…`. | canon (CANON-SUI §5.2) |
50
- | `maxLength` | **Siempre que otro lo va a leer** (cliente, repartidor, local) o se guarda en la base: muestra «n/200» y corta el exceso. 200 para motivos y notas; 500 para descripciones. | según la guía del DS (su ejemplo principal lleva contador); los topes son propuesta |
51
- | `size` | El mismo de los inputs del formulario: `large` en mobile, `medium` en web. Ver «Tamaño en mobile y en web». | canon (aprobado por el dueño, 03-10-2026), extensión SUI; el «cuándo» es propuesta, falta aprobación |
52
- | `rows` | `3` para motivos y notas (el default del componente es `4`). `2` para una nota corta en un formulario largo. `4` o más solo para una descripción larga. | propuesta, falta aprobación |
53
- | `resizable` | `true` en web. En mobile **`false`**: la manija no se puede arrastrar con el dedo y parece un adorno. | según la guía del DS (versión con y sin manija); el «cuándo» es propuesta |
54
- | `readonly` | Mostrar un texto ya enviado con la misma forma del campo (copiar un mensaje). | propuesta, falta aprobación |
50
+ | `maxLength` | **Siempre que otro lo va a leer** (cliente, repartidor, local) o se guarda en la base: muestra «n/200» y corta el exceso. 200 para motivos y notas; 500 para descripciones. | según la guía del DS (su ejemplo principal lleva contador); los topes: canon (aprobado por el dueño, 05-10-2026, bloque B9) |
51
+ | `size` | El mismo de los inputs del formulario: `large` en mobile, `medium` en web. Ver «Tamaño en mobile y en web». | canon (aprobado por el dueño, 03-10-2026), extensión SUI; el «cuándo»: canon (aprobado por el dueño, 05-10-2026, bloque B1) |
52
+ | `rows` | `3` para motivos y notas (el default del componente es `4`). `2` para una nota corta en un formulario largo. `4` o más solo para una descripción larga. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
53
+ | `resizable` | `true` en web. En mobile y en la tablet táctil **`false`** (`!bp.tactil()`, D16): la manija no se puede arrastrar con el dedo y parece un adorno. | según la guía del DS (versión con y sin manija); el «cuándo»: canon (aprobado por el dueño, 05-10-2026, bloque B8) |
54
+ | `readonly` | Mostrar un texto ya enviado con la misma forma del campo (copiar un mensaje). | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
55
55
  | `disabled` | Mientras se envía. | según la guía del DS |
56
- | `autocomplete` | No hace falta: ningún texto libre se autocompleta. | propuesta, falta aprobación |
56
+ | `autocomplete` | No hace falta: ningún texto libre se autocompleta. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
57
57
 
58
58
  **Usos de hoy que rompen la regla** (medido el 04-10-2026; los `sublabel` sin paréntesis, los
59
59
  «(opcional)» en el label y los placeholders con `...` ya se corrigieron en la app, commits
@@ -61,9 +61,12 @@ Regla corta: **se redacta y puede pasar de una línea → textarea · una línea
61
61
 
62
62
  - **7 sin `maxLength`**: 4 son las URL de una línea de arriba y 1 es de solo lectura
63
63
  (`components/copy-text-dialog/copy-text-dialog.html:9`); quedan 2 «Notas» que se guardan en la base:
64
- `pages/super-admin/super-admin.html:334`, `pages/super-admin/master-gastos/master-gastos.html:228`.
65
- - **Ninguno lleva `size`**: los 50 quedan en `medium` también en el teléfono, aunque los inputs del
66
- mismo formulario ya vayan en `large`.
64
+ `pages/super-admin/super-admin.html:339`, `pages/super-admin/master-gastos/master-gastos.html:235`.
65
+ - **`size` ya cumple** (medido de nuevo el 06-10-2026, tras la migración a D16): los 51 usos de la
66
+ app (sin vitrinas) van con `bp.sizeControl()`.
67
+ - **49 de 51 sin `resizable`**: la manija sale también en el celular y la tablet, donde no se puede
68
+ arrastrar con el dedo (p. ej. «Nota para el repartidor», `pages/envios/envios.html:422`). Solo
69
+ `copy-text-dialog.html:9` y `mi-negocio.html:714` la apagan, y fijo, también en la computadora.
67
70
 
68
71
  ## Tamaño en mobile y en web
69
72
 
@@ -90,14 +93,34 @@ también en web, así que cada fila mide 24 en las dos plataformas.
90
93
 
91
94
  | uso | mobile | web | fuente |
92
95
  |---|---|---|---|
93
- | motivo, nota | el `size` del formulario (`large` si los inputs van en `large`), `rows=3`, `[resizable]="false"` | `medium`, `rows=3`, manija | propuesta, falta aprobación |
94
- | descripción larga | igual, `rows=4` | `medium`, `rows=4` | propuesta, falta aprobación |
96
+ | motivo, nota | el `size` del formulario (`large` si los inputs van en `large`), `rows=3`, sin manija | `medium`, `rows=3`, manija | canon (aprobado por el dueño, 05-10-2026, bloque B1) |
97
+ | descripción larga | igual, `rows=4` | `medium`, `rows=4` | canon (aprobado por el dueño, 05-10-2026, bloque B1) |
98
+
99
+ «Mobile» aquí incluye la tablet táctil (D16): la manija se apaga con `[resizable]="!bp.tactil()"`,
100
+ no con `[resizable]="false"` ni por ancho, para que tampoco salga en una tablet ancha.
95
101
 
96
102
  ```html
97
- <sui-textarea [size]="bp.isMobile() ? 'large' : 'medium'" [rows]="3"
98
- [resizable]="!bp.isMobile()" … /> <!-- bp = BreakpointsService -->
103
+ <sui-textarea [size]="bp.sizeControl()" [rows]="3"
104
+ [resizable]="!bp.tactil()" … /> <!-- bp = BreakpointsService -->
99
105
  ```
100
106
 
107
+ ### Por dispositivo (D16)
108
+
109
+ Fila `textarea` de la tabla D16 (dueño, 05-10-2026), la misma de `sui-input`: se toca, así que va
110
+ por tipo de puntero además del ancho, y mide lo mismo que los campos y el botón del formulario.
111
+
112
+ | dispositivo | size | nota |
113
+ |---|---|---|
114
+ | celular chico (< 380 px) | `large` | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino). Sin manija |
115
+ | celular (380–767 px) | `large` | el mismo padding que el `sui-input` `large` de arriba. Sin manija |
116
+ | tablet táctil (`pointer: coarse`) | `large` | también se toca con el dedo: `large` y sin manija, igual que el celular |
117
+ | computadora (`pointer: fine`) | `medium` | con manija; `small` y `xsmall` no se usan |
118
+
119
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`; el espacio extra va al ancho del
120
+ formulario, no a un campo más alto. El alto lo siguen poniendo las `rows` en todos los dispositivos.
121
+
122
+ En master-pedidos: `[size]="bp.sizeControl()"` + `[resizable]="!bp.tactil()"`.
123
+
101
124
  ## «No usar»: por qué no hoy y cuándo sí
102
125
 
103
126
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -147,12 +170,56 @@ Outputs: ninguno.
147
170
  - **Accesibilidad (04-10-2026)**: el control trae su `id`; el `label` interno apunta a él con `for`,
148
171
  el hint o el error se enlazan con `aria-describedby` y `error` pone `aria-invalid`.
149
172
 
173
+ ## Bien y mal
174
+
175
+ URL de una imagen
176
+
177
+ ```html
178
+ <!-- ❌ mal: una URL es un dato de una línea, y sin maxLength (pages/mi-negocio/mi-negocio.html:533, components/add-product-modal/add-product-modal.html:72) -->
179
+ <sui-textarea [size]="bp.sizeControl()" [rows]="2" placeholder="https://ejemplo.com/logo.png"
180
+ [value]="logoUrlInput()" (valueChange)="logoUrlInput.set($event)" />
181
+ ```
182
+
183
+ ```html
184
+ <!-- ✅ bien -->
185
+ <sui-input type="url" [size]="bp.sizeControl()" placeholder="https://ejemplo.com/logo.png"
186
+ [value]="logoUrlInput()" (valueChange)="logoUrlInput.set($event)" />
187
+ ```
188
+
189
+ Nota que se guarda en la base
190
+
191
+ ```html
192
+ <!-- ❌ mal: sin maxLength no hay contador ni tope, y la nota se guarda (pages/super-admin/super-admin.html:339) -->
193
+ <sui-textarea [size]="bp.sizeControl()" label="Notas" sublabel="(Opcional)" [rows]="3"
194
+ [ngModel]="subNotes()" (ngModelChange)="subNotes.set($event)" />
195
+ ```
196
+
197
+ ```html
198
+ <!-- ✅ bien -->
199
+ <sui-textarea [size]="bp.sizeControl()" label="Notas" sublabel="(Opcional)" [rows]="3" [maxLength]="200"
200
+ [resizable]="!bp.tactil()" [ngModel]="subNotes()" (ngModelChange)="subNotes.set($event)" />
201
+ ```
202
+
203
+ Nota para el repartidor en el celular
204
+
205
+ ```html
206
+ <!-- ❌ mal: sin resizable, la manija sale en el celular y la tablet, donde no se arrastra con el dedo; y el tope de una nota es 200 (pages/envios/envios.html:422) -->
207
+ <sui-textarea [size]="bp.sizeControl()" [maxLength]="300" label="Nota para el repartidor"
208
+ placeholder="Ej. frágil, tocar el timbre, entregar en recepción" [rows]="3" [(value)]="nota" />
209
+ ```
210
+
211
+ ```html
212
+ <!-- ✅ bien -->
213
+ <sui-textarea [size]="bp.sizeControl()" [maxLength]="200" label="Nota para el repartidor" [resizable]="!bp.tactil()"
214
+ placeholder="Ej. frágil, tocar el timbre, entregar en recepción" [rows]="3" [(value)]="nota" />
215
+ ```
216
+
150
217
  ## Ejemplo
151
218
 
152
219
  ```html
153
220
  <sui-textarea label="Nota para el repartidor" sublabel="(Opcional)" [rows]="3" [maxLength]="200"
154
- [size]="bp.isMobile() ? 'large' : 'medium'" placeholder="Ej. frágil, tocar el timbre, entregar en recepción"
155
- [resizable]="!bp.isMobile()" [(value)]="nota" />
221
+ [size]="bp.sizeControl()" placeholder="Ej. frágil, tocar el timbre, entregar en recepción"
222
+ [resizable]="!bp.tactil()" [(value)]="nota" />
156
223
 
157
224
  <sui-textarea label="Motivo del rechazo" [required]="true" [rows]="3" [maxLength]="200"
158
225
  hint="Lo va a leer el local" [error]="intentado() && !motivo()"
@@ -30,8 +30,8 @@ pocas horas → select.**
30
30
 
31
31
  ## Qué variante usar
32
32
 
33
- > **La guía del DS no tiene página para este componente.** Todo es **propuesta, falta
34
- > aprobación**, aunque ya sea práctica de la app.
33
+ > **La guía del DS no tiene página para este componente.** Las reglas marcadas canon
34
+ > están aprobadas; lo que sigue en **propuesta** espera decisión.
35
35
  >
36
36
  > Uso medido el 03-10-2026 en `master-pedidos/src/app` (sin prototipos ni vitrinas): **7 usos en
37
37
  > 4 pantallas** — horario del local (`weekly-schedule-editor`, 2), turnos del repartidor
@@ -43,25 +43,25 @@ pocas horas → select.**
43
43
 
44
44
  | valor | cuándo | fuente |
45
45
  |---|---|---|
46
- | `12h` (default) | Siempre: en Perú la hora se dice «9:30 PM». Los 7 usos lo llevan. | propuesta |
47
- | `24h` | No usar en la app. | propuesta |
46
+ | `12h` (default) | Siempre: en Perú la hora se dice «9:30 PM». Los 7 usos lo llevan. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
47
+ | `24h` | No usar en la app. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
48
48
 
49
49
  ### `step`
50
50
 
51
51
  | valor | cuándo | fuente |
52
52
  |---|---|---|
53
- | `5` (default) | Horas reales que la persona conoce al minuto: apertura y cierre del local, «cerrar hasta». Con saltos de 30 se redondeaban cierres reales (comentario en `weekly-schedule-editor.html:37`). | propuesta |
54
- | `30` | Bloques de un turno, que se planifican por media hora (`driver-schedule.html:140`). | propuesta |
55
- | `15` | Citas o reservas en cuartos de hora. Sin caso hoy. | propuesta |
56
- | `1` | No usar: 60 opciones en la columna para una precisión que nadie pide. | propuesta |
53
+ | `5` (default) | Horas reales que la persona conoce al minuto: apertura y cierre del local, «cerrar hasta». Con saltos de 30 se redondeaban cierres reales (comentario en `weekly-schedule-editor.html:37`). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
54
+ | `30` | Bloques de un turno, que se planifican por media hora (`driver-schedule.html:140`). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
55
+ | `15` | Citas o reservas en cuartos de hora. Sin caso hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
56
+ | `1` | No usar: 60 opciones en la columna para una precisión que nadie pide. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
57
57
 
58
58
  ### `durationPresets`, `showFooter`, `inline`
59
59
 
60
60
  | input | valor | cuándo | fuente |
61
61
  |---|---|---|---|
62
- | `durationPresets` | `[]` (default desde el 04-10-2026) | **Siempre.** Los presets (15 min, 30 min, 45 min, 1 h) ponen la hora como «tiempo desde la medianoche»: «30 min» deja 12:30 AM. Por eso el default pasó a `[]`; los 7 usos de la app ya los apagaban. | propuesta |
63
- | `durationPresets` | lista propia | No usar mientras se lean como hora del día. | propuesta |
64
- | `showFooter` | `true` (default) | Cancelar/Aplicar: la hora no cambia hasta confirmar. Es lo correcto cuando la hora se guarda o publica algo (el horario del local). | propuesta |
62
+ | `durationPresets` | `[]` (default desde el 04-10-2026) | **Siempre.** Los presets (15 min, 30 min, 45 min, 1 h) ponen la hora como «tiempo desde la medianoche»: «30 min» deja 12:30 AM. Por eso el default pasó a `[]`; los 7 usos de la app ya los apagaban. | según el código |
63
+ | `durationPresets` | lista propia | No usar mientras se lean como hora del día. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
64
+ | `showFooter` | `true` (default) | Cancelar/Aplicar: la hora no cambia hasta confirmar. Es lo correcto cuando la hora se guarda o publica algo (el horario del local). | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
65
65
  | `showFooter` | `false` | Se aplica al tocar cada columna. Solo dentro de un formulario que ya tiene su propio «Guardar». | propuesta |
66
66
  | `inline` | `true` | El panel es el contenido, dentro de un `sui-modal` (sin campo ni popover). | propuesta |
67
67
 
@@ -69,28 +69,30 @@ pocas horas → select.**
69
69
 
70
70
  | input | cuándo | fuente |
71
71
  |---|---|---|
72
- | `size="medium"` (40 px, default) | Web. En mobile va `large` (48), que existe desde el 03-10-2026 (ver «Tamaño»). | propuesta |
73
- | `size="small"` (36 px) | Filas densas en web. | propuesta |
74
- | `label` | Siempre, corto y en verbo o momento: «Abre», «Cierra», «Inicio», «Cerrar hasta». | propuesta |
75
- | `sublabel` / `tooltip` | «Opcional» o una aclaración que no entra en el label. | propuesta |
76
- | `hint` | Qué pasa con esa hora: «Se reabre sola a medianoche». | propuesta |
77
- | `error` + `errorMessage` | La hora no cuadra: «Cierra antes de abrir». | propuesta |
78
- | `required` | La hora es obligatoria para guardar. | propuesta |
79
- | `disabled` | Mientras se guarda (como hacen el horario y los turnos). | propuesta |
80
- | `placeholder` | Lo que se elige: «Hora de cierre». El default «Seleccionar hora» sirve. | propuesta |
81
-
82
- Usos de hoy que rompen la regla: los 7 cumplen `12h`, `durationPresets=[]` y `label`, pero **los 7
83
- van con `size="medium"` fijo**, también en pantallas del teléfono (turnos y votaciones del
84
- repartidor): campo de 40, contra el `large` de la tabla de «Tamaño». Cancelar / Aplicar ya salen en
85
- 48 en el teléfono desde el 04-10-2026 (el componente los fuerza en mobile).
72
+ | `size="medium"` (40 px, default) | Web. En mobile va `large` (48), que existe desde el 03-10-2026 (ver «Tamaño»). | mobile `large`: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono — el campo `medium` mide 40 · web `medium`: canon (aprobado por el dueño, 05-10-2026, bloque B1) |
73
+ | `size="small"` (36 px) | No usar: es chico. Las filas densas de web van en `medium`. | canon (dueño, 05-10-2026, D16) |
74
+ | `label` | Siempre, corto y en verbo o momento: «Abre», «Cierra», «Inicio», «Cerrar hasta». | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
75
+ | `sublabel` / `tooltip` | «Opcional» o una aclaración que no entra en el label. | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
76
+ | `hint` | Qué pasa con esa hora: «Se reabre sola a medianoche». | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
77
+ | `error` + `errorMessage` | La hora no cuadra: «Cierra antes de abrir». | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
78
+ | `required` | La hora es obligatoria para guardar. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
79
+ | `disabled` | Mientras se guarda (como hacen el horario y los turnos). | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
80
+ | `placeholder` | El default «Elige una hora» sirve. Si hace falta decir qué hora, en imperativo con tuteo: «Elige la hora de cierre». | canon (dueño, 05-10-2026, P4 a); el default cambió en la 0.25.0 (antes «Seleccionar hora») |
81
+
82
+ Usos de hoy que rompen la regla (medido de nuevo el 06-10-2026): los 7 cumplen `12h`,
83
+ `durationPresets=[]` y `label`, y ya no van en `medium` fijo, pero **los 7 van con
84
+ `bp.isMobile() ? 'large' : 'medium'`** en vez de `bp.sizeControl()`: en la tablet táctil el campo
85
+ queda en 40 mientras el botón de al lado ya sube a 48 (p. ej.
86
+ `pages/driver/driver-dashboard/driver-dashboard.html:1521` junto a «Pedir cierre»). Cancelar /
87
+ Aplicar ya salen en 48 en el teléfono desde el 04-10-2026 (el componente los fuerza en mobile).
86
88
 
87
89
  ### Las piezas que trae (exportadas, sin carpeta ni story propias)
88
90
 
89
91
  | pieza | qué es | cuándo suelta | fuente |
90
92
  |---|---|---|---|
91
- | `sui-time-picker-item` | una fila de la columna (36 px) | No usar: para filas de horario que se tocan con el pulgar va `sui-radio-label` (`checkout.html:469`). | propuesta |
92
- | `sui-time-picker-duration` | la pastilla de un preset | No usar: es la de los presets de duración. | propuesta |
93
- | `sui-time-picker-status` | pastilla Disponible/Ocupado/En reunión/Desconectado | No usar: el estado del repartidor ya tiene su badge. | propuesta |
93
+ | `sui-time-picker-item` | una fila de la columna (36 px) | No usar: para filas de horario que se tocan con el pulgar va `sui-radio-label` (`checkout.html:469`). | canon (aprobado por el dueño, 05-10-2026, bloque B7) |
94
+ | `sui-time-picker-duration` | la pastilla de un preset | No usar: es la de los presets de duración. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
95
+ | `sui-time-picker-status` | pastilla Disponible/Ocupado/En reunión/Desconectado | No usar: el estado del repartidor ya tiene su badge. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
94
96
 
95
97
  ## Tamaño en mobile y en web
96
98
 
@@ -116,14 +118,32 @@ campo y la de las filas van en 16/24; la fila sigue en 44 (el padding bajó de 1
116
118
 
117
119
  | uso | mobile | web | fuente |
118
120
  |---|---|---|---|
119
- | horario en un formulario | `large` (48) o `xlarge` (52) si va junto a campos xlarge | `medium`, o `small` en filas densas | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web: propuesta, falta aprobación |
121
+ | horario en un formulario | `large` (48) o `xlarge` (52) si va junto a campos xlarge | `medium`, también en filas densas | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · web `medium`: canon (aprobado por el dueño, 05-10-2026, bloque B1) · también en filas densas, nunca `small`: canon (dueño, 05-10-2026, D16) |
120
122
 
121
123
  ```html
122
124
  <sui-time-picker label="Cierra" format="12h" [step]="5" [durationPresets]="[]"
123
- [size]="bp.isMobile() ? 'large' : 'medium'"
125
+ [size]="bp.sizeControl()"
124
126
  [value]="cierre()" (valueChange)="cierre.set($event)" />
125
127
  ```
126
128
 
129
+ ### Por dispositivo (D16)
130
+
131
+ Fila `time-picker` de la tabla D16 (dueño, 05-10-2026), la misma de `sui-input` y `sui-select`: se
132
+ toca, así que va por tipo de puntero además del ancho, y mide lo mismo que los campos y el botón
133
+ que tiene al lado.
134
+
135
+ | dispositivo | size | nota |
136
+ |---|---|---|
137
+ | celular chico (< 380 px) | `large` (48) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino) |
138
+ | celular (380–767 px) | `large` (48) | `xlarge` (52) solo si va junto a campos `xlarge` |
139
+ | tablet táctil (`pointer: coarse`) | `large` (48) | con `large` el panel también crece (filas de 44, Cancelar / Aplicar en 48); el arreglo automático del pie solo mira el ancho (≤ 767 px), así que en la tablet hace falta pasar `large` |
140
+ | computadora (`pointer: fine`) | `medium` (40) | también en filas densas; `small` no se usa |
141
+
142
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`; el espacio extra va a ancho y columnas,
143
+ no a campos más altos.
144
+
145
+ En master-pedidos: `[size]="bp.sizeControl()"`.
146
+
127
147
  ## «No usar»: por qué no hoy y cuándo sí
128
148
 
129
149
  Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
@@ -154,7 +174,7 @@ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
154
174
  | `hint` | `string \| null` | `null` |
155
175
  | `errorMessage` | `string \| null` | `null` |
156
176
  | `error` | `boolean` | `false` |
157
- | `placeholder` | `string` | `'Seleccionar hora'` |
177
+ | `placeholder` | `string` | `'Elige una hora'` |
158
178
  | `disabled` | `boolean` | `false` |
159
179
  | `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
160
180
  | `format` | `'12h' \| '24h'` | `'12h'` |
@@ -234,13 +254,56 @@ interface SuiTimeDurationPreset { label: string; minutes: number; }
234
254
  defecto (antes venían en inglés del Figma); `label` sigue sirviendo para cambiarlo.
235
255
  - El atributo `title` del host se borra solo (no sale el tooltip gris del navegador).
236
256
 
257
+ ## Bien y mal
258
+
259
+ Hora junto a un botón
260
+
261
+ ```html
262
+ <!-- ❌ mal: bp.isMobile() deja el campo en medium (40) en la tablet táctil, y el botón de al lado con bp.sizeControl() sube a large (48) (pages/driver/driver-dashboard/driver-dashboard.html:1521) -->
263
+ <sui-time-picker [size]="bp.isMobile() ? 'large' : 'medium'" format="12h" [step]="5" [durationPresets]="[]"
264
+ label="Cerrar hasta" [value]="horaCierreProp()" (valueChange)="onHoraCierreChange($event)" />
265
+ ```
266
+
267
+ ```html
268
+ <!-- ✅ bien -->
269
+ <sui-time-picker [size]="bp.sizeControl()" format="12h" [step]="5" [durationPresets]="[]"
270
+ label="Cerrar hasta" [value]="horaCierreProp()" (valueChange)="onHoraCierreChange($event)" />
271
+ ```
272
+
273
+ Presets de duración
274
+
275
+ ```html
276
+ <!-- ❌ mal: los presets no suman sobre la hora: «30 min» deja 12:30 AM (ver Trampas) -->
277
+ <sui-time-picker label="Cerrar por" [durationPresets]="[{ label: '30 min', minutes: 30 }, { label: '1 h', minutes: 60 }]"
278
+ [value]="hasta()" (valueChange)="hasta.set($event)" />
279
+ ```
280
+
281
+ ```html
282
+ <!-- ✅ bien: se pide la hora del día, sin presets -->
283
+ <sui-time-picker label="Cerrar hasta" format="12h" [step]="5" [durationPresets]="[]" [size]="bp.sizeControl()"
284
+ [value]="hasta()" (valueChange)="hasta.set($event)" />
285
+ ```
286
+
287
+ Formato y paso
288
+
289
+ ```html
290
+ <!-- ❌ mal: en Perú se dice «9:30 PM», y 60 minutos en la columna para una precisión que nadie pide -->
291
+ <sui-time-picker label="Abre" format="24h" [step]="1" [value]="apertura()" (valueChange)="apertura.set($event)" />
292
+ ```
293
+
294
+ ```html
295
+ <!-- ✅ bien -->
296
+ <sui-time-picker label="Abre" format="12h" [step]="5" [durationPresets]="[]" [size]="bp.sizeControl()"
297
+ [value]="apertura()" (valueChange)="apertura.set($event)" />
298
+ ```
299
+
237
300
  ## Ejemplo
238
301
 
239
302
  ```html
240
303
  <!-- Horario del local: abre / cierra -->
241
- <sui-time-picker label="Abre" format="12h" [step]="5" [durationPresets]="[]"
304
+ <sui-time-picker label="Abre" format="12h" [step]="5" [durationPresets]="[]" [size]="bp.sizeControl()"
242
305
  [value]="apertura()" (valueChange)="apertura.set($event)" />
243
- <sui-time-picker label="Cierra" format="12h" [step]="5" [durationPresets]="[]"
306
+ <sui-time-picker label="Cierra" format="12h" [step]="5" [durationPresets]="[]" [size]="bp.sizeControl()"
244
307
  [error]="cierraAntes()" errorMessage="Cierra antes de abrir"
245
308
  [value]="cierre()" (valueChange)="cierre.set($event)" />
246
309
  ```