@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,135 @@
1
+ ---
2
+ name: sui-icon
3
+ selector: sui-icon
4
+ resumen: Un ícono monocromo de RemixIcon (o uno propio del DS) que toma el color del texto
5
+ alternativas: [sui-key-icon (el ícono dentro de un círculo de color), sui-emoji (emoji con emoción), sui-brand-logo (el logo de otra marca en su color), sui-compact-button (un ícono que se toca)]
6
+ ---
7
+
8
+ # sui-icon
9
+
10
+ Story: [Atoms/Icon/Icon](https://sui-design-system.web.app/?path=/docs/atoms-icon-icon--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para **todo ícono**: dentro de un texto, una fila, una card, un título. Es la única
15
+ forma de poner un ícono: nada de `<i class="ri-…">` ni SVG pegado en el template. Los íconos
16
+ propios del DS (`info-custom-fill`, `heart-half-fill`…) también pasan por aquí.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Un ícono que se toca: `sui-compact-button` o un `sui-button` con `leftIcon`/`onlyIcon`.
21
+ - Un ícono dentro de un círculo de color (cabecera de un modal, inicio de una fila): `sui-key-icon`.
22
+ - Emoción (estado vacío, celebración): `sui-emoji`.
23
+ - El logo de una marca cuando la marca es lo que se muestra: `sui-brand-logo`.
24
+
25
+ ## Qué variante usar
26
+
27
+ > **La guía del DS no tiene página para el ícono**: usa RemixIcon en todos sus ejemplos, sin
28
+ > reglas de tamaño. La escala de abajo sale de los tokens del DS (`--sui-icon-size-*` y
29
+ > `--sui-icon-*` en `sui-tokens.scss`). Lo marcado «canon» ya es regla del proyecto; el resto es
30
+ > **propuesta, falta aprobación**.
31
+ >
32
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: 406 íconos en 95 archivos, sin contar
33
+ > prototipos ni vitrinas. 331 `-line`, 43 `-fill`. Ninguno usa el input `color`.
34
+
35
+ ### `size`
36
+
37
+ | valor | tamaño de hoy | cuándo | fuente |
38
+ |---|---|---|---|
39
+ | `12` | 5 | Dentro de un badge `small`. | propuesta (token `--sui-icon-size-xs`) |
40
+ | `16` | 69 | Junto a texto chico: metadatos, botones `2xsmall`/`xsmall`, dentro de un kbd. | propuesta (token `--sui-icon-size-sm`) |
41
+ | `20` (default) | 114 | El normal: botones, inputs, filas, navegación. | propuesta (token `--sui-icon-size-md`) |
42
+ | `24` | 5 | Cabeceras y acciones sueltas. | propuesta (token `--sui-icon-size-lg`) |
43
+ | `32` | 2 | Ícono protagonista. Si va dentro de un círculo, es `sui-key-icon`. | propuesta (token `--sui-icon-size-xl`) |
44
+ | `26` | 7 | Solo el ícono del hero de los onboarding (`ob__hero-icon`). | canon (`CLAUDE.md`, patrón de los pasos de onboarding) |
45
+ | `14`, `18` | 149 | Fuera de la escala, pero el DS mismo los usa (tabs, product-card). **A discutir**: no migrar en masa. | propuesta |
46
+ | `13`, `22`, `28`, `44`… | 49 | Sin regla: van al más cercano de la escala. | propuesta |
47
+
48
+ **Usos de hoy fuera de la escala sin regla: 49.** `22` (20 usos: `components/ota-quick-fab/ota-quick-fab.html:11`,
49
+ `pages/schedule/schedule.html:10`), `13` (14: `pages/super-admin/master-drivers/master-drivers.html:359`, `:419`),
50
+ `28` (4: `pages/envios/envios.html:691`), `44`, `48` y `36` (6: `pages/support/support.html:9`,
51
+ `components/product-detail-view/product-detail-view.html:30`), y uno cada uno de `10`, `11`, `15`,
52
+ `30`, `34`. Los de 36 px en adelante casi siempre son un ícono protagonista que quiere ser
53
+ `sui-key-icon` o un `sui-emoji`.
54
+
55
+ ### `name`: `-line` o `-fill`
56
+
57
+ | valor | cuándo | fuente |
58
+ |---|---|---|
59
+ | `-line` | El normal. | propuesta |
60
+ | `-fill` | El seleccionado (el tab activo) o un glifo chico sobre color. | propuesta |
61
+ | propios del DS (`info-custom-fill`, `heart-half-fill`, `building-skyline`, `avatar-placeholder`) | Los usan componentes del DS; en la app no hacen falta. | propuesta |
62
+
63
+ ### `color`
64
+
65
+ | valor | cuándo | fuente |
66
+ |---|---|---|
67
+ | sin `color` (default) | El normal: hereda el color del texto. Casi siempre es lo que se quiere. | propuesta |
68
+ | `var(--sui-icon-sub-600)` | Ícono de apoyo junto a un texto principal. | propuesta |
69
+ | `var(--sui-icon-soft-400)` | Decorativo, metadatos. | propuesta |
70
+ | `var(--sui-icon-disabled-300)` | Deshabilitado. | propuesta |
71
+ | `var(--sui-icon-white-0)` | Sobre fondo oscuro o de color. | propuesta |
72
+ | un hex o un color de estado | No usar: si el ícono dice un estado, va en `sui-key-icon` `lighter`. | propuesta |
73
+
74
+ ## Tamaño en mobile y en web
75
+
76
+ En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
77
+ pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
78
+ breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
79
+ el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propuesta**.
80
+
81
+ | uso | mobile | web |
82
+ |---|---|---|
83
+ | junto al texto de una fila | `20` | `16` |
84
+ | ícono protagonista | `32` | `24` |
85
+ | metadatos | `16` | `16` |
86
+ | dentro de un botón o un input | lo decide el componente | igual |
87
+
88
+ ```html
89
+ <sui-icon name="store-2-line" [size]="bp.isMobile() ? 20 : 16" />
90
+ ```
91
+
92
+ Un ícono suelto **nunca** es el área táctil: si se toca, va en `sui-compact-button` o
93
+ `sui-button` `onlyIcon`, que dan los 44 px. Hoy solo 2 íconos cambian por breakpoint
94
+ (`pages/discounts/discounts.html:101` y `:106`, con `bp.isTablet() ? 20 : 16`).
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
+ | tamaños `13`, `22`, `28`, `44`… | no hay regla que los pida | ninguno: van al más cercano de 12/16/20/24/32 |
101
+ | `color` con un hex | rompe el tema oscuro | ninguno |
102
+ | `<i class="ri-…">` o SVG pegado | se salta el componente | 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` | `string` | — (requerido) |
112
+ | `size` | `number \| string` | `20` |
113
+ | `color` | `string` | `''` |
114
+
115
+ Outputs: ninguno.
116
+ <!-- api:fin -->
117
+
118
+ ## Trampas
119
+
120
+ - **`name` va sin el prefijo `ri-`**: `name="store-2-line"`, no `ri-store-2-line`.
121
+ - **`size` acepta número o string**: `[size]="20"` son px; `size="1.25em"` es CSS. Con
122
+ `size="20"` (string sin unidad) el ícono no toma tamaño.
123
+ - **El nombre no se valida**: si no existe en RemixIcon, sale vacío sin error.
124
+ - **No tiene `aria-label`**: los propios del DS llevan `aria-hidden`; los de RemixIcon son un
125
+ `<i>` vacío. Si el ícono es lo único que dice algo, el texto va al lado o en el contenedor.
126
+ - **La app necesita la fuente de RemixIcon** (`remixicon/fonts/remixicon.css` en `styles.scss`):
127
+ el paquete del DS no la trae.
128
+ - Dentro de un `sui-kbd`, el kbd le fuerza el color `text-sub-600`.
129
+
130
+ ## Ejemplo
131
+
132
+ ```html
133
+ <sui-icon name="store-2-line" [size]="16" />
134
+ <sui-icon name="time-line" [size]="20" color="var(--sui-icon-sub-600)" />
135
+ ```
@@ -0,0 +1,200 @@
1
+ ---
2
+ name: sui-image-upload
3
+ selector: sui-image-upload
4
+ resumen: Subir una imagen y ver su vista previa en el mismo lugar (logo, portada, foto de producto, comprobante)
5
+ alternativas: [sui-image-upload-profile (foto de perfil con botones Subir/Cambiar/Eliminar al lado), sui-file-upload (documentos que no son foto: PDF, Excel), app-image-cropper (el recortador de la app, que se abre desde el lápiz)]
6
+ ---
7
+
8
+ # sui-image-upload
9
+
10
+ Story: [Molecules/Upload/Image Upload](https://sui-design-system.web.app/?path=/docs/molecules-upload-image-upload--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para subir **una imagen** y que la persona la vea apenas la elige: el logo y la portada
15
+ del local, la foto de un producto, la foto de perfil, la captura del Yape o del comprobante, el QR
16
+ de cobro del repartidor, el banner de una campaña.
17
+
18
+ **No lo uses** para:
19
+
20
+ - Documentos que no son foto (PDF, Excel): `sui-file-upload`.
21
+ - Varias imágenes a la vez: no lo soporta; una por campo.
22
+ - La miniatura de una opción de producto (36 px dentro de una fila): `option-image` de la app.
23
+
24
+ El archivo que entrega **no se sube tal cual**: pasa por `ImageCompressorService` (HEIC → JPEG,
25
+ 1200 px + miniatura de 400) y, si hay que encuadrarlo, por `app-image-cropper` antes. Ver Trampas.
26
+
27
+ ## Qué variante usar
28
+
29
+ > **La guía del DS no tiene página para este componente** (el «Image Upload» del Figma de origen
30
+ > es otra cosa: la foto con botones, que en SUI es `sui-image-upload-profile`). Todo es
31
+ > **propuesta, falta aprobación**.
32
+ >
33
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (sin prototipos ni vitrinas): **13 usos en
34
+ > 10 pantallas**. `shape`: 11 `rect`, 2 `circle`. `size`: 7 `xl`, 3 `lg`, 3 sin size (fluidos).
35
+ > `fluid`: 6. `editable`: 3 `true`, 2 según haya imagen, 1 `false`, 7 sin poner.
36
+
37
+ ### `shape` — según cómo se va a ver la imagen después
38
+
39
+ | valor | cuándo | fuente |
40
+ |---|---|---|
41
+ | `circle` (default) | **Solo la foto de una persona** (perfil del cliente, del repartidor, del usuario del local). Así se ve después en `sui-avatar`. | propuesta |
42
+ | `rect` | **Todo lo demás**: el logo del local (en el home se ve como cuadrado redondeado), la portada, la foto del producto, comprobantes, QR, banners. | propuesta |
43
+
44
+ ### `size` y `fluid` — según la forma de la imagen
45
+
46
+ | valor | px | cuándo | fuente |
47
+ |---|---|---|---|
48
+ | `fluid` | ancho del contenedor, alto hasta 320 | **Capturas y documentos** (comprobante, Yape, QR) y **imágenes apaisadas** (portada 16:9, banner). Una captura de celular es vertical: en un cuadrado se recorta. | propuesta |
49
+ | `xl` | 200 | **Imágenes cuadradas**: logo, foto del producto, foto de perfil. | propuesta |
50
+ | `lg` (default) | 160 | Imagen cuadrada al lado de otra cosa en la misma fila (el logo junto al nombre del local en web). | propuesta |
51
+ | `md` | 120 | No usar: chico para ver si la foto quedó bien. | no usar |
52
+ | `sm` | 80 | No usar: no entra el texto (el subtítulo se esconde). | no usar |
53
+
54
+ ### `editable` — qué hace el lápiz
55
+
56
+ | valor | cuándo | fuente |
57
+ |---|---|---|
58
+ | `true` | **Siempre.** Con imagen muestra dos botones a la vista: lápiz y tacho. El lápiz emite `editRequested`: si la pantalla tiene recortador, lo abre (`app-image-cropper`); si no, llama a `abrirSelector()` para elegir otra (como el Yape del repartidor). | propuesta |
59
+ | `false` (default) | No usar: con imagen, el lápiz aparece **solo al pasar el mouse** (en el celular no se ve) y el «Quitar» de abajo es un botón aparte (32 px). | no usar |
60
+
61
+ ### Textos: `title`, `subtitle`
62
+
63
+ | input | cuándo | fuente |
64
+ |---|---|---|
65
+ | `title` | Verbo + qué: «Subir logo», «Subir comprobante», «Subir captura del pago». | propuesta |
66
+ | `subtitle` | Formatos y tamaño, **solo los que el componente acepta** (JPG, PNG o WebP), o el encuadre que se va a aplicar («se recorta a 16:9»). Mientras procesa: «Procesando…». | propuesta |
67
+
68
+ ### `maxSize`, `disabled`, `src`
69
+
70
+ | input | cuándo | fuente |
71
+ |---|---|---|
72
+ | `maxSize` | Siempre, en **bytes**. 10 MB para capturas y comprobantes, 20–50 MB para fotos que se van a comprimir. | propuesta |
73
+ | `disabled` | Mientras se comprime o se sube (`subiendo()`), para que no se elija otra encima. | propuesta |
74
+ | `src` (model) | La URL guardada, o la vista previa local mientras se sube. Con `[(src)]` el componente la pone solo al elegir. | propuesta |
75
+
76
+ ### Usos de hoy que rompen la propuesta
77
+
78
+ - **5 subtítulos prometen HEIC**: hasta el 03-10-2026 el componente lo rechazaba; con la versión
79
+ nueva del DS ya pasa (ver Trampas por la vista previa en Chrome):
80
+ `components/plan-change-modal/plan-change-modal.html:150`, `pages/driver/driver-wallet/driver-wallet.html:243`,
81
+ `pages/promociones/promociones.html:185` y `:269`, `pages/customer/order-tracking/order-tracking.html:985`.
82
+ - **1 logo en círculo** → `rect`: `pages/business-onboarding/step-info/step-info.html:42` (en
83
+ `mi-negocio.html:518` el mismo logo es `rect`, y en el home del cliente se ve cuadrado).
84
+ - **3 imágenes en cuadrado que deberían ir `fluid`**: comprobantes en
85
+ `components/plan-change-modal/plan-change-modal.html:150` y `pages/central/central-gastos/central-gastos.html:118`;
86
+ la portada 16:9 en `pages/mi-negocio/mi-negocio.html:572` (en el onboarding ya va `fluid`).
87
+ - **8 sin `editable`**: `components/avatar-editor/avatar-editor.ts:33` (pone `false` aunque tiene
88
+ recortador), `pages/customer/order-tracking/order-tracking.html:985` (cliente, solo celular),
89
+ `components/plan-change-modal/plan-change-modal.html:150`, `pages/central/central-gastos/central-gastos.html:118`,
90
+ `pages/promociones/promociones.html:185` y `:269`, y `pages/business-onboarding/step-info/step-info.html:42` y `:56`.
91
+ - **2 áreas de subida armadas a mano** que van con este componente (`rect`, `fluid`, `editable`):
92
+ `components/renewal-modal/renewal-modal.html:64` (comprobante, con SVG propio) y
93
+ `pages/products/add-product/add-product.html:223` (foto del producto, con dropzone propia).
94
+ No cuenta `components/option-image/option-image.ts:68`: es una miniatura de 36 px en una fila.
95
+
96
+ ## Tamaño en mobile y en web
97
+
98
+ En mobile se toca con el dedo: lo que se toca mide **44 px o más**. El área vacía se toca entera
99
+ (80 a 200 px), así que pasa; los botones con imagen, no. En pantallas de los dos se elige con el
100
+ servicio de breakpoints de la app (`bp`, en `services/breakpoints.service.ts`).
101
+
102
+ | uso | mobile | web | fuente |
103
+ |---|---|---|---|
104
+ | comprobante, captura, QR, portada, banner | `fluid` | `fluid` (en una columna de ≤ 480 px) | propuesta |
105
+ | logo, foto de producto, foto de perfil | `xl` (200) | `xl` (200), o `lg` (160) al lado del nombre | propuesta |
106
+ | lápiz y tacho (`editable`) | 40 px (32 en `sm`) | 40 px | canon (aprobado por el dueño, 03-10-2026), extensión SUI |
107
+ | «Quitar» (sin `editable`) | 32 px (`sui-button` `xsmall`) | 32 px | canon (aprobado por el dueño, 03-10-2026) |
108
+
109
+ ```html
110
+ <sui-image-upload shape="rect" [size]="bp.isMobile() ? 'xl' : 'lg'" [editable]="true"
111
+ [src]="logo()" [maxSize]="50 * 1024 * 1024" title="Subir logo"
112
+ subtitle="JPG, PNG o WebP — máx 50 MB"
113
+ (imageSelected)="alElegirLogo($event)" (editRequested)="abrirRecortador()"
114
+ (removed)="quitarLogo()" />
115
+ ```
116
+
117
+ Desde el 03-10-2026 el lápiz y el tacho miden **40** (antes 34; en `sm`, de 80 de lado, no entran dos
118
+ de 40 y quedan en 32) y el «Quitar» es un `sui-button` `xsmall` de **32** (antes 28). En `circle`
119
+ los dos botones van centrados abajo, dentro del círculo.
120
+
121
+ ## «No usar»: por qué no hoy y cuándo sí
122
+
123
+ Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
124
+ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
125
+
126
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
127
+ |---|---|---|
128
+ | `size="md"` (120) | chico para ver si la foto quedó bien | una grilla de fotos extra del producto (galería) |
129
+ | `size="sm"` (80) | no entra el texto | una fila de varias miniaturas con su «+» |
130
+ | `editable=false` | el lápiz solo aparece con el mouse; en el celular no se ve | una pantalla solo de web donde reemplazar al pasar el mouse sea lo esperado |
131
+ | `shape="circle"` para algo que no es una persona | el logo y los productos se ven cuadrados | — |
132
+ | para PDF | no muestra vista previa de documentos | — (va `sui-file-upload`) |
133
+
134
+ ## API
135
+
136
+ <!-- api:inicio -->
137
+ <!-- generada: no editar a mano — `npm run docs` -->
138
+
139
+ | input | tipo | default |
140
+ |---|---|---|
141
+ | `fluid` | `boolean` | `false` |
142
+ | `shape` | `'circle' \| 'rect'` | `'circle'` |
143
+ | `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'lg'` |
144
+ | `src` · model, `[(src)]` | `string \| null` | `null` |
145
+ | `maxSize` | `number` | `0` |
146
+ | `title` | `string \| null` | `null` |
147
+ | `subtitle` | `string \| null` | `null` |
148
+ | `disabled` | `boolean` | `false` |
149
+ | `editable` | `boolean` | `false` |
150
+
151
+ | output | payload |
152
+ |---|---|
153
+ | `imageSelected` | `File` |
154
+ | `removed` | `void` |
155
+ | `editRequested` | `void` |
156
+ | `errorEvent` | `string` |
157
+ <!-- api:fin -->
158
+
159
+ Método público: `abrirSelector()` — abre el selector de archivo (para el lápiz cuando no hay
160
+ recortador; se llama con una referencia: `#qr` → `qr.abrirSelector()`).
161
+
162
+ ## Trampas
163
+
164
+ - **Acepta HEIC/HEIF** desde el 03-10-2026 (por tipo y, como Chrome suele dejar el tipo vacío, por
165
+ extensión). **La vista previa de un HEIC no se ve en Chrome** (solo Safari lo dibuja): el
166
+ componente pone el archivo crudo como `src`, así que en Android o en la compu queda en blanco
167
+ hasta que la pantalla lo pasa por `ImageCompressorService` y pone el JPG en `src`.
168
+ - El mensaje de tipo no soportado dice «Tipo no soportado. Usa JPG, PNG, WebP, GIF o HEIC.»
169
+ (antes en voseo).
170
+ - **El default de `shape` es `circle`** y el de `size` es `lg`: para un logo o un comprobante hay
171
+ que pasar los dos.
172
+ - **Con `fluid`, `size` no hace nada** (`promociones.html:185` pasa `size="lg"` y `fluid` a la vez).
173
+ - **`removed` ya vacía `src`** por dentro; quien lo usa solo limpia su `File` y su estado.
174
+ - **Al elegir, pone la vista previa sola** (`src` = data URL) y emite el `File` original, sin
175
+ comprimir ni recortar. Comprimir y recortar es trabajo de la pantalla.
176
+ - Con imagen y sin `editable`, **el componente mide el cuadrado + 8 + 32** (el «Quitar» queda
177
+ dentro; antes se salía y tapaba lo de abajo). Al reservar espacio en un layout, contar ese alto.
178
+ - Con `circle` + `editable` los botones van centrados abajo, sobre la foto (antes, en la esquina, el
179
+ círculo recortaba el tacho).
180
+ - Con `src` puesto, tocar el área vacía no hace nada: para elegir otra va el lápiz o `abrirSelector()`.
181
+ - El `alt` de la vista previa dice «Vista previa».
182
+ - El atributo `title` del host se borra solo (no sale el tooltip gris del navegador).
183
+ - Ya trae el arreglo de iOS para el `:active` pegado.
184
+
185
+ ## Ejemplo
186
+
187
+ ```html
188
+ <!-- Comprobante: ancho completo, el lápiz elige otra captura -->
189
+ <sui-image-upload #comprobante shape="rect" [fluid]="true" [editable]="true"
190
+ [src]="vistaPrevia()" [maxSize]="10 * 1024 * 1024"
191
+ title="Subir comprobante" subtitle="Captura del Yape o del banco — máx 10 MB"
192
+ (imageSelected)="alElegir($event)" (editRequested)="comprobante.abrirSelector()"
193
+ (removed)="quitar()" />
194
+
195
+ <!-- Foto del producto: cuadrada, el lápiz abre el recortador -->
196
+ <sui-image-upload shape="rect" size="xl" [editable]="true" [src]="foto()"
197
+ title="Subir foto" subtitle="JPG, PNG o WebP — se comprime sola"
198
+ (imageSelected)="alElegir($event)" (editRequested)="abrirRecortador()"
199
+ (removed)="quitarFoto()" />
200
+ ```
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: sui-image-upload-profile
3
+ selector: sui-image-upload-profile
4
+ resumen: Foto de perfil o logo en círculo con los botones Subir, o Eliminar y Cambiar, al lado
5
+ alternativas: [sui-image-upload (la imagen grande con su vista previa y el lápiz que abre el recortador; es lo que usa hoy la app), sui-avatar (solo mostrar la foto)]
6
+ ---
7
+
8
+ # sui-image-upload-profile
9
+
10
+ Story: [Molecules/Upload/Image Upload Profile](https://sui-design-system.web.app/?path=/docs/molecules-upload-image-upload-profile--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** en una **pantalla de ajustes** donde la foto es un dato más de la cuenta: un círculo
15
+ chico (56–64 px) con su texto y los botones al lado, en una fila de un formulario.
16
+
17
+ **No lo uses** para:
18
+
19
+ - **La foto de perfil de la app hoy**: `app-avatar-editor` usa `sui-image-upload` `circle` `xl`
20
+ con el recortador, en las tres pantallas de perfil (cliente, repartidor, local). Una foto de
21
+ 200 px que se ve antes de guardar es mejor para quien se sube su cara por primera vez.
22
+ - El logo del local: en la app el logo se ve **cuadrado** (home del cliente) y este componente lo
23
+ muestra en círculo.
24
+ - Comprobantes, portadas o fotos de productos: `sui-image-upload`.
25
+ - Solo mostrar la foto: `sui-avatar`.
26
+
27
+ ## Qué variante usar
28
+
29
+ > **La guía del DS no tiene página para este componente** (existe en el Figma de origen, sin
30
+ > texto de uso). Todo es **propuesta, falta aprobación**.
31
+ >
32
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. La foto de perfil va con
33
+ > `app-avatar-editor` (3 pantallas).
34
+
35
+ ### `type`
36
+
37
+ | valor | cuándo | fuente |
38
+ |---|---|---|
39
+ | `avatar` (default) | La foto de una persona. Vacío muestra una silueta. | propuesta |
40
+ | `company` | Un negocio. Vacío muestra edificios. Ojo: lo muestra en círculo. | propuesta |
41
+
42
+ ### `alignment`
43
+
44
+ | valor | cuándo | fuente |
45
+ |---|---|---|
46
+ | `vertical` (default) | Con texto: título y requisitos («Mín. 400 × 400 px, PNG o JPEG»), avatar de 64. | propuesta |
47
+ | `horizontal` | Sin texto, solo los botones al lado del avatar de 56. Cuando el label ya está arriba (`sui-form-label`). | propuesta |
48
+
49
+ ### Textos y estados
50
+
51
+ | input | cuándo | fuente |
52
+ |---|---|---|
53
+ | `title` | Qué es: «Tu foto», «Foto de perfil». Solo se ve en `vertical`. | propuesta |
54
+ | `subtitle` | Requisitos reales: formatos que se aceptan y para qué se usa («La ve el cliente cuando llevas su pedido»). | propuesta |
55
+ | `labels` | Ya vienen en español con tuteo (Subir, Eliminar, Cambiar). Cambiarlos solo si el contexto pide otro verbo («Quitar»). | propuesta |
56
+ | `imageUrl` | La URL guardada. Con imagen muestra Eliminar + Cambiar. | propuesta |
57
+ | `companyLogoSrc` | Solo con `type="company"`: el logo, que gana sobre `imageUrl`. | propuesta |
58
+ | `loading` | **Siempre** mientras se comprime y se sube: deshabilita los botones y atenúa la foto. | propuesta |
59
+ | `disabled` | La persona no puede cambiarla (cuenta verificada con foto bloqueada). | propuesta |
60
+
61
+ Usos de hoy que rompen la regla: **0**.
62
+
63
+ ## Tamaño en mobile y en web
64
+
65
+ **No tiene `size`.** El avatar mide 64 (vertical) o 56 (horizontal) y los botones son `sui-button`
66
+ `xsmall` de **32 px**: en mobile **no llegan** a los 44 px.
67
+
68
+ | uso | mobile | web | fuente |
69
+ |---|---|---|---|
70
+ | foto en una pantalla de ajustes | — **no hay tamaño**: botones de 32 | `vertical`, botones de 32 | medido |
71
+
72
+ ```html
73
+ <!-- Solo web, hasta que tenga size -->
74
+ <sui-image-upload-profile title="Foto de perfil" subtitle="JPG o PNG, mín. 400 × 400 px"
75
+ [imageUrl]="foto()" [loading]="subiendo()"
76
+ (upload)="input.click()" (change)="input.click()" (remove)="quitar()" />
77
+ <input #input type="file" accept="image/jpeg,image/png,image/webp" hidden (change)="alElegir($event)" />
78
+ ```
79
+
80
+ **Sin tamaño suficiente para mobile.** Hace falta en el DS un `size` que lleve los botones a
81
+ `large` (48 px). Mientras tanto, en el celular va `sui-image-upload` `circle` `xl`.
82
+
83
+ ## «No usar»: por qué no hoy y cuándo sí
84
+
85
+ Nada se borra del DS. Lo marcado «no usar» no tiene caso en la app de hoy; si un flujo nuevo cae
86
+ en la columna de la derecha, se usa (aprobado por el dueño, 03-10-2026).
87
+
88
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
89
+ |---|---|---|
90
+ | todo el componente (0 usos) | la foto de perfil va con `app-avatar-editor` (grande, con recortador) | ajustes del equipo del local en web (foto de cada usuario en una fila) |
91
+ | `type="company"` | el logo del local se ve cuadrado, no en círculo | si el DS le suma la forma cuadrada |
92
+ | `alignment="horizontal"` | sin caso | una fila de una tabla de usuarios del local, con el nombre en la columna de al lado |
93
+
94
+ ## API
95
+
96
+ <!-- api:inicio -->
97
+ <!-- generada: no editar a mano — `npm run docs` -->
98
+
99
+ | input | tipo | default |
100
+ |---|---|---|
101
+ | `imageUrl` | `string \| null` | `null` |
102
+ | `companyLogoSrc` | `string \| null` | `null` |
103
+ | `title` | `string` | `'Subir imagen'` |
104
+ | `subtitle` | `string` | `'Mín. 400x400px, PNG o JPEG'` |
105
+ | `alignment` | `'vertical' \| 'horizontal'` | `'vertical'` |
106
+ | `type` | `'avatar' \| 'company'` | `'avatar'` |
107
+ | `labels` | `SuiImageUploadProfileLabels` | `{}` |
108
+ | `disabled` | `boolean` | `false` |
109
+ | `loading` | `boolean` | `false` |
110
+
111
+ | output | payload |
112
+ |---|---|
113
+ | `upload` | `void` |
114
+ | `remove` | `void` |
115
+ | `change` | `void` |
116
+ <!-- api:fin -->
117
+
118
+ Es `ControlValueAccessor` de la URL (`string | null`); `remove` la deja en `null`.
119
+
120
+ ```ts
121
+ interface SuiImageUploadProfileLabels { upload?: string; remove?: string; change?: string; }
122
+ ```
123
+
124
+ ## Trampas
125
+
126
+ - **No abre el selector de archivos**: no tiene `<input type="file">`. «Subir» y «Cambiar» solo
127
+ emiten `upload` y `change`; quien lo usa pone su propio input (y luego el compresor y el
128
+ recortador).
129
+ - **El avatar siempre es gris** (`color="gray"` fijo): no sigue el color por rol aprobado (local
130
+ naranja, repartidor verde, cliente azul) para el estado vacío.
131
+ - **El orden de los botones lo fija el componente**: Eliminar (rojo) a la izquierda, Cambiar a la
132
+ derecha. No sigue el orden del footer (secundario a la izquierda, principal a la derecha).
133
+ - `type="company"` es un círculo igual que el avatar.
134
+ - En `horizontal` no se ve el texto aunque se pase `title`.
135
+ - `loading` también deshabilita; no muestra spinner.
136
+ - El atributo `title` del host se borra solo (no sale el tooltip gris del navegador); el `title`
137
+ sí se usa como `alt` de la foto.
138
+
139
+ ## Ejemplo
140
+
141
+ ```html
142
+ <sui-image-upload-profile title="Foto de perfil" subtitle="La ve el cliente cuando llevas su pedido"
143
+ [imageUrl]="foto()" [loading]="subiendo()"
144
+ (upload)="elegir()" (change)="elegir()" (remove)="quitar()" />
145
+ ```
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: sui-inline-input
3
+ selector: sui-inline-input
4
+ resumen: Texto que se edita en su lugar: en reposo muestra el dato y un lápiz; al tocarlo, campo con ✓ y ✕
5
+ alternativas: [sui-input (campo de formulario, siempre editable), sui-modal con sui-input (editar con más contexto o varios datos a la vez)]
6
+ ---
7
+
8
+ # sui-inline-input
9
+
10
+ Story: [Molecules/Input/Inline Input](https://sui-design-system.web.app/?path=/docs/molecules-input-inline-input--docs)
11
+
12
+ ## Cuándo usarlo / cuándo no
13
+
14
+ **Úsalo** para corregir **un solo dato de una línea** en una lista o ficha, sin abrir un modal:
15
+ renombrar una categoría de la carta, el alias de una dirección. En reposo se lee como texto con un
16
+ lápiz; al tocar el lápiz pasa a campo con ✓ (confirmar) y ✕ (cancelar). Enter confirma y Escape
17
+ cancela.
18
+
19
+ **No lo uses** para:
20
+
21
+ - Un formulario: `sui-input`, que siempre está editable.
22
+ - Varios datos que se editan juntos o que necesitan explicación: un modal con sus `sui-input`.
23
+ - Un dato con validación compleja o que dispara algo grande (precio, estado): mejor un flujo con
24
+ confirmación.
25
+
26
+ Regla corta: **un dato, en su lugar, que se corrige rápido → inline · varios o delicados → modal.**
27
+
28
+ ## Qué variante usar
29
+
30
+ > **La guía del DS no tiene página para este componente.** Viene del Figma («Inline Input»).
31
+ > Todo lo de abajo es **propuesta, falta aprobación**.
32
+ >
33
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**. Hay listas con campos siempre
34
+ > abiertos que se parecen (`pages/super-admin/master-settings/master-settings.html:99`, nombre de
35
+ > cada categoría del home), pero ahí se editan varias filas y se guarda todo junto: está bien con
36
+ > `sui-input`.
37
+
38
+ | prop / evento | cuándo | fuente |
39
+ |---|---|---|
40
+ | `value` | El dato. `[(value)]` o `formControlName`, nunca los dos. | API |
41
+ | `placeholder` | Lo que se ve si está vacío: «Sin nombre». **Siempre**: el default es «Placeholder text...». | propuesta, falta aprobación |
42
+ | `leftIcon` | Un ícono que dice qué dato es (`price-tag-3-line` para una categoría). `false` si el texto se explica solo. El default es `user-3-line`. | propuesta, falta aprobación |
43
+ | `editLabel` | Nombre accesible del lápiz: «Editar nombre». | propuesta, falta aprobación |
44
+ | `error` | El valor escrito no sirve (vacío, repetido). Solo se ve en edición; no trae mensaje. | propuesta, falta aprobación |
45
+ | `disabled` | Mientras se guarda. | propuesta, falta aprobación |
46
+ | `(confirm)` | Guardar. Llega el texto nuevo. | API |
47
+ | `(cancel)` · `(edit)` | Volver atrás sin guardar · avisar que se empezó a editar. | API |
48
+
49
+ ## Tamaño en mobile y en web
50
+
51
+ **No tiene `size`**: mide 36 px de alto y sus botones (lápiz, ✓, ✕) son de 24 × 24. El texto ya
52
+ sube a 16 px en mobile (sin zoom de iOS). **No tiene tamaño suficiente para mobile**: los botones
53
+ de 24 px quedan lejos de los 44 que pide un dedo. Usarlo en el panel web; en el teléfono, editar
54
+ con un `sui-input` `large`.
55
+
56
+ | uso | mobile | web |
57
+ |---|---|---|
58
+ | renombrar en una lista | `sui-input` `large` en un modal | este, 36 px |
59
+
60
+ ## «No usar»: por qué no hoy y cuándo sí
61
+
62
+ | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
63
+ |---|---|---|
64
+ | el componente entero (0 usos) | no hay datos que se corrijan sueltos en una lista | renombrar una categoría de la carta en web, o el alias de una dirección guardada |
65
+ | `leftIcon` default (`user-3-line`) | casi nunca el dato es una persona | el nombre de un miembro del equipo |
66
+
67
+ ## API
68
+
69
+ <!-- api:inicio -->
70
+ <!-- generada: no editar a mano — `npm run docs` -->
71
+
72
+ | input | tipo | default |
73
+ |---|---|---|
74
+ | `value` · model, `[(value)]` | `string` | `''` |
75
+ | `placeholder` | `string` | `'Placeholder text...'` |
76
+ | `leftIcon` | `string \| false` | `'user-3-line'` |
77
+ | `error` | `boolean` | `false` |
78
+ | `disabled` | `boolean` | `false` |
79
+ | `editLabel` | `string` | `'Editar'` |
80
+
81
+ | output | payload |
82
+ |---|---|
83
+ | `confirm` | `string` |
84
+ | `cancel` | `void` |
85
+ | `edit` | `void` |
86
+ <!-- api:fin -->
87
+
88
+ Implementa `ControlValueAccessor`.
89
+
90
+ ## Trampas
91
+
92
+ - **Los defaults están pensados para la story**: `placeholder` «Placeholder text...» y
93
+ `leftIcon` `user-3-line`. Pasa los dos siempre.
94
+ - `error` no trae mensaje: decir qué falta en otro lado (toast o hint cercano).
95
+ - Cancelar restaura el texto de antes; `(confirm)` es el único momento de guardar.
96
+ - Ocupa todo el ancho de su contenedor.
97
+
98
+ ## Ejemplo
99
+
100
+ ```html
101
+ <sui-inline-input [(value)]="nombreCategoria" placeholder="Sin nombre" leftIcon="price-tag-3-line"
102
+ editLabel="Editar nombre" [error]="!nombreCategoria().trim()"
103
+ (confirm)="renombrar($event)" />
104
+ ```