@ajuarezso/sui-design-system 0.19.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 (97) hide show
  1. package/docs/INDEX.md +136 -0
  2. package/docs/sui-alert/README.md +229 -0
  3. package/docs/sui-app-store-badge/README.md +137 -0
  4. package/docs/sui-avatar/README.md +263 -0
  5. package/docs/sui-avatar-group/README.md +115 -0
  6. package/docs/sui-badge/README.md +229 -0
  7. package/docs/sui-banner/README.md +190 -0
  8. package/docs/sui-brand-logo/README.md +143 -0
  9. package/docs/sui-breadcrumb-item/README.md +96 -0
  10. package/docs/sui-breadcrumbs/README.md +122 -0
  11. package/docs/sui-button/README.md +209 -0
  12. package/docs/sui-button-group/README.md +178 -0
  13. package/docs/sui-button-group-item/README.md +102 -0
  14. package/docs/sui-card/README.md +168 -0
  15. package/docs/sui-chart-legend/README.md +140 -0
  16. package/docs/sui-chart-legend-dot/README.md +118 -0
  17. package/docs/sui-checkbox/README.md +147 -0
  18. package/docs/sui-checkbox-card/README.md +150 -0
  19. package/docs/sui-checkbox-label/README.md +143 -0
  20. package/docs/sui-circular-progress-bar/README.md +131 -0
  21. package/docs/sui-color-dot/README.md +112 -0
  22. package/docs/sui-color-picker/README.md +124 -0
  23. package/docs/sui-compact-avatar-group/README.md +103 -0
  24. package/docs/sui-compact-button/README.md +190 -0
  25. package/docs/sui-compact-select/README.md +127 -0
  26. package/docs/sui-compact-select-for-input/README.md +117 -0
  27. package/docs/sui-content-card/README.md +147 -0
  28. package/docs/sui-content-divider/README.md +124 -0
  29. package/docs/sui-content-label/README.md +148 -0
  30. package/docs/sui-counter-input/README.md +145 -0
  31. package/docs/sui-date-selector/README.md +98 -0
  32. package/docs/sui-datepicker/README.md +193 -0
  33. package/docs/sui-day-cell/README.md +118 -0
  34. package/docs/sui-day-label/README.md +81 -0
  35. package/docs/sui-divider/README.md +102 -0
  36. package/docs/sui-drawer-footer/README.md +127 -0
  37. package/docs/sui-drawer-header/README.md +140 -0
  38. package/docs/sui-emoji/README.md +138 -0
  39. package/docs/sui-empty-state/README.md +145 -0
  40. package/docs/sui-fancy-button/README.md +148 -0
  41. package/docs/sui-file-icon/README.md +103 -0
  42. package/docs/sui-file-upload/README.md +154 -0
  43. package/docs/sui-file-upload-card/README.md +129 -0
  44. package/docs/sui-flag/README.md +99 -0
  45. package/docs/sui-form-hint/README.md +124 -0
  46. package/docs/sui-form-label/README.md +148 -0
  47. package/docs/sui-icon/README.md +135 -0
  48. package/docs/sui-image-upload/README.md +200 -0
  49. package/docs/sui-image-upload-profile/README.md +145 -0
  50. package/docs/sui-inline-input/README.md +104 -0
  51. package/docs/sui-inline-select/README.md +101 -0
  52. package/docs/sui-input/README.md +244 -0
  53. package/docs/sui-integration-switch/README.md +142 -0
  54. package/docs/sui-kbd/README.md +97 -0
  55. package/docs/sui-key-icon/README.md +125 -0
  56. package/docs/sui-link-button/README.md +221 -0
  57. package/docs/sui-logo/README.md +152 -0
  58. package/docs/sui-notification/README.md +179 -0
  59. package/docs/sui-notification-footer/README.md +98 -0
  60. package/docs/sui-notification-tab-menu/README.md +112 -0
  61. package/docs/sui-otp-input/README.md +116 -0
  62. package/docs/sui-pagination/README.md +146 -0
  63. package/docs/sui-password-strength/README.md +99 -0
  64. package/docs/sui-payment-icon/README.md +98 -0
  65. package/docs/sui-period-range/README.md +93 -0
  66. package/docs/sui-popover/README.md +178 -0
  67. package/docs/sui-product-card/README.md +173 -0
  68. package/docs/sui-progress-bar/README.md +132 -0
  69. package/docs/sui-progress-bar-label/README.md +143 -0
  70. package/docs/sui-radio/README.md +134 -0
  71. package/docs/sui-radio-card/README.md +160 -0
  72. package/docs/sui-radio-label/README.md +137 -0
  73. package/docs/sui-rating/README.md +199 -0
  74. package/docs/sui-rich-editor/README.md +114 -0
  75. package/docs/sui-segmented-control/README.md +144 -0
  76. package/docs/sui-select/README.md +180 -0
  77. package/docs/sui-slider/README.md +143 -0
  78. package/docs/sui-social-button/README.md +158 -0
  79. package/docs/sui-status-badge/README.md +164 -0
  80. package/docs/sui-stepper/README.md +166 -0
  81. package/docs/sui-store-card/README.md +147 -0
  82. package/docs/sui-switch/README.md +146 -0
  83. package/docs/sui-switch-card/README.md +149 -0
  84. package/docs/sui-switch-label/README.md +139 -0
  85. package/docs/sui-tab-chips/README.md +185 -0
  86. package/docs/sui-tab-menu-horizontal/README.md +142 -0
  87. package/docs/sui-tab-menu-vertical/README.md +136 -0
  88. package/docs/sui-tag/README.md +145 -0
  89. package/docs/sui-tag-input/README.md +120 -0
  90. package/docs/sui-textarea/README.md +157 -0
  91. package/docs/sui-time-picker/README.md +237 -0
  92. package/docs/sui-toast/README.md +190 -0
  93. package/docs/sui-tooltip/README.md +201 -0
  94. package/fesm2022/ajuarezso-sui-design-system.mjs +466 -279
  95. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  96. package/package.json +1 -1
  97. package/types/ajuarezso-sui-design-system.d.ts +367 -72
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: sui-drawer-header
3
+ selector: sui-drawer-header
4
+ resumen: Cabecera de un panel lateral (título, descripción, cerrar); hoy sin contenedor en SUI y sin uso en la app
5
+ alternativas: [sui-modal (con title y description: la cabecera de todos los modales de la app), sui-modal-header (la cabecera suelta del modal), sui-page-header (título de una página)]
6
+ ---
7
+
8
+ # sui-drawer-header
9
+
10
+ Story: [Molecules/Drawer/Drawer Header](https://sui-design-system.web.app/?path=/docs/molecules-drawer-drawer-header--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Hoy no se usa.** SUI no tiene el contenedor del drawer (el panel que sale del borde): solo esta
15
+ cabecera y su pie. En la app, todo lo que se abre encima es un `sui-modal` (fullscreen en mobile,
16
+ canon) o un `sui-modal-sheet`, y su cabecera sale de los inputs `title` y `description` del modal.
17
+
18
+ **Úsalo** cuando exista un panel lateral de web (un detalle que se abre a la derecha sin tapar la
19
+ lista, como el pedido en el panel de órdenes) y haga falta su cabecera.
20
+
21
+ **No lo uses** para:
22
+
23
+ - La cabecera de un modal o un sheet: `sui-modal` con `title`/`description` (o `sui-modal-header`).
24
+ - El título de una página: `sui-page-header`.
25
+ - Mobile: un panel lateral en 390 px es un modal fullscreen.
26
+
27
+ Regla corta: **modal o sheet → sui-modal con title · panel lateral de web → drawer-header (cuando exista el panel).**
28
+
29
+ ## Qué variante usar
30
+
31
+ > **Lo que dice la guía del DS**: el drawer es «un panel que sale desde el borde de la pantalla».
32
+ > Su cabecera trae título y **botón de cerrar visible por default**. No habla de tipos ni tamaños.
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`): **0 usos**.
35
+
36
+ ### `type`
37
+
38
+ | type | cuándo | fuente |
39
+ |---|---|---|
40
+ | `basic` (default) | Lo normal: título y cerrar. | propuesta, falta aprobación |
41
+ | `left-icon` | El ícono dice de qué es el panel antes de leer («history-line» en el historial). En `small` va suelto (24); en `large`/`xlarge`, en un círculo con borde. | propuesta, falta aprobación |
42
+
43
+ ### `size`
44
+
45
+ | size | qué cambia | cuándo | fuente |
46
+ |---|---|---|---|
47
+ | `small` (default) | 64 px, todo en una línea; **no muestra `description`** | Panel con título que se explica solo. Es el único que admite `link`. | propuesta, falta aprobación |
48
+ | `large` | 88 px, título arriba y `description` debajo | Panel que necesita una línea de contexto («Últimos 30 días»). | propuesta, falta aprobación |
49
+ | `xlarge` | padding 24, título 20, descripción 16 | No: extensión de SUI sin caso; en web no hace falta letra más grande. | propuesta, falta aprobación |
50
+
51
+ ### Lo demás
52
+
53
+ | input | valor | cuándo | fuente |
54
+ |---|---|---|---|
55
+ | `showDismiss` | `true` (default) | Siempre. | según la guía del DS (cerrar visible por default) |
56
+ | `showDismiss` | `false` | Solo si el panel no se puede cerrar sin decidir (y entonces es un modal, no un drawer). | propuesta, falta aprobación |
57
+ | `showDivider` | `true` | Cuando el cuerpo scrollea por debajo de la cabecera. | propuesta, falta aprobación |
58
+ | `badge` | número | Pendientes dentro del panel (círculo rojo). | propuesta, falta aprobación |
59
+ | `badge` | texto o `SuiBadgeConfig` | Un estado o etiqueta al lado del título. Pasa `variant: 'lighter'`: el default de aquí es `light` (ver Trampas). | canon (README de `sui-badge`: `lighter` en cabeceras) |
60
+ | `link` | texto | Una acción menor en la cabecera («Ver todo»). Solo en `small`. | propuesta, falta aprobación |
61
+ | `dismissAriaLabel` | «Cerrar» (default) | Ya está en español. | según el código |
62
+
63
+ Usos de hoy que rompen las reglas: **0** (no se usa).
64
+
65
+ ## Tamaño en mobile y en web
66
+
67
+ **No tiene tamaño para mobile**: el botón de cerrar mide **24 px** (compact-button `large`), lejos de
68
+ los 40-44 del dedo. Es una pieza de web.
69
+
70
+ | uso | mobile | web | fuente |
71
+ |---|---|---|---|
72
+ | cabecera de panel | no se usa: `sui-modal` fullscreen con `title` | `small` o `large` | propuesta, falta aprobación |
73
+
74
+ ```html
75
+ @if (!bp.isMobile()) {
76
+ <sui-drawer-header size="large" title="Pedido #1042" description="Sabores Andinos · hace 5 min" (dismiss)="cerrar()" />
77
+ }
78
+ ```
79
+
80
+ ## «No usar»: por qué no hoy y cuándo sí
81
+
82
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
83
+ |---|---|---|
84
+ | el componente entero | SUI no tiene el panel que lo contiene; los modales traen su cabecera | un panel lateral de detalle en web (el pedido en el panel de órdenes) |
85
+ | `xlarge` | sin caso | nunca en web |
86
+ | `showDismiss` en `false` | un panel siempre se cierra | nunca en un drawer |
87
+ | en mobile | cerrar de 24 px | nunca |
88
+
89
+ ## API
90
+
91
+ <!-- api:inicio -->
92
+ <!-- generada: no editar a mano — `npm run docs` -->
93
+
94
+ | input | tipo | default |
95
+ |---|---|---|
96
+ | `type` | `'basic' \| 'left-icon'` | `'basic'` |
97
+ | `size` | `'small' \| 'large' \| 'xlarge'` | `'small'` |
98
+ | `title` | `string` | `''` |
99
+ | `description` | `string \| null` | `null` |
100
+ | `icon` | `string \| null` | `null` |
101
+ | `badge` | `SuiBadgeConfig \| number \| string \| null` | `null` |
102
+ | `link` | `SuiLinkConfig \| string \| null` | `null` |
103
+ | `showDismiss` | `boolean` | `true` |
104
+ | `showDivider` | `boolean` | `false` |
105
+ | `dismissAriaLabel` | `string` | `'Cerrar'` |
106
+
107
+ | output | payload |
108
+ |---|---|
109
+ | `dismiss` | `MouseEvent` |
110
+ | `linkClick` | `MouseEvent` |
111
+ <!-- api:fin -->
112
+
113
+ ```ts
114
+ type SuiDrawerHeaderType = 'basic' | 'left-icon';
115
+ type SuiDrawerHeaderSize = 'small' | 'large' | 'xlarge';
116
+ ```
117
+
118
+ ## Trampas
119
+
120
+ - **`description` no se ve en `small`** y **`link` no se ve en `large`/`xlarge`**: los dos se pasan
121
+ sin error y no aparecen.
122
+ - **El badge de texto sale `orange` + `light` por default**, que va contra el canon del badge
123
+ (`lighter` en cabeceras, naranja solo si pide atención). Pasa un `SuiBadgeConfig` completo.
124
+ - **`badge` en `0` sí se dibuja** (un círculo rojo con «0»). Pasa `null` para no mostrarlo.
125
+ - **`left-icon` sin `icon` no dibuja nada.**
126
+ - El título es un `<h2>`: si la página ya tiene un `h2` al mismo nivel, revisa el orden de títulos.
127
+ - No hay contenedor: el fondo, el ancho y la animación del panel los pones tú.
128
+
129
+ ## Ejemplo
130
+
131
+ ```html
132
+ <sui-drawer-header
133
+ type="left-icon"
134
+ size="large"
135
+ icon="history-line"
136
+ title="Historial de pedidos"
137
+ description="Últimos 30 días"
138
+ [showDivider]="true"
139
+ (dismiss)="cerrar()" />
140
+ ```
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: sui-emoji
3
+ selector: sui-emoji
4
+ resumen: Un emoji 3D animado (Fluent) para los momentos con emoción: estados vacíos, celebraciones, onboarding
5
+ alternativas: [sui-icon (ícono funcional, monocromo), sui-empty-state (el estado vacío completo, que ya trae su emoji)]
6
+ ---
7
+
8
+ # sui-emoji
9
+
10
+ Story: [Atoms/Emoji](https://sui-design-system.web.app/?path=/docs/atoms-emoji--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** donde la pantalla tiene que **sentirse**, no solo funcionar: un estado vacío, «¡Pedido
15
+ confirmado!», los pasos de una landing, la barra de calificación.
16
+
17
+ **No lo uses** para:
18
+
19
+ - Un ícono funcional (un botón, una fila, un menú): eso es `sui-icon`. Un emoji no es un ícono.
20
+ - Muchos a la vez animados: cada uno es un APNG de ~1 MB en bucle.
21
+ - Una imagen propia que no es un emoji (la moneda de sol): un `<img>`.
22
+
23
+ ## Qué variante usar
24
+
25
+ > **La guía del DS no tiene este componente**: es propio de SUI. Lo marcado «canon» ya es regla
26
+ > del proyecto; el resto es **propuesta, falta aprobación**.
27
+ >
28
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: 10 emojis en 3 archivos, sin contar
29
+ > prototipos ni vitrinas. El catálogo tiene 59.
30
+
31
+ ### Dónde va
32
+
33
+ | caso | cómo | fuente |
34
+ |---|---|---|
35
+ | Estados vacíos y celebraciones | Emoji animado, uno solo, en `xl`. Nada de íconos genéricos en un estado vacío. | canon (preferencia del dueño: emojis animados en los estados vacíos) |
36
+ | Pasos de una landing | `lg`, uno por paso. | propuesta |
37
+ | Junto a un título o dentro de un texto | `md` o `sm`, como acento. | propuesta |
38
+ | Como ícono de un botón | No: el botón lleva `leftIcon`. | propuesta |
39
+
40
+ ### `size`
41
+
42
+ | valor | px | cuándo | fuente |
43
+ |---|---|---|---|
44
+ | `xl` | 48 | Estado vacío, celebración. | propuesta |
45
+ | `lg` | 32 | Pasos de una landing, la barra de calificación. | propuesta |
46
+ | `md` (default) | 24 | Acompaña un título. | propuesta |
47
+ | `sm` | 20 | Dentro de una línea de texto. | propuesta |
48
+ | `xs` | 16 | No usar hoy. | propuesta |
49
+ | `full` | 100 % | Llena su caja: lo usa `sui-empty-state`. | propuesta |
50
+
51
+ ### `animated`, `src`, `name`, `ariaLabel`
52
+
53
+ | input | cuándo | fuente |
54
+ |---|---|---|
55
+ | `animated` (default `true`) | Uno solo → animado. **Varios a la vez → `false`.** Ojo: solo las 5 caritas de la calificación (`pensive-face` … `grinning-face-smiling-eyes`) tienen copia estática; para el resto, `false` no cambia nada. | propuesta (la regla ya está escrita en `sui-emoji.ts`) |
56
+ | `name` | Uno del catálogo. Si no está, se agrega al catálogo del DS. | propuesta |
57
+ | `src` | Un emoji que no está en el catálogo, mientras se agrega. **Nunca** un `<img>` suelto con la URL del emoji. | propuesta |
58
+ | `ariaLabel` | Solo si el emoji dice algo que el texto no dice. Si no, queda decorativo (`aria-hidden`). | propuesta |
59
+
60
+ **Usos de hoy que romperían la propuesta:**
61
+
62
+ - **2 emojis como ícono de botón**: «Encargarme yo» en `pages/orders/orders.html:322` y `:353` → `leftIcon`.
63
+ - **5 animados a la vez** en `pages/public/landing-customers/landing-customers.html:160`–`:184`
64
+ (más otro en `:56`). No tienen copia estática: o se acepta el peso en la landing o se generan
65
+ las copias.
66
+ - **Un catálogo paralelo**: `core/fluent-emoji.ts` arma sus propias URLs (otro CDN incluido) y lo
67
+ importan 8 archivos (`components/permission-prime-modal/permission-prime-modal.ts`,
68
+ `pages/role-selector/role-selector.ts`, `pages/customer/order-tracking/order-tracking.ts`…).
69
+ - **10 `<img>` con un emoji**, fuera del componente: `pages/products/add-product/add-product.html:122`
70
+ (la URL del paquete escrita a mano, y 3 más en el mismo archivo),
71
+ `components/location-flow-outlet/location-flow-outlet.html:14`,
72
+ `pages/customer/order-tracking/order-tracking.html:249`. No cuentan las imágenes de los rubros
73
+ (`pages/customer/store-browser/store-browser.html:193` y similares): vienen de datos y no son
74
+ del catálogo.
75
+
76
+ ## Tamaño en mobile y en web
77
+
78
+ En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
79
+ pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
80
+ breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
81
+ el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propuesta**.
82
+
83
+ | uso | mobile | web |
84
+ |---|---|---|
85
+ | estado vacío, celebración | `xl` (48) | `xl` (48) |
86
+ | pasos de una landing | `lg` (32) | `xl` (48) |
87
+ | dentro de un texto | `md` (24) | `sm` (20) |
88
+
89
+ ```html
90
+ <sui-emoji name="hamburger" [size]="bp.isMobile() ? 'lg' : 'xl'" />
91
+ ```
92
+
93
+ El emoji no se toca, así que la regla del dedo no aplica: en los casos de ilustración va igual o
94
+ más grande en web, donde sobra espacio. El tamaño con nombre más grande es `xl` (48); para uno más
95
+ grande, `size="full"` dentro de una caja con el alto que se quiera.
96
+
97
+ ## «No usar»: por qué no hoy y cuándo sí
98
+
99
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
100
+ |---|---|---|
101
+ | `size` `xs` | a 16 px un emoji ya no se distingue | dentro de un tag de categoría, solo con copia estática |
102
+ | como ícono de botón o de fila | un emoji no es un ícono | ninguno |
103
+
104
+ ## API
105
+
106
+ <!-- api:inicio -->
107
+ <!-- generada: no editar a mano — `npm run docs` -->
108
+
109
+ | input | tipo | default |
110
+ |---|---|---|
111
+ | `name` | `SuiEmojiName \| null` | `null` |
112
+ | `src` | `string \| null` | `null` |
113
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `'md'` |
114
+ | `ariaLabel` | `string \| null` | `null` |
115
+ | `animated` | `boolean` | `true` |
116
+
117
+ Outputs: ninguno.
118
+ <!-- api:fin -->
119
+
120
+ ## Trampas
121
+
122
+ - **Pesan**: los animados son APNG de ~1 MB y 73 fotogramas cada uno, servidos desde
123
+ `raw.githubusercontent.com`. Si ese servidor se cae, no hay emoji.
124
+ - **`animated=false` solo sirve para 5**: las caritas. El resto no tiene copia estática.
125
+ - **`src` gana sobre `name`.**
126
+ - **No toma color**: no responde a `currentColor` ni al tema.
127
+ - Sin `ariaLabel` es decorativo: el lector de pantalla no lo dice.
128
+ - `loading="lazy"`: fuera de la pantalla, no carga hasta que se acerca.
129
+
130
+ ## Ejemplo
131
+
132
+ ```html
133
+ <!-- Celebración -->
134
+ <sui-emoji name="party-popper" size="xl" />
135
+
136
+ <!-- La barra de calificación: cinco juntos, estáticos -->
137
+ <sui-emoji name="neutral-face" size="lg" [animated]="false" ariaLabel="Regular" />
138
+ ```
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: sui-empty-state
3
+ selector: sui-empty-state
4
+ resumen: Pantalla o lista sin nada que mostrar (o que no pudo cargar) con emoji animado, título, explicación y una acción opcional
5
+ alternativas: [sui-alert (un aviso dentro de una pantalla que sí tiene contenido), sui-banner (aviso de toda la app), skeleton (mientras carga, nunca un empty)]
6
+ ---
7
+
8
+ # sui-empty-state
9
+
10
+ Story: [Molecules/Empty State](https://sui-design-system.web.app/?path=/docs/molecules-empty-state--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** cuando una lista o una pantalla no tiene nada que mostrar: el carrito vacío, sin pedidos
15
+ aún, una búsqueda sin resultados, un filtro que no trae nada. También cuando la lista **no pudo
16
+ cargar**, con una acción para reintentar.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Mientras carga: eso es un skeleton. Un empty que aparece y después se llena se lee como «no
21
+ hay nada» por un segundo.
22
+ - Un aviso dentro de una pantalla que sí tiene contenido («Tu local está cerrado»): `sui-alert`.
23
+ - Un error de un formulario: el mensaje va en el campo (`error` / `errorMessage`).
24
+
25
+ Regla corta: **no hay nada que mostrar → empty-state · está cargando → skeleton · hay contenido y
26
+ algo que avisar → alert.**
27
+
28
+ ## Qué variante usar
29
+
30
+ > **La guía del DS no tiene página del empty state.** El componente de SUI se construyó a
31
+ > propósito con Fluent Emoji animados en vez de ilustraciones: es una decisión del proyecto
32
+ > (memoria «emojis animados en empty states», 17-04-2026).
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **66
35
+ > empty-states en 40 archivos**. 25 con `action` (10 con `route`). 4 con `emoji` propio, 22 con la
36
+ > URL del zorro pegada a mano (que ya es el default) y 40 sin `emoji`. 29 con un atributo `icon`
37
+ > que el componente no tiene.
38
+
39
+ ### Las piezas
40
+
41
+ | prop | cuándo | fuente |
42
+ |---|---|---|
43
+ | `emoji` vacío (default: el zorro) | Lo normal. El zorro es la mascota de los empty states y sale solo: **no pegues su URL**. | canon (memoria del proyecto) |
44
+ | `emoji` propio | Cuando el emoji dice algo del caso: el reloj de arena en «Aún no tienes facturas» (se está esperando algo), el chef en los avisos del local. Siempre de `FLUENT_EMOJI_ANIM` (`core/fluent-emoji.ts`) o de `assets/emoji-anim/`. | canon (memoria del proyecto) |
45
+ | `title` (obligatorio) | Qué pasa, en corto y sin punto: «Tu carrito está vacío», «Sin pedidos aún». En una búsqueda, repite lo buscado: «Nada con “pollo broaster”». | propuesta (práctica de la app) |
46
+ | `subtitle` | Qué va a pasar o qué puede hacer la persona: «Cuando hagas tu primer pedido, aparecerá aquí.» | propuesta |
47
+ | `action` como string + `(actionClicked)` | La salida es algo de esta misma pantalla: «Reintentar», «Ver todo el catálogo», «Activar captura». | propuesta |
48
+ | `action` como `{ label, route }` | La salida es otra pantalla: «Ver negocios» → `/cliente/inicio`. | propuesta |
49
+ | sin `action` | No hay un paso obvio, o la pantalla ya tiene el botón para llenarla (el «Nuevo local» de arriba). | propuesta |
50
+ | error de carga | Siempre con `action="Reintentar"`. Excepción: la pantalla reintenta sola y lo dice («Seguimos intentando»). | propuesta |
51
+
52
+ **Usos de hoy que rompen las reglas:**
53
+
54
+ - **29 con `icon="…"`**: `icon` no es un input, el atributo no hace nada. Ejemplos:
55
+ `pages/customer/cart/cart.html:18`, `pages/drivers/drivers.html:87`,
56
+ `pages/customer/order-history/order-history.html:20`. Se borra.
57
+ - **22 con la URL del zorro pegada** (`emoji="…/Animals/Fox.png"`), que ya es el default:
58
+ `pages/customers/customers.html:65`, `pages/products/products.html:113`,
59
+ `pages/locations/locations.html:16`. Se borra.
60
+ - **4 errores de carga sin «Reintentar»**:
61
+ `pages/driver/driver-dashboard/driver-dashboard.html:1071`,
62
+ `pages/customer/order-history/order-history.html:20`,
63
+ `pages/super-admin/master-drivers/master-drivers.html:524` y `:754`.
64
+ (`pages/public/pedido-en-vivo/pedido-en-vivo.html:50` no cuenta: reintenta solo.)
65
+
66
+ ## Tamaño en mobile y en web
67
+
68
+ El emoji mide 120 en las dos; el padding pasa solo de 48 / 24 en web a 32 / 20 desde tablet hacia
69
+ abajo (media query `bp.medium` del componente). El `size` solo cambia **el botón de la acción**:
70
+
71
+ | size | botón | fuente |
72
+ |---|---|---|
73
+ | `medium` (default) | 40 px (`sui-button` `medium`) | lo que había en el DS |
74
+ | `large` | 48 px (`sui-button` `large`, texto 16) | canon (aprobado por el dueño, 03-10-2026): extensión SUI |
75
+
76
+ | uso | mobile | web | fuente |
77
+ |---|---|---|---|
78
+ | ilustración + texto | lo resuelve el componente | lo resuelve el componente | lo que hay en el DS |
79
+ | botón de la acción | `large` (48) | `medium` (40) | propuesta: el tamaño es extensión SUI aprobada (03-10-2026); el «cuándo» falta aprobarlo |
80
+
81
+ ```html
82
+ <sui-empty-state
83
+ title="Tu carrito está vacío"
84
+ [action]="{ label: 'Ver negocios', route: '/cliente/inicio' }"
85
+ [size]="bp.isMobile() ? 'large' : 'medium'" />
86
+ ```
87
+
88
+ ## «No usar»: por qué no hoy y cuándo sí
89
+
90
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
91
+ |---|---|---|
92
+ | un emoji que no sea animado (PNG estático, SVG, ícono) | la regla del proyecto es emoji animado | nunca |
93
+ | empty con `action` que hace lo mismo que un botón ya visible en la pantalla | dos botones para lo mismo | nunca |
94
+
95
+ ## API
96
+
97
+ <!-- api:inicio -->
98
+ <!-- generada: no editar a mano — `npm run docs` -->
99
+
100
+ | input | tipo | default |
101
+ |---|---|---|
102
+ | `emoji` | `string` | `''` |
103
+ | `title` | `string` | — (requerido) |
104
+ | `subtitle` | `string` | `''` |
105
+ | `action` | `SuiEmptyStateAction \| string \| null` | `null` |
106
+ | `size` | `'medium' \| 'large'` | `'medium'` |
107
+
108
+ | output | payload |
109
+ |---|---|
110
+ | `actionClicked` | `void` |
111
+ <!-- api:fin -->
112
+
113
+ ```ts
114
+ interface SuiEmptyStateAction { label: string; route?: string; }
115
+ ```
116
+
117
+ `EMPTY_STATE_FOX_EMOJI` (exportada) es la URL del zorro.
118
+
119
+ ## Trampas
120
+
121
+ - **`icon` no existe.** Viene de un `app-empty-state` viejo; Angular no se queja porque lo toma
122
+ como atributo HTML.
123
+ - **`emoji` es una URL**, no un nombre de `SuiEmoji` (`'bell'` no funciona).
124
+ - **`title` es obligatorio** y el host borra el atributo `title` del DOM (sin tooltip nativo).
125
+ - Con `route`, el botón usa `routerLink` y **no emite** `actionClicked`.
126
+ - El botón es `sui-button` `filled` `primary`: el color no se cambia; el tamaño sí, con `size` (`medium` 40 · `large` 48).
127
+ - El emoji carga con `loading="lazy"`: en una captura de pantalla completa puede salir vacío.
128
+
129
+ ## Ejemplo
130
+
131
+ ```html
132
+ <!-- Lista vacía con salida a otra pantalla -->
133
+ <sui-empty-state
134
+ title="Tu carrito está vacío"
135
+ subtitle="Explora las tiendas y agrega productos para empezar."
136
+ [action]="{ label: 'Ver negocios', route: '/cliente/inicio' }" />
137
+
138
+ <!-- Error de carga -->
139
+ <sui-empty-state
140
+ [emoji]="emoji.thinking"
141
+ title="No se pudieron cargar tus pedidos"
142
+ subtitle="Revisa tu conexión y vuelve a intentar."
143
+ action="Reintentar"
144
+ (actionClicked)="cargar()" />
145
+ ```
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: sui-fancy-button
3
+ selector: sui-fancy-button
4
+ resumen: Botón con brillo y degradé para el CTA de una landing o campaña
5
+ alternativas: [sui-button (toda acción dentro de la app), sui-app-store-badge (descargar la app desde una landing)]
6
+ ---
7
+
8
+ # sui-fancy-button
9
+
10
+ Story: [Atoms/Button/Fancy Button](https://sui-design-system.web.app/?path=/docs/atoms-button-fancy-button--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Hoy no se usa** (0 usos en la app). Es el mismo botón que `sui-button` con un acabado de
15
+ marketing: brillo arriba, borde interior claro y un anillo del color del botón.
16
+
17
+ **Cuándo sí, en un flujo nuevo**: el CTA principal de una landing (`/empresas`, `/repartidores`),
18
+ «Mejorar plan» o una campaña puntual. Uno por pantalla.
19
+
20
+ **No lo uses** para:
21
+
22
+ - **Cualquier acción dentro de la app**: `sui-button`. Al lado de botones normales, el fancy
23
+ compite con todo y rompe la jerarquía.
24
+ - **Una acción destructiva**: `sui-button` `color="error"`.
25
+ - **Descargar la app**: `sui-app-store-badge`.
26
+
27
+ ## Qué variante usar
28
+
29
+ > **La guía del DS no dice cuándo usar cada tipo.** Su página lo presenta como «botones normales
30
+ > con una apariencia vistosa» y muestra los cuatro tipos, los tres tamaños, los íconos y el
31
+ > deshabilitado, sin do/don't. Todo el componente está en **«no usar» (canon, aprobado por el
32
+ > dueño, 03-10-2026)**; la tabla dice dónde iría cada tipo si aparece el caso.
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0** fancy-buttons, sin contar
35
+ > prototipos ni vitrinas.
36
+
37
+ ### Lo que sí dice la guía del DS
38
+
39
+ - **Para qué es**: un botón normal con un acabado más vistoso.
40
+ - **Default**: `neutral` (negro) en la guía; **`primary` en SUI**.
41
+ - **Tamaños**: `medium` (40), `small` (36) y `xsmall` (32). No hay más grandes.
42
+ - **Hover**: el brillo se aclara, no se oscurece. `basic` pasa a fondo gris plano.
43
+ - **Deshabilitado**: fondo gris plano, sin brillo, sin anillo ni sombra, igual en los cuatro tipos.
44
+
45
+ ### `type` (el relleno)
46
+
47
+ | type | dónde iría, en un flujo nuevo | ejemplo de copy | fuente |
48
+ |---|---|---|---|
49
+ | `primary` (default SUI) | El CTA principal de una landing o una campaña. Uno por pantalla. | «Empieza gratis», «Mejorar plan» | no usar hoy · cuándo sí: canon (aprobado por el dueño, 03-10-2026) |
50
+ | `neutral` (default de la guía) | El CTA de una landing sobre una sección clara donde el naranja ya se usó arriba. | «Ver planes» | no usar hoy (en la app va `sui-button`) · cuándo sí: propuesta |
51
+ | `basic` | El secundario al lado de un fancy `primary` en la misma landing. | «Saber más» | no usar hoy (en la app va `sui-button`) · cuándo sí: propuesta |
52
+ | `destructive` | Ninguno a la vista: una acción destructiva nunca es marketing. | — | no usar (en la app va `sui-button` `error`) · canon (aprobado por el dueño, 03-10-2026) |
53
+
54
+ ### `size`
55
+
56
+ | size | cuándo | fuente |
57
+ |---|---|---|
58
+ | `medium` (40, default) | El CTA de la landing en desktop. | escala y default según la guía del DS · cuándo: propuesta |
59
+ | `small` (36) | Un CTA dentro de una card de la landing (la card de un plan). | escala según la guía del DS · cuándo: propuesta |
60
+ | `xsmall` (32) | Sin caso: en una landing el CTA nunca es tan chico. | escala según la guía del DS · cuándo: propuesta |
61
+
62
+ ### Íconos y `disabled`
63
+
64
+ | prop | cuándo | fuente |
65
+ |---|---|---|
66
+ | `rightIcon` (`arrow-right-line`) | El CTA lleva a otra página: «Empieza gratis →». | propuesta |
67
+ | `leftIcon` | El ícono dice la acción (descargar, WhatsApp). | propuesta |
68
+ | `disabled` | Casi nunca: un CTA de marketing no se deshabilita, se esconde. | cómo se ve: según la guía del DS · cuándo: propuesta |
69
+ | `href` | El CTA navega (lo normal en una landing): pinta un `<a>`; `rel` ya viene en `'noopener noreferrer'`. | propuesta |
70
+
71
+ ## Tamaño en mobile y en web
72
+
73
+ En mobile se toca con el dedo: el área táctil tiene que medir **44 px o más**. En web, con mouse,
74
+ va un tamaño más chico. La app ya lo resuelve con `BreakpointsService`
75
+ (`src/app/services/breakpoints.service.ts`, mobile = hasta 767 px):
76
+ `[size]="bp.isMobile() ? 'large' : 'small'"`, 27 usos hoy en `master-pedidos` (16 `large`/`small`,
77
+ 9 `large`/`medium`, 2 `medium`/`xsmall`). Regla del dueño, 03-10-2026.
78
+
79
+ | uso | mobile | web | fuente |
80
+ |---|---|---|---|
81
+ | CTA principal de una landing | no usar fancy: `sui-button` `large` (48) | `medium` (40) | propuesta |
82
+ | CTA dentro de la card de un plan | no usar fancy: `sui-button` `large` | `small` (36) | propuesta |
83
+
84
+ ```html
85
+ @if (bp.isMobile()) {
86
+ <sui-button size="large">Empieza gratis</sui-button>
87
+ } @else {
88
+ <sui-fancy-button type="primary" size="medium">Empieza gratis</sui-fancy-button>
89
+ }
90
+ ```
91
+
92
+ **El fancy no tiene un tamaño táctil**: el más grande mide 40, por debajo de 44. En mobile el CTA
93
+ va con `sui-button` `large`. Hoy no hay usos (todo el componente está en «no usar»).
94
+
95
+ ## «No usar»: por qué no hoy y cuándo sí
96
+
97
+ Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
98
+ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
99
+
100
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
101
+ |---|---|---|
102
+ | `sui-fancy-button` (los 4 tipos) | Es estilo de marketing (brillo, degradé); en la app compite con todo | el CTA principal de una landing (`/empresas`, `/repartidores`), «Mejorar plan» o una campaña |
103
+ | `type="destructive"` | Una acción destructiva va con `sui-button` `error` | no se ve un caso: una destructiva no es marketing |
104
+
105
+ ## API
106
+
107
+ <!-- api:inicio -->
108
+ <!-- generada: no editar a mano — `npm run docs` -->
109
+
110
+ | input | tipo | default |
111
+ |---|---|---|
112
+ | `type` | `'primary' \| 'neutral' \| 'basic' \| 'destructive'` | `'primary'` |
113
+ | `size` | `'medium' \| 'small' \| 'xsmall'` | `'medium'` |
114
+ | `leftIcon` | `string \| null` | `null` |
115
+ | `rightIcon` | `string \| null` | `null` |
116
+ | `disabled` | `boolean` | `false` |
117
+ | `href` | `string \| null` | `null` |
118
+ | `target` | `string \| null` | `null` |
119
+ | `rel` | `string \| null` | `'noopener noreferrer'` |
120
+ | `htmlType` | `'button' \| 'submit' \| 'reset'` | `'button'` |
121
+ | `ariaLabel` | `string \| null` | `null` |
122
+
123
+ | output | payload |
124
+ |---|---|
125
+ | `clicked` | `MouseEvent` |
126
+ <!-- api:fin -->
127
+
128
+ El clic se escucha con `(clicked)`. Slots: `<ng-content>` (el texto).
129
+
130
+ ## Trampas
131
+
132
+ - **`type` es el relleno**, no el `type` HTML: ese se llama **`htmlType`**. `type="submit"` no
133
+ compila (no es un tipo válido) y no hace un submit.
134
+ - **El radio es 10 px, no pill.** Al lado de un `sui-button` (pill en SUI) se ven de dos familias.
135
+ - **No hay `large` ni `xlarge`**: el más grande mide 40. En mobile, donde el CTA de la app es de
136
+ 48, un fancy queda más bajo.
137
+ - **El default es `primary`**; en la guía es `neutral`.
138
+ - El anillo del `neutral` es un hex crudo (`#242628`): no hay token para ese gris.
139
+ - Ya trae el arreglo de iOS para el `:active` pegado: no lo agregues.
140
+
141
+ ## Ejemplo
142
+
143
+ ```html
144
+ <!-- Solo en una landing: el CTA principal -->
145
+ <sui-fancy-button type="primary" rightIcon="arrow-right-line" href="/auth/empresa/registro">
146
+ Empieza gratis
147
+ </sui-fancy-button>
148
+ ```
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: sui-file-icon
3
+ selector: sui-file-icon
4
+ resumen: El ícono de un archivo con su extensión (PDF, XLSX, JPG…) en el color de su tipo
5
+ alternativas: [sui-file-upload-card (el archivo que se está subiendo, con progreso), sui-icon (un ícono genérico de documento)]
6
+ ---
7
+
8
+ # sui-file-icon
9
+
10
+ Story: [Atoms/Icon/File Icon](https://sui-design-system.web.app/?path=/docs/atoms-icon-file-icon--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** en una **lista de archivos**: comprobantes, documentos del repartidor, un reporte para
15
+ descargar. La etiqueta con la extensión le dice a la persona qué va a abrir.
16
+
17
+ **No lo uses** para:
18
+
19
+ - Un archivo que se está subiendo: `sui-file-upload-card` (ya lo trae adentro).
20
+ - Una foto: si se puede ver, se muestra la miniatura.
21
+ - Un ícono de «documento» en general, sin archivo detrás: `sui-icon`.
22
+
23
+ ## Qué variante usar
24
+
25
+ > **La guía del DS no tiene página para este componente.** Todo es **propuesta, falta
26
+ > aprobación**.
27
+ >
28
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usa por dentro
29
+ > `sui-file-upload-card`.
30
+
31
+ ### `filename`, `extension`, `color`
32
+
33
+ | input | cuándo | fuente |
34
+ |---|---|---|
35
+ | `filename` | Siempre que haya nombre: saca la extensión y el color solo (`comprobante.pdf` → PDF en rojo). | propuesta |
36
+ | `extension` | Solo si el nombre no la trae (un archivo de Storage sin extensión). | propuesta |
37
+ | `color` | No usar: el color dice el tipo y forzarlo miente (un CSV en rojo parece PDF). | propuesta |
38
+
39
+ Colores automáticos: PDF rojo · Word y texto azul · Excel y CSV verde · PowerPoint naranja ·
40
+ imágenes rosa · video morado · audio celeste · comprimidos amarillo · el resto gris.
41
+
42
+ ### `size`
43
+
44
+ | valor | px | cuándo | fuente |
45
+ |---|---|---|---|
46
+ | `medium` (default) | 40 | Lista de documentos. | propuesta |
47
+ | `xsmall` | 32 | Filas densas, tablas. | propuesta |
48
+
49
+ Usos de hoy que rompen la regla: **0**.
50
+
51
+ ## Tamaño en mobile y en web
52
+
53
+ En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
54
+ pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
55
+ breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
56
+ el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propuesta**.
57
+
58
+ | uso | mobile | web |
59
+ |---|---|---|
60
+ | fila de una lista | `medium` (40) | `xsmall` (32) |
61
+
62
+ ```html
63
+ <sui-file-icon [filename]="doc.nombre" [size]="bp.isMobile() ? 'medium' : 'xsmall'" />
64
+ ```
65
+
66
+ El ícono no se toca: si la fila abre el archivo, la fila da los 44 px. `medium` es el tamaño más
67
+ grande que tiene.
68
+
69
+ ## «No usar»: por qué no hoy y cuándo sí
70
+
71
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
72
+ |---|---|---|
73
+ | todo el componente (0 usos directos) | no hay listas de archivos | los documentos del repartidor (DNI, licencia, SOAT) o un reporte para descargar en CSV |
74
+ | `color` | el color dice el tipo; forzarlo miente | ninguno: si la extensión no se reconoce, sale gris y está bien |
75
+
76
+ ## API
77
+
78
+ <!-- api:inicio -->
79
+ <!-- generada: no editar a mano — `npm run docs` -->
80
+
81
+ | input | tipo | default |
82
+ |---|---|---|
83
+ | `filename` | `string` | `''` |
84
+ | `extension` | `string` | `''` |
85
+ | `size` | `'xsmall' \| 'medium'` | `'medium'` |
86
+ | `color` | `'red' \| 'orange' \| 'yellow' \| 'green' \| 'teal' \| 'blue' \| 'purple' \| 'pink' \| 'gray' \| ''` | `''` |
87
+
88
+ Outputs: ninguno.
89
+ <!-- api:fin -->
90
+
91
+ ## Trampas
92
+
93
+ - **La extensión se corta a 4 letras** y va en mayúsculas: `.jpeg` → `JPEG`, `.numbers` → `NUMB`.
94
+ - **`extension` gana sobre `filename`.**
95
+ - **El nombre para el lector de pantalla está en inglés** («File: PDF») y no se puede cambiar.
96
+ - `size` es `xsmall` o `medium`: no hay `small` ni `large`.
97
+
98
+ ## Ejemplo
99
+
100
+ ```html
101
+ <sui-file-icon filename="comprobante-yape.pdf" />
102
+ <sui-file-icon filename="ventas-setiembre.csv" size="xsmall" />
103
+ ```