@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,7 +28,7 @@ Regla corta: **un dato, en su lugar, que se corrige rápido → inline · varios
28
28
  ## Qué variante usar
29
29
 
30
30
  > **La guía del DS no tiene página para este componente.** Viene del Figma («Inline Input»).
31
- > Todo lo de abajo es **propuesta, falta aprobación**.
31
+ > Las reglas de abajo son **canon (aprobado por el dueño, 05-10-2026)**; las filas «API» describen el componente.
32
32
  >
33
33
  > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. Hay listas con campos siempre
34
34
  > abiertos que se parecen (`pages/super-admin/master-settings/master-settings.html:101`, nombre de
@@ -38,11 +38,11 @@ Regla corta: **un dato, en su lugar, que se corrige rápido → inline · varios
38
38
  | prop / evento | cuándo | fuente |
39
39
  |---|---|---|
40
40
  | `value` | El dato. `[(value)]` o `formControlName`, nunca los dos. | API |
41
- | `placeholder` | Lo que se ve si está vacío: «Sin nombre». **Siempre**: el default genérico es «Escribe aquí…» (en español desde el 04-10-2026). | propuesta, falta aprobación |
42
- | `leftIcon` | Un ícono que dice qué dato es (`price-tag-3-line` para una categoría). `false` si el texto se explica solo. El default es `user-3-line`. | propuesta, falta aprobación |
43
- | `editLabel` | Nombre accesible del lápiz: «Editar nombre». | propuesta, falta aprobación |
44
- | `error` | El valor escrito no sirve (vacío, repetido). Solo se ve en edición; no trae mensaje. | propuesta, falta aprobación |
45
- | `disabled` | Mientras se guarda. | propuesta, falta aprobación |
41
+ | `placeholder` | Lo que se ve si está vacío: «Sin nombre». **Siempre**: el default genérico es «Escribe aquí…» (en español desde el 04-10-2026). | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
42
+ | `leftIcon` | Un ícono que dice qué dato es (`price-tag-3-line` para una categoría). `false` si el texto se explica solo. El default es `user-3-line`. | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
43
+ | `editLabel` | Nombre accesible del lápiz: «Editar nombre». | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
44
+ | `error` | El valor escrito no sirve (vacío, repetido). Solo se ve en edición; no trae mensaje. | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
45
+ | `disabled` | Mientras se guarda. | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
46
46
  | `(confirm)` | Guardar. Llega el texto nuevo. | API |
47
47
  | `(cancel)` · `(edit)` | Volver atrás sin guardar · avisar que se empezó a editar. | API |
48
48
 
@@ -51,13 +51,25 @@ Regla corta: **un dato, en su lugar, que se corrige rápido → inline · varios
51
51
  **No tiene `size`**: mide 38 px de alto (8 + 20 + 8 de padding y línea, más 1 + 1 de borde) y sus
52
52
  botones (lápiz, ✓, ✕) son de 24 × 24 (ícono de 20 + 2 de padding). En edición el texto sube a 16 px
53
53
  en mobile (sin zoom de iOS). **No tiene tamaño suficiente para mobile**: los botones
54
- de 24 px quedan lejos de los 44 que pide un dedo. Usarlo en el panel web; en el teléfono, editar
55
- con un `sui-input` `large`.
54
+ de 24 px quedan lejos de los 44 que pide un dedo. Usarlo en el panel web; en el teléfono y en la
55
+ tablet táctil, editar con un `sui-input` `large`.
56
56
 
57
57
  | uso | mobile | web |
58
58
  |---|---|---|
59
59
  | renombrar en una lista | `sui-input` `large` en un modal | este, 38 px |
60
60
 
61
+ ### Por dispositivo (D16)
62
+
63
+ **No tiene `size`**: mide 38 px fijos y sus botones son de 24, así que no hay escala que repartir
64
+ por dispositivo. Lo que sí aplica es la regla de lo que se toca (D16, dueño 05-10-2026): en toda
65
+ pantalla táctil (celular chico, celular y tablet con `pointer: coarse`) los botones de 24 no llegan
66
+ a 44, y ahí se edita con un `sui-input` en un modal. Este queda para la computadora (y el
67
+ ultrawide, igual que ella). La condición es `bp.tactil()` y no `bp.isMobile()`: con `isMobile` el
68
+ iPad se queda con los botones de 24.
69
+
70
+ En master-pedidos: `@if (bp.tactil())` → `sui-input` con `[size]="bp.sizeControl()"` en un modal;
71
+ si no, `sui-inline-input`.
72
+
61
73
  ## «No usar»: por qué no hoy y cuándo sí
62
74
 
63
75
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -90,12 +102,58 @@ Implementa `ControlValueAccessor`.
90
102
 
91
103
  ## Trampas
92
104
 
93
- - **Los defaults están pensados para la story**: `placeholder` «Placeholder text...» y
105
+ - **Los defaults están pensados para la story**: `placeholder` «Escribe aquí…» y
94
106
  `leftIcon` `user-3-line`. Pasa los dos siempre.
95
107
  - `error` no trae mensaje: decir qué falta en otro lado (toast o hint cercano).
96
108
  - Cancelar restaura el texto de antes; `(confirm)` es el único momento de guardar.
97
109
  - Ocupa todo el ancho de su contenedor.
98
110
 
111
+ ## Bien y mal
112
+
113
+ Alias de una dirección
114
+
115
+ ```html
116
+ <!-- ❌ mal: con los defaults, vacío dice «Escribe aquí…» y el ícono es una persona (user-3-line) -->
117
+ <sui-inline-input [(value)]="alias" (confirm)="guardarAlias($event)" />
118
+ ```
119
+
120
+ ```html
121
+ <!-- ✅ bien -->
122
+ <sui-inline-input [(value)]="alias" placeholder="Sin alias" leftIcon="map-pin-line"
123
+ editLabel="Editar alias" (confirm)="guardarAlias($event)" />
124
+ ```
125
+
126
+ Formulario reactivo
127
+
128
+ ```html
129
+ <!-- ❌ mal: dos dueños del mismo valor; [(value)] y formControlName se pisan -->
130
+ <sui-inline-input formControlName="nombre" [(value)]="nombre" placeholder="Sin nombre" />
131
+ ```
132
+
133
+ ```html
134
+ <!-- ✅ bien -->
135
+ <sui-inline-input formControlName="nombre" placeholder="Sin nombre" leftIcon="price-tag-3-line"
136
+ editLabel="Editar nombre" (confirm)="renombrar($event)" />
137
+ ```
138
+
139
+ Renombrar en una pantalla táctil
140
+
141
+ ```html
142
+ <!-- ❌ mal: con bp.isMobile() la tablet táctil se queda con el lápiz, el ✓ y el ✕ de 24 px -->
143
+ @if (!bp.isMobile()) {
144
+ <sui-inline-input [(value)]="nombreCategoria" placeholder="Sin nombre" leftIcon="price-tag-3-line" />
145
+ }
146
+ ```
147
+
148
+ ```html
149
+ <!-- ✅ bien (el sui-input va dentro de un sui-modal) -->
150
+ @if (bp.tactil()) {
151
+ <sui-input label="Nombre de la categoría" [size]="bp.sizeControl()" [(value)]="nombreCategoria" />
152
+ } @else {
153
+ <sui-inline-input [(value)]="nombreCategoria" placeholder="Sin nombre" leftIcon="price-tag-3-line" />
154
+ }
155
+ ```
156
+
99
157
  ## Ejemplo
100
158
 
101
159
  ```html
@@ -50,12 +50,26 @@ entera.
50
50
 
51
51
  | uso | mobile | web | fuente |
52
52
  |---|---|---|---|
53
- | dentro de una frase | evitar: usar `sui-select` | 20 px, en línea con el texto | propuesta, falta aprobación |
54
- | al final de un `sui-input` | el alto lo da el input (`large`) | el alto lo da el input (`medium`) | propuesta, falta aprobación |
53
+ | dentro de una frase | evitar: usar `sui-select` | 20 px, en línea con el texto | canon (aprobado por el dueño, 05-10-2026, bloque B7) |
54
+ | al final de un `sui-input` | el alto lo da el input (`large`) | el alto lo da el input (`medium`) | mobile (input `large`): canon (decisión del dueño 04-10-2026, piso táctil 44; ver `sui-input`) · web (input `medium`): canon (aprobado por el dueño, 05-10-2026, bloque B1) |
55
55
 
56
56
  Las opciones del menú miden **36 px también en mobile**: a diferencia de `sui-select` y de los
57
57
  compactos, este no tiene la regla de 44 en ≤ 767 px (`sui-inline-select.scss` no la trae).
58
58
 
59
+ ### Por dispositivo (D16)
60
+
61
+ **No tiene `size`**: mide 20 px (la línea del texto) en cualquier pantalla, así que no hay escala
62
+ que repartir por dispositivo. D16 (dueño, 05-10-2026) se aplica según dónde va:
63
+
64
+ - **Al final de un `sui-input`**: el alto lo pone el input, que sigue su fila D16 (`large` en el
65
+ celular chico, el celular y la tablet táctil; `medium` en la computadora y el ultrawide).
66
+ - **Dentro de una frase**: solo en la computadora (y el ultrawide). En toda pantalla táctil
67
+ (celular chico, celular y tablet con `pointer: coarse`) la palabra de 20 px no llega a 44: va un
68
+ `sui-select`. La condición es `bp.tactil()`, no `bp.isMobile()`, para que el iPad también cambie.
69
+
70
+ En master-pedidos: el `sui-input` que lo contiene con `[size]="bp.sizeControl()"`; en una frase,
71
+ `@if (bp.tactil())` → `sui-select` con `[size]="bp.sizeControl()"`.
72
+
59
73
  ## «No usar»: por qué no hoy y cuándo sí
60
74
 
61
75
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -95,6 +109,52 @@ Implementa `ControlValueAccessor`.
95
109
  - No mezclar `[(selected)]` con `formControlName`.
96
110
  - El menú mide al menos 200 px aunque el texto sea corto.
97
111
 
112
+ ## Bien y mal
113
+
114
+ Unidad al final de un campo
115
+
116
+ ```html
117
+ <!-- ❌ mal: sin [trailingControl] el slot es un ícono de 20 × 20 con pointer-events: none y el selector no responde -->
118
+ <sui-input label="Peso" type="number" [size]="bp.sizeControl()" [(value)]="peso">
119
+ <sui-inline-select data-slot="end" icon="ruler-line" [items]="unidades" [(selected)]="unidad" />
120
+ </sui-input>
121
+ ```
122
+
123
+ ```html
124
+ <!-- ✅ bien -->
125
+ <sui-input label="Peso" type="number" [size]="bp.sizeControl()" [trailingControl]="true" [(value)]="peso">
126
+ <sui-inline-select data-slot="end" icon="ruler-line" [items]="unidades" [(selected)]="unidad" />
127
+ </sui-input>
128
+ ```
129
+
130
+ Formulario reactivo
131
+
132
+ ```html
133
+ <!-- ❌ mal: dos dueños del mismo valor; [(selected)] y formControlName se pisan -->
134
+ <sui-inline-select formControlName="periodo" [items]="periodos" [(selected)]="periodo" />
135
+ ```
136
+
137
+ ```html
138
+ <!-- ✅ bien -->
139
+ <sui-inline-select formControlName="periodo" icon="calendar-line" [items]="periodos" />
140
+ ```
141
+
142
+ Frase en una pantalla táctil
143
+
144
+ ```html
145
+ <!-- ❌ mal: en el celular y la tablet táctil se toca una palabra de 20 px de alto -->
146
+ <p>Mostrar ventas de <sui-inline-select icon="calendar-line" [items]="periodos" [(selected)]="periodo" /></p>
147
+ ```
148
+
149
+ ```html
150
+ <!-- ✅ bien -->
151
+ @if (bp.tactil()) {
152
+ <sui-select label="Periodo" [options]="opcionesPeriodo" [size]="bp.sizeControl()" [(value)]="periodoId" />
153
+ } @else {
154
+ <p>Mostrar ventas de <sui-inline-select icon="calendar-line" [items]="periodos" [(selected)]="periodo" /></p>
155
+ }
156
+ ```
157
+
98
158
  ## Ejemplo
99
159
 
100
160
  ```html
@@ -33,13 +33,16 @@ Regla corta: **una línea → input · varias → textarea · de una lista → s
33
33
  > escribir un valor de una sola línea y muestra ejemplos (ícono, tamaños, afijos, label y hint,
34
34
  > contraseña con ojo, contraseña con niveles, error, con botón, tarjeta, con select, con tags,
35
35
  > fecha y contador) sin do/don't. Lo marcado «según la guía del DS» sale de esos ejemplos; el
36
- > resto es **propuesta, falta aprobación**, salvo lo que ya es canon (CLAUDE.md, CANON-SUI).
36
+ > resto es canon (CLAUDE.md, CANON-SUI o aprobado por el dueño el 05-10-2026); lo que sigue en **propuesta** espera decisión.
37
37
  >
38
- > Uso medido el 04-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`, más
39
- > `master-ejercicios`): **195 usos en 61 archivos**. Tipos: 42 `text`, 36 sin `type` (`text`),
40
- > 34 `amount`, 21 `search`, 21 `number`, 18 `tel`, 10 `email`, 7 `date`, 3 `password-toggle`,
41
- > 2 `url`, 1 `datetime-local`. Tamaños: 88 `bp.isMobile() ? 'large' : 'medium'`, 77 sin `size`
42
- > (`medium`), 18 `large`, 3 `xlarge`, 3 `medium`, 1 `small`, 3 `bp.controlSize()`, 2 otros dinámicos.
38
+ > Uso medido el 06-10-2026 en `master-pedidos/src/app` @ `9f0e54c3` (misma exclusión que
39
+ > `sui-badge`, más `master-ejercicios`): **200 usos en 66 archivos** — 196 en 63 `.html` y 4 en
40
+ > templates inline de 3 `.ts` (`components/option-image/option-image.ts`, `pages/dx/modal-test/modal-test.ts`,
41
+ > `pages/dx/sandbox/sandbox.ts`). Tipos: 45 `text`, 35 sin `type` (`text`), 35 `amount`,
42
+ > 22 `search`, 22 `tel`, 18 `number`, 10 `email`, 7 `date`, 3 `password-toggle`, 2 `url`,
43
+ > 1 `datetime-local`. Tamaños, tras la migración a D16: 195 `bp.sizeControl()` (191 en `.html`
44
+ > y los 4 inline), 3 `xlarge` (los buscadores principales del cliente), 1 `bp.controlSize()` y
45
+ > 1 dinámico propio (`components/product-detail-view/product-detail-view.html:223`). Ninguno sin `size`.
43
46
 
44
47
  ### `type` — qué dato es
45
48
 
@@ -52,10 +55,10 @@ El `type` decide el teclado del teléfono y el filtro de teclas. Por dentro, `nu
52
55
  | `email` | Correo. Pide el teclado con `@`. Va con `autocomplete="email"`. | según la guía del DS (ejemplo con label y hint) |
53
56
  | `tel` | Celular peruano de 9 dígitos, con `[maxlength]="9"` y placeholder `987 654 321`. | según la guía del DS (tipo nativo); el formato es propuesta |
54
57
  | `amount` | **Todo monto en soles**, siempre con `prefix="S/"` y placeholder `0.00`. Pone comas de miles y dos decimales al salir. | canon (CANON-SUI §5.5, 27-07-2026) |
55
- | `number` | Un entero que no es dinero: minutos, kilómetros, cupos, porcentaje. Si es dinero, `amount`. | propuesta, falta aprobación |
58
+ | `number` | Un entero que no es dinero: minutos, kilómetros, cupos, porcentaje. Si es dinero, `amount`. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
56
59
  | `search` | **Todo buscador.** Pide la lupa en el teclado sola (y no lleva `inputmode`). | canon (CLAUDE.md «La lupa del teclado», 14-08-2026) |
57
60
  | `password-toggle` | **Toda contraseña**: login y registro. El ojo deja revisar lo escrito en el teléfono. | según la guía del DS (sus dos ejemplos de contraseña traen el ojo) |
58
- | `password` | No usar: sin ojo, en el teléfono no se puede revisar lo tipeado. | propuesta, falta aprobación |
61
+ | `password` | No usar: sin ojo, en el teléfono no se puede revisar lo tipeado. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
59
62
  | `date` / `datetime-local` | Una fecha suelta en un formulario del panel («Válido hasta», «Fecha del gasto»). Abre el selector nativo. Para un calendario propio, ver `sui-datepicker`. | propuesta, falta aprobación |
60
63
  | `url` | Un enlace (imagen de campaña). | según la guía del DS (ejemplo con afijo `https://`) |
61
64
  | `card` | No usar hoy: no hay pago con tarjeta. | según la guía del DS (ejemplo «Payment Input») |
@@ -74,21 +77,21 @@ El `type` decide el teclado del teléfono y el filtro de teclas. Por dentro, `nu
74
77
  | `sublabel` | **«(Opcional)»**, entre paréntesis, en un campo que no es obligatorio, en vez de escribir «(opcional)» en el label. También «(No editable)». El componente no pone los paréntesis: sin ellos queda pegado («ReferenciaOpcional»). | según la guía del DS (`(Optional)`) y canon (README de `sui-form-label`) |
75
78
  | `tooltip` | Una aclaración que no entra en el hint. Hoy sin uso. | según la guía del DS (ícono de info del label) |
76
79
  | `hint` | Una línea que ayuda a llenar bien: «9 dígitos, empezando con 9», «Mínimo 6 caracteres». | según la guía del DS |
77
- | `hintIcon` | No usar hoy: el hint se lee solo; el ícono suma ruido en formularios largos. | propuesta, falta aprobación |
80
+ | `hintIcon` | No usar hoy: el hint se lee solo; el ícono suma ruido en formularios largos. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
78
81
  | `error` + `errorMessage` | El error va **con** su mensaje, que reemplaza al hint. `error` solo pinta el borde. | según la guía del DS (`Has Error`) |
79
82
  | `placeholder` | Un ejemplo del formato, no el nombre del campo: «987 654 321», «Ej: Av. Perú 224», «0.00». Elipsis `…`, no `...`. | canon (CANON-SUI §5.2 y §5.5) |
80
83
  | `prefix` | `S/` en los montos. Nada más hoy. | canon (CANON-SUI §5.5) |
81
- | `icon` + `iconPosition` | `search-line` a la izquierda en buscadores; `map-pin-2-line` en un campo de dirección de solo lectura. `right` no tiene caso hoy. | según la guía del DS (ejemplo con ícono); el «cuándo» es propuesta |
84
+ | `icon` + `iconPosition` | `search-line` a la izquierda en buscadores; `map-pin-2-line` en un campo de dirección de solo lectura. `right` no tiene caso hoy. | según la guía del DS (ejemplo con ícono); el «cuándo»: canon (aprobado por el dueño, 05-10-2026, bloque B9) |
82
85
  | `showClear` | Buscadores: la X borra la búsqueda de un toque. | propuesta, falta aprobación (ya lo hacen los 3 buscadores del cliente) |
83
- | `fullRadius` | Solo el buscador principal del cliente (home, carta del local, rubro), que va encima de chips redondos. Los formularios, con el radio normal. | propuesta, falta aprobación (ya es práctica: `pages/customer/store-browser/store-browser.html:43`) |
86
+ | `fullRadius` | Solo el buscador principal del cliente (home, carta del local, rubro), que va encima de chips redondos. Los formularios, con el radio normal. | canon (aprobado por el dueño, 05-10-2026, bloque B9) (ya es práctica: `pages/customer/store-browser/store-browser.html:43`) |
84
87
  | `maxlength` | Teléfono (9), nombres con tope, códigos. | propuesta, falta aprobación |
85
88
  | `inputmode` | Solo cuando el `type` no pide el teclado correcto: un DNI o un número de cuenta en `type="text"` → `numeric`. **Nunca `search`.** | canon (CLAUDE.md «La lupa del teclado», 14-08-2026) |
86
89
  | `enterkeyhint` | `next` en formularios de varios pasos, `send` en un chat, `done` en el último campo. El buscador ya pide `search` solo. | propuesta, falta aprobación |
87
- | `autocomplete` | Siempre en datos de la persona: `name`, `given-name`, `email`, `tel`, `current-password`, `new-password`. `off` en buscadores. | propuesta, falta aprobación |
88
- | `readonly` | Un dato que se muestra en forma de campo pero se elige en otro lado (el distrito que sale del mapa). | propuesta, falta aprobación |
90
+ | `autocomplete` | Siempre en datos de la persona: `name`, `given-name`, `email`, `tel`, `current-password`, `new-password`. `off` en buscadores. | canon (aprobado por el dueño, 05-10-2026, bloque B5) |
91
+ | `readonly` | Un dato que se muestra en forma de campo pero se elige en otro lado (el distrito que sale del mapa). | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
89
92
  | `disabled` | Mientras se envía, o cuando el campo no aplica todavía. | según la guía del DS |
90
93
  | `min` / `max` | **No hacen nada** (el `<input>` real es `text`). Validar en el componente que lo usa. | código del DS |
91
- | `paste` | `false` solo si pegar un monto armaría un valor equivocado. Hoy sin uso. | propuesta, falta aprobación |
94
+ | `paste` | `false` solo si pegar un monto armaría un valor equivocado. Hoy sin uso. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
92
95
  | `closeOnOutsideClick` | Déjalo en `true`: tocar fuera baja el teclado. `false` solo si la pantalla maneja el foco a mano (1 uso). | código del DS |
93
96
  | `leadingControl` / `trailingControl` / `leadingDivider` / `trailingDivider` | Componer un control adentro: el país del teléfono (`sui-compact-select-for-input` en `[data-slot=start]`) o una acción al lado. Hoy sin uso. | según la guía del DS (ejemplos «With Select» y «With Button») |
94
97
 
@@ -114,23 +117,41 @@ teléfono también va en 16 en todos los tamaños (antes se quedaba en 14 al lad
114
117
 
115
118
  | uso | mobile | web | fuente |
116
119
  |---|---|---|---|
117
- | campo de formulario | `large` (48), igual que el botón del footer | `medium` (40) | propuesta, falta aprobación |
118
- | buscador principal del cliente (home, carta, rubro) | `xlarge` (52) + `fullRadius` | `xlarge` + `fullRadius` | propuesta (ya es práctica en las 3 pantallas) |
119
- | buscador o filtro de una lista del panel | `large` (48) | `small` (36) | propuesta (ya es práctica en `pages/orders/orders.html:72`) |
120
- | campo dentro de una tabla o fila densa | no aplica | `xsmall` (32) | según la guía del DS |
120
+ | campo de formulario | `large` (48), igual que el botón del footer | `medium` (40) | mobile `large`: canon (decisión del dueño 04-10-2026, piso táctil 44: `medium` 40 no llega y `large` 48 es el primer size que sí) · web `medium`: canon (aprobado por el dueño, 05-10-2026, bloque B1) |
121
+ | buscador principal del cliente (home, carta, rubro) | `xlarge` (52) + `fullRadius` | `xlarge` + `fullRadius` | canon (aprobado por el dueño, 05-10-2026, bloque B1) (ya es práctica en las 3 pantallas) |
122
+ | buscador o filtro de una lista del panel | `large` (48) | `medium` (40) | mobile `large`: canon (decisión del dueño 04-10-2026, piso táctil 44: `large` 48 es el primer size que llega) · web `medium`: canon (dueño, 05-10-2026, D16) (`pages/orders/orders.html:73` ya va con `bp.sizeControl()`; medido el 06-10-2026) |
123
+ | campo dentro de una tabla o fila densa | no aplica | `medium` (40) | canon (dueño, 05-10-2026, D16): nada en `xsmall` (la guía del DS lo usa ahí) |
121
124
 
122
125
  ```html
123
- <sui-input [size]="bp.isMobile() ? 'large' : 'medium'" label="Teléfono" type="tel" … />
126
+ <sui-input [size]="bp.sizeControl()" label="Teléfono" type="tel" … />
124
127
  <!-- bp = BreakpointsService de la app -->
125
128
  ```
126
129
 
127
- No uses `bp.controlSize()` en campos: da `xlarge` (52) en mobile, más alto que el botón `large`
128
- del footer (3 usos hoy: `pages/customer/checkout/checkout.html:269`, `:384`,
129
- `pages/super-admin/master-sonidos-push/master-sonidos-push.html:43`). El texto sube solo a 16 px
130
- en mobile (evita el zoom de iOS): no hace falta pedirlo.
130
+ No uses `bp.controlSize()` en campos: es el de checkbox/radio/switch, da `xlarge` (52) en mobile,
131
+ más alto que el botón `large` del footer, y `large` en la computadora (1 uso hoy:
132
+ `pages/customer/checkout/checkout.html:385`, el cupón). El texto sube solo a 16 px en mobile (evita
133
+ el zoom de iOS): no hace falta pedirlo.
131
134
 
132
- Hoy: **88 usos** ya van con `bp.isMobile() ? 'large' : 'medium'`; **77 sin `size`** quedan en 40 px
133
- también en el teléfono (no alinea con el botón `large`).
135
+ Hoy (medido el 06-10-2026): **195 de los 200 usos** ya van con `bp.sizeControl()` (191 en `.html` y
136
+ 4 en templates inline de `.ts`); quedan los 3 buscadores principales en `xlarge` fijo (van bien), el cupón con `bp.controlSize()` y un dinámico propio.
137
+
138
+ ### Por dispositivo (D16)
139
+
140
+ Fila `input` de la tabla D16 (dueño, 05-10-2026). Se toca, así que va por tipo de puntero además
141
+ del ancho, igual que `sui-button`: campo y botón de al lado miden lo mismo en cada dispositivo.
142
+
143
+ | dispositivo | size | nota |
144
+ |---|---|---|
145
+ | 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) |
146
+ | celular (380–767 px) | `large` (48) | mismo alto que el botón `large` del footer |
147
+ | tablet táctil (`pointer: coarse`) | `large` (48) | también se toca con el dedo; `bp.isMobile()` la dejaba en `medium` |
148
+ | computadora (`pointer: fine`) | `medium` (40) | también filtros y campos dentro de tablas; `small` y `xsmall` no se usan |
149
+
150
+ Buscador principal del cliente (home, carta, rubro): `xlarge` (52) + `fullRadius` en todos los
151
+ dispositivos (B1). Ultrawide (≥ 1920 px): igual que la computadora, `medium`; el espacio extra va a
152
+ ancho y columnas, no a campos más altos.
153
+
154
+ En master-pedidos: `[size]="bp.sizeControl()"` · buscador principal: `size="xlarge"` + `[fullRadius]="true"`.
134
155
 
135
156
  ## «No usar»: por qué no hoy y cuándo sí
136
157
 
@@ -148,7 +169,7 @@ en la columna de la derecha, se usa.
148
169
  | `iconPosition="right"` | el ícono de la derecha se confunde con una acción | un dato con unidad visual (un ícono de moto en «Placa») |
149
170
  | `paste=false` | pegar ayuda más de lo que rompe | un monto que llega con formato raro desde otra app |
150
171
  | afijos con control (`leadingControl`…) | solo hay teléfonos de Perú (+51) | teléfono con código de país, o monto con moneda (ver `sui-compact-select-for-input`) |
151
- | `size="xsmall"` | no hay campos dentro de tablas | edición rápida de un precio dentro de una tabla del panel |
172
+ | `size="xsmall"` | es chico (D16, 05-10-2026) | nunca: la edición rápida de un precio dentro de una tabla va `medium` |
152
173
 
153
174
  ## API
154
175
 
@@ -221,13 +242,55 @@ proyectados con `leadingControl` / `trailingControl`).
221
242
  - En el teléfono la X de limpiar y el ojo se ven de 12-20 px pero se tocan en 44 × 44 (área
222
243
  invisible, 04-10-2026).
223
244
 
245
+ ## Bien y mal
246
+
247
+ Tamaño del campo del cupón
248
+
249
+ ```html
250
+ <!-- ❌ mal: bp.controlSize() es de checkbox/radio/switch: xlarge en el celular y large en la computadora (pages/customer/checkout/checkout.html:385) -->
251
+ <sui-input [size]="bp.controlSize()" placeholder="Código de descuento" [(value)]="cupon" />
252
+ ```
253
+
254
+ ```html
255
+ <!-- ✅ bien (y el botón «Aplicar» de al lado, también con bp.sizeControl()) -->
256
+ <sui-input [size]="bp.sizeControl()" placeholder="Código de descuento" [(value)]="cupon" />
257
+ ```
258
+
259
+ DNI con el label afuera
260
+
261
+ ```html
262
+ <!-- ❌ mal: el label suelto no conoce el id del campo (su for no apunta a nada) y el DNI no es un número (pages/driver-onboarding/step-info/step-info.html:56 y :60) -->
263
+ <sui-form-label label="DNI" [required]="true" for="ob-dni" />
264
+ <sui-input [size]="bp.sizeControl()" type="number" inputmode="numeric" placeholder="74523618"
265
+ [maxlength]="8" [(value)]="dni" />
266
+ ```
267
+
268
+ ```html
269
+ <!-- ✅ bien -->
270
+ <sui-input label="DNI" [required]="true" type="text" inputmode="numeric" placeholder="74523618"
271
+ [maxlength]="8" hint="8 dígitos" [size]="bp.sizeControl()" [(value)]="dni" />
272
+ ```
273
+
274
+ Teléfono con espacios en el placeholder
275
+
276
+ ```html
277
+ <!-- ❌ mal: con [maxlength]="9", quien copia los espacios del placeholder llega al tope antes del último dígito (pages/mi-negocio/mi-negocio.html:689) -->
278
+ <sui-input [size]="bp.sizeControl()" type="tel" placeholder="987 654 321" [maxlength]="9" [(value)]="telefono" />
279
+ ```
280
+
281
+ ```html
282
+ <!-- ✅ bien -->
283
+ <sui-input label="Teléfono" type="tel" [maxlength]="9" autocomplete="tel" placeholder="987654321"
284
+ [size]="bp.sizeControl()" [(value)]="telefono" />
285
+ ```
286
+
224
287
  ## Ejemplo
225
288
 
226
289
  ```html
227
290
  <!-- Campo de formulario -->
228
291
  <sui-input label="Teléfono" [required]="true" type="tel" [maxlength]="9" autocomplete="tel"
229
292
  placeholder="987654321" hint="9 dígitos, empezando con 9"
230
- [size]="bp.isMobile() ? 'large' : 'medium'" [(value)]="telefono" />
293
+ [size]="bp.sizeControl()" [(value)]="telefono" />
231
294
 
232
295
  <!-- Monto -->
233
296
  <sui-input label="Monto de la compra" type="amount" prefix="S/" placeholder="0.00" [(value)]="monto" />
@@ -38,26 +38,26 @@ Regla corta: **servicio externo que se prende y se configura → integration-swi
38
38
 
39
39
  | combinación | cuándo | fuente |
40
40
  |---|---|---|
41
- | `horizontal` · `card` (default) | Una integración suelta en una pantalla de ajustes de web. | propuesta |
42
- | `vertical` · `card` | Una grilla de integraciones, o la misma en mobile (el «Administrar» baja a ancho completo). | propuesta |
43
- | `horizontal` · `list` | Una lista de integraciones dentro de una card que ya pone el borde. | propuesta |
44
- | `vertical` · `list` | Ver «No usar». | propuesta |
41
+ | `horizontal` · `card` (default) | Una integración suelta en una pantalla de ajustes de web. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
42
+ | `vertical` · `card` | Una grilla de integraciones, o la misma en mobile (el «Administrar» baja a ancho completo). | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
43
+ | `horizontal` · `list` | Una lista de integraciones dentro de una card que ya pone el borde. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
44
+ | `vertical` · `list` | Ver «No usar». | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
45
45
 
46
46
  ### Las piezas
47
47
 
48
48
  | prop | cuándo | fuente |
49
49
  |---|---|---|
50
- | `title` | Siempre. El nombre del servicio: «WhatsApp Business». | propuesta |
51
- | `description` | Qué hace conectarlo, en una línea: «Avisa al cliente por WhatsApp cuando su pedido sale del local.» | propuesta |
52
- | `brandIconSrc` | El logo del servicio (`assets/brand/brand-logos/<marca>-original.svg`). | propuesta |
53
- | `brandIcon` | Un ícono Remix cuando no hay logo. | propuesta |
54
- | logo proyectado `[sui-integration-brand]` | Un `sui-brand-logo` u otro elemento propio. | propuesta |
55
- | `manage` (`true`, dice «Administrar») | Siempre que el servicio tenga configuración. El default ya está en español (03-10-2026). | propuesta |
56
- | `[manage]="false"` | El servicio no se configura: solo se prende. | propuesta |
57
- | `showToggle=false` | Se administra pero no se apaga desde aquí. | propuesta |
58
- | `badge` | Integración nueva. Con string sale naranja `light`; pasa el objeto (`purple` para lo nuevo, según el badge). | propuesta |
59
- | `disabled` | Falta un dato para conectarla (el RUC, la cuenta). | propuesta |
60
- | `[active]` + `(activeChange)` | El estado. | propuesta |
50
+ | `title` | Siempre. El nombre del servicio: «WhatsApp Business». | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
51
+ | `description` | Qué hace conectarlo, en una línea: «Avisa al cliente por WhatsApp cuando su pedido sale del local.» | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
52
+ | `brandIconSrc` | El logo del servicio (`assets/brand/brand-logos/<marca>-original.svg`). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
53
+ | `brandIcon` | Un ícono Remix cuando no hay logo. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
54
+ | logo proyectado `[sui-integration-brand]` | Un `sui-brand-logo` u otro elemento propio. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
55
+ | `manage` (`true`, dice «Administrar») | Siempre que el servicio tenga configuración. El default ya está en español (03-10-2026). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
56
+ | `[manage]="false"` | El servicio no se configura: solo se prende. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
57
+ | `showToggle=false` | Se administra pero no se apaga desde aquí. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
58
+ | `badge` | Integración nueva. Con string sale naranja `light`; pasa el objeto (`purple` para lo nuevo, según el badge). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
59
+ | `disabled` | Falta un dato para conectarla (el RUC, la cuenta). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
60
+ | `[active]` + `(activeChange)` | El estado. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
61
61
 
62
62
  **Usos de hoy que rompen las reglas:** 0 (no hay usos).
63
63
 
@@ -74,7 +74,7 @@ Regla corta: **servicio externo que se prende y se configura → integration-swi
74
74
  | layout | `vertical` | `horizontal` |
75
75
 
76
76
  ```html
77
- <sui-integration-switch [size]="bp.isMobile() ? 'large' : 'medium'"
77
+ <sui-integration-switch [size]="bp.sizeControl()"
78
78
  [type]="bp.isMobile() ? 'vertical' : 'horizontal'" … />
79
79
  ```
80
80
 
@@ -82,11 +82,33 @@ Regla corta: **servicio externo que se prende y se configura → integration-swi
82
82
  y a diferencia de `sui-switch-card`, tocar la tarjeta no prende nada: solo responde el
83
83
  interruptor. Para algo que se prende y apaga en el teléfono, `sui-switch-card` es la salida.
84
84
 
85
+ ### Por dispositivo (D16)
86
+
87
+ No está en la tabla D16 por componente: va como **lo que se toca**, porque el `size` solo agranda
88
+ «Administrar», que es un botón. Fuente: D16, dueño 05-10-2026.
89
+
90
+ | dispositivo | size | nota |
91
+ |---|---|---|
92
+ | celular chico (< 380) | `large` (44) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino) |
93
+ | celular (380–767) | `large` (44) | |
94
+ | tablet táctil (`pointer: coarse`) | `large` (44) | también se toca con el dedo: Apple pide 44 pt en el iPad |
95
+ | computadora (`pointer: fine`) | `medium` (38) | nunca más chico |
96
+
97
+ En el ultrawide, igual que en la computadora: el espacio extra va a más columnas, no a un
98
+ «Administrar» más grande.
99
+
100
+ D16 no alcanza al interruptor: es `sui-switch` `medium` fijo dentro del componente, aunque los
101
+ switches sueltos vayan en `xlarge`/`large`. El badge interno arranca en `small`: pásalo como objeto
102
+ con `size: bp.sizeBadge()`.
103
+
104
+ En master-pedidos: `[size]="bp.sizeControl()"`. El `type` sigue por ancho
105
+ (`bp.isMobile() ? 'vertical' : 'horizontal'`): es layout, no tamaño.
106
+
85
107
  ## «No usar»: por qué no hoy y cuándo sí
86
108
 
87
109
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
88
110
  |---|---|---|
89
- | todo el componente (0 usos) | no hay integraciones; además le falta tamaño para mobile | conectar Culqi / Izipay o WhatsApp Business desde el panel del local (web primero) |
111
+ | todo el componente (0 usos) | no hay integraciones (el tamaño para mobile ya existe: `large`, 04-10-2026) | conectar Culqi / Izipay o WhatsApp Business desde el panel del local (web primero) |
90
112
  | `vertical` · `list` | sin borde y en columna, el bloque se pierde | casi nunca: una sola integración destacada en una pantalla vacía |
91
113
 
92
114
  ## API
@@ -135,6 +157,51 @@ Slot: `[sui-integration-brand]` (reemplaza al logo). Implementa `ControlValueAcc
135
157
  El interruptor toma su nombre de ese título (y su descripción de `description`) con
136
158
  `aria-labelledby` (revisión 04-10-2026); antes el lector decía solo «interruptor».
137
159
 
160
+ ## Bien y mal
161
+
162
+ La app no tiene usos todavía: los pares salen de «Cuándo usarlo» y de «Trampas».
163
+
164
+ Un ajuste propio de la app
165
+
166
+ ```html
167
+ <!-- ❌ mal: avisar de pedidos nuevos es un ajuste de la app, no un servicio externo -->
168
+ <sui-integration-switch title="Notificaciones" brandIcon="notification-3-line"
169
+ [manage]="false" [active]="avisos()" (activeChange)="avisos.set($event)" />
170
+ ```
171
+
172
+ ```html
173
+ <!-- ✅ bien -->
174
+ <sui-switch-card label="Notificaciones" [size]="bp.controlSize()"
175
+ [checked]="avisos()" (checkedChange)="avisos.set($event)" />
176
+ ```
177
+
178
+ Servicio que solo se prende
179
+
180
+ ```html
181
+ <!-- ❌ mal: manage arranca en true y pinta «Administrar» aunque no haya nada que configurar -->
182
+ <sui-integration-switch title="Mapbox" brandIcon="map-2-line" [size]="bp.sizeControl()"
183
+ [active]="mapbox()" (activeChange)="mapbox.set($event)" />
184
+ ```
185
+
186
+ ```html
187
+ <!-- ✅ bien -->
188
+ <sui-integration-switch title="Mapbox" brandIcon="map-2-line" [manage]="false"
189
+ [active]="mapbox()" (activeChange)="mapbox.set($event)" />
190
+ ```
191
+
192
+ Integración nueva
193
+
194
+ ```html
195
+ <!-- ❌ mal: el string sale naranja light y en small, que D16 no usa -->
196
+ <sui-integration-switch title="Culqi" brandIcon="bank-card-line" badge="Nuevo" … />
197
+ ```
198
+
199
+ ```html
200
+ <!-- ✅ bien -->
201
+ <sui-integration-switch title="Culqi" brandIcon="bank-card-line" [size]="bp.sizeControl()"
202
+ [badge]="{ label: 'Nuevo', color: 'purple', size: bp.sizeBadge() }" … />
203
+ ```
204
+
138
205
  ## Ejemplo
139
206
 
140
207
  ```html
@@ -23,7 +23,7 @@ cerrar, las flechas y el enter al pie de un menú.
23
23
 
24
24
  > **La guía del DS tiene una sola variante** (la tecla con texto) y la muestra dentro del
25
25
  > buscador del command menu. Lo marcado «según la guía del DS» sale de ahí; el resto es
26
- > **propuesta, falta aprobación**.
26
+ > **canon (aprobado por el dueño, 05-10-2026)**.
27
27
  >
28
28
  > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usan por dentro
29
29
  > `sui-command-menu-search`, `sui-command-menu-item`, `sui-command-menu-footer`, `sui-filter`,
@@ -40,26 +40,50 @@ cerrar, las flechas y el enter al pie de un menú.
40
40
  | valor | cuándo | fuente |
41
41
  |---|---|---|
42
42
  | `default` | Tecla con texto: ⌘K, Esc. | según la guía del DS |
43
- | `subtle` | Tecla con un ícono de 16 px (flechas, enter) al pie de un menú. Extensión de SUI (sale del Figma del command menu). | propuesta |
43
+ | `subtle` | Tecla con un ícono de 16 px (flechas, enter) al pie de un menú. Extensión de SUI (sale del Figma del command menu). | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
44
44
 
45
45
  Usos de hoy que rompen la regla: **0**.
46
46
 
47
47
  ## Tamaño en mobile y en web
48
48
 
49
- No es táctil: es una tecla dibujada. En mobile no hay teclado físico, así que no se muestra; en
50
- web tiene un solo tamaño. Donde la pantalla existe en los dos (panel del local, super admin) se
51
- oculta con el servicio de breakpoints de la app (`bp`, en `services/breakpoints.service.ts`). Todo
52
- es **propuesta**.
49
+ No es táctil: es una tecla dibujada. Donde se usa con el dedo no hay teclado físico, así que no se
50
+ muestra; con mouse tiene un solo tamaño. Donde la pantalla existe en los dos (panel del local,
51
+ super admin) se oculta con el servicio de breakpoints de la app (`bp`, en
52
+ `services/breakpoints.service.ts`). Que no vaya en mobile es **canon (aprobado por el dueño,
53
+ 05-10-2026, bloque B7)**; que la tablet táctil cuente como mobile sale de D16 (ver abajo).
53
54
 
54
- | uso | mobile | web |
55
+ | uso | mobile (celular y tablet táctil) | web (computadora) |
55
56
  |---|---|---|
56
57
  | atajo de teclado | no se muestra | tamaño único (20 px de alto) |
57
58
 
58
59
  ```html
59
- @if (!bp.isMobile()) { <sui-kbd>⌘K</sui-kbd> }
60
+ @if (!bp.tactil()) { <sui-kbd>⌘K</sui-kbd> }
60
61
  ```
61
62
 
62
- No tiene tamaños: en mobile no hay teclado físico, así que no se pinta.
63
+ No tiene tamaños: con el dedo no hay teclas, así que no se pinta.
64
+
65
+ ### Por dispositivo (D16)
66
+
67
+ El tamaño no aplica: `sui-kbd` no tiene `size` (20 px fijo). Lo que depende del dispositivo es
68
+ **si se muestra**, y eso no va por ancho sino por puntero, como D16: el iPad (768–1024 px,
69
+ `pointer: coarse`) da `bp.isMobile()` falso, y con `!bp.isMobile()` el ⌘K saldría en una pantalla
70
+ sin teclas.
71
+
72
+ | dispositivo | se muestra | nota |
73
+ |---|---|---|
74
+ | celular chico (< 380) | no | con el dedo no hay teclas |
75
+ | celular (380–767) | no | |
76
+ | tablet táctil (`pointer: coarse`) | no | misma razón que el celular: se usa con el dedo |
77
+ | computadora (`pointer: fine`) | sí, 20 px | |
78
+ | ultrawide | sí, 20 px | igual que la computadora |
79
+
80
+ **Pendiente**: el iPad con teclado físico. Con un teclado conectado los atajos sí funcionan, pero
81
+ la pantalla sigue siendo táctil y ni el ancho ni el puntero dicen si hay un teclado conectado;
82
+ falta que el dueño decida si se muestra ahí. Hasta entonces va oculto, que es el lado seguro: un atajo que falta no confunde, uno
83
+ que no se puede apretar sí.
84
+
85
+ En master-pedidos: `@if (!bp.tactil()) { <sui-kbd>⌘K</sui-kbd> }` (`tactil` = celular por ancho
86
+ o cualquier pantalla `pointer: coarse`). No uses `!bp.isMobile()`: deja pasar la tablet.
63
87
 
64
88
  ## «No usar»: por qué no hoy y cuándo sí
65
89
 
@@ -88,6 +112,46 @@ Slot: `<ng-content>` (el texto o el `sui-icon`).
88
112
  - El ícono de adentro va a 16 px y toma `text-sub-600` aunque le pongas otro color.
89
113
  - Mide 20 px de alto fijo: no crece con el texto de al lado.
90
114
 
115
+ ## Bien y mal
116
+
117
+ La app no lo usa directo: los pares salen de «Cuándo usarlo» y de «Trampas».
118
+
119
+ Flecha al pie de un menú
120
+
121
+ ```html
122
+ <!-- ❌ mal: subtle no se elige solo al poner un ícono; sale con el fondo blanco del texto -->
123
+ <sui-kbd><sui-icon name="arrow-up-line" [size]="16" /></sui-kbd>
124
+ ```
125
+
126
+ ```html
127
+ <!-- ✅ bien -->
128
+ <sui-kbd variant="subtle"><sui-icon name="arrow-up-line" [size]="16" /></sui-kbd>
129
+ ```
130
+
131
+ Atajo en una pantalla que también se ve en el celular
132
+
133
+ ```html
134
+ <!-- ❌ mal: con el dedo no hay teclas; con !bp.isMobile() el ⌘K igual sale en el iPad (768–1024, táctil) -->
135
+ @if (!bp.isMobile()) { <sui-kbd>⌘K</sui-kbd> }
136
+ ```
137
+
138
+ ```html
139
+ <!-- ✅ bien -->
140
+ @if (!bp.tactil()) { <sui-kbd>⌘K</sui-kbd> }
141
+ ```
142
+
143
+ Una etiqueta que no es una tecla
144
+
145
+ ```html
146
+ <!-- ❌ mal: no es un atajo; además sale en MAYÚSCULAS -->
147
+ <sui-kbd>Nuevo</sui-kbd>
148
+ ```
149
+
150
+ ```html
151
+ <!-- ✅ bien -->
152
+ <sui-badge color="purple" [size]="bp.sizeBadge()">Nuevo</sui-badge>
153
+ ```
154
+
91
155
  ## Ejemplo
92
156
 
93
157
  ```html