@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,137 @@
1
+ ---
2
+ name: sui-radio-label
3
+ selector: sui-radio-label
4
+ resumen: Círculo con su texto (y opcionalmente descripción, badge y link) para elegir una opción de una lista corta
5
+ alternativas: [sui-radio (el círculo solo), sui-radio-card (cada opción es una tarjeta), sui-select (más de 6 opciones), sui-checkbox-label (varias a la vez)]
6
+ ---
7
+
8
+ # sui-radio-label
9
+
10
+ Story: [Atoms/Checkbox, Radio & Switch/Radio Label](https://sui-design-system.web.app/?path=/docs/atoms-checkbox-radio-switch-radio-label--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para una lista corta de opciones de texto donde se elige una y la lista es densa: las
15
+ franjas horarias del checkout, tipo de documento. Toda la fila se toca. Va dentro de un
16
+ `sui-radio-group`.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Opciones con identidad propia (ícono o logo, descripción, borde): `sui-radio-card`. Es lo que
21
+ usa la app para método de pago, tipo de entrega y modo de asignación.
22
+ - **Una lista de motivos que se toca en el teléfono**: la app ya resolvió ese caso con
23
+ `sui-radio-card type="basic"` y `bp.controlSize()` (motivos de cancelación del local,
24
+ `pages/orders/orders.html:566`). El radio-label no tiene `size` y en mobile queda chico.
25
+ - Más de ~6 opciones: `sui-select`.
26
+ - Varias a la vez: `sui-checkbox-label`.
27
+ - Prender algo al instante: `sui-switch-label`.
28
+
29
+ Regla corta: **lista densa de texto → radio-label · motivos u opciones que se tocan en el teléfono
30
+ o con peso → radio-card · muchas → select.**
31
+
32
+ ## Qué variante usar
33
+
34
+ > **La guía del DS muestra las piezas, no cuándo usarlas.** Su ejemplo con label es una lista de
35
+ > motivos («Spam», «Acoso», «Infringe las reglas»); el «avanzado» suma (Sublabel), badge «NEW»,
36
+ > descripción, Link Button y la versión con el círculo a la derecha.
37
+ >
38
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`):
39
+ > **1 uso**, las franjas horarias del checkout, con `flip`. Más **1 radio nativo** de motivos
40
+ > (ver abajo a qué componente va).
41
+
42
+ ### Las piezas
43
+
44
+ | prop | cuándo | fuente |
45
+ |---|---|---|
46
+ | `value` | Siempre (es obligatorio). Lo que lee el `sui-radio-group`. | API |
47
+ | `label` | Siempre. La opción en pocas palabras («Dirección no encontrada», «12:00 — 12:30 p. m.»). | según la guía del DS (pieza) |
48
+ | `sublabel` | Precisión corta entre paréntesis: «(recomendado)». | según la guía del DS |
49
+ | `description` | Una frase de qué pasa si se elige. Sube el label a peso medio. Si casi todas las opciones la necesitan, probablemente es `sui-radio-card`. | según la guía del DS (pieza); el «cuándo» es propuesta |
50
+ | `badge` | Solo novedad. Con string sale naranja `light`: pasa el objeto. | según la guía del DS (pieza «NEW»); el color es propuesta |
51
+ | `link` | «Ver detalle» que no elige la opción. Solo se ve con `description`. | según la guía del DS |
52
+ | `flip` | Círculo a la derecha en listas de opciones tipo hoja (sheet) y de ajustes, donde el texto es lo que se lee y el círculo es el indicador, como las franjas del checkout. En formularios, a la izquierda. | canon (aprobado por el dueño, 03-10-2026) |
53
+ | `disabled` | La opción existe pero no aplica (franja ya llena). | según la guía del DS |
54
+ | `size` | `medium` (default, Figma): círculo 20, label 14/20. `large`: círculo 24, label 16/24. `xlarge`: círculo 28, label 16/24. En large y xlarge el sublabel y la descripción pasan a 14/20, el badge sin `size` propio sube a `medium` / `large` y el link a `medium`. Se usa con `[size]="bp.controlSize()"`. | `medium`: según la guía del DS · `large` / `xlarge`: canon (aprobado por el dueño, 03-10-2026), extensión SUI |
55
+
56
+ **Usos de hoy:**
57
+
58
+ - **1 radio nativo de motivos:** `pages/driver/driver-order-detail/driver-order-detail.html:812`
59
+ (motivos de cancelación del repartidor). Por la pantalla hermana va a `sui-radio-card
60
+ type="basic"` como `pages/orders/orders.html:566`, no a este componente.
61
+ - El único uso actual, `pages/customer/checkout/checkout.html:480`, controla la selección con
62
+ `[checked]` + `(selected)` por fila, sin `sui-radio-group`. Funciona porque el padre fija el
63
+ estado, pero no se enchufa a un formulario.
64
+
65
+ ## Tamaño en mobile y en web
66
+
67
+ En mobile se toca con el dedo: el área táctil tiene que medir **44 px o más**. En web, con mouse,
68
+ va un tamaño más chico. La app ya lo resuelve con `BreakpointsService`
69
+ (`src/app/services/breakpoints.service.ts`, mobile = hasta 767 px); para controles,
70
+ `bp.controlSize()` devuelve `xlarge` en mobile y `large` en web (regla de controles grandes del
71
+ dueño, 28-09-2026).
72
+
73
+ | uso | mobile | web | fuente |
74
+ |---|---|---|---|
75
+ | opciones de un formulario o una hoja (franjas horarias, método de entrega) | `xlarge` (círculo 28, label 16/24) | `large` (círculo 24, label 16/24) | canon (aprobado por el dueño, 03-10-2026) |
76
+ | lista densa de desktop | — | `medium` (círculo 20, label 14/20) | propuesta, falta aprobación |
77
+ | opciones con mucho contexto cada una | `sui-radio-card` con `bp.controlSize()` | `sui-radio-card` con `bp.controlSize()` | propuesta |
78
+
79
+ ```html
80
+ <sui-radio-label value="recojo" [size]="bp.controlSize()" label="Recojo en tienda" />
81
+ ```
82
+
83
+ Toda la fila se toca (el host recibe el click). Con `xlarge` el contenido baja 2 px para que la
84
+ línea del label (24) quede centrada con el círculo (28).
85
+
86
+ ## «No usar»: por qué no hoy y cuándo sí
87
+
88
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
89
+ |---|---|---|
90
+ | `badge` | ninguna opción es nueva | una opción recién agregada a una lista que el usuario ya conoce |
91
+ | `link` | ninguna opción necesita detalle | «Plan Pro» con «Ver precios» (con `description`) |
92
+
93
+ ## API
94
+
95
+ <!-- api:inicio -->
96
+ <!-- generada: no editar a mano — `npm run docs` -->
97
+
98
+ | input | tipo | default |
99
+ |---|---|---|
100
+ | `value` | `string` | — (requerido) |
101
+ | `label` | `string` | `''` |
102
+ | `sublabel` | `string \| null` | `null` |
103
+ | `description` | `string \| null` | `null` |
104
+ | `badge` | `SuiBadgeConfig \| string \| null` | `null` |
105
+ | `link` | `SuiLinkConfig \| string \| null` | `null` |
106
+ | `size` | `'medium' \| 'large' \| 'xlarge'` | `'medium'` |
107
+ | `flip` | `boolean` | `false` |
108
+ | `disabled` | `boolean` | `false` |
109
+ | `checked` · model, `[(checked)]` | `boolean` | `false` |
110
+
111
+ | output | payload |
112
+ |---|---|
113
+ | `selected` | `string` |
114
+ | `linkClick` | `MouseEvent` |
115
+ <!-- api:fin -->
116
+
117
+ ## Trampas
118
+
119
+ - **No implementa `ControlValueAccessor`.** El formulario se engancha al `sui-radio-group`, no a
120
+ cada opción. Sin grupo, se maneja con `[(checked)]`.
121
+ - **No tiene `size`**: el círculo mide 20 px siempre. Choca con la regla de controles grandes
122
+ (dueño, 28-09-2026) en mobile; si hace falta grande, `sui-radio-card`.
123
+ - **Tocar una opción ya elegida no la desmarca** (bien, es un radio). Tocar el link tampoco la elige.
124
+ - **`link` solo se dibuja con `description`.**
125
+ - El `sui-radio` de adentro no recibe clics (`pointer-events: none`): no le pongas handlers.
126
+ - El badge con string sale naranja; en `sui-radio-card` el default es azul.
127
+ - `flip` usa CSS `order`: el orden para lector de pantalla no cambia.
128
+
129
+ ## Ejemplo
130
+
131
+ ```html
132
+ <sui-radio-group [(ngModel)]="motivo" class="lista-vertical">
133
+ @for (m of motivos; track m) {
134
+ <sui-radio-label [value]="m" [label]="m" />
135
+ }
136
+ </sui-radio-group>
137
+ ```
@@ -0,0 +1,199 @@
1
+ ---
2
+ name: sui-rating
3
+ selector: sui-rating
4
+ resumen: Muestra una nota con estrellas o la pide (estrellas, emojis, corazones o números)
5
+ alternativas: [sui-icon (una estrella o un corazón sueltos, sin nota), sui-badge (la nota escrita como dato corto)]
6
+ ---
7
+
8
+ # sui-rating
9
+
10
+ Story: [Atoms/Rating](https://sui-design-system.web.app/?path=/docs/atoms-rating--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para dos cosas distintas:
15
+
16
+ 1. **Mostrar una nota** (de un local, un repartidor, un cliente, una reseña): `readonly`, y con
17
+ `halfStep` si es un promedio.
18
+ 2. **Pedir una nota** (calificar el pedido, al local, al repartidor): interactivo, con
19
+ `(valueChange)` o un `FormControl`.
20
+
21
+ **No lo uses** para:
22
+
23
+ - Un ícono suelto de estrella o corazón (favoritos, «lo guardaron 12»): `sui-icon`.
24
+ - Escribir el número de la nota: eso lo escribe la pantalla con coma («4,7»), no el rating.
25
+ - Recalcular la nota a partir de una lista de reseñas (ver la regla de abajo).
26
+
27
+ **La nota que se muestra sale del agregado de la entidad** (`rating` y `ratingCount` del
28
+ documento, que calcula la Cloud Function sobre todas las calificaciones), nunca de promediar la
29
+ lista cargada, que viene con tope. La fórmula depende de `n`: otro denominador da otro número.
30
+ **Canon** (CLAUDE.md, «Una nota, una sola cuenta», 26-08-2026).
31
+
32
+ ## Qué variante usar
33
+
34
+ > **La guía del DS no trae un componente de rating: trae ejemplos** para que cada producto arme
35
+ > el suyo («cada sistema de calificación se comporta distinto»). Los ejemplos son: nota con
36
+ > reseñas («4.5 ∙ 5.2K Ratings · 18 reviews»), celdas, barra de estrellas, barra de corazones,
37
+ > barra de emojis, barra de números del 1 al 5 y barra con área de texto. No trae tamaños, ni
38
+ > do/don't. Lo marcado «según la guía del DS» es que el ejemplo existe; el cuándo es
39
+ > **propuesta, falta aprobación**, salvo lo que diga «canon».
40
+ >
41
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **23 ratings en 13 pantallas**, sin
42
+ > contar prototipos ni vitrinas (`master-preview`, `master-prototipos`, `mockup-sheets-*`,
43
+ > `dx/*`, `_guia-*`, `master-rutina`, `master-medico`, `master-ejercicios`, `dev-index`).
44
+ > `appearance`: 21 `inline` (13 por default, 8 explícitos), 2 `bar`. `type`: 20 `star`,
45
+ > 1 `emoji`, 1 `heart`, 1 dinámico. `size`: 10 `small`, 6 `medium`, 1 `large`, 4 `xlarge`, 2 en
46
+ > `bar` (sin size). 20 son `readonly`.
47
+
48
+ ### `appearance` — para qué
49
+
50
+ | appearance | cuándo | ejemplo real | fuente |
51
+ |---|---|---|---|
52
+ | `inline` (default), `readonly` | **Mostrar** una nota: la fila de estrellas pelada. | `components/ratings-detail/ratings-detail.html:31` (la nota del local) | según la guía del DS (ejemplo «Rating Review») |
53
+ | `inline`, interactivo | **A discutir.** Pedir la nota en grande (`xlarge`). Cada estrella mide 28 px, por debajo de los 44 que pide un dedo. | `pages/customer/rate-order/rate-order.html:93` y `:166` | propuesta, falta aprobación |
54
+ | `bar` | **Pedir** una nota en el celular: celdas de 64 × 36 fáciles de tocar. | `components/rate-entity-card/rate-entity-card.html:40` | según la guía del DS (ejemplo «Rating Bar») |
55
+ | `cell` | **No usar** hoy (ver abajo). | — | según la guía del DS (ejemplo «Rating Cell») |
56
+ | `bar-area` | **No usar** hoy (ver abajo). | — | según la guía del DS (ejemplo «Rating Bar With Textarea») |
57
+
58
+ ### `type`
59
+
60
+ | type | cuándo | fuente |
61
+ |---|---|---|
62
+ | `star` (default) | La nota de un pedido, un local, un repartidor o un cliente: la que entra al promedio. | según la guía del DS (ejemplo) · propuesta (cuándo) |
63
+ | `emoji` | Cómo le fue a la persona con la app o con un proceso (no entra a la nota de nadie). Solo en `bar`. Hoy: `components/rate-entity-card/rate-entity-card.html:38`. | según la guía del DS (ejemplo «Single Selectable») · propuesta (cuándo) |
64
+ | `heart` | **No usar** como nota (ver abajo). | según la guía del DS (ejemplo «Rating Bar Heart») |
65
+ | `number` | **No usar** hoy (ver abajo). Solo en `bar`. | según la guía del DS (ejemplo de 1 a 5) |
66
+
67
+ ### `size` (solo cuenta en `inline`)
68
+
69
+ | size | px | cuándo | fuente |
70
+ |---|---|---|---|
71
+ | `small` | 16 | Web: filas y listas (cada reseña, tablas, historial). | propuesta, falta aprobación |
72
+ | `medium` (default) | 20 | Web: perfil, ficha, detalle. Mobile: filas y listas. | propuesta, falta aprobación |
73
+ | `large` | 24 | Web: la nota grande de un resumen, la card de una calificación enviada. Mobile: perfil y ficha. | propuesta, falta aprobación |
74
+ | `xlarge` | 28 | Extensión SUI. Mobile: la nota grande de un resumen. | propuesta, falta aprobación |
75
+
76
+ ### El resto de las propiedades
77
+
78
+ | propiedad | valor | cuándo | fuente |
79
+ |---|---|---|---|
80
+ | `readonly` | `true` | **Todo rating que muestra una nota.** Sin él se puede tocar y cambiar. | propuesta, falta aprobación |
81
+ | `halfStep` | `true` | Obligatorio si el valor es un **promedio** (sin él, 4,5 se pinta como 4). Una nota individual es entera y no lo necesita. Solo funciona en `inline` + `readonly`. | según la guía del DS (muestra 4.5) |
82
+ | `value` | `0` | Solo dentro del botón que invita a calificar, junto al texto «Calificar» (`pages/customer/order-history/order-history.html:352`). Suelto, cinco estrellas vacías se leen como «0 estrellas». | propuesta, falta aprobación |
83
+ | `max` | `5` (default) | Siempre 5 en notas: la fórmula de la nota asume 5. | propuesta, falta aprobación |
84
+ | `max` | otro | Solo con `type="number"` (encuesta de 1 a 10). | propuesta, falta aprobación |
85
+ | `alignment` | `inline` (default) | Solo los íconos; el número y el conteo los escribe la pantalla. | propuesta, falta aprobación |
86
+ | `alignment` | `horizontal` | Junto con `reviewLink`. | propuesta, falta aprobación |
87
+ | `alignment` | `vertical` | **No usar** (ver abajo). | propuesta, falta aprobación |
88
+ | `reviewLink` | `{ label, href? }` | Link «Ver 128 reseñas» que abre la hoja de reseñas. Hoy sin usos. | según la guía del DS («18 reviews») |
89
+ | `showValue` | `true` | **No usar** (ver abajo). | propuesta, falta aprobación |
90
+ | `reviewCount` | número | **No usar** (ver abajo). | propuesta, falta aprobación |
91
+ | `emojis` | lista | Dejar el default (cinco caras, de triste a feliz). Cambiarlo rompe la lectura de la escala. | propuesta, falta aprobación |
92
+ | `ariaLabel` | texto | Decir qué se califica: «Califica al repartidor», «Nota del local». El default es «Calificación». | propuesta, falta aprobación |
93
+ | `reason` / `reasonPlaceholder` / `reasonRows` | — | Solo en `bar-area`. El placeholder por defecto es «Cuéntanos por qué» (03-10-2026). | propuesta, falta aprobación |
94
+
95
+ **Usos de hoy que rompen la regla:**
96
+
97
+ - **1 `reviewCount`** (hasta el 03-10-2026 pintaba «Ratings» en inglés; ahora «calificaciones»):
98
+ `pages/super-admin/master-users/master-user-sheet.html:142`.
99
+ - **1 rating usado como ícono** (`type="heart"` con `max=1` para los favoritos):
100
+ `components/ratings-detail/ratings-detail.html:45`. Va `sui-icon name="heart-3-fill"`.
101
+ - **A discutir, 2 `inline` interactivos de 28 px** como input:
102
+ `pages/customer/rate-order/rate-order.html:93` y `:166`. Alternativa: `appearance="bar"`.
103
+
104
+ ## No usar: por qué no hoy y cuándo sí
105
+
106
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
107
+ |---|---|---|
108
+ | `appearance="cell"` | En el celular `bar` es más clara y más fácil de tocar. | Calificar una sola cosa a pantalla completa en tablet o web. |
109
+ | `appearance="bar-area"` | La calificación de hoy separa la nota, los chips y el comentario. | Una encuesta corta de una sola card: nota + «Cuéntanos qué pasó». |
110
+ | `type="heart"` | La app califica con estrellas; el corazón es favoritos. | «¿Cuánto te gustó?» de una campaña, donde una estrella se leería como la nota del local. |
111
+ | `type="number"` | No hay encuestas de 1 a 10. | «¿Qué tan probable es que nos recomiendes?» con `max=10` (ocupa 640 px de ancho). |
112
+ | `showValue` | Escribe «4.7» con punto; la app escribe «4,7». | Si el DS formatea en `es-PE`. |
113
+ | `reviewCount` | Abrevia «1.2K calificaciones» (la etiqueta está en español desde 03-10-2026). | Una lista de locales donde el conteo exacto no importa. |
114
+ | `alignment="vertical"` | Solo ordena `showValue` y `reviewCount`, que no se usan. | Junto con esos dos, si se arreglan. |
115
+
116
+ ## Tamaño en mobile y en web
117
+
118
+ Criterio de la app: **en mobile se lee y se toca con el dedo, así que va más grande; en web
119
+ (desktop), más chico.** Mobile es `≤ 767 px`, el mismo corte de `BreakpointsService.isMobile()`
120
+ en master-pedidos. Fuente: canon del dueño (03-10-2026), el mismo patrón que ya usan 27 controles
121
+ de la app.
122
+
123
+ | uso | mobile | web | fuente |
124
+ |---|---|---|---|
125
+ | Mostrar en una fila o lista | `medium` (20) | `small` (16) | propuesta, falta aprobación |
126
+ | Mostrar en perfil o ficha | `large` (24) | `medium` (20) | propuesta, falta aprobación |
127
+ | La nota grande de un resumen | `xlarge` (28) | `large` (24) | propuesta, falta aprobación |
128
+ | Pedir una nota | `appearance="bar"` (celdas de 64 × 36) | `bar`, o `inline` `large` con mouse | propuesta, falta aprobación |
129
+
130
+ ```ts
131
+ readonly bp = inject(BreakpointsService); // master-pedidos: src/app/services/breakpoints.service.ts
132
+ ```
133
+
134
+ ```html
135
+ <sui-rating [value]="local.rating" [readonly]="true" [halfStep]="true"
136
+ [size]="bp.isMobile() ? 'medium' : 'small'" ariaLabel="Nota del local" />
137
+ ```
138
+
139
+ En `bar` el `size` no cuenta (íconos fijos de 20) y en `cell` tampoco (32): el tamaño por
140
+ plataforma solo se elige en `inline`.
141
+
142
+ ## API
143
+
144
+ <!-- api:inicio -->
145
+ <!-- generada: no editar a mano — `npm run docs` -->
146
+
147
+ | input | tipo | default |
148
+ |---|---|---|
149
+ | `appearance` | `'inline' \| 'cell' \| 'bar' \| 'bar-area'` | `'inline'` |
150
+ | `type` | `'star' \| 'heart' \| 'emoji' \| 'number'` | `'star'` |
151
+ | `value` · model, `[(value)]` | `number` | `0` |
152
+ | `max` | `number` | `5` |
153
+ | `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
154
+ | `readonly` | `boolean` | `false` |
155
+ | `halfStep` | `boolean` | `false` |
156
+ | `showValue` | `boolean` | `false` |
157
+ | `reviewCount` | `number \| null` | `null` |
158
+ | `reviewLink` | `SuiRatingReviewLink \| null` | `null` |
159
+ | `alignment` | `'inline' \| 'vertical' \| 'horizontal'` | `'inline'` |
160
+ | `emojis` | `string[]` | `[ 'pensive-face', 'confused-face', 'neutral-face', 'slightly-smiling-face', 'grinning-face-smiling-eyes', ]` |
161
+ | `ariaLabel` | `string` | `'Calificación'` |
162
+ | `reason` · model, `[(reason)]` | `string` | `''` |
163
+ | `reasonPlaceholder` | `string` | `'Cuéntanos por qué'` |
164
+ | `reasonRows` | `number` | `3` |
165
+
166
+ | output | payload |
167
+ |---|---|
168
+ | `valueChange` | `number` |
169
+ <!-- api:fin -->
170
+
171
+ Implementa `ControlValueAccessor` sobre `value` (sirve con `formControlName`). `reason` es un
172
+ `model` aparte: no entra al `FormControl`.
173
+
174
+ ## Trampas
175
+
176
+ - **`showValue`, `reviewCount` y `reviewLink` solo se ven con `alignment="horizontal"` o
177
+ `"vertical"`.** Con el default `inline` no aparecen.
178
+ - **`reviewCount` agrega «calificaciones»** (en singular con 1; antes «Ratings») y `showValue`
179
+ formatea con punto.
180
+ - **`reasonPlaceholder` por defecto dice «Cuéntanos por qué»** (hasta el 03-10-2026, «Tell us why!»).
181
+ - **`halfStep` solo funciona en `inline` + `readonly`.** En un input no hay medias.
182
+ - **En `bar` el `size` no hace nada** (íconos de 20, celdas de 64); en `cell` los íconos miden 32.
183
+ - **En `bar` y `bar-area` se pinta solo la celda elegida**, no las anteriores: no es una fila de
184
+ estrellas que se llena.
185
+ - `emoji` y `number` **solo se dibujan en `bar`**.
186
+ - `(valueChange)` emite de 1 a `max`, nunca 0; volver a tocar la misma no la quita.
187
+ - El host lleva `role="radiogroup"` y `aria-label`: si la pantalla ya escribe la nota al lado,
188
+ ponle `aria-hidden="true"` para que no se lea dos veces.
189
+
190
+ ## Ejemplo
191
+
192
+ ```html
193
+ <!-- Mostrar la nota del local (promedio, desde el agregado) -->
194
+ <span class="nota">{{ notaTexto }}</span>
195
+ <sui-rating [value]="local.rating" [readonly]="true" [halfStep]="true" size="small" aria-hidden="true" />
196
+
197
+ <!-- Pedir la nota al repartidor -->
198
+ <sui-rating appearance="bar" type="star" [(value)]="nota" ariaLabel="Califica al repartidor" />
199
+ ```
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: sui-rich-editor
3
+ selector: sui-rich-editor
4
+ resumen: Barra de formato (negrita, cursiva, alineación, enlace) con un área de texto editable opcional
5
+ alternativas: [sui-textarea (todo texto libre de la app hoy, sin formato)]
6
+ ---
7
+
8
+ # sui-rich-editor
9
+
10
+ Story: [Molecules/Rich Editor](https://sui-design-system.web.app/?path=/docs/molecules-rich-editor--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** solo si un texto **necesita formato** y se va a mostrar con ese formato: negritas,
15
+ listas o enlaces en un texto largo que se publica en la web.
16
+
17
+ **No lo uses** para:
18
+
19
+ - Notas, motivos, descripciones de productos, mensajes y avisos: `sui-textarea`. Todo eso se
20
+ guarda y se muestra como texto plano.
21
+ - Un push o un aviso del celular: no muestran formato.
22
+
23
+ Regla corta: **hoy, siempre `sui-textarea`.**
24
+
25
+ ## Qué variante usar
26
+
27
+ > **La guía del DS no tiene página para este componente.** Viene del Figma («Rich Editor»), donde
28
+ > solo está la barra de formato. Todo lo de abajo es **propuesta, falta aprobación**.
29
+ >
30
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**.
31
+
32
+ | prop / evento | cuándo | fuente |
33
+ |---|---|---|
34
+ | `layout="full"` (default) | Título, tamaño, B I U S, alineación, comentario, enlace, mención. | API |
35
+ | `layout="formatting"` | Solo B I U S y alineación: lo único que el editor aplica solo. | propuesta, falta aprobación |
36
+ | `layout="compact"` | Solo título y tamaño (los dos son avisos a la pantalla, no formato real). | — |
37
+ | `layout="social"` | Comentario, enlace, mención (también avisos). | — |
38
+ | `showMore` | El botón ⋮ al final. Apagarlo si no hay más acciones. | API |
39
+ | `editable` | `true` para tener el área donde se escribe; `false` deja solo la barra. | API |
40
+ | `placeholder` | «Escribe algo…» (default) o algo del contexto. | API |
41
+ | `value` | El contenido, **en HTML**. | API |
42
+ | `headingLabel` · `fontSizeLabel` | Lo que dicen los botones de título y tamaño («Header», «14px» por default). | API |
43
+ | `(action)` | Cada botón de la barra: la pantalla tiene que resolver título, tamaño, enlace, comentario y mención. | API |
44
+
45
+ ## Tamaño en mobile y en web
46
+
47
+ **No tiene `size`.** Los botones de la barra son de 28 px: **no tiene tamaño suficiente para
48
+ mobile**. Si alguna vez se usa, que sea en el panel web.
49
+
50
+ ## «No usar»: por qué no hoy y cuándo sí
51
+
52
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
53
+ |---|---|---|
54
+ | el componente entero (0 usos) | ningún texto de la app lleva formato | una página de ayuda o de términos que se escribe desde el super admin y se muestra en la web |
55
+ | `layout` `full`, `compact`, `social` | título, tamaño, enlace, comentario y mención no los hace el editor: solo avisa | si se monta un editor completo (Tiptap) detrás |
56
+
57
+ ## API
58
+
59
+ <!-- api:inicio -->
60
+ <!-- generada: no editar a mano — `npm run docs` -->
61
+
62
+ ### `sui-rich-editor`
63
+
64
+ | input | tipo | default |
65
+ |---|---|---|
66
+ | `layout` | `'full' \| 'compact' \| 'formatting' \| 'social'` | `'full'` |
67
+ | `showMore` | `boolean` | `true` |
68
+ | `editable` | `boolean` | `false` |
69
+ | `placeholder` | `string` | `'Escribe algo…'` |
70
+ | `value` · model, `[(value)]` | `string` | `''` |
71
+ | `headingLabel` | `string` | `'Header'` |
72
+ | `fontSizeLabel` | `string` | `'14px'` |
73
+
74
+ | output | payload |
75
+ |---|---|
76
+ | `action` | `SuiRichEditorAction` |
77
+ | `valueChange` | `string` |
78
+
79
+ ### `sui-rich-editor-item`
80
+
81
+ | input | tipo | default |
82
+ |---|---|---|
83
+ | `type` | `'text' \| 'dropdown' \| 'icon' \| 'color'` | `'icon'` |
84
+ | `state` | `'default' \| 'hover' \| 'active'` | `'default'` |
85
+ | `label` | `string` | `''` |
86
+ | `icon` | `string` | `''` |
87
+ | `color` | `'gray' \| 'blue' \| 'orange' \| 'red' \| 'green' \| 'yellow' \| 'purple' \| 'sky' \| 'pink' \| 'teal'` | `'gray'` |
88
+ | `colorHex` | `string \| null` | `null` |
89
+ | `ariaLabel` | `string` | `''` |
90
+ | `disabled` | `boolean` | `false` |
91
+
92
+ | output | payload |
93
+ |---|---|
94
+ | `clicked` | `void` |
95
+ <!-- api:fin -->
96
+
97
+ Sub-componente: `sui-rich-editor-item` (cada botón de la barra).
98
+
99
+ ## Trampas
100
+
101
+ - **`value` es HTML.** Mostrarlo con `[innerHTML]` sin limpiarlo abre la puerta a código ajeno.
102
+ Limpiarlo en el servidor antes de guardar.
103
+ - **Solo B I U S y alineación funcionan solos** (usa `document.execCommand`, que está en desuso).
104
+ Título, tamaño, enlace, comentario y mención solo emiten `(action)`: la pantalla tiene que hacer
105
+ el resto.
106
+ - Por default muestra solo la barra: sin `[editable]="true"` no hay dónde escribir.
107
+ - Labels por default en inglés o técnicos («Header», «14px»).
108
+
109
+ ## Ejemplo
110
+
111
+ ```html
112
+ <sui-rich-editor layout="formatting" [showMore]="false" [editable]="true"
113
+ placeholder="Escribe la respuesta…" [(value)]="html" />
114
+ ```
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: sui-segmented-control
3
+ selector: sui-segmented-control
4
+ resumen: Píldora de 2 a 4 opciones hermanas donde se elige una y se aplica en el momento
5
+ alternativas: [sui-tab-menu-horizontal (navegar entre secciones de contenido), sui-tab-chips (fila de filtros con muchas opciones), sui-radio-card (elegir una opción de un formulario que se guarda después), sui-button-group (varias opciones a la vez)]
6
+ ---
7
+
8
+ # sui-segmented-control
9
+
10
+ Story: [Atoms/Segmented Control](https://sui-design-system.web.app/?path=/docs/atoms-segmented-control--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para cambiar entre 2 a 4 modos de **la misma vista**, que se aplican apenas se tocan:
15
+ cuadrícula o lista en el catálogo, el local cuyo horario estás viendo, el rol que vas a invitar.
16
+
17
+ **No lo uses** para:
18
+
19
+ - Navegar entre secciones de contenido distinto: `sui-tab-menu-horizontal`.
20
+ - Una fila de filtros con muchas opciones o que scrollea: `sui-tab-chips`.
21
+ - Elegir un valor que se guarda después con un botón: `sui-radio-card` (no se enchufa a un formulario).
22
+ - Varias opciones a la vez: `sui-button-group`.
23
+ - 5 o más opciones: los segmentos se reparten el ancho y los textos se cortan.
24
+
25
+ Regla corta: **2-4 modos de la misma vista, efecto inmediato → segmented · secciones → tab menu · filtros → tab-chips.**
26
+
27
+ ## Qué variante usar
28
+
29
+ > **La guía del DS lo define como control para elegir una opción de un conjunto lineal de
30
+ > opciones muy relacionadas «y aplicarla de inmediato»**. Muestra la versión base y la redondeada
31
+ > (`Rounded`). No trae tamaños ni do/don't.
32
+ >
33
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-badge`):
34
+ > **5 usos en 4 archivos**. Tamaños: 3 `small`, 1 `medium`, 1 sin `size` (`medium`). 1 con solo
35
+ > íconos (vista cuadrícula / lista del catálogo).
36
+
37
+ ### `size`
38
+
39
+ | size | cuándo | fuente |
40
+ |---|---|---|
41
+ | `xlarge` | Mobile: es el único que se acerca a los 44 px de área táctil (segmento de 40 px). | canon (dueño: «componentes grandes», 28-09-2026, y tamaño por plataforma, 03-10-2026) |
42
+ | `large` | No aporta: 32 px, chico para el dedo y grande para web. | propuesta, falta aprobación |
43
+ | `medium` (default) | Web, junto a títulos o filtros. | canon (dueño: tamaño por plataforma, 03-10-2026); el valor exacto es propuesta |
44
+ | `small` | Web, solo íconos en una barra de herramientas (cuadrícula / lista). | propuesta, falta aprobación |
45
+
46
+ ### Ítems (`tabs`)
47
+
48
+ | qué | cuándo | fuente |
49
+ |---|---|---|
50
+ | texto | Lo normal. Una o dos palabras por segmento («Por distancia», «Precio único»). | según la guía del DS (ejemplos con texto) |
51
+ | `icon` + texto | Cuando el ícono ayuda a reconocer el modo rápido. | propuesta, falta aprobación |
52
+ | `iconOnly` | Solo para modos universales (cuadrícula / lista). El `label` pasa a ser el nombre accesible: escríbelo igual. | propuesta, falta aprobación |
53
+ | `disabled` (por ítem) | Un modo que existe pero no aplica todavía. | propuesta, falta aprobación |
54
+
55
+ **Usos de hoy que rompen las reglas:**
56
+
57
+ - **2 dentro de un borrador que se guarda después (a discutir):**
58
+ `pages/super-admin/master-settings/master-settings.html:296` (modo de envío: «Por distancia» /
59
+ «Precio único») y `:329` («Por calle» / «En línea recta»). La guía dice que se aplica de
60
+ inmediato; aquí la elección espera al «Guardar». Es trabajo de `sui-radio-card`.
61
+ - **1 con textos largos, a verificar en mobile:** `pages/super-admin/master-roles/master-roles.html:47`
62
+ («Administrador de ciudad» / «Jefe de operaciones»). Por ancho de texto quedan apretados cerca
63
+ del borde a 390 px; no se midió en la pantalla real.
64
+ - **2 en `small` con texto** (la propuesta deja `small` solo para íconos): `master-settings.html:296`
65
+ y `:329`. El tercero en `small`, `pages/products/products.html:80`, está bien: solo íconos.
66
+ - **5 sin tamaño por plataforma** (todos fijos): ninguno cambia a `xlarge` en mobile. Ejemplo:
67
+ `pages/driver/driver-schedule/driver-schedule.html:32` (`size="medium"` en una pantalla del
68
+ repartidor, que se usa en el teléfono).
69
+
70
+ ## Tamaño en mobile y en web
71
+
72
+ Alto de cada segmento: `small` 28 px, `medium` 28 px, `large` 32 px, `xlarge` 40 px (el control
73
+ suma 8 px de borde interno).
74
+
75
+ | uso | mobile | web |
76
+ |---|---|---|
77
+ | modos con texto (local del horario, rol) | `xlarge` (segmento de 40 px) | `medium` |
78
+ | solo íconos en una barra (cuadrícula / lista) | `xlarge` | `small` |
79
+
80
+ ```html
81
+ <sui-segmented-control [size]="bp.isMobile() ? 'xlarge' : 'medium'" … />
82
+ ```
83
+
84
+ El más grande llega a 40 px por segmento: queda 4 px corto de los 44 px de área táctil. Es el
85
+ mejor disponible para mobile.
86
+
87
+ ## «No usar»: por qué no hoy y cuándo sí
88
+
89
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
90
+ |---|---|---|
91
+ | `large` | 32 px: no llega al dedo en mobile y sobra en web | un control dentro de un sheet de mobile muy apretado donde `xlarge` no entra |
92
+ | `disabled` por ítem | ningún modo está bloqueado | un modo que depende del plan («Reportes completos» en plan básico) |
93
+ | 5+ ítems | se cortan los textos | nunca: pasa a `sui-tab-chips` |
94
+
95
+ ## API
96
+
97
+ <!-- api:inicio -->
98
+ <!-- generada: no editar a mano — `npm run docs` -->
99
+
100
+ | input | tipo | default |
101
+ |---|---|---|
102
+ | `tabs` | `SuiSegmentedControlItem<T>[]` | — (requerido) |
103
+ | `active` · model, `[(active)]` | `T` | `undefined` |
104
+ | `size` | `'small' \| 'medium' \| 'large' \| 'xlarge'` | `'medium'` |
105
+
106
+ | output | payload |
107
+ |---|---|
108
+ | `tabChange` | `T` |
109
+ <!-- api:fin -->
110
+
111
+ ```ts
112
+ interface SuiSegmentedControlItem<T = string> {
113
+ value: T;
114
+ label: string;
115
+ icon?: string; // RemixIcon, 20 px fijo
116
+ iconOnly?: boolean; // requiere icon; label pasa a aria-label
117
+ disabled?: boolean;
118
+ }
119
+ ```
120
+
121
+ ## Trampas
122
+
123
+ - **Sin `active` igual dibuja el fondo blanco bajo el primer ítem**, aunque ninguno esté elegido.
124
+ Pásale siempre un valor inicial.
125
+ - **Emite dos veces**: `tabChange` y `activeChange`. Con `[(active)]` no hace falta `(tabChange)`.
126
+ - **No implementa `ControlValueAccessor`**: no va con `formControlName`.
127
+ - **Ocupa todo el ancho del padre.** Para que no se estire, envuélvelo con un `max-width`.
128
+ - El indicador se mide con el DOM: si arranca oculto queda en ancho 0 hasta que algo cambie de tamaño.
129
+ - `iconOnly` sin `icon` no dibuja nada. El ícono mide 20 px en todos los tamaños.
130
+ - `disabled` es por ítem; no hay `disabled` del control entero.
131
+ - Los tamaños son extensión de SUI: la guía tiene uno solo. Su versión redondeada (`Rounded`)
132
+ no existe en SUI.
133
+
134
+ ## Ejemplo
135
+
136
+ ```html
137
+ <div style="max-width: 320px">
138
+ <sui-segmented-control
139
+ [size]="bp.isMobile() ? 'xlarge' : 'small'"
140
+ [tabs]="[{ value: 'grid', label: 'Vista cuadrícula', icon: 'layout-grid-line', iconOnly: true },
141
+ { value: 'list', label: 'Vista lista', icon: 'list-unordered', iconOnly: true }]"
142
+ [(active)]="vista" />
143
+ </div>
144
+ ```