@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,132 @@
1
+ ---
2
+ name: sui-progress-bar
3
+ selector: sui-progress-bar
4
+ resumen: Barra que muestra cuánto falta para completar algo, pintada con el estado de lo que mide
5
+ alternativas: [sui-progress-bar-label (la misma barra con título, número y descripción), sui-circular-progress-bar (el avance en un círculo, junto a un título), un gráfico (repartir un total entre partes)]
6
+ ---
7
+
8
+ # sui-progress-bar
9
+
10
+ Story: [Atoms/Progress/Progress Bar](https://sui-design-system.web.app/?path=/docs/atoms-progress-progress-bar--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para mostrar **cuánto avanzó algo hacia un final**: una descarga, una foto que se sube,
15
+ la meta del día, el saldo que queda. Va pelada (sin texto) solo cuando otra cosa de la pantalla ya
16
+ dice qué mide y cuánto.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Una barra con título o número visible: `sui-progress-bar-label` (la arma con la tipografía y el
21
+ espaciado del DS).
22
+ - **Repartir un total entre partes** (visitas por dispositivo, ventas por canal): eso no es un
23
+ avance hacia algo, es una proporción. Va un gráfico, o la barra en `blue` si es una sola cifra.
24
+ - Una espera sin porcentaje conocido: un spinner o un skeleton.
25
+
26
+ ## Qué variante usar
27
+
28
+ > **La guía del DS lo define como «un gráfico simple para mostrar qué tan completo está algo»**
29
+ > y trae cuatro colores (`blue` default, `red`, `orange`, `green`), una sola altura, `value` y
30
+ > `max`. No dice cuándo usar cada color. Cada color apunta a un token de estado
31
+ > (`--sui-state-*`), igual que el badge: de ahí sale su significado, que es el mismo que el del
32
+ > badge aprobado. Lo marcado «según la guía del DS» sale de ahí; el resto es **propuesta, falta
33
+ > aprobación**.
34
+ >
35
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **2 barras peladas en 1 pantalla**
36
+ > (`overview-visitors`), sin contar prototipos ni vitrinas (`master-preview`,
37
+ > `master-prototipos`, `mockup-sheets-*`, `dx/*`, `_guia-*`, `master-rutina`, `master-medico`,
38
+ > `master-ejercicios`, `dev-index`). Las otras 4 barras de la app usan `sui-progress-bar-label`.
39
+
40
+ ### `color` — el estado de lo que mide
41
+
42
+ | color | token | cuándo | ejemplo | fuente |
43
+ |---|---|---|---|---|
44
+ | `blue` (default) | `information` | Avance neutro: no hay nada que juzgar. | Subir una foto, descargar, pasos de un formulario | según la guía del DS (default y token) · propuesta (cuándo) |
45
+ | `green` | `success` | Se cumplió o va bien. | Meta cumplida, saldo alto | según la guía del DS (token) · propuesta (cuándo) |
46
+ | `orange` | `warning` | Va en curso y pide atención. | Saldo bajando, meta del día a medias | según la guía del DS (token) · propuesta (cuándo) |
47
+ | `red` | `error` | Se perdió o se acabó. | Meta perdida, saldo agotado | según la guía del DS (token) · propuesta (cuándo) |
48
+ | `purple` | `feature` | **No usar** (ver abajo). Extensión SUI. | — | propuesta, falta aprobación |
49
+
50
+ **Ojo con el naranja**: en este proyecto el `orange` de estado (`--sui-state-warning-base`) es
51
+ el mismo `#fa7319` de la marca. Una barra naranja sin un juicio detrás se lee como «marca», no
52
+ como «atención».
53
+
54
+ ### `size`
55
+
56
+ | size | alto | cuándo | fuente |
57
+ |---|---|---|---|
58
+ | `small` | 4 px | Web: dentro de una card o una fila densa. | propuesta, falta aprobación |
59
+ | `medium` (default) | 6 px | Web: lo normal y la barra principal. Mobile: dentro de una fila densa. Es la única altura de la guía. | según la guía del DS |
60
+ | `large` | 8 px | Mobile: lo normal y la barra principal (descarga, meta del día). | propuesta, falta aprobación |
61
+ | `xlarge` | 10 px | **No usar** (ver abajo). | propuesta, falta aprobación |
62
+
63
+ ### `value` y `ariaLabel`
64
+
65
+ | propiedad | regla | fuente |
66
+ |---|---|---|
67
+ | `value` | Siempre de 0 a 100. Si el dato viene como fracción (0,6) o como «3 de 5», se convierte antes. | propuesta, falta aprobación |
68
+ | `ariaLabel` | **Obligatorio** en la barra pelada: sin título visible, el lector de pantalla no sabe qué mide. | propuesta, falta aprobación |
69
+
70
+ **Usos de hoy que rompen la regla — a discutir, 2:**
71
+ `pages/overview/components/overview-visitors/overview-visitors.html:22` y `:45` pintan en
72
+ `orange` cómo se reparten las visitas por dispositivo. No es un avance ni pide atención: con esta
73
+ regla va `blue`, o mejor un gráfico. Tampoco llevan `ariaLabel`.
74
+
75
+ ## No usar: por qué no hoy y cuándo sí
76
+
77
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
78
+ |---|---|---|
79
+ | `color="purple"` | No está en la guía y no hay caso. | El avance de una función en prueba, con el mismo morado que el badge «Beta». |
80
+ | `size="xlarge"` | Ninguna barra es lo único de su pantalla. | Una pantalla de carga larga, donde la barra es lo único (importar la carta de un local). |
81
+
82
+ ## Tamaño en mobile y en web
83
+
84
+ Criterio de la app: **en mobile se lee y se toca con el dedo, así que va más grande; en web
85
+ (desktop), más chico.** Mobile es `≤ 767 px`, el mismo corte de `BreakpointsService.isMobile()`
86
+ en master-pedidos. Fuente: canon del dueño (03-10-2026), el mismo patrón que ya usan 27 controles
87
+ de la app.
88
+
89
+ | uso | mobile | web | fuente |
90
+ |---|---|---|---|
91
+ | Dentro de una fila o card densa | `medium` (6) | `small` (4) | propuesta, falta aprobación |
92
+ | Lo normal, y la barra que es lo principal (descarga, meta del día) | `large` (8) | `medium` (6) | propuesta, falta aprobación |
93
+
94
+ ```ts
95
+ readonly bp = inject(BreakpointsService); // master-pedidos: src/app/services/breakpoints.service.ts
96
+ ```
97
+
98
+ ```html
99
+ <sui-progress-bar [value]="progreso()" [size]="bp.isMobile() ? 'medium' : 'small'" ariaLabel="Subiendo la foto" />
100
+ ```
101
+
102
+ ## API
103
+
104
+ <!-- api:inicio -->
105
+ <!-- generada: no editar a mano — `npm run docs` -->
106
+
107
+ | input | tipo | default |
108
+ |---|---|---|
109
+ | `value` | `number` | `0` |
110
+ | `color` | `'blue' \| 'green' \| 'orange' \| 'red' \| 'purple'` | `'blue'` |
111
+ | `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
112
+ | `ariaLabel` | `string \| null` | `null` |
113
+
114
+ Outputs: ninguno.
115
+ <!-- api:fin -->
116
+
117
+ ## Trampas
118
+
119
+ - **No hay `max`** (la guía sí lo tiene): `value` es un porcentaje de 0 a 100, con tope.
120
+ - **El default es `blue`**, no el naranja de la marca.
121
+ - El azul de la barra es `--sui-state-information-base`, **no** `--sui-primary-base` (que en
122
+ este proyecto es naranja).
123
+ - El ancho es el 100 % del padre: dentro de un flex, dale `flex: 1` o un ancho.
124
+ - Lleva `role="progressbar"` con `aria-valuenow`; la animación se apaga con
125
+ `prefers-reduced-motion`.
126
+
127
+ ## Ejemplo
128
+
129
+ ```html
130
+ <!-- Dentro de una fila que ya dice «Subiendo la foto · 64 %» -->
131
+ <sui-progress-bar [value]="progreso()" ariaLabel="Subiendo la foto" />
132
+ ```
@@ -0,0 +1,143 @@
1
+ ---
2
+ name: sui-progress-bar-label
3
+ selector: sui-progress-bar-label
4
+ resumen: La barra de progreso con lo que mide, cuánto va y, si hace falta, qué hacer
5
+ alternativas: [sui-progress-bar (la barra pelada, cuando otra cosa ya la rotula), sui-circular-progress-bar (el avance en un círculo, junto a un título)]
6
+ ---
7
+
8
+ # sui-progress-bar-label
9
+
10
+ Story: [Atoms/Progress/Progress Bar Label](https://sui-design-system.web.app/?path=/docs/atoms-progress-progress-bar-label--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** siempre que una barra de progreso lleve **título o número visible**: «Descargando
15
+ actualización 64 %», «Meta del día · 3 de 5 entregas», «Saldo restante · S/ 12.40 de S/ 20.00».
16
+ Arma la barra (`sui-progress-bar` adentro), el título, el número y una fila opcional con
17
+ descripción y link, con el espaciado del DS.
18
+
19
+ **No lo uses** para:
20
+
21
+ - Una barra que ya está rotulada por la fila donde vive: `sui-progress-bar`.
22
+ - Un avance que va en un cuadrado al lado de un título: `sui-circular-progress-bar`.
23
+ - Repartir un total entre partes: un gráfico.
24
+
25
+ ## Qué variante usar
26
+
27
+ > **La guía del DS no tiene una página propia para esto**: son los ejemplos «With Label» y
28
+ > «Advanced» de la página de la barra de progreso (título + «80%», y debajo un link
29
+ > «Upgrade» con una descripción). No dice cuándo usar cada forma. Lo marcado «según la guía del
30
+ > DS» sale de esos ejemplos; el resto es **propuesta, falta aprobación**.
31
+ >
32
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **4 en 3 pantallas** (la descarga del
33
+ > OTA, el saldo y la meta del día en el dashboard del repartidor, el saldo en la billetera), sin
34
+ > contar prototipos ni vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`,
35
+ > `dx/*`, `_guia-*`, `master-rutina`, `master-medico`, `master-ejercicios`, `dev-index`). Todas
36
+ > `on-top`; 3 con `percentage` de texto; 1 con `showBottom`; ninguna con `link`.
37
+
38
+ `color` y `size` se eligen con las tablas de `sui-progress-bar`: el color es el **estado de lo
39
+ que mide** (blue neutro, green cumplido, orange pide atención, red perdido o agotado).
40
+
41
+ | propiedad | valor | cuándo | ejemplo real | fuente |
42
+ |---|---|---|---|---|
43
+ | `type` | `on-top` (default) | Título y número arriba, barra abajo. Lo normal. | Las 4 de la app | según la guía del DS («With Label») |
44
+ | `type` | `on-right` | Sin título: barra y número en una línea, dentro de una fila que ya dice qué mide a la izquierda. | Pedidos por distrito en una tabla | propuesta, falta aprobación |
45
+ | `title` | texto | Qué mide, en sentence case, sin punto: «Saldo restante», «Meta del día». | `pages/driver/driver-wallet/driver-wallet.html:43` | según la guía del DS |
46
+ | `percentage` | `true` (default) | El porcentaje es la unidad que importa (una descarga). | `components/ota-update/ota-update.html:132` | según la guía del DS («80%») |
47
+ | `percentage` | texto | Hay una unidad real: entregas, soles. «3 de 5 entregas», «S/ 12.40 de S/ 20.00». | `pages/driver/driver-dashboard/driver-dashboard.html:512` | propuesta, falta aprobación |
48
+ | `percentage` | `false` | El número ya está escrito al lado, o no significa nada. | — | propuesta, falta aprobación |
49
+ | `showBottom` + `description` | texto | Qué está pasando o qué hacer mientras avanza: «No cierres la app, estamos dejando todo listo.» | `components/ota-update/ota-update.html:132` | según la guía del DS («Advanced») |
50
+ | `link` | texto o `{ label, href }` | La acción que resuelve lo que la barra avisa: «Recargar» cuando el saldo está en rojo. Va con `showBottom`. | — (sin usos) | según la guía del DS («Upgrade») · propuesta (cuándo) |
51
+ | `ariaLabel` | texto | Lo que mide, si el título no alcanza («Saldo restante sobre el saldo de cortesía»). | `pages/driver/driver-dashboard/driver-dashboard.html:240` | propuesta, falta aprobación |
52
+
53
+ **Usos de hoy que rompen la regla — a discutir, 1:**
54
+ `components/ota-update/ota-update.html:132` pinta la descarga en `orange`. Una descarga es avance
55
+ neutro: con la regla de color va `blue`. En la app el naranja se lee como la marca, así que puede
56
+ ser una decisión de marca y no un error: decide el dueño. Las de saldo y meta (`driver-wallet:43`,
57
+ `driver-dashboard:240` y `:512`) ya pintan verde, naranja y rojo según el estado: cumplen.
58
+
59
+ ## No usar: por qué no hoy y cuándo sí
60
+
61
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
62
+ |---|---|---|
63
+ | `type="on-right"` | Ninguna barra de hoy vive en una fila con su nombre al lado. | Una tabla del super admin con el avance por distrito o por local. |
64
+ | `link` | Ninguna barra de hoy ofrece la acción que la resuelve. | «Recargar» bajo el saldo del repartidor cuando está en rojo. |
65
+
66
+ ## Tamaño en mobile y en web
67
+
68
+ Criterio de la app: **en mobile se lee y se toca con el dedo, así que va más grande; en web
69
+ (desktop), más chico.** Mobile es `≤ 767 px`, el mismo corte de `BreakpointsService.isMobile()`
70
+ en master-pedidos. Fuente: canon del dueño (03-10-2026), el mismo patrón que ya usan 27 controles
71
+ de la app.
72
+
73
+ El `size` solo cambia la barra; el título y el número no cambian de tamaño.
74
+
75
+ | uso | mobile | web | fuente |
76
+ |---|---|---|---|
77
+ | Dentro de una card o fila densa (saldo en el dashboard) | `medium` (6) | `small` (4) | propuesta, falta aprobación |
78
+ | Lo normal, y la barra que es lo principal (descarga, meta del día) | `large` (8) | `medium` (6) | propuesta, falta aprobación |
79
+
80
+ ```ts
81
+ readonly bp = inject(BreakpointsService); // master-pedidos: src/app/services/breakpoints.service.ts
82
+ ```
83
+
84
+ ```html
85
+ <sui-progress-bar-label title="Saldo restante" [value]="balancePercent()"
86
+ [size]="bp.isMobile() ? 'large' : 'medium'" [color]="balanceColor()" />
87
+ ```
88
+
89
+ Hoy las 4 de la app tienen un size fijo para las dos plataformas.
90
+
91
+ ## API
92
+
93
+ <!-- api:inicio -->
94
+ <!-- generada: no editar a mano — `npm run docs` -->
95
+
96
+ | input | tipo | default |
97
+ |---|---|---|
98
+ | `value` | `number` | `0` |
99
+ | `type` | `'on-top' \| 'on-right'` | `'on-top'` |
100
+ | `title` | `string` | `''` |
101
+ | `percentage` | `boolean \| string` | `true` |
102
+ | `showBottom` | `boolean` | `false` |
103
+ | `description` | `string` | `''` |
104
+ | `link` | `SuiLinkConfig \| string \| null` | `null` |
105
+ | `color` | `'blue' \| 'green' \| 'orange' \| 'red' \| 'purple'` | `'blue'` |
106
+ | `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
107
+ | `ariaLabel` | `string \| null` | `null` |
108
+
109
+ | output | payload |
110
+ |---|---|
111
+ | `linkClick` | `void` |
112
+ <!-- api:fin -->
113
+
114
+ Output: `(linkClick)`. Con `link` de texto el `<a>` no navega y solo emite; con
115
+ `{ label, href }` navega y además emite.
116
+
117
+ ## Trampas
118
+
119
+ - **`description` y `link` solo se ven con `[showBottom]="true"`.**
120
+ - **`on-right` ignora `title`, `description` y `link`**: solo barra y número.
121
+ - `percentage` acepta `true`, `false` o un texto: un texto vacío vuelve al porcentaje.
122
+ - El porcentaje automático se redondea (`64.6` → «65%»).
123
+ - El link se pinta en el azul de información, no en el naranja de la marca.
124
+ - Si no hay `title` y `percentage` es `false`, no se dibuja la fila de arriba.
125
+ - Tiene el strip del `title` nativo: no aparece el tooltip gris del navegador.
126
+
127
+ ## Ejemplo
128
+
129
+ ```html
130
+ <!-- Meta del día del repartidor -->
131
+ <sui-progress-bar-label
132
+ title="Meta del día"
133
+ [value]="hechas / meta * 100"
134
+ [percentage]="hechas + ' de ' + meta + ' entregas'"
135
+ [color]="perdida ? 'red' : cumplida ? 'green' : 'orange'"
136
+ size="large" />
137
+
138
+ <!-- Saldo en rojo, con la acción que lo resuelve -->
139
+ <sui-progress-bar-label
140
+ title="Saldo restante" [value]="18" percentage="S/ 3.60 de S/ 20.00" color="red"
141
+ [showBottom]="true" link="Recargar" description="para seguir recibiendo pedidos"
142
+ (linkClick)="abrirRecarga()" />
143
+ ```
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: sui-radio
3
+ selector: sui-radio
4
+ resumen: El círculo solo para elegir una opción de una lista corta, sin texto propio
5
+ alternativas: [sui-radio-label (círculo con su texto, lista densa), sui-radio-card (opción con peso o que se toca en el teléfono), sui-select (más de 6 opciones), sui-segmented-control (2-4 modos que se aplican al instante), sui-checkbox (varias a la vez)]
6
+ ---
7
+
8
+ # sui-radio
9
+
10
+ Story: [Atoms/Checkbox, Radio & Switch/Radio](https://sui-design-system.web.app/?path=/docs/atoms-checkbox-radio-switch-radio--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para elegir **una** opción de una lista corta, solo como círculo: cuando el texto vive
15
+ en otra parte (una columna «Por defecto» en una tabla, una fila propia con foto y precio).
16
+ Va dentro de un `sui-radio-group`, que es el que hace que elegir una desmarque la otra.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Un círculo con su texto en una lista densa (franjas horarias): `sui-radio-label`.
21
+ - Opciones con peso (ícono, descripción, borde) o que se tocan en el teléfono: `sui-radio-card`
22
+ (método de pago, tipo de entrega, motivos de cancelación). Crece con `bp.controlSize()`; el
23
+ radio-label no tiene `size`.
24
+ - Más de ~6 opciones: `sui-select`.
25
+ - 2-4 modos de la misma vista que se aplican al instante: `sui-segmented-control`.
26
+ - Varias a la vez: `sui-checkbox`.
27
+
28
+ Regla corta: **lista densa de texto → radio-label · con peso o en el teléfono → radio-card · muchas → select · sin texto → este.**
29
+
30
+ ## Qué variante usar
31
+
32
+ > **La guía del DS lo define como control para «una sola selección de una lista corta de
33
+ > opciones»**, y su ejemplo con label es una lista de motivos para reportar algo («Spam»,
34
+ > «Acoso», «Infringe las reglas»). Muestra deshabilitado, con label y con label avanzado. No
35
+ > trae do/don't de tamaños.
36
+ >
37
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`):
38
+ > **2 `sui-radio` en 2 archivos**, ambos en modo suelto (`standaloneChecked`), con tamaño
39
+ > dinámico. Más **1 `<input type="radio">` nativo**.
40
+
41
+ ### Estado y modo
42
+
43
+ | qué | cuándo | fuente |
44
+ |---|---|---|
45
+ | dentro de `sui-radio-group` + `[value]` | Siempre que haya más de una opción. El grupo hace la exclusión y se enchufa a `[(ngModel)]`. | según la guía del DS (es un radio group) |
46
+ | suelto con `[(standaloneChecked)]` | Solo cuando la exclusión la hace la fila o el padre (la fila de opciones del detalle de producto). **Suelto, al tocarlo se desmarca** como un checkbox. | propuesta, falta aprobación |
47
+ | `disabled` | La opción existe pero no aplica ahora (una variante agotada). | según la guía del DS |
48
+
49
+ ### `size`
50
+
51
+ | size | px | cuándo | fuente |
52
+ |---|---|---|---|
53
+ | `xlarge` | 28 | Mobile, vía `bp.controlSize()`. | canon (aprobado por el dueño, 28-09-2026: «componentes grandes») |
54
+ | `large` | 24 | Desktop, vía `bp.controlSize()`. | canon (aprobado por el dueño, 28-09-2026) |
55
+ | `medium` (default) | 20 | Solo dentro de un componente que fija su escala (detalle de producto). Es el único tamaño de la guía. | según la guía del DS (único tamaño); el «cuándo» es propuesta |
56
+
57
+ **Usos de hoy que rompen la regla:**
58
+
59
+ - **1 radio nativo → `sui-radio-card type="basic"`:**
60
+ `pages/driver/driver-order-detail/driver-order-detail.html:812` (motivos de cancelación del
61
+ repartidor, el mismo caso del ejemplo de la guía). La pantalla hermana del local ya lo resolvió
62
+ así: `pages/orders/orders.html:566`.
63
+ - **1 suelto que se puede desincronizar:** `pages/super-admin/master-settings/master-settings.html:105`
64
+ (categoría por defecto). Usa `[standaloneChecked]` + `$event && …`: al tocar el que ya está
65
+ elegido, el círculo se apaga por dentro pero el padre sigue diciendo que es el elegido. Va en
66
+ un `sui-radio-group` con `[ngModel]`.
67
+
68
+ ## Tamaño en mobile y en web
69
+
70
+ | uso | mobile | web |
71
+ |---|---|---|
72
+ | círculo en una fila o tabla | `xlarge` (28 px) | `large` (24 px) |
73
+ | dentro de un componente que fija su escala | lo que pase el padre | lo que pase el padre |
74
+
75
+ ```html
76
+ <sui-radio [size]="bp.controlSize()" … /> <!-- isMobile() ? 'xlarge' : 'large' -->
77
+ ```
78
+
79
+ El más grande mide 28 px: el área táctil de 44 px la tiene que dar la fila.
80
+
81
+ ## «No usar»: por qué no hoy y cuándo sí
82
+
83
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
84
+ |---|---|---|
85
+ | suelto (`standaloneChecked`) fuera de una fila propia | se desmarca al tocarlo de nuevo: no es un radio | nunca como grupo; solo como dibujo dentro de una fila que maneja el clic |
86
+
87
+ ## API
88
+
89
+ <!-- api:inicio -->
90
+ <!-- generada: no editar a mano — `npm run docs` -->
91
+
92
+ ### `sui-radio`
93
+
94
+ | input | tipo | default |
95
+ |---|---|---|
96
+ | `size` | `'medium' \| 'large' \| 'xlarge'` | `'medium'` |
97
+ | `value` | `SuiRadioValue` | `null` |
98
+ | `disabled` | `boolean` | `false` |
99
+ | `standaloneChecked` · model, `[(standaloneChecked)]` | `boolean` | `false` |
100
+
101
+ Outputs: ninguno.
102
+
103
+ ### `sui-radio-group`
104
+
105
+ Inputs: ninguno.
106
+
107
+ Outputs: ninguno.
108
+ <!-- api:fin -->
109
+
110
+ `sui-radio-group`: sin inputs; implementa `ControlValueAccessor` (`[(ngModel)]`, `formControlName`)
111
+ y proyecta los radios (`sui-radio`, `sui-radio-label`, `sui-radio-card`).
112
+
113
+ ## Trampas
114
+
115
+ - **Suelto, togglea.** `standaloneChecked` se invierte con cada toque: se puede desmarcar. Para
116
+ semántica de radio, `sui-radio-group`.
117
+ - **`sui-radio-group` no tiene `value`**: se maneja con `[(ngModel)]` o un form control.
118
+ - **`sui-radio-group` es `inline-flex` en fila con gap 16.** Para lista vertical hay que darle
119
+ `flex-direction: column; align-items: flex-start` desde afuera.
120
+ - **Deshabilitar el control del grupo no deshabilita los radios** (`setDisabledState` no hace
121
+ nada): pasa `[disabled]` a cada uno.
122
+ - No hay `small`: el más chico es `medium` (20 px).
123
+ - Sin marcar, en foco, el círculo se pinta del color de marca: viene del Figma, no es un error.
124
+ - No dibuja texto ni `aria-label`: pelado, pon el texto en un `<label>` o usa `sui-radio-label`.
125
+
126
+ ## Ejemplo
127
+
128
+ ```html
129
+ <sui-radio-group [(ngModel)]="categoriaPorDefecto">
130
+ @for (cat of categorias; track cat.id) {
131
+ <sui-radio [size]="bp.controlSize()" [value]="cat.id" [attr.aria-label]="cat.nombre" />
132
+ }
133
+ </sui-radio-group>
134
+ ```
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: sui-radio-card
3
+ selector: sui-radio-card
4
+ resumen: Opción con tarjeta (ícono o foto, título, descripción y el radio) para elegir UNA de una lista corta
5
+ alternativas: [sui-radio-label (la misma elección sin tarjeta, en un formulario denso), sui-select (lista larga o que no entra en pantalla), sui-segmented-control (2–4 vistas de la misma pantalla), sui-checkbox-card (se pueden elegir varias), sui-switch-card (se prende o se apaga un ajuste)]
6
+ ---
7
+
8
+ # sui-radio-card
9
+
10
+ Story: [Molecules/Card/Radio Card](https://sui-design-system.web.app/?path=/docs/molecules-card-radio-card--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para elegir una sola opción de una lista corta cuando cada opción merece explicarse:
15
+ «Delivery / Recojo en tienda», cómo cobrar («A mi saldo / Por Yape»), el medio de pago, el motivo
16
+ de una cancelación, el modo de asignación de repartidores.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Varias opciones que se suman: `sui-checkbox-card`.
21
+ - Un ajuste que se prende o se apaga: `sui-switch-card`.
22
+ - Una lista larga (más de 6–7 opciones) o que crece con los datos: `sui-select`.
23
+ - Cambiar de vista dentro de la misma pantalla: `sui-segmented-control` o tabs.
24
+
25
+ Regla corta: **una de pocas, con explicación → radio-card · una de muchas → select · varias →
26
+ checkbox-card.**
27
+
28
+ ## Qué variante usar
29
+
30
+ > **La guía del DS no tiene página de la radio card.** De la guía sale solo lo del radio que lleva
31
+ > adentro: **«para elegir una sola opción de una lista corta»**. El resto es práctica de la app
32
+ > («propuesta») o regla ya aprobada («canon»).
33
+ >
34
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **31
35
+ > radio-cards en 14 archivos**. Tipos: 23 `left-icon` (3 de ellos con emoji animado por
36
+ > `iconSrc`), 6 `basic`, 1 `avatar`, 1 `company`. Tamaños: 24 `bp.controlSize()`, 4 `medium`, 1
37
+ > `xlarge` fijo, 1 dinámico, 1 sin `size`. 6 con `sublabel`, 3 con `disabled`, 1 con `badge`.
38
+
39
+ ### `type` (el leading)
40
+
41
+ | type | cuándo | fuente |
42
+ |---|---|---|
43
+ | `left-icon` con `icon` | Lo normal: un ícono Remix que dice de qué va la opción (`truck-line` Delivery, `store-2-line` Recojo). | propuesta (práctica de la app) |
44
+ | `left-icon` con `iconSrc` | Emoji animado cuando la elección es de las grandes del rol (el vehículo del repartidor, el rol al registrarse, el tipo de mandadito). Los emojis van de `assets/emojis/` o `FLUENT_EMOJI_ANIM`. | propuesta |
45
+ | `left-icon` con `emoji` | Lo mismo con un nombre de `SuiEmoji` en vez de una URL. Hoy 0 usos; vale igual. | propuesta |
46
+ | `basic` | Opciones de texto puro: motivos de cancelación, quién paga el envío, los premios de una meta. | propuesta |
47
+ | `avatar` (`imageUrl`) | El logo redondo de un medio de pago (Yape, Plin, efectivo en el checkout). | propuesta |
48
+ | `company` (`imageUrl`) | Elegir entre tus locales (cambiar de negocio en mi-negocio). | propuesta |
49
+ | `brand`, `card-provider` | Ver «No usar». | propuesta |
50
+
51
+ ### Las piezas
52
+
53
+ | prop | cuándo | fuente |
54
+ |---|---|---|
55
+ | `value` (obligatorio) | Siempre, aunque no haya grupo. Es lo que emite `selected`. | propuesta |
56
+ | `label` | Siempre. El nombre de la opción, corto: «Delivery», «Lo antes posible». | propuesta |
57
+ | `description` | Casi siempre: la consecuencia de elegirla («Lo revisamos y te transferimos. Puede tardar unas horas.»). | propuesta |
58
+ | `sublabel` | Una precisión corta entre paréntesis («(canal estable)», «(sin OTA)»). Nunca la explicación: eso es `description`. | propuesta |
59
+ | `badge` | Marca una opción frente a las otras: «Por defecto». Con string sale azul `light`; pasa el objeto con el color que corresponda según el badge (un «Por defecto» es `gray`). | propuesta |
60
+ | `disabled` | La opción existe pero hoy no se puede: di por qué en la `description` («El local está cerrado ahora»). | propuesta |
61
+ | `checked` / `[(ngModel)]` / `sui-radio-group` | El estado: `[checked]` + `(selected)` sueltos (lo normal en la app), o `ngModel` con `name` (checkout), o dentro de un `sui-radio-group`. | propuesta |
62
+
63
+ ### `size` (el radio de adentro)
64
+
65
+ | size | cuándo | fuente |
66
+ |---|---|---|
67
+ | `xlarge` (28) | Mobile, vía `bp.controlSize()`. | canon (aprobado por el dueño, 28-09-2026: «componentes grandes») |
68
+ | `large` (24) | Desktop, vía `bp.controlSize()`. | canon (aprobado por el dueño, 28-09-2026) |
69
+ | `medium` (20, default) | No usar en pantallas nuevas. | canon (aprobado por el dueño, 28-09-2026) |
70
+
71
+ **Usos de hoy que rompen las reglas:**
72
+
73
+ - **5 sin el size del breakpoint**: `components/por-cobrar-card/por-cobrar-card.html:38` y `:48`,
74
+ `pages/driver/driver-dashboard/driver-dashboard.html:581`,
75
+ `pages/super-admin/master-orders/master-orders.html:720` (los cuatro en `medium`) y
76
+ `pages/mi-negocio/mi-negocio.html:22` (sin `size`). Además `pages/customer/mandadito/mandadito.html:30`
77
+ va en `xlarge` fijo (en web debería ser `large`).
78
+ - **A revisar:** `pages/super-admin/master-orders/master-orders.html:720` lista a los repartidores
79
+ candidatos, una lista que crece con la flota (con muchos, `sui-select` o una lista con búsqueda).
80
+ `pages/role-selector/role-selector.html:24` usa la radio como botón: elegir ya avanza, sin
81
+ `[checked]`.
82
+
83
+ ## Tamaño en mobile y en web
84
+
85
+ La card entera es el área táctil (≥ 72 de alto con descripción, 16 de padding): llega al piso de
86
+ 44 sola. El `size` cambia solo el radio.
87
+
88
+ | uso | mobile | web |
89
+ |---|---|---|
90
+ | toda radio-card | `xlarge` (radio 28) | `large` (radio 24) |
91
+
92
+ ```html
93
+ <sui-radio-card [size]="bp.controlSize()" … /> <!-- isMobile() ? 'xlarge' : 'large' -->
94
+ ```
95
+
96
+ ## «No usar»: por qué no hoy y cuándo sí
97
+
98
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
99
+ |---|---|---|
100
+ | `type="brand"` (0 usos) | no hay servicios de terceros que elegir | elegir el canal por el que te contactamos (WhatsApp, correo) con su logo (`brand`) |
101
+ | `type="card-provider"` (0 usos) | no hay pago con tarjeta guardada | elegir una tarjeta guardada en el checkout, cuando entre Culqi / Niubiz |
102
+ | `size="medium"` | el radio de 20 se pierde en el teléfono | una tabla densa solo de desktop |
103
+
104
+ ## API
105
+
106
+ <!-- api:inicio -->
107
+ <!-- generada: no editar a mano — `npm run docs` -->
108
+
109
+ | input | tipo | default |
110
+ |---|---|---|
111
+ | `type` | `'basic' \| 'left-icon' \| 'avatar' \| 'card-provider' \| 'brand' \| 'company'` | `'basic'` |
112
+ | `size` | `'medium' \| 'large' \| 'xlarge'` | `'medium'` |
113
+ | `value` | `string` | — (requerido) |
114
+ | `label` | `string` | `''` |
115
+ | `sublabel` | `string \| null` | `null` |
116
+ | `description` | `string \| null` | `null` |
117
+ | `icon` | `string \| null` | `null` |
118
+ | `emoji` | `SuiEmojiName \| null` | `null` |
119
+ | `iconSrc` | `string \| null` | `null` |
120
+ | `imageUrl` | `string \| null` | `null` |
121
+ | `brand` | `SuiBrandLogoCompany \| null` | `null` |
122
+ | `badge` | `SuiBadgeConfig \| string \| null` | `null` |
123
+ | `disabled` | `boolean` | `false` |
124
+ | `checked` · model, `[(checked)]` | `boolean` | `false` |
125
+
126
+ | output | payload |
127
+ |---|---|
128
+ | `selected` | `string` |
129
+ <!-- api:fin -->
130
+
131
+ Implementa `ControlValueAccessor` (el valor del form es el `value` elegido). Dentro de un
132
+ `sui-radio-group`, el grupo decide cuál está marcada.
133
+
134
+ ## Trampas
135
+
136
+ - **`value` es obligatorio** aunque la uses suelta: sin él Angular tira error de input requerido.
137
+ - **Precedencia del leading en `left-icon`: `icon` > `emoji` > `iconSrc`.** Si pasas `icon` y
138
+ `iconSrc`, gana el ícono.
139
+ - Con `iconSrc` el círculo pasa a modo «relleno» (sin padding): el emoji ocupa los 40 × 40.
140
+ - `avatar`, `company` y `card-provider` leen la imagen de **`imageUrl`**; `brand` lee `brand` (o
141
+ `imageUrl` si la marca no está en el catálogo). No hay slot para proyectar el leading (a
142
+ diferencia de `sui-checkbox-card`).
143
+ - Suelta (sin grupo), elegirla la marca pero **no desmarca a las otras**: el padre tiene que
144
+ bindear `[checked]` de todas a la misma señal.
145
+ - `badge` con string sale **azul `light` `small`** (en `sui-content-label` sale naranja).
146
+ - `size` cambia solo el radio, no el padding ni el alto de la card.
147
+
148
+ ## Ejemplo
149
+
150
+ ```html
151
+ <sui-radio-card
152
+ [size]="bp.controlSize()"
153
+ type="left-icon"
154
+ value="pickup"
155
+ icon="store-2-line"
156
+ label="Recojo en tienda"
157
+ description="Lo recoges en el local"
158
+ [checked]="modo() === 'pickup'"
159
+ (selected)="modo.set('pickup')" />
160
+ ```