@ajuarezso/sui-design-system 0.20.0 → 0.21.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 (59) hide show
  1. package/docs/INDEX.md +51 -51
  2. package/docs/sui-alert/README.md +13 -0
  3. package/docs/sui-badge/README.md +17 -0
  4. package/docs/sui-banner/README.md +190 -0
  5. package/docs/sui-breadcrumb-item/README.md +96 -0
  6. package/docs/sui-breadcrumbs/README.md +122 -0
  7. package/docs/sui-button/README.md +17 -0
  8. package/docs/sui-card/README.md +168 -0
  9. package/docs/sui-chart-legend/README.md +140 -0
  10. package/docs/sui-chart-legend-dot/README.md +118 -0
  11. package/docs/sui-checkbox-card/README.md +150 -0
  12. package/docs/sui-compact-select/README.md +127 -0
  13. package/docs/sui-compact-select-for-input/README.md +117 -0
  14. package/docs/sui-content-card/README.md +147 -0
  15. package/docs/sui-content-label/README.md +148 -0
  16. package/docs/sui-counter-input/README.md +145 -0
  17. package/docs/sui-date-selector/README.md +98 -0
  18. package/docs/sui-datepicker/README.md +193 -0
  19. package/docs/sui-day-cell/README.md +118 -0
  20. package/docs/sui-day-label/README.md +81 -0
  21. package/docs/sui-drawer-footer/README.md +127 -0
  22. package/docs/sui-drawer-header/README.md +140 -0
  23. package/docs/sui-empty-state/README.md +145 -0
  24. package/docs/sui-file-upload/README.md +154 -0
  25. package/docs/sui-file-upload-card/README.md +129 -0
  26. package/docs/sui-image-upload/README.md +200 -0
  27. package/docs/sui-image-upload-profile/README.md +145 -0
  28. package/docs/sui-inline-input/README.md +104 -0
  29. package/docs/sui-inline-select/README.md +101 -0
  30. package/docs/sui-input/README.md +244 -0
  31. package/docs/sui-integration-switch/README.md +142 -0
  32. package/docs/sui-notification/README.md +179 -0
  33. package/docs/sui-notification-footer/README.md +98 -0
  34. package/docs/sui-notification-tab-menu/README.md +112 -0
  35. package/docs/sui-otp-input/README.md +116 -0
  36. package/docs/sui-pagination/README.md +146 -0
  37. package/docs/sui-password-strength/README.md +99 -0
  38. package/docs/sui-period-range/README.md +93 -0
  39. package/docs/sui-popover/README.md +178 -0
  40. package/docs/sui-product-card/README.md +173 -0
  41. package/docs/sui-radio-card/README.md +160 -0
  42. package/docs/sui-rating/README.md +7 -6
  43. package/docs/sui-rich-editor/README.md +114 -0
  44. package/docs/sui-select/README.md +180 -0
  45. package/docs/sui-stepper/README.md +166 -0
  46. package/docs/sui-store-card/README.md +147 -0
  47. package/docs/sui-switch-card/README.md +149 -0
  48. package/docs/sui-tab-chips/README.md +185 -0
  49. package/docs/sui-tab-menu-horizontal/README.md +142 -0
  50. package/docs/sui-tab-menu-vertical/README.md +136 -0
  51. package/docs/sui-tag-input/README.md +120 -0
  52. package/docs/sui-textarea/README.md +157 -0
  53. package/docs/sui-time-picker/README.md +237 -0
  54. package/docs/sui-toast/README.md +190 -0
  55. package/docs/sui-tooltip/README.md +201 -0
  56. package/fesm2022/ajuarezso-sui-design-system.mjs +273 -231
  57. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  58. package/package.json +1 -1
  59. package/types/ajuarezso-sui-design-system.d.ts +208 -52
@@ -0,0 +1,190 @@
1
+ ---
2
+ name: sui-toast
3
+ selector: sui-toast-outlet
4
+ resumen: Aviso efímero que confirma el resultado de una acción y se va solo; se dispara con SuiToastService
5
+ alternativas: [sui-alert (aviso que se queda, en su contexto), sui-banner (toda la app), sui-notification (fila de la bandeja, con hora), sui-form-hint (error de un campo)]
6
+ ---
7
+
8
+ # sui-toast
9
+
10
+ Story: [Molecules/Feedback/Toast](https://sui-design-system.web.app/?path=/docs/molecules-feedback-toast--docs)
11
+
12
+ No hay una etiqueta `<sui-toast>`: el toast son **dos piezas**. `SuiToastService` (se inyecta y se
13
+ llama: `toast.success(…)`) y `<sui-toast-outlet />`, que se monta **una sola vez** en la raíz de
14
+ la app y dibuja la pila. Cada toast es, por dentro, un `sui-alert` `size="large"`. El apilado, la
15
+ salida y los tiempos copian a Sonner (la librería de toasts que usa la guía del DS).
16
+
17
+ ## Cuándo usarlo / cuándo no
18
+
19
+ **Úsalo** para el **resultado de algo que la persona acaba de hacer** («Cambios guardados», «No
20
+ se pudo eliminar el producto») y para un aviso que **llega mientras usa la app** y no necesita
21
+ quedarse (un push con la app abierta, «Nueva versión disponible»). Aparece, se lee y se va.
22
+
23
+ **No lo uses** para:
24
+
25
+ - Algo que tiene que seguir visible para que la persona actúe: un error que bloquea, un motivo
26
+ de rechazo, un «no puedes eliminar tu cuenta porque…». Eso es `sui-alert`, ahí mismo. Un toast
27
+ con `duration: Infinity` y sin acción es un alert mal puesto.
28
+ - Un **error al cargar** una pantalla: el toast se va y deja la pantalla vacía sin explicación.
29
+ Va un `sui-alert` `filled` o un `sui-empty-state` con «Reintentar».
30
+ - El error de un campo de formulario: `sui-form-hint` o el `errorMessage` del input.
31
+ - Algo de toda la app que dura (plan vencido): `sui-banner`.
32
+
33
+ Regla corta (canon, la misma del alert): **contexto → alert · toda la app → banner · efímero →
34
+ toast · bandeja → notification.**
35
+
36
+ ## Qué variante usar
37
+
38
+ > La guía del DS define el toast pero no dice cuándo va cada tipo. Lo marcado «según la guía del
39
+ > DS» sale de su texto o de su código publicado; «canon» es lo ya aprobado (README de `sui-alert`,
40
+ > `docs/CANON-SUI.md` o un pedido del dueño escrito en el código); el resto es **propuesta**.
41
+ >
42
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (sin prototipos, vitrinas ni tests):
43
+ > **~700 llamadas en 106 archivos**; de ellas, **560 con título fijo** (en 102 archivos) — 348 `error`,
44
+ > 179 `success`, 23 `info`, 10 `warning`, 0 `feature` — más 3 `show()`. El resto arma el título con variables.
45
+
46
+ ### Lo que sí dice la guía del DS
47
+
48
+ - **Para qué es**: feedback **breve** en tamaño compacto; varios se pueden **apilar**.
49
+ - **Una línea**: lo arma con un alert `small` (título solo, sin descripción) de 360 px de ancho.
50
+ SUI lo arma con un alert `large`, que sí admite descripción.
51
+ - **Defaults**: relleno `stroke`, posición `bottom-center`, cerrable. SUI arranca en
52
+ `stroke-dark` y `bottom-right`.
53
+ - **Ojo con la palabra «notification»**: en la guía, una notification es un aviso temporal en una
54
+ esquina con título, descripción y acción (un pago, una actualización). En SUI ese caso **también
55
+ es un toast** (`description` + `action`); `sui-notification` es otra cosa: la fila de la bandeja.
56
+
57
+ ### El tipo — qué método llamar
58
+
59
+ | método | cuándo | ejemplo real de la app | fuente |
60
+ |---|---|---|---|
61
+ | `success()` | La acción salió como se esperaba. Dice **qué** quedó hecho. | `pages/sales-channels/instagram/instagram.ts:102` («Cambios guardados») | propuesta (sigue la regla canon del alert) |
62
+ | `error()` | La acción **no** salió. Dice qué no se pudo, nunca «Error al…» ni el mensaje técnico. | `pages/driver/driver-profile/driver-profile.ts:516` («No se pudo guardar el vehículo») | canon (copy: `docs/CANON-SUI.md` §5.7) |
63
+ | `warning()` | Salió, **pero** con un pero que la persona tiene que saber. | `pages/super-admin/master-promos/master-promos.ts:171` («Push enviada, pero ningún cliente está dentro del radio») | propuesta |
64
+ | `info()` | Algo que **llega** y no es el resultado de lo que hiciste: un push con la app abierta, una versión nueva. | `core/services/aviso-unico.service.ts:52` · `core/services/update.service.ts:59` | propuesta |
65
+ | `feature()` | No usar hoy (0 usos). **Cuándo sí:** avisar una función nueva en el momento en que se activa («Ya puedes programar tus pedidos»). | — | propuesta |
66
+ | `show({ variant })` | Lo mismo que los de arriba, cuando hace falta pasar todo junto. | `pages/empresa/about/about.ts:103` | según el componente |
67
+
68
+ ### `style` — el relleno
69
+
70
+ | style | cuándo | fuente |
71
+ |---|---|---|
72
+ | `stroke-dark` (default SUI) | **Siempre.** Flota sobre cualquier pantalla y el oscuro contrasta con todas. | canon (README de `sui-alert`: «default del toast») |
73
+ | `stroke` (default de la guía) | No usar hoy: blanco sobre blanco se confunde con el contenido. **Cuándo sí:** una pantalla de fondo oscuro (una landing), donde el oscuro se pierde. | propuesta |
74
+ | `lighter` · `light` · `filled` | No usar hoy: un toast que pesa más que el oscuro compite con el botón principal, y si tiene que pesar más, no es un toast. **Cuándo sí:** ninguno previsto; ese caso es un alert o un modal. | propuesta |
75
+
76
+ ### Tiempo, cierre, acción y texto
77
+
78
+ | opción | valor | cuándo | fuente |
79
+ |---|---|---|---|
80
+ | `duration` | `4000` (default) | Un título corto. | según el componente (valor de Sonner) |
81
+ | `duration` | `6000` | Título más `description`, o un título largo que no se alcanza a leer en 4 s. | propuesta |
82
+ | `duration` | `60_000` | Los avisos de un pedido que llegan con la app abierta: tiempo de verlos sin quedarse tapando. | canon (pedido del dueño, 28-09-2026, en `aviso-unico.service.ts`) |
83
+ | `duration` | `Infinity` | **Solo con `action`**: hay algo que hacer y no se puede perder («Actualizar»). Sin acción, es un alert. | propuesta |
84
+ | `dismissible` | `true` (default) | Siempre: la X permite quitarlo antes. La guía lo trae cerrable por defecto. | según la guía del DS |
85
+ | `dismissible` | `false` | No usar hoy. **Cuándo sí:** un toast de progreso que se reemplaza solo usando el mismo `id` («Subiendo foto…» → «Foto subida»). | propuesta (la guía muestra un ejemplo no cerrable) |
86
+ | `action` | `{ label, onClick, keepOpen? }` | **Una** acción corta que resuelve ahí mismo: «Actualizar», «Deshacer», «Reintentar». Se dibuja como link subrayado. | propuesta |
87
+ | `title` | frase corta | Qué pasó, en sentence case, **sin punto final**. Una idea. | canon (copy de la app) |
88
+ | `description` | segunda frase | Si hace falta una segunda frase, va aquí y no pegada al título con un punto. | propuesta |
89
+ | `position` | `bottom-right` (default) | Siempre. En mobile toda posición pasa a ancho completo; las `bottom-*` quedan abajo, por encima de la barra inferior. | propuesta |
90
+ | `position` | `top-*` | No usar hoy. **Cuándo sí:** una pantalla con una barra de acción fija abajo que el toast taparía. | propuesta |
91
+ | `position` | `bottom-left` · `bottom-center` | No usar hoy: dos esquinas abren dos pilas. **Cuándo sí:** si se decide cambiar la esquina de toda la app, con `setDefaultPosition()`, una sola vez. | propuesta |
92
+ | `id` | texto | Para reemplazar un toast en curso o no repetir el mismo aviso. | según el componente |
93
+
94
+ ### Usos de hoy que rompen la regla
95
+
96
+ - **Rompen el canon — 3 toasts de error que no se van y no tienen acción → `sui-alert`** en el
97
+ modal de eliminar cuenta: `pages/empresa/about/about.ts:103`, `pages/repartidor/about/about.ts:97`,
98
+ `pages/customer/about/about.ts:135` («No puedes eliminar tu cuenta» + el motivo, `duration: Infinity`).
99
+ - **Rompen el canon de copy — 104 errores que empiezan con «Error…»** («Error al cargar productos»)
100
+ → «No se pudo…»: `pages/products/products.ts:415`, `pages/customers/customers.ts:244`,
101
+ `pages/settings/team/team.ts:315`. Y **26** que concatenan `e.message` al texto (puede salir
102
+ texto técnico o en inglés).
103
+ - **Rompen el canon de copy — 5 títulos en minúscula:** `pages/driver/driver-profile/driver-profile.ts:538`
104
+ («ubicación activada»), `:552`, `:597`, `:614`, `pages/driver/driver-order-detail/driver-order-detail.ts:438`.
105
+ - **Romperían la propuesta — 47 errores al cargar como toast** → alert o empty state con
106
+ «Reintentar»: `pages/products/products.ts:415`, `pages/driver/driver-history/driver-history.ts:198`.
107
+ - **Romperían la propuesta — 126 títulos con punto final**, casi todos dos frases en una →
108
+ título + `description`: `components/map-picker-modal/map-picker-modal.ts:260` («Permiso denegado.
109
+ Usa la barra de búsqueda…»), `core/services/compartir-viaje.service.ts:78`. 62 pasan de 60
110
+ caracteres.
111
+
112
+ ## Tamaño en mobile y en web
113
+
114
+ El toast **no tiene `size`**: siempre es un alert `large`.
115
+
116
+ | uso | mobile (≤ 767 px) | web | fuente |
117
+ |---|---|---|---|
118
+ | ancho | todo el ancho, con margen lateral | hasta 360 px, en la esquina | según el componente |
119
+ | dónde | abajo, por encima de la barra inferior (nativa en iOS) | abajo a la derecha | según el componente |
120
+ | la X de cerrar | se ve de 20 px; **se toca en 40 × 40** | igual | canon (aprobado por el dueño, 03-10-2026): área táctil invisible, extensión SUI |
121
+ | la acción | link `medium` (20 px de alto) | link `medium` | según el componente |
122
+
123
+ No hay patrón `bp.isMobile()`: el outlet ya cambia solo por breakpoint. Lo que sí cambia por
124
+ plataforma es el largo del texto: en mobile el título envuelve antes, así que una sola idea por toast.
125
+
126
+ ## «No usar»: por qué no hoy y cuándo sí
127
+
128
+ Nada se borra del DS. Si un flujo nuevo cae en la columna de la derecha, se usa.
129
+
130
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
131
+ |---|---|---|
132
+ | `feature()` | no hay novedades que se anuncien al activarlas | «Ya puedes programar tus pedidos», justo cuando se activa |
133
+ | `style` `stroke` | blanco sobre blanco | una pantalla de fondo oscuro (landing) |
134
+ | `style` `lighter`, `light`, `filled` | un toast que pesa más ya no es un toast | ninguno previsto: es un alert o un modal |
135
+ | `dismissible: false` | todo toast se puede quitar | un toast de progreso que se reemplaza con el mismo `id` |
136
+ | `position` distinta de la default | dos pilas en dos esquinas | una pantalla con barra fija abajo (`top-*`), o mover toda la app con `setDefaultPosition()` |
137
+ | `duration: Infinity` sin `action` | no se va y no hay nada que hacer | ninguno: eso es un alert |
138
+
139
+ ## API
140
+
141
+ <!-- api:inicio -->
142
+ <!-- generada: no editar a mano — `npm run docs` -->
143
+
144
+ Inputs: ninguno.
145
+
146
+ Outputs: ninguno.
147
+ <!-- api:fin -->
148
+
149
+ ## Trampas
150
+
151
+ - **La X se toca en 40 × 40** aunque se vea de 20 (un `::before` invisible sobre su `<button>`,
152
+ desde 03-10-2026). Solo llega a la app cuando deje de usar su copia local del toast (ver abajo).
153
+ - **La app no usa el servicio del paquete.** `master-pedidos` tiene una copia local en
154
+ `src/app/components/sui/sui-toast/` y el outlet montado en `app.ts:66` es esa copia. La API es la
155
+ misma; la diferencia es que la copia lee la altura de la barra nativa desde `LiquidGlassService`,
156
+ y la del paquete desde el token `SUI_TAB_BAR`. Si inyectas `SuiToastService` del paquete en la
157
+ app, **no aparece nada**: su outlet no está montado. Migrar = importar del paquete y proveer
158
+ `SUI_TAB_BAR`.
159
+ - **El comentario de `style` miente:** dice `// default 'stroke'`, pero el código pone `'stroke-dark'`.
160
+ - **Sin outlet no hay toasts:** el temporizador de cierre vive en el outlet, no en el servicio. Si el
161
+ outlet no está montado, los toasts se acumulan en el signal y nunca se ven ni se van.
162
+ - `dismissible` arranca en `true` aquí y en `false` en `sui-alert` y `sui-banner`.
163
+ - La acción cierra el toast al tocarla, salvo `keepOpen: true`.
164
+ - Al pasar el dedo o el mouse por la pila se abre en abanico y se queda abierta 1,2 s después de
165
+ cerrar uno, para seguir tocando (patrón Sonner).
166
+ - La pila lleva `aria-live="polite"`: el lector de pantalla anuncia cada toast.
167
+ - El título es texto plano; la `description` del alert interno va por `innerHTML`: no le pases
168
+ texto escrito por el usuario sin sanear.
169
+
170
+ ## Ejemplo
171
+
172
+ ```ts
173
+ private readonly toast = inject(SuiToastService);
174
+
175
+ guardar() {
176
+ this.toast.success('Cambios guardados');
177
+ }
178
+
179
+ fallo() {
180
+ this.toast.error('No se pudo eliminar el producto', { description: 'Revisa tu conexión y vuelve a intentar.', duration: 6000 });
181
+ }
182
+
183
+ versionNueva(v: string) {
184
+ this.toast.info('Nueva versión disponible', {
185
+ description: `Actualiza para usar la versión ${v}.`,
186
+ duration: Infinity,
187
+ action: { label: 'Actualizar', onClick: () => location.reload() },
188
+ });
189
+ }
190
+ ```
@@ -0,0 +1,201 @@
1
+ ---
2
+ name: sui-tooltip
3
+ selector: "[suiTooltip], [suiTooltipLarge]"
4
+ resumen: Directiva que muestra una ayuda corta al pasar el mouse o al enfocar un elemento; solo web, no sirve con el dedo
5
+ alternativas: [sui-form-hint (ayuda visible bajo un campo), sui-modal-sheet (explicación que se abre al tocar, en mobile), sui-popover (panel que señala algo y pide una acción)]
6
+ ---
7
+
8
+ # sui-tooltip
9
+
10
+ Story: [Molecules/Tooltip](https://sui-design-system.web.app/?path=/docs/molecules-tooltip--docs)
11
+
12
+ Es una **directiva**, no una etiqueta: se pone sobre el elemento que explica
13
+ (`<button suiTooltip="Editar">`). El globo lo dibuja `sui-tooltip-panel` en el overlay del CDK.
14
+
15
+ ## Cuándo usarlo / cuándo no
16
+
17
+ **Úsalo** en **web** para dar contexto a algo que se puede tocar o enfocar: el nombre de un botón
18
+ de solo ícono («Editar», «Exportar»), o qué significa un término al lado de un dato («Tarifa de
19
+ servicio»). Es un extra: la pantalla tiene que entenderse sin él.
20
+
21
+ **No lo uses** para:
22
+
23
+ - **Mobile.** No hay hover: la directiva solo escucha `mouseenter` y `focus`. Con el dedo depende de
24
+ cómo el navegador imite el mouse: a veces abre, se cierra al hacer scroll y no se cierra al tocar
25
+ afuera. En las pantallas del cliente y del repartidor, la explicación va **visible** (una línea bajo
26
+ el dato, `sui-form-hint`) o en un `sui-modal-sheet` que se abre al tocar el ícono.
27
+ - Información que hace falta para decidir (un precio, una condición): eso se escribe en la pantalla.
28
+ - Un elemento que no se puede enfocar (`<svg>`, `<span>`): con teclado nunca aparece. El host tiene
29
+ que ser un botón.
30
+ - Algo que pide una acción («Siguiente», «Entendido»): eso es `sui-popover`.
31
+
32
+ ## Qué variante usar
33
+
34
+ > La guía del DS dice para qué es y cómo se llaman sus tamaños, pero no cuándo va cada uno. Lo
35
+ > marcado «según la guía del DS» sale de su texto o su código publicado; el resto es **propuesta**.
36
+ >
37
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (sin prototipos ni vitrinas): **6 tooltips**
38
+ > en 6 archivos — 2 `suiTooltip` de texto en el panel del local y 4 `suiTooltipLarge` en el flujo de
39
+ > compra del cliente.
40
+
41
+ ### Lo que sí dice la guía del DS
42
+
43
+ - **Para qué es**: agrega contexto a elementos **interactivos** y aparece al pasar el mouse o con el
44
+ **foco del teclado**. Por eso no sirve con el dedo.
45
+ - **Tres tamaños**, con nombres corridos un paso respecto a SUI (tabla abajo).
46
+ - **Default**: tema `dark` y tamaño intermedio. SUI arranca en tema `light`.
47
+ - La flecha siempre está; la posición sigue al espacio disponible.
48
+
49
+ ### `size` (input `suiTooltipSize`) — equivalencia con la guía
50
+
51
+ | SUI | guía | qué es | cuándo | fuente |
52
+ |---|---|---|---|---|
53
+ | `small` (24 px de alto, texto 12) | `xsmall` | texto de una línea, chico | El nombre de un ícono en una tabla o barra densa. | escala según la guía del DS · cuándo: propuesta |
54
+ | `medium` (34 px, texto 14) — default SUI | `small` (default de la guía) | texto de una línea | Lo normal: una frase corta que explica. | escala según la guía del DS · cuándo: propuesta |
55
+ | `large` (280 px, título + descripción + ícono) | `medium` | contenido rico | Explicar un término con título y una o dos frases. Se activa solo al usar `[suiTooltipLarge]`. | escala según la guía del DS · cuándo: propuesta |
56
+ | `xlarge` (320 px) | — | rico, más ancho | No usar hoy. Extensión de SUI. **Cuándo sí:** una explicación rica que en 280 px queda en más de cuatro líneas. | propuesta |
57
+
58
+ ### Contenido: `suiTooltip` o `suiTooltipLarge`
59
+
60
+ | input | cuándo | ejemplo real de la app | fuente |
61
+ |---|---|---|---|
62
+ | `suiTooltip="…"` | Una frase, sin punto final. | `components/customer-segments/customer-segments.html:8` («Ingresos por tipo de cliente») | propuesta |
63
+ | `[suiTooltipLarge]="{ title, description, icon }"` | Un término que necesita título y explicación. | `core/service-fee.ts:33` («Tarifa de servicio») | propuesta |
64
+ | `suiTooltipLarge.dismissible: true` | No usar hoy: lo deja abierto hasta tocar la X o Escape, que es lo que hace un popover. **Cuándo sí:** en web, una explicación larga que la persona lee con calma mientras mueve el mouse. | `core/service-fee.ts:39` (hoy en `true`, en pantallas solo de mobile) | propuesta |
65
+
66
+ ### `theme`, `position` y el resto
67
+
68
+ | prop | valor | cuándo | fuente |
69
+ |---|---|---|---|
70
+ | `theme` | `auto` | **Siempre.** Oscuro sobre la app en claro (lo que pide la guía) y claro sobre la app en oscuro. | propuesta (la guía: `dark` por default) |
71
+ | `theme` | `dark` | Igual que `auto` en modo claro, pero no se invierte en modo oscuro. Hoy lo usan los 4 del cliente. | según la guía del DS (default) |
72
+ | `theme` | `light` (default SUI) | No usar hoy: sobre una página clara parece una card más. **Cuándo sí:** ya lo da `auto` en modo oscuro. | propuesta |
73
+ | `position` | `top` (default) | Siempre que haya espacio. Si no lo hay, el CDK lo da vuelta solo. | propuesta |
74
+ | `position` | `right` · `left` | Íconos de una barra lateral angosta (el sidebar colapsado). | propuesta |
75
+ | `position` | `bottom` · `*-start` · `*-end` | Un elemento pegado al borde de arriba o a un costado de la pantalla. | propuesta |
76
+ | `delay` | `200` (default) | Siempre: evita que se abra al cruzar con el mouse. | propuesta |
77
+ | `delay` | otro valor | No usar hoy. **Cuándo sí:** ninguno previsto. | propuesta |
78
+ | `disabled` | `true` | Cuando lo que dice ya está a la vista (el sidebar expandido muestra el nombre). | propuesta |
79
+ | `showArrow` | `true` (default) | Siempre: la flecha dice de qué elemento habla. | según la guía del DS |
80
+ | `showArrow` | `false` | No usar hoy. **Cuándo sí:** sobre un punto de un gráfico, donde la flecha tapa el dato. | propuesta |
81
+
82
+ ### Usos de hoy que rompen la regla
83
+
84
+ - **4 tooltips en pantallas que solo existen en el celular** (la explicación de la tarifa de
85
+ servicio del cliente): `pages/customer/cart/cart.html:177`, `pages/customer/checkout/checkout.html:366`,
86
+ `pages/customer/confirmation/confirmation.html:188`, `pages/customer/order-tracking/order-tracking.html:684`.
87
+ Rompen la guía (hover o foco). Pasarían a un `sui-modal-sheet` al tocar el ícono, con el mismo
88
+ texto de `core/service-fee.ts`.
89
+ - **2 tooltips sobre un `<svg>` que no se puede enfocar** (y con `#a3a3a3` suelto):
90
+ `components/customer-segments/customer-segments.html:8`, `components/product-categories/product-categories.html:8`.
91
+ Ni el teclado ni el dedo llegan. El host pasaría a un botón de solo ícono con `aria-label`.
92
+
93
+ ## Tamaño en mobile y en web
94
+
95
+ | uso | mobile | web | fuente |
96
+ |---|---|---|---|
97
+ | nombre de un ícono | no aplica: el ícono lleva el nombre escrito o `aria-label` | `small` | propuesta |
98
+ | frase que explica | no aplica: el texto va visible bajo el dato (`sui-form-hint`) | `medium` | propuesta |
99
+ | explicación con título | no aplica: `sui-modal-sheet` al tocar el ícono | `large` (automático con `[suiTooltipLarge]`) | propuesta |
100
+
101
+ En pantallas que se usan en los dos (panel del local, super admin), el tooltip se apaga en mobile
102
+ y la ayuda se muestra de otra forma:
103
+
104
+ ```html
105
+ <button class="info" type="button" aria-label="Qué es la tarifa de servicio"
106
+ [suiTooltipLarge]="tarifa" theme="auto" [disabled]="bp.isMobile()"
107
+ (click)="bp.isMobile() && abrirExplicacion()">
108
+ <sui-icon name="information-line" [size]="16" />
109
+ </button>
110
+ ```
111
+
112
+ ## «No usar»: por qué no hoy y cuándo sí
113
+
114
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
115
+ |---|---|---|
116
+ | cualquier tooltip en mobile | no hay hover; con el dedo abre de casualidad | nunca: texto visible o un sheet |
117
+ | `suiTooltipSize="xlarge"` | 280 px alcanzan para lo que hay | una explicación rica que en 280 px pasa de cuatro líneas |
118
+ | `dismissible: true` | queda abierto como un popover | en web, una explicación larga para leer con calma |
119
+ | `theme="light"` | sobre página clara parece una card | ya lo da `auto` en modo oscuro |
120
+ | `showArrow=false` | la flecha dice de qué habla | sobre un punto de un gráfico |
121
+ | `delay` distinto de 200 | se abriría al cruzar con el mouse | ninguno previsto |
122
+
123
+ ## API
124
+
125
+ <!-- api:inicio -->
126
+ <!-- generada: no editar a mano — `npm run docs` -->
127
+
128
+ ### `[suiTooltip], [suiTooltipLarge]`
129
+
130
+ | input | tipo | default |
131
+ |---|---|---|
132
+ | `suiTooltip` | `string` | `''` |
133
+ | `suiTooltipLarge` | `SuiTooltipLargeData \| null` | `null` |
134
+ | `position` | `'top' \| 'top-start' \| 'top-end' \| 'right' \| 'bottom' \| 'bottom-start' \| 'bottom-end' \| 'left'` | `'top'` |
135
+ | `suiTooltipSize` (propiedad `size`) | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
136
+ | `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` |
137
+ | `delay` | `number` | `200` |
138
+ | `disabled` | `boolean` | `false` |
139
+ | `showArrow` | `boolean` | `true` |
140
+
141
+ Outputs: ninguno.
142
+
143
+ ### `sui-tooltip-panel`
144
+
145
+ | input | tipo | default |
146
+ |---|---|---|
147
+ | `text` | `string` | `''` |
148
+ | `position` | `'top' \| 'top-start' \| 'top-end' \| 'right' \| 'bottom' \| 'bottom-start' \| 'bottom-end' \| 'left'` | `'top'` |
149
+ | `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
150
+ | `theme` | `'light' \| 'dark'` | `'light'` |
151
+ | `showArrow` | `boolean` | `true` |
152
+ | `title` | `string \| null` | `null` |
153
+ | `description` | `string \| null` | `null` |
154
+ | `icon` | `string \| null` | `null` |
155
+ | `dismissible` | `boolean` | `false` |
156
+
157
+ | output | payload |
158
+ |---|---|
159
+ | `dismissed` | `void` |
160
+ <!-- api:fin -->
161
+
162
+ ```ts
163
+ interface SuiTooltipLargeData {
164
+ title: string;
165
+ description?: string;
166
+ icon?: string; // RemixIcon sin el prefijo ri-
167
+ dismissible?: boolean; // true = se queda abierto hasta la X o Escape
168
+ }
169
+ ```
170
+
171
+ `SuiTooltipPanel` (`sui-tooltip-panel`) es el globo que monta la directiva; también se exporta, pero
172
+ no se usa directo en pantallas.
173
+
174
+ ## Trampas
175
+
176
+ - **El tamaño se pasa como `suiTooltipSize`**, no como `size`: así no choca con el `size` del
177
+ componente que lo lleva (`<sui-button size="small" suiTooltip="…">`).
178
+ - **`position`, `theme`, `delay` y `disabled` sí se llaman así, sin prefijo**: si el host es un
179
+ componente con un input del mismo nombre (`disabled` de `sui-button`), el valor llega a los dos.
180
+ - **`suiTooltipSize="large"` con `suiTooltip` de texto dibuja una caja vacía**: el tamaño rico solo
181
+ lee `suiTooltipLarge`. Con `[suiTooltipLarge]` el tamaño pasa a `large` solo.
182
+ - **Defaults distintos a la guía**: tema `light` (la guía, `dark`) y nombres de tamaño corridos un paso.
183
+ - Se cierra al hacer scroll en cualquier contenedor y con Escape. Con `dismissible`, no se cierra al
184
+ sacar el mouse.
185
+ - Pone `aria-describedby` en el host y le borra el `title` nativo (si no, saldría además el globo
186
+ gris del navegador).
187
+ - En `dark`, el ícono del tooltip rico usa un gris fijo del `.scss`, no un token.
188
+
189
+ ## Ejemplo
190
+
191
+ ```html
192
+ <!-- Nombre de un botón de solo ícono, en web -->
193
+ <sui-compact-button icon="download-2-line" ariaLabel="Exportar" suiTooltip="Exportar" theme="auto" />
194
+
195
+ <!-- Término con explicación, en web -->
196
+ <button type="button" aria-label="Qué es la tarifa de servicio"
197
+ [suiTooltipLarge]="{ title: 'Tarifa de servicio', description: 'Nos ayuda a mantener la plataforma funcionando.', icon: 'information-line' }"
198
+ theme="auto">
199
+ <sui-icon name="information-line" [size]="16" />
200
+ </button>
201
+ ```