@ajuarezso/sui-design-system 0.24.1 → 0.25.1

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 (120) hide show
  1. package/docs/sui-accordion/README.md +85 -11
  2. package/docs/sui-activity-feed/README.md +65 -11
  3. package/docs/sui-activity-filter/README.md +54 -5
  4. package/docs/sui-alert/README.md +54 -0
  5. package/docs/sui-app-store-badge/README.md +64 -10
  6. package/docs/sui-avatar/README.md +92 -29
  7. package/docs/sui-avatar-group/README.md +75 -9
  8. package/docs/sui-badge/README.md +85 -17
  9. package/docs/sui-banner/README.md +85 -20
  10. package/docs/sui-brand-logo/README.md +95 -31
  11. package/docs/sui-breadcrumb-item/README.md +54 -3
  12. package/docs/sui-breadcrumbs/README.md +54 -6
  13. package/docs/sui-button/README.md +76 -12
  14. package/docs/sui-button-group/README.md +91 -23
  15. package/docs/sui-button-group-item/README.md +81 -14
  16. package/docs/sui-card/README.md +105 -18
  17. package/docs/sui-chart-legend/README.md +63 -10
  18. package/docs/sui-chart-legend-dot/README.md +59 -10
  19. package/docs/sui-checkbox/README.md +109 -29
  20. package/docs/sui-checkbox-card/README.md +70 -14
  21. package/docs/sui-checkbox-label/README.md +92 -26
  22. package/docs/sui-circular-progress-bar/README.md +80 -19
  23. package/docs/sui-color-dot/README.md +72 -12
  24. package/docs/sui-color-picker/README.md +71 -13
  25. package/docs/sui-command-menu-footer/README.md +50 -1
  26. package/docs/sui-command-menu-item/README.md +74 -14
  27. package/docs/sui-command-menu-search/README.md +58 -3
  28. package/docs/sui-compact-avatar-group/README.md +73 -13
  29. package/docs/sui-compact-button/README.md +123 -34
  30. package/docs/sui-compact-select/README.md +61 -7
  31. package/docs/sui-compact-select-for-input/README.md +70 -6
  32. package/docs/sui-content-card/README.md +75 -14
  33. package/docs/sui-content-divider/README.md +67 -16
  34. package/docs/sui-content-label/README.md +99 -20
  35. package/docs/sui-counter-input/README.md +102 -18
  36. package/docs/sui-date-selector/README.md +69 -11
  37. package/docs/sui-datepicker/README.md +85 -18
  38. package/docs/sui-day-cell/README.md +75 -17
  39. package/docs/sui-day-label/README.md +56 -7
  40. package/docs/sui-divider/README.md +64 -9
  41. package/docs/sui-drawer-footer/README.md +63 -2
  42. package/docs/sui-drawer-header/README.md +69 -12
  43. package/docs/sui-dropdown-caption/README.md +58 -6
  44. package/docs/sui-dropdown-item/README.md +75 -9
  45. package/docs/sui-dropdown-menu/README.md +83 -14
  46. package/docs/sui-dropdown-search/README.md +60 -4
  47. package/docs/sui-emoji/README.md +94 -30
  48. package/docs/sui-empty-state/README.md +71 -7
  49. package/docs/sui-fancy-button/README.md +74 -14
  50. package/docs/sui-file-icon/README.md +70 -12
  51. package/docs/sui-file-upload/README.md +77 -17
  52. package/docs/sui-file-upload-card/README.md +64 -12
  53. package/docs/sui-filter/README.md +83 -14
  54. package/docs/sui-flag/README.md +73 -8
  55. package/docs/sui-form-hint/README.md +56 -7
  56. package/docs/sui-form-label/README.md +57 -5
  57. package/docs/sui-href/README.md +47 -0
  58. package/docs/sui-icon/README.md +86 -18
  59. package/docs/sui-image-upload/README.md +90 -22
  60. package/docs/sui-image-upload-profile/README.md +70 -11
  61. package/docs/sui-img-retry/README.md +50 -1
  62. package/docs/sui-inline-input/README.md +67 -9
  63. package/docs/sui-inline-select/README.md +62 -2
  64. package/docs/sui-input/README.md +90 -27
  65. package/docs/sui-integration-switch/README.md +84 -17
  66. package/docs/sui-kbd/README.md +73 -9
  67. package/docs/sui-key-icon/README.md +85 -23
  68. package/docs/sui-link-button/README.md +96 -27
  69. package/docs/sui-logo/README.md +93 -22
  70. package/docs/sui-modal/README.md +72 -13
  71. package/docs/sui-modal-footer/README.md +86 -12
  72. package/docs/sui-modal-header/README.md +57 -1
  73. package/docs/sui-modal-sheet/README.md +74 -12
  74. package/docs/sui-notification/README.md +81 -11
  75. package/docs/sui-notification-footer/README.md +55 -5
  76. package/docs/sui-notification-tab-menu/README.md +61 -5
  77. package/docs/sui-otp-input/README.md +70 -9
  78. package/docs/sui-page-header/README.md +89 -19
  79. package/docs/sui-pagination/README.md +73 -13
  80. package/docs/sui-password-strength/README.md +50 -1
  81. package/docs/sui-payment-icon/README.md +80 -18
  82. package/docs/sui-period-range/README.md +70 -11
  83. package/docs/sui-popover/README.md +81 -15
  84. package/docs/sui-product-card/README.md +89 -21
  85. package/docs/sui-progress-bar/README.md +82 -15
  86. package/docs/sui-progress-bar-label/README.md +79 -18
  87. package/docs/sui-radio/README.md +84 -7
  88. package/docs/sui-radio-card/README.md +70 -16
  89. package/docs/sui-radio-label/README.md +89 -22
  90. package/docs/sui-rating/README.md +101 -31
  91. package/docs/sui-rich-editor/README.md +47 -2
  92. package/docs/sui-segmented-control/README.md +90 -21
  93. package/docs/sui-select/README.md +80 -11
  94. package/docs/sui-sidebar/README.md +71 -16
  95. package/docs/sui-slider/README.md +75 -8
  96. package/docs/sui-social-button/README.md +71 -11
  97. package/docs/sui-status-badge/README.md +75 -14
  98. package/docs/sui-stepper/README.md +75 -18
  99. package/docs/sui-store-card/README.md +85 -22
  100. package/docs/sui-switch/README.md +82 -11
  101. package/docs/sui-switch-card/README.md +80 -16
  102. package/docs/sui-switch-label/README.md +91 -14
  103. package/docs/sui-tab-chips/README.md +93 -21
  104. package/docs/sui-tab-menu-horizontal/README.md +68 -7
  105. package/docs/sui-tab-menu-vertical/README.md +64 -11
  106. package/docs/sui-table/README.md +77 -16
  107. package/docs/sui-tag/README.md +86 -12
  108. package/docs/sui-tag-input/README.md +77 -13
  109. package/docs/sui-textarea/README.md +84 -17
  110. package/docs/sui-time-picker/README.md +96 -33
  111. package/docs/sui-toast/README.md +81 -20
  112. package/docs/sui-tooltip/README.md +80 -22
  113. package/docs/sui-topbar/README.md +64 -10
  114. package/docs/sui-topbar-button/README.md +61 -7
  115. package/docs/sui-topbar-item/README.md +68 -7
  116. package/docs/sui-topbar-user/README.md +61 -5
  117. package/fesm2022/ajuarezso-sui-design-system.mjs +15 -10
  118. package/fesm2022/ajuarezso-sui-design-system.mjs.map +1 -1
  119. package/package.json +1 -1
  120. package/types/ajuarezso-sui-design-system.d.ts +7 -3
@@ -18,7 +18,7 @@ la barra se llena (rojo, naranja, verde) y cada condición se marca a medida que
18
18
 
19
19
  - El login: la contraseña ya existe, no se evalúa.
20
20
  - Una sola regla («Mínimo 6 caracteres»): alcanza el `hint` del `sui-input`, como hoy en
21
- `pages/auth/register/register.html:124`.
21
+ `pages/auth/register/register.html:132`.
22
22
 
23
23
  Regla corta: **contraseña nueva con 2+ reglas → este · una regla → hint.**
24
24
 
@@ -43,6 +43,12 @@ Regla corta: **contraseña nueva con 2+ reglas → este · una regla → hint.**
43
43
 
44
44
  No se toca: es texto (12 px) y una barra de 4 px a todo el ancho. **No necesita `bp`.**
45
45
 
46
+ ### Por dispositivo (D16)
47
+
48
+ No aplica: no tiene `size` y no se toca; mide lo mismo en el celular chico, el celular, la tablet,
49
+ la computadora y el ultrawide. Lo que sí cambia por dispositivo es el campo de arriba:
50
+ `sui-input` con `[size]="bp.sizeControl()"` (D16, dueño 05-10-2026).
51
+
46
52
  ## «No usar»: por qué no hoy y cuándo sí
47
53
 
48
54
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -89,6 +95,49 @@ interface SuiPasswordStrengthCondition {
89
95
  - `strengthChange` no emite el nivel inicial.
90
96
  - No incluye el campo: va debajo de un `sui-input type="password-toggle"`.
91
97
 
98
+ ## Bien y mal
99
+
100
+ Reglas de la contraseña
101
+
102
+ ```html
103
+ <!-- ❌ mal: sin conditions usa las default (8, mayúscula, número) y marca «débil» lo que el registro acepta. No hay usos en la app: la vitrina lo muestra a propósito como fila de «mal» (pages/super-admin/master-preview/_guia-moleculas/campos.ts:339) -->
104
+ <sui-password-strength [value]="clave()" />
105
+ ```
106
+
107
+ ```html
108
+ <!-- ✅ bien -->
109
+ <sui-password-strength [value]="clave()" [conditions]="reglas" />
110
+ ```
111
+
112
+ Una sola regla
113
+
114
+ ```html
115
+ <!-- ❌ mal: una barra de tres niveles para una sola condición -->
116
+ <sui-input label="Contraseña" type="password-toggle" [size]="bp.sizeControl()" [(value)]="clave" />
117
+ <sui-password-strength [value]="clave()" [conditions]="soloSeisCaracteres" />
118
+ ```
119
+
120
+ ```html
121
+ <!-- ✅ bien -->
122
+ <sui-input label="Contraseña" type="password-toggle" [size]="bp.sizeControl()"
123
+ hint="Mínimo 6 caracteres" [(value)]="clave" />
124
+ ```
125
+
126
+ En el login
127
+
128
+ ```html
129
+ <!-- ❌ mal: la contraseña ya existe; no hay nada que evaluar -->
130
+ <sui-input label="Contraseña" type="password-toggle" autocomplete="current-password"
131
+ [size]="bp.sizeControl()" [(value)]="clave" />
132
+ <sui-password-strength [value]="clave()" [conditions]="reglas" />
133
+ ```
134
+
135
+ ```html
136
+ <!-- ✅ bien -->
137
+ <sui-input label="Contraseña" type="password-toggle" autocomplete="current-password"
138
+ [size]="bp.sizeControl()" [(value)]="clave" />
139
+ ```
140
+
92
141
  ## Ejemplo
93
142
 
94
143
  ```html
@@ -23,8 +23,8 @@ el color ya elegidos.
23
23
 
24
24
  ## Qué variante usar
25
25
 
26
- > **La guía del DS no tiene página para este componente.** Todo es **propuesta, falta
27
- > aprobación**.
26
+ > **La guía del DS no tiene página para este componente.** Las reglas marcadas canon están
27
+ > aprobadas; lo que sigue en propuesta espera decisión.
28
28
  >
29
29
  > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**.
30
30
 
@@ -32,39 +32,61 @@ el color ya elegidos.
32
32
 
33
33
  | valor | ícono y color | cuándo | fuente |
34
34
  |---|---|---|---|
35
- | `water` | gota, celeste | No usar hoy. | propuesta |
36
- | `gas` | fuego, rojo | No usar hoy. | propuesta |
37
- | `electricity` | foco, amarillo | No usar hoy. | propuesta |
38
- | `donate` | mano con corazón, rosa | No usar hoy. | propuesta |
39
- | `internet` | wifi, azul | No usar hoy. | propuesta |
40
- | `phone` | celular, naranja | No usar hoy. | propuesta |
41
- | `rent` | casa, verde | No usar hoy. | propuesta |
42
- | `tax` | documento, morado | No usar hoy. | propuesta |
35
+ | `water` | gota, celeste | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
36
+ | `gas` | fuego, rojo | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
37
+ | `electricity` | foco, amarillo | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
38
+ | `donate` | mano con corazón, rosa | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
39
+ | `internet` | wifi, azul | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
40
+ | `phone` | celular, naranja | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
41
+ | `rent` | casa, verde | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
42
+ | `tax` | documento, morado | No usar hoy. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
43
43
 
44
44
  ### `size` y `ariaLabel`
45
45
 
46
46
  | input | cuándo | fuente |
47
47
  |---|---|---|
48
- | `size` `40` (default) | El único tamaño del Figma. Los demás (32, 48, 56, 64) heredan la escala de `sui-key-icon`. | propuesta |
49
- | `ariaLabel` | Solo si al lado no está escrito el servicio. Si no, es decorativo. | propuesta |
48
+ | `size` `40` (default) | El único tamaño del Figma. Los demás (32, 48, 56, 64) heredan la escala de `sui-key-icon`. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
49
+ | `ariaLabel` | Solo si al lado no está escrito el servicio. Si no, es decorativo. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
50
50
 
51
51
  Usos de hoy que rompen la regla: **0**.
52
52
 
53
53
  ## Tamaño en mobile y en web
54
54
 
55
- En mobile se lee y se toca con el dedo, así que va más grande; en web, más chico. En las
56
- pantallas que se usan en los dos (panel del local, super admin) se elige con el servicio de
57
- breakpoints de la app (`bp`, en `services/breakpoints.service.ts`); en las que solo existen en
58
- el celular (cliente, repartidor) va directo el valor de mobile. Todo es **propuesta**.
55
+ No se toca: es un ícono que se lee. Va un paso más grande en el celular de 380 px o más (`40`)
56
+ y más chico en la computadora (`32`); la tablet y el celular chico (< 380 px) van con el valor de
57
+ web (D16). Se elige siempre con el servicio de breakpoints de la app (`bp`, en
58
+ `services/breakpoints.service.ts`), **también en las pantallas que solo existen en el celular**
59
+ (cliente, repartidor): un `40` fijo ahí deja el celular chico con el valor de mobile.
60
+ Es **canon (dueño, 05-10-2026, P1 b)**: un paso más grande en el celular que en computadora, y
61
+ se migra todo ahora, no solo al tocar cada pantalla.
59
62
 
60
63
  | uso | mobile | web |
61
64
  |---|---|---|
62
65
  | fila de una lista | `40` | `32` |
63
66
 
64
67
  ```html
65
- <sui-payment-icon type="electricity" [size]="bp.isMobile() ? 40 : 32" />
68
+ <sui-payment-icon type="electricity" [size]="bp.celular() ? 40 : 32" />
66
69
  ```
67
70
 
71
+ ### Por dispositivo (D16)
72
+
73
+ Fila `payment-icon` de la tabla D16 (dueño, 05-10-2026, P1 b): no se toca, así que sube un paso
74
+ **solo en el celular de 380 px o más**.
75
+
76
+ | dispositivo | size | nota |
77
+ |---|---|---|
78
+ | celular chico (< 380 px) | `32` | valor «web»: no se toca, no sube aunque sea un celular |
79
+ | celular (380–767 px) | `40` | valor «mobile», un paso más que en la computadora |
80
+ | tablet táctil (`pointer: coarse`) | `32` | valor «web»: el puntero no cambia lo que no se toca |
81
+ | computadora (`pointer: fine`) | `32` | |
82
+
83
+ Ultrawide (≥ 1920 px): igual que la computadora, `32`; el espacio extra va a más columnas, no a
84
+ íconos más grandes.
85
+
86
+ En master-pedidos: `[size]="bp.celular() ? 40 : 32"` (no hay helper propio: `bp.sizeAvatar` y
87
+ `bp.sizeBadge` devuelven los nombres de otra escala). No uses `bp.isMobile()`: incluye el celular
88
+ chico, que va con el valor de web.
89
+
68
90
  ## «No usar»: por qué no hoy y cuándo sí
69
91
 
70
92
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -91,8 +113,48 @@ Outputs: ninguno.
91
113
  - **`type` decide el ícono y el color**: no se pueden cambiar. Si necesitas otro, usa `sui-key-icon`.
92
114
  - **`size` es un número**: `[size]="48"`.
93
115
 
94
- ## Ejemplo
116
+ ## Bien y mal
117
+
118
+ Ícono en una fila de pagos
119
+
120
+ ```html
121
+ <!-- ❌ mal: isMobile incluye el celular chico, que va con el valor de web (D16) -->
122
+ <sui-payment-icon type="water" [size]="bp.isMobile() ? 40 : 32" />
123
+ ```
124
+
125
+ ```html
126
+ <!-- ✅ bien -->
127
+ <sui-payment-icon type="water" [size]="bp.celular() ? 40 : 32" />
128
+ ```
129
+
130
+ Servicio ya escrito al lado
95
131
 
96
132
  ```html
133
+ <!-- ❌ mal: el lector dice «Pago de luz» y después «Luz»; el texto ya lo nombra -->
134
+ <sui-payment-icon type="electricity" ariaLabel="Pago de luz" />
135
+ <span>Luz</span>
136
+ ```
137
+
138
+ ```html
139
+ <!-- ✅ bien -->
97
140
  <sui-payment-icon type="electricity" />
141
+ <span>Luz</span>
142
+ ```
143
+
144
+ Tamaño fijo
145
+
146
+ ```html
147
+ <!-- ❌ mal: size es un número; "48" llega como texto y no es ninguno de 32/40/48/56/64 -->
148
+ <sui-payment-icon type="rent" size="48" />
149
+ ```
150
+
151
+ ```html
152
+ <!-- ✅ bien -->
153
+ <sui-payment-icon type="rent" [size]="48" />
154
+ ```
155
+
156
+ ## Ejemplo
157
+
158
+ ```html
159
+ <sui-payment-icon type="electricity" [size]="bp.celular() ? 40 : 32" />
98
160
  ```
@@ -21,21 +21,21 @@ costado del calendario.
21
21
  - **Cambiar de período en un resumen** («Hoy · 7 días · 30 días»): `sui-segmented-control` si son 2
22
22
  a 4 opciones, `sui-tab-chips` si son 5 o más o se deslizan (canon, dueño 04-10-2026). Hoy la app
23
23
  los tiene en `sui-tab-chips` (super admin `master-overview.html:13`, ganancias del repartidor) y
24
- en `sui-select` (resumen del local, `overview.html:44`): con 3 opciones pasan a segmented.
24
+ en `sui-segmented-control` (resumen del local, `overview.html:43`, medido el 06-10-2026).
25
25
 
26
26
  ## Qué variante usar
27
27
 
28
- > **La guía del DS no tiene página para este componente** (vive dentro del datepicker). Todo es
29
- > **propuesta, falta aprobación**.
28
+ > **La guía del DS no tiene página para este componente** (vive dentro del datepicker). Las reglas
29
+ > marcadas canon están aprobadas; lo que sigue en propuesta espera decisión.
30
30
  >
31
31
  > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos directos**. Lo usa por dentro
32
32
  > `sui-datepicker`.
33
33
 
34
34
  | input | valor | cuándo | fuente |
35
35
  |---|---|---|---|
36
- | `label` | texto | El período en palabras de la persona: «Hoy», «Últimos 7 días», «Este mes». Sin fechas: para eso está el calendario al lado. | propuesta |
37
- | `active` | `true` | El preset que coincide con el rango elegido. Uno solo; si el rango se tocó a mano, ninguno. | propuesta |
38
- | `disabled` | `true` | El período no tiene datos (un local que abrió hace 10 días con «Últimos 3 meses»). Mejor sacarlo de la lista si nunca va a tener datos. | propuesta |
36
+ | `label` | texto | El período en palabras de la persona: «Hoy», «Últimos 7 días», «Este mes». Sin fechas: para eso está el calendario al lado. | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
37
+ | `active` | `true` | El preset que coincide con el rango elegido. Uno solo; si el rango se tocó a mano, ninguno. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
38
+ | `disabled` | `true` | El período no tiene datos (un local que abrió hace 10 días con «Últimos 3 meses»). Mejor sacarlo de la lista si nunca va a tener datos. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
39
39
 
40
40
  Usos de hoy que rompen la regla: **0**.
41
41
 
@@ -47,17 +47,34 @@ se desplaza de costado.
47
47
 
48
48
  | size | alto | texto | uso | fuente |
49
49
  |---|---|---|---|---|
50
- | `large` | **44** (10 + 24 + 10) | 16/24 | mobile | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
51
- | `medium` (default) | 36 | 14/20 | web, columna de presets | medido (Figma 443:341) |
50
+ | `large` | **44** (10 + 24 + 10) | 16/24 | celular y tablet táctil | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · la tablet: D16, dueño 05-10-2026 |
51
+ | `medium` (default) | 36 | 14/20 | computadora, columna de presets | medido (Figma 443:341) |
52
52
 
53
53
  ```html
54
- <sui-period-range [size]="bp.isMobile() ? 'large' : 'medium'" label="Últimos 7 días"
54
+ <sui-period-range [size]="bp.tactil() ? 'large' : 'medium'" label="Últimos 7 días"
55
55
  [active]="preset() === '7d'" (clicked)="aplicar('7d')" />
56
56
  ```
57
57
 
58
58
  Fuera del datepicker, en el celular los períodos fijos de 2 a 4 opciones van en
59
59
  `sui-segmented-control` y los de más opciones en `sui-tab-chips` (canon del dueño, 04-10-2026).
60
60
 
61
+ ### Por dispositivo (D16)
62
+
63
+ No está en la tabla por componente de D16; se toca (es un ítem clickeable), así que va como «lo
64
+ que se toca» (D16, dueño 05-10-2026).
65
+
66
+ | dispositivo | size | nota |
67
+ |---|---|---|
68
+ | celular chico (< 380 px) | `large` (44) | D16 pide `medium` con área tocable de 44; `medium` mide 36 y el DS no estira su área, así que va `large` (interino) |
69
+ | celular (380–767 px) | `large` (44) | |
70
+ | tablet táctil (`pointer: coarse`) | `large` (44) | se toca con el dedo: Apple pide 44 pt también en el iPad |
71
+ | computadora (`pointer: fine`) | `medium` (36) | la columna de presets al costado del calendario |
72
+
73
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`.
74
+
75
+ En master-pedidos: `[size]="bp.tactil() ? 'large' : 'medium'"` (no hay helper propio; es la misma
76
+ cuenta que `bp.sizeControl()`). No uses `bp.isMobile()`: deja la tablet táctil en `medium` (36).
77
+
61
78
  ## «No usar»: por qué no hoy y cuándo sí
62
79
 
63
80
  | qué | por qué no hoy | cuándo sí, en un flujo nuevo |
@@ -89,9 +106,51 @@ Fuera del datepicker, en el celular los períodos fijos de 2 a 4 opciones van en
89
106
  - Ancho fijo de 168 px.
90
107
  - `active` no se apaga solo: lo maneja quien lo usa.
91
108
 
109
+ ## Bien y mal
110
+
111
+ Períodos de un resumen
112
+
113
+ ```html
114
+ <!-- ❌ mal: un resumen con períodos fijos no es la columna de un calendario -->
115
+ <sui-period-range label="Hoy" [active]="periodo() === 'hoy'" (clicked)="periodo.set('hoy')" />
116
+ <sui-period-range label="7 días" [active]="periodo() === '7d'" (clicked)="periodo.set('7d')" />
117
+ <sui-period-range label="30 días" [active]="periodo() === '30d'" (clicked)="periodo.set('30d')" />
118
+ ```
119
+
120
+ ```html
121
+ <!-- ✅ bien: de 2 a 4 períodos fijos, segmented-control -->
122
+ <sui-segmented-control [size]="bp.tactil() ? '2xlarge' : 'medium'"
123
+ [tabs]="periodOptions" [(active)]="periodo" />
124
+ ```
125
+
126
+ Texto del preset
127
+
128
+ ```html
129
+ <!-- ❌ mal: las fechas las muestra el calendario de al lado; el preset dice el período en palabras -->
130
+ <sui-period-range label="29/09 – 05/10" (clicked)="aplicar('7d')" />
131
+ ```
132
+
133
+ ```html
134
+ <!-- ✅ bien -->
135
+ <sui-period-range label="Últimos 7 días" (clicked)="aplicar('7d')" />
136
+ ```
137
+
138
+ Tamaño en la tablet
139
+
140
+ ```html
141
+ <!-- ❌ mal: isMobile deja la tablet táctil en medium (36), bajo el piso de 44 -->
142
+ <sui-period-range [size]="bp.isMobile() ? 'large' : 'medium'" label="Hoy" />
143
+ ```
144
+
145
+ ```html
146
+ <!-- ✅ bien -->
147
+ <sui-period-range [size]="bp.tactil() ? 'large' : 'medium'" label="Hoy" />
148
+ ```
149
+
92
150
  ## Ejemplo
93
151
 
94
152
  ```html
95
- <sui-period-range label="Hoy" [active]="true" />
96
- <sui-period-range label="Últimos 30 días" (clicked)="aplicar('30d')" />
153
+ <sui-period-range [size]="bp.tactil() ? 'large' : 'medium'" label="Hoy" [active]="true" />
154
+ <sui-period-range [size]="bp.tactil() ? 'large' : 'medium'" label="Últimos 30 días"
155
+ (clicked)="aplicar('30d')" />
97
156
  ```
@@ -32,8 +32,9 @@ una función nueva que conviene mostrar donde está («Aquí programas tus pedid
32
32
  > La guía del DS dice para qué es, pero no cuándo va cada pie ni cada posición. Lo marcado «según la
33
33
  > guía del DS» sale de su texto; «canon» es lo ya aprobado en la app; el resto es **propuesta**.
34
34
  >
35
- > Uso medido el 03-10-2026 en `master-pedidos/src/app`: **0 usos**, y ningún recorrido de
36
- > bienvenida hecho a mano. Todo lo de abajo es para el primer flujo que lo necesite.
35
+ > Uso medido el 03-10-2026 en `master-pedidos/src/app` (re-medido el 06-10-2026, sin cambios): **0
36
+ > usos** fuera de la página de guía de master-preview, y ningún recorrido de bienvenida hecho a
37
+ > mano. Todo lo de abajo es para el primer flujo que lo necesite.
37
38
 
38
39
  ### Lo que sí dice la guía del DS
39
40
 
@@ -55,11 +56,11 @@ una función nueva que conviene mostrar donde está («Aquí programas tus pedid
55
56
 
56
57
  | prop | valor | cuándo | fuente |
57
58
  |---|---|---|---|
58
- | `doubleButton` | `true` (default) | Desde el segundo paso de un recorrido («Atrás» / «Siguiente»), o un aviso suelto con «Ahora no» / «Probar». | propuesta |
59
- | `doubleButton` | `false` | El primer paso de un recorrido o un aviso suelto con una sola salida («Entendido»). | propuesta |
59
+ | `doubleButton` | `true` (default) | Desde el segundo paso de un recorrido («Atrás» / «Siguiente»), o un aviso suelto con «Ahora no» / «Probar». | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
60
+ | `doubleButton` | `false` | El primer paso de un recorrido o un aviso suelto con una sola salida («Entendido»). | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
60
61
  | `backLabel` · `nextLabel` | texto en español | Los defaults ya son «Atrás» y «Siguiente» (03-10-2026); el último paso pasa `nextLabel="Listo"`. | canon (CANON-SUI §5.1 y §5.3: sentence case, tuteo) |
61
62
  | orden | secundario a la izquierda, primario a la derecha | Ya lo hace el componente (stroke neutral + filled primary), igual que `sui-modal-footer`. | canon (CLAUDE.md, «Botones — composición y orden») |
62
- | `step` | `{ current, total }` | Con `stepper`. Sin `step`, el componente asume **1 de 4**. | propuesta |
63
+ | `step` | `{ current, total }` | Con `stepper`. Sin `step`, el componente asume **1 de 4**. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
63
64
 
64
65
  ### Flecha, ícono, texto y cierre
65
66
 
@@ -71,13 +72,13 @@ una función nueva que conviene mostrar donde está («Aquí programas tus pedid
71
72
  | `position` | `bottom-*` | El elemento está abajo (la barra de pestañas): el popover va encima. | propuesta |
72
73
  | `position` | `left-*` · `right-*` | Elementos de una barra lateral (el sidebar del panel). | propuesta |
73
74
  | `position` | `*-left` · `*-center` · `*-right` | Alinea la flecha con el elemento cuando el popover no puede centrarse sobre él (está cerca de un borde). | propuesta |
74
- | `icon` | el de lo que se explica | Siempre uno que diga el tema (`calendar-schedule-line` para programar). El default es un ícono de persona. | propuesta |
75
- | `icon` | `null` | Cuando el texto ya basta y el ícono sería decoración. | propuesta |
75
+ | `icon` | el de lo que se explica | Siempre uno que diga el tema (`calendar-schedule-line` para programar). El default es un ícono de persona. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
76
+ | `icon` | `null` | Cuando el texto ya basta y el ícono sería decoración. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
76
77
  | `title` | frase corta | Qué es, en sentence case y sin punto final. | canon (CANON-SUI §5.1 y §5.2) |
77
78
  | `description` | una o dos frases | Qué hace o por qué importa. | propuesta |
78
- | `dismissIcon` | `true` (default) | Siempre: un recorrido se puede saltar. | propuesta |
79
- | `dismissIcon` | `false` | No usar hoy. **Cuándo sí:** un paso que no se puede saltar porque sin él no funciona lo siguiente. | propuesta |
80
- | `[data-slot=body]` | contenido propio | No usar hoy. **Cuándo sí:** el paso necesita una imagen o una lista en vez de título y texto. | propuesta |
79
+ | `dismissIcon` | `true` (default) | Siempre: un recorrido se puede saltar. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
80
+ | `dismissIcon` | `false` | No usar hoy. **Cuándo sí:** un paso que no se puede saltar porque sin él no funciona lo siguiente. | canon (aprobado por el dueño, 05-10-2026, bloque B8) |
81
+ | `[data-slot=body]` | contenido propio | No usar hoy. **Cuándo sí:** el paso necesita una imagen o una lista en vez de título y texto. | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
81
82
 
82
83
  ## Tamaño en mobile y en web
83
84
 
@@ -96,19 +97,37 @@ extensión SUI 03-10-2026).
96
97
  | uso | mobile | web | fuente |
97
98
  |---|---|---|---|
98
99
  | el panel | 320 px (cabe desde 352 px de pantalla) | 320 px | según el componente |
99
- | botones del pie | `large` (48) | `small` (36) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
100
+ | botones del pie | `large` (48), también en la tablet táctil | `medium` (40) | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · tablet y web: D16, dueño 05-10-2026; antes `small` (el default del componente: hay que pasarlo) |
100
101
  | la X | se ve de 24, se toca en 40 | igual | canon (aprobado por el dueño, 03-10-2026) |
101
102
 
102
103
  ```html
103
- <sui-popover footer="stretch" [size]="bp.isMobile() ? 'large' : 'small'" … />
104
+ <sui-popover footer="stretch" [size]="bp.sizeControl()" … />
104
105
  ```
105
106
 
106
107
  `large` es el siguiente de la escala del `sui-button` (48, el del footer de los modales). `medium`
107
- (40) queda para quien ya lo usa: no llega al piso de 44.
108
+ (40) es el de la computadora, con puntero fino (D16); no llega a 44, por eso no va en lo táctil.
108
109
 
109
110
  En mobile, si el recorrido es la bienvenida de la app, conviene una pantalla o un
110
111
  `sui-modal-sheet` por paso en vez del popover (propuesta, falta aprobación).
111
112
 
113
+ ### Por dispositivo (D16)
114
+
115
+ Fila `popover` (botones del pie) de la tabla D16 (dueño, 05-10-2026). Los botones se tocan, así
116
+ que van por tipo de puntero además del ancho. El panel no cambia: 320 px en todos.
117
+
118
+ | dispositivo | size | nota |
119
+ |---|---|---|
120
+ | celular chico (< 380 px) | `large` (48) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino). El panel de 320 cabe desde 352 px |
121
+ | celular (380–767 px) | `large` (48) | |
122
+ | tablet táctil (`pointer: coarse`) | `large` (48) | se toca con el dedo: Apple pide 44 pt también en el iPad |
123
+ | computadora (`pointer: fine`) | `medium` (40) | el default es `small` (36): hay que pasarlo |
124
+
125
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`.
126
+
127
+ En master-pedidos: `[size]="bp.sizeControl()"` — el `size` del popover es el de sus `sui-button`,
128
+ así que va el mismo helper del botón (`large` con `bp.tactil()`, `medium` si no). No uses
129
+ `bp.isMobile()`: deja la tablet táctil en `medium`.
130
+
112
131
  ## «No usar»: por qué no hoy y cuándo sí
113
132
 
114
133
  Hoy el popover entero tiene **0 usos**; esto es lo que no se usaría aunque llegue un flujo nuevo.
@@ -168,6 +187,52 @@ Slot: `[data-slot=body]` reemplaza título y descripción.
168
187
  (crecen si el texto no entra). Hasta el 03-10-2026 no pasaba: el `.scss` apuntaba a
169
188
  `.sui-popover__btn` y el template pone `.sui-popover__action`.
170
189
 
190
+ ## Bien y mal
191
+
192
+ Botones del pie
193
+
194
+ ```html
195
+ <!-- ❌ mal: sin size queda en small, botones de 36. Sale de la página de guía, no de un uso real
196
+ (pages/super-admin/master-preview/_guia-moleculas/avisos.ts:224) -->
197
+ <sui-popover position="top-center" icon="wallet-3-line" title="Aquí ves lo que ganaste hoy"
198
+ [doubleButton]="false" nextLabel="Entendido" />
199
+ ```
200
+
201
+ ```html
202
+ <!-- ✅ bien -->
203
+ <sui-popover position="top-center" icon="wallet-3-line" title="Aquí ves lo que ganaste hoy"
204
+ [doubleButton]="false" nextLabel="Entendido" [size]="bp.sizeControl()" />
205
+ ```
206
+
207
+ Recorrido con puntos
208
+
209
+ ```html
210
+ <!-- ❌ mal: sin step, los puntos dicen «1 de 4» aunque el recorrido tenga 3 pasos -->
211
+ <sui-popover footer="stepper" icon="calendar-schedule-line" title="Programa tus pedidos"
212
+ [size]="bp.sizeControl()" (back)="anterior()" (next)="siguiente()" (dismissed)="saltar()" />
213
+ ```
214
+
215
+ ```html
216
+ <!-- ✅ bien -->
217
+ <sui-popover footer="stepper" [step]="{ current: 2, total: 3 }" icon="calendar-schedule-line"
218
+ title="Programa tus pedidos" [size]="bp.sizeControl()"
219
+ (back)="anterior()" (next)="siguiente()" (dismissed)="saltar()" />
220
+ ```
221
+
222
+ Ícono del tema
223
+
224
+ ```html
225
+ <!-- ❌ mal: sin icon sale una persona (user-6-line), que no dice nada de programar -->
226
+ <sui-popover title="Programa tus pedidos" description="Elige el día y la hora."
227
+ [size]="bp.sizeControl()" />
228
+ ```
229
+
230
+ ```html
231
+ <!-- ✅ bien -->
232
+ <sui-popover icon="calendar-schedule-line" title="Programa tus pedidos"
233
+ description="Elige el día y la hora." [size]="bp.sizeControl()" />
234
+ ```
235
+
171
236
  ## Ejemplo
172
237
 
173
238
  ```html
@@ -175,10 +240,11 @@ Slot: `[data-slot=body]` reemplaza título y descripción.
175
240
  <sui-popover position="top-left" icon="calendar-schedule-line"
176
241
  title="Programa tus pedidos" description="Elige el día y la hora, y el pedido entra solo a la cocina."
177
242
  footer="stepper" [step]="{ current: 2, total: 3 }"
178
- backLabel="Atrás" nextLabel="Siguiente"
243
+ backLabel="Atrás" nextLabel="Siguiente" [size]="bp.sizeControl()"
179
244
  (back)="anterior()" (next)="siguiente()" (dismissed)="saltar()" />
180
245
 
181
246
  <!-- Aviso suelto con una sola salida -->
182
247
  <sui-popover position="bottom-center" icon="wallet-3-line" title="Aquí ves lo que ganaste hoy"
183
- [doubleButton]="false" nextLabel="Entendido" (next)="cerrar()" (dismissed)="cerrar()" />
248
+ [doubleButton]="false" nextLabel="Entendido" [size]="bp.sizeControl()"
249
+ (next)="cerrar()" (dismissed)="cerrar()" />
184
250
  ```
@@ -30,34 +30,38 @@ Regla corta: **producto en la grilla de la carta → product-card · producto en
30
30
  > de la carta de la app. La card **dibuja, no decide**: el precio, si se vende ahora y la
31
31
  > etiqueta de no disponible le llegan ya resueltos.
32
32
  >
33
- > Uso medido el 03-10-2026 en `master-pedidos/src/app` (misma exclusión que `sui-card`): **3
33
+ > Uso medido el 03-10-2026 y re-medido el 06-10-2026 en `master-pedidos/src/app` (misma exclusión
34
+ > que `sui-card`; las líneas son las del 06-10-2026): **3
34
35
  > product-cards en 2 archivos**: la carta del cliente
35
36
  > (`pages/customer/restaurant-menu/restaurant-menu.html:323` y `:386`) y la grilla del local
36
- > (`pages/products/products.html:145`, con `action="edit"`).
37
+ > (`pages/products/products.html:147`, con `action="edit"`).
37
38
 
38
39
  ### Las piezas
39
40
 
40
41
  | prop | cuándo | fuente |
41
42
  |---|---|---|
42
- | `name`, `price` (obligatorios) | Siempre. El precio sale con 2 decimales y punto: «S/ 35.00». | propuesta |
43
- | `description` | Una línea que diga qué trae: «Con hierbas aromáticas y papas nativas». | propuesta |
44
- | `image` como objeto `{ url, fallbackUrl, position }` | Lo normal: `url` = la miniatura, `fallbackUrl` = la foto grande por si la miniatura no carga, `position` = encuadre vertical guardado. | propuesta (así lo hace la carta) |
45
- | `image` como string | Solo la url, sin respaldo. | propuesta |
46
- | `image = null` + `fallback` | Sin foto: banda de color con el nombre (default). La carta pasa `{ color }` para variar el color por visita con `SUI_PRODUCT_FALLBACK_COLORS`. | propuesta |
47
- | `available=false` + `unavailableLabel` | Agotado o fuera de horario; la etiqueta dice cuál («Agotado», «Desde las 12 m.»). Se atenúa y pierde el «+». | propuesta |
48
- | `quantity` | Cuántos hay en el carrito: con más de 0, el «+» pasa a stepper (− / cantidad / +). | propuesta |
49
- | `closed` | El local no recibe pedidos: se ve, no se agrega. | propuesta |
50
- | `action="add"` (default) | La carta del cliente. | propuesta |
51
- | `action="edit"` | La grilla del dueño: lápiz siempre (también en agotado, que es justo el que quiere tocar), nunca stepper. | propuesta |
52
- | `currencySymbol` | Default `S/`. No se cambia: la app cobra en soles. | propuesta |
53
- | `fallback.variant="icon"` | Ver «No usar». | propuesta |
43
+ | `name`, `price` (obligatorios) | Siempre. El precio sale con 2 decimales y punto: «S/ 35.00». | canon (CANON-SUI §5.5: «S/ » + espacio, punto decimal y 2 decimales; el precio se pasa como número y el componente formatea) |
44
+ | `description` | Una línea que diga qué trae: «Con hierbas aromáticas y papas nativas». | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
45
+ | `image` como objeto `{ url, fallbackUrl, position }` | Lo normal: `url` = la miniatura, `fallbackUrl` = la foto grande por si la miniatura no carga, `position` = encuadre vertical guardado. | canon (aprobado por el dueño, 05-10-2026, bloque B9) (así lo hace la carta) |
46
+ | `image` como string | Solo la url, sin respaldo. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
47
+ | `image = null` + `fallback` | Sin foto: banda de color con el nombre (default). La carta pasa `{ color }` para variar el color por visita con `SUI_PRODUCT_FALLBACK_COLORS`. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
48
+ | `available=false` + `unavailableLabel` | Agotado o fuera de horario; la etiqueta dice cuál («Agotado», «Desde las 12 m.»). Se atenúa y pierde el «+». | canon (aprobado por el dueño, 05-10-2026, bloque B4) |
49
+ | `quantity` | Cuántos hay en el carrito: con más de 0, el «+» pasa a stepper (− / cantidad / +). | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
50
+ | `closed` | El local no recibe pedidos: se ve, no se agrega. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
51
+ | `action="add"` (default) | La carta del cliente. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
52
+ | `action="edit"` | La grilla del dueño: lápiz siempre (también en agotado, que es justo el que quiere tocar), nunca stepper. | canon (aprobado por el dueño, 05-10-2026, bloque B2) |
53
+ | `currencySymbol` | Default `S/`. No se cambia: la app cobra en soles. | canon (aprobado por el dueño, 05-10-2026, bloque B9) |
54
+ | `fallback.variant="icon"` | Ver «No usar». | canon (aprobado por el dueño, 05-10-2026, bloque B6) |
54
55
 
55
56
  Outputs: `openDetail` (toque en la card), `add`, `increment`, `decrement`, `edit`.
56
57
 
57
- **Usos de hoy que rompen las reglas:** 0. **Pendiente de migrar:** el precio tachado y la chapa de
58
- descuento ya existen en el DS (`precioLista`, ver «Precio con descuento»), pero la carta los sigue
59
- dibujando afuera (`pages/customer/restaurant-menu/restaurant-menu.scss:426`, deuda anotada) y
60
- ninguna de las 3 cards pasa `precioLista` ni `size`.
58
+ **Usos de hoy que rompen las reglas:** 3 (medido el 06-10-2026). Las 3 cards pasan
59
+ `[size]="bp.isMobile() ? 'large' : 'small'"` (`products.html:147`, `restaurant-menu.html:323` y
60
+ `:386`): `small` en la computadora y en la tablet táctil, cuando D16 pide `medium` y `large`. Va
61
+ `bp.sizeControl()` (ver «Por dispositivo (D16)»). **Pendiente de migrar:** el precio tachado y la
62
+ chapa de descuento ya existen en el DS (`precioLista`, ver «Precio con descuento»), pero la carta
63
+ los sigue dibujando afuera (`pages/customer/restaurant-menu/restaurant-menu.scss:426`, deuda
64
+ anotada) y ninguna de las 3 cards pasa `precioLista`.
61
65
 
62
66
  ## Tamaño en mobile y en web
63
67
 
@@ -77,13 +81,32 @@ lápiz sí siguen al lado del precio.
77
81
  | uso | mobile | web | fuente |
78
82
  |---|---|---|---|
79
83
  | grilla de la carta | 2 columnas (`1fr 1fr`, gap 12) | `repeat(auto-fill, minmax(220px, 1fr))` desde 600 px y `minmax(180px, 1fr)` en desktop | lo que hay en la app |
80
- | botón «+», lápiz, stepper | `large` (44) | `small` (36) | canon (dueño, 04-10-2026): piso táctil 44 en el teléfono |
84
+ | botón «+», lápiz, stepper | `large` (44), también en la tablet táctil | `medium` (40) | mobile: canon (dueño, 04-10-2026): piso táctil 44 en el teléfono · tablet y web: D16, dueño 05-10-2026; antes `small` (el default del componente: hay que pasarlo) |
81
85
 
82
86
  ```html
83
- <sui-product-card [size]="bp.isMobile() ? 'large' : 'small'" … />
87
+ <sui-product-card [size]="bp.sizeControl()" … />
84
88
  ```
85
89
 
86
- `medium` (40) queda para quien ya lo usa: no llega al piso de 44 del teléfono.
90
+ `medium` (40) es el de la computadora (D16); la tablet va como el teléfono, porque se toca.
91
+
92
+ ### Por dispositivo (D16)
93
+
94
+ Fila `product-card` de la tabla D16 (dueño, 05-10-2026). El «+», el lápiz y el stepper se tocan,
95
+ así que van por tipo de puntero además del ancho.
96
+
97
+ | dispositivo | size | nota |
98
+ |---|---|---|
99
+ | celular chico (< 380 px) | `large` (44) | D16 pide `medium` con área tocable de 44; mientras el DS no estire el área de los `medium`, va `large` (interino). El stepper baja a su propia línea |
100
+ | celular (380–767 px) | `large` (44) | grilla de 2 columnas: el stepper baja a su propia línea |
101
+ | tablet táctil (`pointer: coarse`) | `large` (44) | se toca con el dedo: Apple pide 44 pt también en el iPad |
102
+ | computadora (`pointer: fine`) | `medium` (40) | el default es `small` (36): hay que pasarlo |
103
+
104
+ Ultrawide (≥ 1920 px): igual que la computadora, `medium`; el espacio extra va a más columnas de
105
+ la grilla, no a botones más grandes.
106
+
107
+ En master-pedidos: `[size]="bp.sizeControl()"` — el «+» y el lápiz son la escala del `sui-button`,
108
+ así que va el mismo helper (`large` con `bp.tactil()`, `medium` si no). No uses
109
+ `bp.isMobile() ? 'large' : 'small'`: deja la tablet táctil y la computadora en `small`.
87
110
 
88
111
  ## Precio con descuento
89
112
 
@@ -158,10 +181,55 @@ interface SuiProductCardFallback { variant?: 'name' | 'icon'; color?: string | n
158
181
  - Cada url nueva vuelve a mostrar el barrido de carga; si la miniatura falla, intenta con
159
182
  `fallbackUrl` antes de apagarlo.
160
183
 
184
+ ## Bien y mal
185
+
186
+ Tamaño de los botones del pie
187
+
188
+ ```html
189
+ <!-- ❌ mal: small (36) en la computadora y en la tablet táctil (pages/customer/restaurant-menu/restaurant-menu.html:323) -->
190
+ <sui-product-card [size]="bp.isMobile() ? 'large' : 'small'"
191
+ [name]="product.name" [price]="product.price" (add)="onCardAdd(product)" />
192
+ ```
193
+
194
+ ```html
195
+ <!-- ✅ bien -->
196
+ <sui-product-card [size]="bp.sizeControl()"
197
+ [name]="product.name" [price]="product.price" (add)="onCardAdd(product)" />
198
+ ```
199
+
200
+ La grilla del dueño del local
201
+
202
+ ```html
203
+ <!-- ❌ mal: sin action="edit" el dueño ve el «+» del cliente, y en agotado ni eso -->
204
+ <sui-product-card [size]="bp.sizeControl()" [name]="p.name" [price]="p.priceNum"
205
+ [available]="seVendeAhora(p)" (openDetail)="editProduct(p)" />
206
+ ```
207
+
208
+ ```html
209
+ <!-- ✅ bien -->
210
+ <sui-product-card [size]="bp.sizeControl()" action="edit" [name]="p.name" [price]="p.priceNum"
211
+ [available]="seVendeAhora(p)" (openDetail)="editProduct(p)" (edit)="editProduct(p)" />
212
+ ```
213
+
214
+ Foto del producto
215
+
216
+ ```html
217
+ <!-- ❌ mal: como string no hay respaldo si la miniatura falla, ni encuadre guardado -->
218
+ <sui-product-card [size]="bp.sizeControl()" [name]="p.name" [price]="p.price"
219
+ [image]="p.thumbnailUrl" />
220
+ ```
221
+
222
+ ```html
223
+ <!-- ✅ bien -->
224
+ <sui-product-card [size]="bp.sizeControl()" [name]="p.name" [price]="p.price"
225
+ [image]="p.thumbnailUrl ? { url: p.thumbnailUrl, fallbackUrl: p.imageUrl, position: p.imagePosition ?? 50 } : null" />
226
+ ```
227
+
161
228
  ## Ejemplo
162
229
 
163
230
  ```html
164
231
  <sui-product-card
232
+ [size]="bp.sizeControl()"
165
233
  [name]="p.name"
166
234
  [description]="p.description ?? ''"
167
235
  [price]="p.price"