@ajuarezso/sui-design-system 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/docs/INDEX.md +75 -80
  2. package/docs/sui-accordion/README.md +171 -0
  3. package/docs/sui-activity-feed/README.md +155 -0
  4. package/docs/sui-activity-filter/README.md +100 -0
  5. package/docs/sui-alert/README.md +13 -0
  6. package/docs/sui-badge/README.md +17 -0
  7. package/docs/sui-banner/README.md +190 -0
  8. package/docs/sui-breadcrumb-item/README.md +96 -0
  9. package/docs/sui-breadcrumbs/README.md +122 -0
  10. package/docs/sui-button/README.md +36 -0
  11. package/docs/sui-card/README.md +168 -0
  12. package/docs/sui-chart-legend/README.md +140 -0
  13. package/docs/sui-chart-legend-dot/README.md +118 -0
  14. package/docs/sui-checkbox-card/README.md +150 -0
  15. package/docs/sui-command-menu-footer/README.md +100 -0
  16. package/docs/sui-command-menu-item/README.md +140 -0
  17. package/docs/sui-command-menu-search/README.md +105 -0
  18. package/docs/sui-compact-select/README.md +130 -0
  19. package/docs/sui-compact-select-for-input/README.md +120 -0
  20. package/docs/sui-content-card/README.md +147 -0
  21. package/docs/sui-content-label/README.md +148 -0
  22. package/docs/sui-counter-input/README.md +148 -0
  23. package/docs/sui-date-selector/README.md +98 -0
  24. package/docs/sui-datepicker/README.md +197 -0
  25. package/docs/sui-day-cell/README.md +118 -0
  26. package/docs/sui-day-label/README.md +81 -0
  27. package/docs/sui-drawer-footer/README.md +127 -0
  28. package/docs/sui-drawer-header/README.md +140 -0
  29. package/docs/sui-dropdown-caption/README.md +92 -0
  30. package/docs/sui-dropdown-item/README.md +163 -0
  31. package/docs/sui-dropdown-menu/README.md +196 -0
  32. package/docs/sui-dropdown-search/README.md +113 -0
  33. package/docs/sui-empty-state/README.md +145 -0
  34. package/docs/sui-file-upload/README.md +154 -0
  35. package/docs/sui-file-upload-card/README.md +129 -0
  36. package/docs/sui-filter/README.md +181 -0
  37. package/docs/sui-href/README.md +85 -0
  38. package/docs/sui-image-upload/README.md +200 -0
  39. package/docs/sui-image-upload-profile/README.md +145 -0
  40. package/docs/sui-img-retry/README.md +107 -0
  41. package/docs/sui-inline-input/README.md +104 -0
  42. package/docs/sui-inline-select/README.md +101 -0
  43. package/docs/sui-input/README.md +247 -0
  44. package/docs/sui-integration-switch/README.md +142 -0
  45. package/docs/sui-modal/README.md +238 -0
  46. package/docs/sui-modal-footer/README.md +178 -0
  47. package/docs/sui-modal-header/README.md +115 -0
  48. package/docs/sui-modal-sheet/README.md +170 -0
  49. package/docs/sui-notification/README.md +179 -0
  50. package/docs/sui-notification-footer/README.md +98 -0
  51. package/docs/sui-notification-tab-menu/README.md +112 -0
  52. package/docs/sui-otp-input/README.md +116 -0
  53. package/docs/sui-page-header/README.md +123 -0
  54. package/docs/sui-pagination/README.md +146 -0
  55. package/docs/sui-password-strength/README.md +99 -0
  56. package/docs/sui-period-range/README.md +93 -0
  57. package/docs/sui-popover/README.md +178 -0
  58. package/docs/sui-product-card/README.md +173 -0
  59. package/docs/sui-radio-card/README.md +160 -0
  60. package/docs/sui-rating/README.md +7 -6
  61. package/docs/sui-rich-editor/README.md +114 -0
  62. package/docs/sui-segmented-control/README.md +3 -0
  63. package/docs/sui-select/README.md +183 -0
  64. package/docs/sui-sidebar/README.md +217 -0
  65. package/docs/sui-stepper/README.md +166 -0
  66. package/docs/sui-store-card/README.md +147 -0
  67. package/docs/sui-switch-card/README.md +149 -0
  68. package/docs/sui-switch-label/README.md +3 -0
  69. package/docs/sui-tab-chips/README.md +188 -0
  70. package/docs/sui-tab-menu-horizontal/README.md +142 -0
  71. package/docs/sui-tab-menu-vertical/README.md +136 -0
  72. package/docs/sui-table/README.md +264 -0
  73. package/docs/sui-tag-input/README.md +123 -0
  74. package/docs/sui-textarea/README.md +160 -0
  75. package/docs/sui-time-picker/README.md +240 -0
  76. package/docs/sui-toast/README.md +190 -0
  77. package/docs/sui-tooltip/README.md +201 -0
  78. package/docs/sui-topbar/README.md +153 -0
  79. package/docs/sui-topbar-button/README.md +95 -0
  80. package/docs/sui-topbar-item/README.md +97 -0
  81. package/docs/sui-topbar-user/README.md +83 -0
  82. package/fesm2022/ajuarezso-sui-design-system.mjs +291 -246
  83. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  84. package/package.json +1 -1
  85. package/types/ajuarezso-sui-design-system.d.ts +208 -50
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: sui-modal-sheet
3
+ selector: sui-modal-sheet
4
+ resumen: Hoja que sube desde abajo, se arrastra entre alturas fijas y puede dejar usable lo de atrás (un mapa)
5
+ alternativas: [sui-modal (pide terminar algo antes de seguir, sin fondo usable), sui-popover (contenido chico anclado a un botón), sui-dropdown-menu (lista de acciones)]
6
+ ---
7
+
8
+ # sui-modal-sheet
9
+
10
+ Story: [Organisms/Modal/Modal Sheet](https://sui-design-system.web.app/?path=/docs/organisms-modal-modal-sheet--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** cuando el contenido **convive con lo de atrás** o se mira a distintas alturas:
15
+
16
+ - El panel del seguimiento sobre un mapa (pedido, envío, viaje): a 25 % se ve el mapa, a 100 %
17
+ el detalle. El mapa sigue respondiendo.
18
+ - Una lista o un detalle que se abre desde abajo y se cierra deslizando (reseñas, movimientos
19
+ de la billetera, elegir la hora de entrega).
20
+
21
+ **No lo uses** para:
22
+
23
+ - Un formulario o una confirmación que hay que terminar: `sui-modal`. El sheet se cierra con un
24
+ deslizón y se pierde lo escrito.
25
+ - Desktop como superficie principal: en una pantalla de 1440 px un sheet a todo el ancho se lee
26
+ como un error (ver tamaño). Si en desktop hay sitio, un panel lateral sirve mejor.
27
+
28
+ ## Qué variante usar
29
+
30
+ > **No está en la guía del DS: es extensión de SUI**, inspirada en el `ion-modal` en modo sheet
31
+ > de Ionic y en las hojas de Apple Maps. No hay Figma que la legisle. Lo marcado **canon** sale
32
+ > de `master-pedidos/CLAUDE.md`; lo demás es **propuesta** sacada del uso real.
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: 13 sheets, sin contar prototipos ni
35
+ > vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`, `dx/*`, `master-rutina`,
36
+ > `master-medico`, `dev-index`) ni las copias de `components/sui/`.
37
+
38
+ ### Lo que sí dice la guía del DS
39
+
40
+ Nada: el sheet no está en la guía. Lo único que hereda del DS es el criterio del body (20 px) y
41
+ el radio Android (`--sui-radius-20`).
42
+
43
+ ### Los dos patrones de la app
44
+
45
+ El sheet no tiene variantes: se configura con tres números. En la app salen **dos recetas**, y
46
+ conviene copiar una de las dos en vez de inventar otra.
47
+
48
+ | patrón | `breakpoints` | `initialBreakpoint` | `backdropBreakpoint` | cuándo | ejemplo real de la app | fuente |
49
+ |---|---|---|---|---|---|---|
50
+ | **Sobre un mapa** | `[0.25, 0.5, 0.7, 1]` (sin `0`) | `0.5` | `1` | el seguimiento: el mapa se usa a cualquier altura y la hoja no se puede cerrar | `pages/customer/order-tracking/order-tracking.html:130` · `pages/driver/driver-order-detail/driver-order-detail.html:60` | propuesta |
51
+ | **Hoja de lectura** | `[0, 0.92]` | `0.92` | `0` | una lista o detalle que se abre y se cierra deslizando, con el fondo apagado | `pages/customer/order-tracking/order-tracking.html:809` (reseñas) · `pages/customer/checkout/checkout.html:448` (hora) | propuesta |
52
+
53
+ Hoy: 4 «sobre un mapa» (más 2 variantes con alturas propias: `pages/envios/envios.html:578` y
54
+ `pages/customer/viaje/viaje.html:24`), 5 hojas de lectura en `0.92`–`0.96`, 2 en `[0, 1]` y 1 en
55
+ `[0, 0.6, 0.95]`.
56
+
57
+ | input | regla | fuente |
58
+ |---|---|---|
59
+ | `breakpoints` | Con `0` en la lista, la hoja **se cierra deslizando**. Sin `0`, no se cierra con el dedo (solo por código o backdrop). | componente |
60
+ | `initialBreakpoint` | Tiene que estar en `breakpoints`. | componente |
61
+ | `backdropBreakpoint` | `0` = fondo apagado desde que abre. `1` = **nunca hay backdrop**: el mapa de atrás se toca siempre. | componente |
62
+ | tope en las hojas de lectura | `0.92`, no `1`: deja ver arriba un borde de la pantalla de atrás, que es lo que dice «esto es una hoja». | propuesta |
63
+ | `showHandle` | Déjalo en `true` siempre que la hoja se arrastre. Hoy nadie lo apaga. | propuesta |
64
+ | `fullBody` | Solo para contenido a sangre (una foto, un mapa dentro de la hoja). | canon (CLAUDE.md, 2026-07-21) |
65
+
66
+ **Usos de hoy a revisar:**
67
+
68
+ - `pages/customer/viaje/viaje.html:24` reabre la hoja en `(closed)` (`hojaAbierta.set(true)`)
69
+ para que no se pueda cerrar. Sin `0` en `breakpoints` y con `[closeOnBackdrop]="false"` ya no se
70
+ cierra; el reabrir sobra o tapa otro caso.
71
+ - 2 footers de modal metidos en hojas: van sin `slot` (no hay slot de footer). Está bien, pero el
72
+ botón scrollea con el contenido: `pages/customer/checkout/checkout.html:490`,
73
+ `pages/super-admin/master-sonidos-push/master-sonidos-push.html:146`.
74
+
75
+ ## Tamaño en mobile y en web
76
+
77
+ El sheet **no tiene `size`**. Mide lo que mide su contenido, con tope en el breakpoint más alto
78
+ (y nunca más que la pantalla menos el safe-area de arriba y 16 px).
79
+
80
+ | | mobile | web desktop | fuente |
81
+ |---|---|---|---|
82
+ | ancho | toda la pantalla menos 8 px a cada lado | **igual: todo el ancho menos 8 px** | componente |
83
+ | esquinas | iOS 36 arriba / 54 abajo · Android 20 | igual | canon (CLAUDE.md, 2026-07-22) |
84
+ | padding del body | `0 20px 20px` | igual | canon (CLAUDE.md, 2026-07-21) |
85
+ | ancho en desktop | — | acotarlo a una columna centrada de 560 px | propuesta (hoy lo hace cada pantalla a mano) |
86
+
87
+ **El sheet no se acota en desktop.** La app lo arregla con CSS propio, cinco reglas en cuatro archivos:
88
+ `components/store-ratings-modal/store-ratings-modal.scss:81`,
89
+ `pages/driver/movimientos/movimientos-sheet.scss:24`,
90
+ `pages/driver/driver-order-detail/driver-order-detail.scss:1028` y
91
+ `pages/customer/order-tracking/order-tracking.scss:1175` y `:1238`, todos a 560 px. Propuesta:
92
+ que el DS traiga ese tope (`max-width` desde 768 px, centrado) y se borren esos parches.
93
+
94
+ ## API
95
+
96
+ <!-- api:inicio -->
97
+ <!-- generada: no editar a mano — `npm run docs` -->
98
+
99
+ | input | tipo | default |
100
+ |---|---|---|
101
+ | `open` · model, `[(open)]` | `boolean` | `false` |
102
+ | `breakpoints` | `number[]` | `[0, 1]` |
103
+ | `initialBreakpoint` | `number` | `1` |
104
+ | `backdropBreakpoint` | `number` | `0` |
105
+ | `showHandle` | `boolean` | `true` |
106
+ | `closeOnBackdrop` | `boolean` | `true` |
107
+ | `closeOnEscape` | `boolean` | `true` |
108
+ | `fullBody` | `boolean` | `false` |
109
+
110
+ | output | payload |
111
+ |---|---|
112
+ | `closed` | `void` |
113
+ | `breakpointChange` | `number` |
114
+ <!-- api:fin -->
115
+
116
+ Métodos públicos: `setCurrentBreakpoint(bp, animated = true)` (avisa por consola y no hace nada
117
+ si `bp` no está en `breakpoints`) y `close()`.
118
+
119
+ Signals públicas: `currentBreakpoint` y `progress` (cambian al soltar, no durante el arrastre) y
120
+ `dragging`.
121
+
122
+ Slot: un solo `<ng-content>`, el body. No hay header ni footer.
123
+
124
+ ## Trampas
125
+
126
+ - **El padding del body es fuente única** (`0 20px 20px`). No le pongas padding lateral ni abajo
127
+ a tus secciones ni lo pises con `::ng-deep .sui-sheet__body`: el margen queda doble (pasó en el
128
+ tracking del repartidor: ~36 px a los lados y ~68 px bajo el último botón).
129
+ - **Anidar radios**: el body ya cumple `exterior = interior + padding` (36 − 20 = 16, el radio de
130
+ `sui-card`). Una card adentro no necesita otro radio.
131
+ - **`breakpointChange` y `progress` no cambian durante el arrastre**, solo al soltar. Si algo
132
+ tiene que seguir al dedo (el padding del mapa), usa `breakpointChange` y acepta el salto, o lee
133
+ la posición del panel.
134
+ - **Arrastre y scroll**: en la altura máxima el body scrollea; desde arriba del todo, jalar hacia
135
+ abajo mueve la hoja. En alturas intermedias el body entero arrastra (`touch-action: none`): un
136
+ carrusel o un slider dentro puede pelear con el gesto. Los campos (`input`, `textarea`,
137
+ `select`) no arrancan arrastre; para otro control que necesita el dedo, ponle el atributo
138
+ `data-sui-no-sheet-drag` (o a un ancestro).
139
+ - **Sin `0` en `breakpoints` no se cierra deslizando.** Si quieres que se cierre y no lo hace, es
140
+ eso.
141
+ - **`closeOnBackdrop` solo actúa cuando hay backdrop** (altura actual por encima de
142
+ `backdropBreakpoint`). Con `backdropBreakpoint` en `1` nunca hay.
143
+ - **El transform es tuyo, el movimiento no**: el sheet se mueve con la propiedad `translate` del
144
+ panel interno, así que puedes escribir `left` / `right` / `transform` sobre `.sui-sheet` (por
145
+ ejemplo para centrarlo en desktop) sin romper el arrastre.
146
+ - Pide ocultar la barra inferior de la app por `SUI_NAVBAR_VISIBILITY`, igual que `sui-modal`.
147
+
148
+ ## Ejemplo
149
+
150
+ ```html
151
+ <!-- Sobre un mapa: no se cierra, el mapa se usa siempre -->
152
+ <sui-modal-sheet
153
+ [(open)]="hojaAbierta"
154
+ [breakpoints]="[0.25, 0.5, 0.7, 1]"
155
+ [initialBreakpoint]="0.5"
156
+ [backdropBreakpoint]="1"
157
+ (breakpointChange)="mapa.setSheetRatio($event)">
158
+ <h2>Tu pedido va en camino</h2>
159
+ …
160
+ </sui-modal-sheet>
161
+
162
+ <!-- Hoja de lectura: se cierra deslizando -->
163
+ <sui-modal-sheet
164
+ [(open)]="resenasAbiertas"
165
+ [breakpoints]="[0, 0.92]"
166
+ [initialBreakpoint]="0.92"
167
+ [backdropBreakpoint]="0">
168
+ <app-ratings-detail … />
169
+ </sui-modal-sheet>
170
+ ```
@@ -0,0 +1,179 @@
1
+ ---
2
+ name: sui-notification
3
+ selector: sui-notification
4
+ resumen: Fila de la bandeja de notificaciones, con quién, qué pasó, hace cuánto y si ya se leyó
5
+ alternativas: [sui-toast (aviso efímero, incluido el «notification» de esquina de la guía), sui-alert (aviso que se queda en su contexto), sui-banner (toda la app)]
6
+ ---
7
+
8
+ # sui-notification
9
+
10
+ Story: [Molecules/Feedback/Notification](https://sui-design-system.web.app/?path=/docs/molecules-feedback-notification--docs)
11
+
12
+ ## Primero: dos cosas distintas con el mismo nombre
13
+
14
+ - **En la guía del DS**, una «notification» es un aviso **temporal en una esquina** con título,
15
+ descripción y una acción (un pago, una actualización). En SUI ese caso **es un `sui-toast`** con
16
+ `description` y `action`.
17
+ - **En SUI**, `sui-notification` es la **fila de la bandeja**: el panel de la campana del Figma del
18
+ DS (foto, título, descripción, hora, punto de no leída). Este README es sobre eso.
19
+
20
+ El componente además arrastra un tercer uso: un aviso con tipo y relleno (`variant`, `variantStyle`)
21
+ igual al de `sui-alert`. Ese uso no va: para eso está el alert.
22
+
23
+ ## Cuándo usarlo / cuándo no
24
+
25
+ **Úsalo** para cada aviso de una **bandeja** que la persona revisa cuando quiere: «Tu pedido llegó»,
26
+ «Nuevo pedido de Pollería El Dorado», «Recarga aprobada». Lleva **la hora**, se marca como leído y
27
+ se puede volver a abrir.
28
+
29
+ **No lo uses** para:
30
+
31
+ - Avisar algo en el momento: `sui-toast` (aunque tenga título, descripción y acción).
32
+ - Un aviso dentro de una pantalla: `sui-alert`.
33
+ - Una lista de actividad sin leído/no leído (el historial de un pedido): `sui-activity-feed`.
34
+
35
+ Regla corta (canon, la misma del alert): **contexto → alert · toda la app → banner · efímero →
36
+ toast · bandeja → notification.**
37
+
38
+ ## Qué variante usar
39
+
40
+ > La guía del DS no tiene esta fila (su «notification» es otra cosa, ver arriba). Lo de abajo sale
41
+ > del Figma del DS y del componente («según el componente»), de lo ya aprobado («canon») o es
42
+ > **propuesta**.
43
+ >
44
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. La bandeja de la app
45
+ > (`pages/notifications/notifications.html:98`, la misma pantalla en las rutas de los 4 roles) dibuja
46
+ > sus filas a mano.
47
+
48
+ ### Qué lleva cada fila
49
+
50
+ | prop | valor | cuándo | fuente |
51
+ |---|---|---|---|
52
+ | `avatar` | `src` con la foto | **Siempre**: la cara o el logo de quien generó el aviso (el local del pedido, el repartidor que lo lleva). Una foto se reconoce antes que un texto. | propuesta |
53
+ | `avatar` | `{ initials }` | Solo si no hay foto. Ojo: sale en un círculo negro, **no** con el color por rol (ver Trampas). | según el componente |
54
+ | `avatar` | el isotipo de la app | Avisos **del sistema** sin una persona detrás («Tu plan vence en 3 días»): así toda la bandeja queda en filas iguales. | propuesta |
55
+ | `title` | frase corta | Qué pasó: «Tu pedido llegó». Sentence case, sin punto final. | canon (copy de la app) |
56
+ | `description` | una o dos frases | El detalle que decide si abrirla: «Pollería El Dorado · S/ 42.50». | propuesta |
57
+ | `timestamp` | texto ya formateado | **Siempre**: la hora es lo que hace bandeja a la bandeja. «Hace 5 min», «Ayer 18:40». | canon (bandeja con hora) · formato: propuesta |
58
+ | `unread` | `true` | Hasta que la persona la abre. El punto es naranja (el primario de la app). | según el componente |
59
+ | `showMore` | `true` | No usar hoy: el botón ⋮ solo aparece con el mouse encima. **Cuándo sí:** en web, acciones por fila (marcar como leída, archivar). | propuesta |
60
+ | `active` | `true` | No usar hoy: pinta la fila como si tuviera el mouse encima. **Cuándo sí:** navegar la bandeja con las flechas del teclado (ver `sui-notification-footer`). | propuesta |
61
+ | `dismissible` | `true` | No usar hoy: los avisos de la bandeja se leen, no se cierran. **Cuándo sí:** una bandeja donde se borran avisos uno por uno. | propuesta |
62
+
63
+ ### `type` — el cuerpo de la fila
64
+
65
+ | type | cuándo | fuente |
66
+ |---|---|---|
67
+ | `basic` (default) | Todas las de hoy: título, descripción y hora. | según el componente |
68
+ | `button` | No usar hoy. **Cuándo sí:** una solicitud que se resuelve desde la misma bandeja, con «Rechazar» / «Aprobar» en `slot="actions"` (por ejemplo, una invitación a un equipo). Secundario a la izquierda, primario a la derecha. | propuesta · orden: canon |
69
+ | `message` | No usar hoy. **Cuándo sí:** el aviso trae lo que escribió otra persona (la nota del cliente, un mensaje del repartidor), en la burbuja. | propuesta |
70
+ | `file` | No usar hoy: la app no manda adjuntos. **Cuándo sí:** un comprobante o una boleta adjunta. | propuesta |
71
+
72
+ ### `variant` y `variantStyle` — el modelo de alert
73
+
74
+ | prop | valor | cuándo | fuente |
75
+ |---|---|---|---|
76
+ | `variant` | `default` (default) | **Siempre** en la bandeja: el tipo lo dice la foto y el texto, no un color. | propuesta |
77
+ | `variant` | `info` · `success` · `warning` · `error` · `feature` | No usar: con tipo y sin foto, la fila se vuelve un alert con borde y sombra. **Cuándo sí:** ninguno; ese aviso es un `sui-alert`. | propuesta (sigue la regla canon) |
78
+ | `variantStyle` | `stroke` (default) | Siempre. Con foto, la fila es plana: sin borde ni sombra. | según el componente |
79
+ | `variantStyle` | `filled` · `light` · `lighter` | No usar: pintan la fila de color, que es lo que hace el alert. **Cuándo sí:** ninguno. | propuesta |
80
+ | `showIcon` | `true` (default) | No cambia nada con foto; el ícono de tipo solo sale en el modelo de alert. | según el componente |
81
+
82
+ ### Slots
83
+
84
+ | slot | cuándo | fuente |
85
+ |---|---|---|
86
+ | `slot="company-logo"` | Logo de 16 px antes de la descripción: el local, cuando la foto es la del repartidor. | propuesta |
87
+ | `slot="actions"` | Los dos botones de `type="button"`. | según el componente |
88
+ | `slot="message"` · `slot="file"` | El cuerpo de `type="message"` y `type="file"`. | según el componente |
89
+
90
+ ### Usos de hoy que romperían la regla
91
+
92
+ - **La bandeja dibuja sus filas a mano — 1 pantalla, 4 rutas:** `pages/notifications/notifications.html:98`
93
+ (ícono de color por tipo, fila teñida si no se leyó, punto a la derecha). **A discutir**: no es un
94
+ cambio 1:1. Con el componente, el tipo se ve en la foto y no en un ícono de color, y la no leída
95
+ lleva solo el punto, sin teñir la fila.
96
+
97
+ ## Tamaño en mobile y en web
98
+
99
+ La fila **no tiene `size`**: foto de 40 px, 12 px de relleno, texto de 14.
100
+
101
+ | uso | mobile | web | fuente |
102
+ |---|---|---|---|
103
+ | la fila | toda la fila se toca para abrirla: mide 64 px o más | igual | según el componente |
104
+ | ⋮ (`showMore`) | no aplica: aparece con el mouse | 24 px | según el componente |
105
+ | la X (`dismissible`) | 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 |
106
+ | botones de `type="button"` | los pone quien la usa: `[size]="bp.isMobile() ? 'large' : 'xsmall'"` | `xsmall` | propuesta |
107
+
108
+ ## «No usar»: por qué no hoy y cuándo sí
109
+
110
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
111
+ |---|---|---|
112
+ | el modelo de alert (`variant` ≠ `default`, rellenos de color) | duplica a `sui-alert` | ninguno: es un alert |
113
+ | `type="button"` | nada se resuelve desde la bandeja | aceptar o rechazar una solicitud (una invitación a un equipo) desde la bandeja |
114
+ | `type="message"` | los avisos no traen texto de otra persona | la nota del cliente o un mensaje del repartidor |
115
+ | `type="file"` | no hay adjuntos | un comprobante o una boleta |
116
+ | `showMore` | solo se ve con mouse | acciones por fila en web |
117
+ | `active` | no se navega con teclado | bandeja con flechas del teclado |
118
+ | `dismissible` | se leen, no se cierran | una bandeja donde se borra aviso por aviso |
119
+
120
+ ## API
121
+
122
+ <!-- api:inicio -->
123
+ <!-- generada: no editar a mano — `npm run docs` -->
124
+
125
+ | input | tipo | default |
126
+ |---|---|---|
127
+ | `variant` | `'info' \| 'success' \| 'warning' \| 'error' \| 'feature' \| 'default'` | `'default'` |
128
+ | `variantStyle` | `'filled' \| 'light' \| 'lighter' \| 'stroke'` | `'stroke'` |
129
+ | `title` | `string \| null` | `null` |
130
+ | `description` | `string \| null` | `null` |
131
+ | `timestamp` | `string \| null` | `null` |
132
+ | `avatar` | `SuiAvatarConfig \| string \| null` | `null` |
133
+ | `showIcon` | `boolean` | `true` |
134
+ | `dismissible` | `boolean` | `false` |
135
+ | `unread` | `boolean` | `false` |
136
+ | `type` | `'basic' \| 'file' \| 'button' \| 'message'` | `'basic'` |
137
+ | `showMore` | `boolean` | `false` |
138
+ | `active` | `boolean` | `false` |
139
+
140
+ | output | payload |
141
+ |---|---|
142
+ | `dismissed` | `void` |
143
+ | `moreClicked` | `MouseEvent` |
144
+ <!-- api:fin -->
145
+
146
+ Slots: `[slot=company-logo]`, `[slot=file]`, `[slot=message]`, el contenido libre, `[slot=actions]`.
147
+
148
+ ## Trampas
149
+
150
+ - **La X se toca en 40 × 40** aunque se vea de 20 (un `::before` invisible sobre su `<button>`,
151
+ desde 03-10-2026): en una fila que se toca entera, el toque a 10 px de la X la cierra en vez de
152
+ abrirla.
153
+ - **Es el avatar el que decide el modelo**: con `avatar` es una fila plana (`role="article"`); sin
154
+ `avatar` es un alert con borde y sombra (`role="status"`, que el lector de pantalla anuncia).
155
+ - **El avatar no es `sui-avatar`**: lo dibuja la fila, en un círculo **negro** con iniciales.
156
+ Ignora `color`, así que no respeta el color por rol de la app (local naranja, repartidor verde,
157
+ cliente azul). Con foto no se nota; sin foto, sí.
158
+ - **La hora cambia de lugar**: sin avatar va a la derecha del título; con avatar, delante de la
159
+ descripción («Hace 5 min ∙ …»).
160
+ - `timestamp` es texto: el formato («Hace 5 min») lo arma quien la usa.
161
+ - `feature` usa `sparkling-fill` aquí y en el alert, y `magic-fill` en el banner.
162
+ - `dismissible` solo emite `(dismissed)`: la fila **no se esconde sola** (a diferencia de alert y
163
+ banner). La saca quien la usa.
164
+ - El ⋮ de `showMore` se ve solo con el mouse encima o con `active`: en mobile no aparece.
165
+ - **`showMore` y `dismissible` juntos se pisan**: el ⋮ y la X van los dos arriba a la derecha.
166
+ - Con avatar (o con `type` distinto de `basic`) y **sin `description`**, queda un «∙» colgando
167
+ después de la hora («Hace 8 min ∙»).
168
+ - Borra el `title` nativo del host.
169
+
170
+ ## Ejemplo
171
+
172
+ ```html
173
+ <div role="list">
174
+ <sui-notification role="listitem"
175
+ [avatar]="pedido.localLogo" title="Tu pedido llegó"
176
+ description="Pollería El Dorado · S/ 42.50" timestamp="Hace 5 min" [unread]="!n.read"
177
+ (click)="abrir(n)" />
178
+ </div>
179
+ ```
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: sui-notification-footer
3
+ selector: sui-notification-footer
4
+ resumen: Pie del panel desplegable de notificaciones (web): ayuda de teclado a la izquierda y un link a los ajustes a la derecha
5
+ alternativas: [sui-link-button (un link suelto a los ajustes), sui-drawer-footer (pie de un panel lateral), sui-modal-footer (pie con botones)]
6
+ ---
7
+
8
+ # sui-notification-footer
9
+
10
+ Story: [Molecules/Feedback/Notification Footer](https://sui-design-system.web.app/?path=/docs/molecules-feedback-notification-footer--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** solo como **pie del panel de la campana** en web: el desplegable que abre la bandeja desde
15
+ la barra superior, con filas `sui-notification` y la cabecera `sui-notification-tab-menu`. Dice
16
+ «Usa ↑ ↓ para moverte» y lleva el link a los ajustes de notificaciones.
17
+
18
+ **No lo uses** para:
19
+
20
+ - La pantalla de notificaciones (la bandeja a pantalla completa): ahí los ajustes ya están en la
21
+ misma pantalla y nadie navega con flechas.
22
+ - Mobile: la mitad del componente es una ayuda de **teclado**.
23
+ - El pie de cualquier otro panel: `sui-drawer-footer` o `sui-modal-footer`.
24
+
25
+ ## Qué variante usar
26
+
27
+ > La guía del DS no tiene página para este componente: sale del Figma del DS (pie del panel de
28
+ > notificaciones). Todo lo de abajo es **propuesta**, salvo lo marcado «según el componente».
29
+ >
30
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. La app no tiene panel
31
+ > desplegable de campana: su bandeja es una pantalla (`pages/notifications/`).
32
+
33
+ | prop | valor | cuándo | fuente |
34
+ |---|---|---|---|
35
+ | `usePrefix` · `useSuffix` | `'Usa'` · `'para moverte'` | Ya son los defaults (03-10-2026); no hace falta pasarlos. | canon (copy de la app: tuteo, español) |
36
+ | `manage` | `'Ajustes de notificaciones'` | El link a los ajustes. Emite `(manageClick)`. | propuesta |
37
+ | `manage` | `{ label, href }` | Cuando los ajustes son otra ruta: se dibuja un `<a>` de verdad. | según el componente |
38
+ | `manage` | `true` (default) | Dice «Administrar notificaciones» (en español desde 03-10-2026). | propuesta |
39
+ | `manage` | `false` · `null` | Cuando los ajustes ya están a la vista en el mismo panel. | propuesta |
40
+
41
+ ## Tamaño en mobile y en web
42
+
43
+ **No tiene `size`**: texto de 12 y link `small` (16 px de alto).
44
+
45
+ | uso | mobile | web | fuente |
46
+ |---|---|---|---|
47
+ | el pie entero | no aplica: es ayuda de teclado; en mobile no se muestra | unos 48 px de alto | propuesta |
48
+ | el link de ajustes | si hiciera falta, un `sui-link-button` `large` suelto | `small` (16 px) | propuesta |
49
+
50
+ ```html
51
+ @if (!bp.isMobile()) {
52
+ <sui-notification-footer usePrefix="Usa" useSuffix="para moverte"
53
+ manage="Ajustes de notificaciones" (manageClick)="abrirAjustes()" />
54
+ }
55
+ ```
56
+
57
+ ## «No usar»: por qué no hoy y cuándo sí
58
+
59
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
60
+ |---|---|---|
61
+ | el componente | no hay panel de campana | si el panel del local o el super admin suman una campana con la bandeja desplegable en la barra superior (web) |
62
+ | `manage` con el texto por defecto | está en inglés | nunca: siempre un texto propio |
63
+
64
+ ## API
65
+
66
+ <!-- api:inicio -->
67
+ <!-- generada: no editar a mano — `npm run docs` -->
68
+
69
+ | input | tipo | default |
70
+ |---|---|---|
71
+ | `usePrefix` | `string` | `'Usa'` |
72
+ | `useSuffix` | `string` | `'para moverte'` |
73
+ | `manage` | `SuiLinkConfig \| string \| boolean \| null` | `true` |
74
+
75
+ | output | payload |
76
+ |---|---|
77
+ | `manageClick` | `MouseEvent` |
78
+ <!-- api:fin -->
79
+
80
+ ```ts
81
+ interface SuiLinkConfig { label: string; href?: string; target?: string; rel?: string; }
82
+ ```
83
+
84
+ ## Trampas
85
+
86
+ - **Textos por defecto en español** desde 03-10-2026: «Usa ↑ ↓ para moverte» y «Administrar
87
+ notificaciones» (antes «Use», «to navigate» y «Manage Notification»).
88
+ - Las teclas ↑ ↓ están fijas: no se pueden cambiar por otras.
89
+ - Con `href` y `target="_blank"` agrega `rel="noopener noreferrer"` solo.
90
+ - Ocupa el 100 % del ancho de su contenedor (el Figma lo dibuja de 540 px).
91
+ - Borra el `title` nativo del host.
92
+
93
+ ## Ejemplo
94
+
95
+ ```html
96
+ <sui-notification-footer usePrefix="Usa" useSuffix="para moverte"
97
+ [manage]="{ label: 'Ajustes de notificaciones', href: '/empresa/notificaciones' }" />
98
+ ```
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: sui-notification-tab-menu
3
+ selector: sui-notification-tab-menu
4
+ resumen: Cabecera con pestañas del panel desplegable de notificaciones (web), con conteo de no leídas y botón de filtro
5
+ alternativas: [sui-tab-chips (pestañas de la bandeja a pantalla completa, en mobile), sui-tab-menu-horizontal (pestañas de una pantalla), sui-segmented-control (cambiar de vista con 2–4 opciones)]
6
+ ---
7
+
8
+ # sui-notification-tab-menu
9
+
10
+ Story: [Molecules/Feedback/Notification Tab Menu](https://sui-design-system.web.app/?path=/docs/molecules-feedback-notification-tab-menu--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** solo como **cabecera del panel de la campana** en web: «Todas · No leídas (3) · Pedidos |
15
+ Archivadas» con el filtro a la derecha, encima de las filas `sui-notification`.
16
+
17
+ **No lo uses** para:
18
+
19
+ - La bandeja a pantalla completa y en mobile: la app usa `sui-tab-chips` («Todas», «No leídas (3)»)
20
+ en `pages/notifications/notifications.html:47`, que se toca mejor con el dedo. Es lo correcto.
21
+ - Las pestañas de cualquier otra pantalla: `sui-tab-menu-horizontal`.
22
+
23
+ ## Qué variante usar
24
+
25
+ > La guía del DS no tiene página para este componente: sale del Figma del DS (cabecera del panel
26
+ > de notificaciones). Todo lo de abajo es **propuesta**, salvo lo marcado «según el componente».
27
+ >
28
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos** (no hay panel de campana).
29
+
30
+ | prop | valor | cuándo | fuente |
31
+ |---|---|---|---|
32
+ | `tabs` | 2 a 4 pestañas | «Todas» primero, luego «No leídas» y los grupos del rol (Pedidos, Promos, Encargos…). Más de 4 no caben en el panel. | propuesta |
33
+ | `tabs[].badge` | número > 0 | El conteo de **no leídas**, solo en la pestaña donde importa. Es un `sui-badge` rojo lleno: un conteo que pide acción. | según el componente · regla de badge: canon |
34
+ | `tabs[].dividerBefore` | `true` | Separa lo que no es bandeja activa: «Archivadas» al final. | según el componente (Figma) |
35
+ | `[(active)]` | el `value` de la pestaña | Siempre enlazado: es un model de dos vías. | según el componente |
36
+ | `showFilter` | `true` (default) | Solo si el panel tiene filtros de verdad (por local, por fecha). | propuesta |
37
+ | `showFilter` | `false` | Lo normal: sin filtros, un botón que no hace nada estorba. | propuesta |
38
+ | `filterLabel` | texto | El nombre del botón de filtro para el lector de pantalla. Default «Filtrar». | según el componente |
39
+
40
+ ## Tamaño en mobile y en web
41
+
42
+ **No tiene `size`**: la fila mide 48 px, pero cada pestaña es un botón de **20 px de alto** (solo el
43
+ texto) y el filtro es un compact-button de 24 px.
44
+
45
+ | uso | mobile | web | fuente |
46
+ |---|---|---|---|
47
+ | las pestañas | **no alcanza**: 20 px de alto para el dedo. Usar `sui-tab-chips` | 20 px de alto, en una fila de 48 | sin tamaño suficiente (no se cambia aquí) |
48
+ | el filtro | 24 px, **bajo el mínimo de 32 px** en mobile | 24 px | sin tamaño suficiente |
49
+
50
+ ```html
51
+ @if (bp.isMobile()) {
52
+ <sui-tab-chips [chips]="pestanas" [value]="activa()" (valueChange)="activa.set($event)" />
53
+ } @else {
54
+ <sui-notification-tab-menu [tabs]="pestanas" [(active)]="activa" [showFilter]="false" />
55
+ }
56
+ ```
57
+
58
+ ## «No usar»: por qué no hoy y cuándo sí
59
+
60
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
61
+ |---|---|---|
62
+ | el componente | no hay panel de campana; la bandeja es una pantalla con `sui-tab-chips` | si el panel del local o el super admin suman la campana con bandeja desplegable en web |
63
+ | `showFilter` | no hay filtros en la bandeja | filtrar avisos por local (central con varios locales) o por fecha |
64
+ | `dividerBefore` | no hay «Archivadas» | si se agrega archivar avisos |
65
+
66
+ ## API
67
+
68
+ <!-- api:inicio -->
69
+ <!-- generada: no editar a mano — `npm run docs` -->
70
+
71
+ | input | tipo | default |
72
+ |---|---|---|
73
+ | `tabs` | `SuiNotificationTab<T>[]` | — (requerido) |
74
+ | `active` · model, `[(active)]` | `T` | `undefined` |
75
+ | `showFilter` | `boolean` | `true` |
76
+ | `filterLabel` | `string` | `'Filtrar'` |
77
+
78
+ | output | payload |
79
+ |---|---|
80
+ | `tabChange` | `T` |
81
+ | `filterClick` | `MouseEvent` |
82
+ <!-- api:fin -->
83
+
84
+ ```ts
85
+ interface SuiNotificationTab<T = string> {
86
+ value: T;
87
+ label: string;
88
+ badge?: number; // > 0 lo muestra
89
+ dividerBefore?: boolean; // línea vertical antes de esta pestaña
90
+ }
91
+ ```
92
+
93
+ ## Trampas
94
+
95
+ - **`showFilter` arranca en `true`**: si no pasas `false`, aparece un botón de filtro.
96
+ - `tabs` es **obligatorio** y `active` es un model: `[(active)]`, no `[value]` como en `sui-tab-chips`.
97
+ - La raya de la pestaña activa usa el primario de la app (naranja), no el azul del Figma.
98
+ - El badge no tiene tope: 120 sale «120». Si hace falta, el texto lo recorta quien lo usa («99+» va
99
+ en `label`, no en `badge`, porque `badge` es un número).
100
+ - El host lleva `role="tablist"` y cada pestaña `role="tab"` con `aria-selected`; no hay panel `tabpanel` asociado: lo arma quien lo usa.
101
+
102
+ ## Ejemplo
103
+
104
+ ```html
105
+ <sui-notification-tab-menu [showFilter]="false" [(active)]="pestana"
106
+ [tabs]="[
107
+ { value: 'todas', label: 'Todas' },
108
+ { value: 'no-leidas', label: 'No leídas', badge: 3 },
109
+ { value: 'pedidos', label: 'Pedidos' },
110
+ { value: 'archivadas', label: 'Archivadas', dividerBefore: true },
111
+ ]" />
112
+ ```