@kaufmann-lab/ui 0.1.20 → 0.1.22
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.
- package/fesm2022/kaufmann-lab-ui-business.mjs +257 -17
- package/fesm2022/kaufmann-lab-ui-business.mjs.map +1 -1
- package/fesm2022/kaufmann-lab-ui-core.mjs +3452 -551
- package/fesm2022/kaufmann-lab-ui-core.mjs.map +1 -1
- package/fesm2022/kaufmann-lab-ui-map.mjs +1 -1
- package/fesm2022/kaufmann-lab-ui-map.mjs.map +1 -1
- package/package.json +1 -1
- package/types/kaufmann-lab-ui-business.d.ts +150 -13
- package/types/kaufmann-lab-ui-core.d.ts +1738 -164
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { AfterContentInit, TemplateRef, Signal, ElementRef, AfterViewInit } from '@angular/core';
|
|
2
|
+
import { AfterContentInit, TemplateRef, Signal, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
|
|
3
3
|
import { ControlValueAccessor } from '@angular/forms';
|
|
4
4
|
import { SafeResourceUrl } from '@angular/platform-browser';
|
|
5
5
|
|
|
@@ -31,8 +31,16 @@ import { SafeResourceUrl } from '@angular/platform-browser';
|
|
|
31
31
|
* `map-pin`, que en este mismo dominio representa ubicación geográfica real
|
|
32
32
|
* de vehículos; reusarlo para "fijar" generaría ambigüedad con los markers
|
|
33
33
|
* de mapa.
|
|
34
|
+
*
|
|
35
|
+
* `refresh` (`refresh-cw` de Lucide) e `info` son extensión propia: la
|
|
36
|
+
* acción "Reintentar" y los avisos informativos (ej. estados de
|
|
37
|
+
* `kf-empty-state` en tono `info`) no tenían glyph equivalente en el set.
|
|
38
|
+
*
|
|
39
|
+
* `layout-grid` (de Lucide, cuatro cuadros) es extensión propia: representa
|
|
40
|
+
* la vista de tarjetas; `grid` dibuja una cuadrícula de tabla y no se
|
|
41
|
+
* distingue de la vista de tabla.
|
|
34
42
|
*/
|
|
35
|
-
type IconName = 'activity' | 'alert-circle' | 'alert-octagon' | 'alert-triangle' | 'award' | 'bar-chart' | 'bell' | 'bus' | 'calculator' | 'calendar' | 'car' | 'cart' | 'check' | 'check-circle' | 'check-square' | 'chevron-down' | 'chevron-left' | 'chevron-left-bar' | 'chevron-right' | 'clipboard' | 'clock' | 'credit-card' | 'crosshair' | 'download' | 'edit' | 'external-link' | 'eye' | 'eye-off' | 'file' | 'filter' | 'gauge' | 'gift' | 'grid' | 'history' | 'home' | 'inbox' | 'layers' | 'list' | 'log-out' | 'mail' | 'map' | 'map-pin' | 'maximize' | 'menu' | 'message-circle' | 'mic' | 'mic-off' | 'minimize' | 'minus' | 'monitor' | 'more-vertical' | 'navigation' | 'pause' | 'phone' | 'pin' | 'play' | 'plus' | 'search' | 'settings' | 'shield-check' | 'sort' | 'star' | 'ticket' | 'tool' | 'trash' | 'truck' | 'upload-cloud' | 'user' | 'user-search' | 'video' | 'x' | 'zap';
|
|
43
|
+
type IconName = 'activity' | 'alert-circle' | 'alert-octagon' | 'alert-triangle' | 'award' | 'bar-chart' | 'bell' | 'bus' | 'calculator' | 'calendar' | 'car' | 'cart' | 'check' | 'check-circle' | 'check-square' | 'chevron-down' | 'chevron-left' | 'chevron-left-bar' | 'chevron-right' | 'clipboard' | 'clock' | 'credit-card' | 'crosshair' | 'download' | 'edit' | 'external-link' | 'eye' | 'eye-off' | 'file' | 'filter' | 'gauge' | 'gift' | 'grid' | 'history' | 'home' | 'inbox' | 'info' | 'layers' | 'layout-grid' | 'list' | 'log-out' | 'mail' | 'map' | 'map-pin' | 'maximize' | 'menu' | 'message-circle' | 'mic' | 'mic-off' | 'minimize' | 'minus' | 'monitor' | 'more-vertical' | 'navigation' | 'pause' | 'phone' | 'pin' | 'play' | 'plus' | 'refresh' | 'search' | 'settings' | 'shield-check' | 'sort' | 'star' | 'ticket' | 'tool' | 'trash' | 'truck' | 'upload-cloud' | 'user' | 'user-search' | 'video' | 'x' | 'zap';
|
|
36
44
|
|
|
37
45
|
type IconSize = 'sm' | 'md' | 'lg';
|
|
38
46
|
/** Ángulos de rotación soportados por `rotate` — cubre los casos reales del
|
|
@@ -128,7 +136,7 @@ declare class AdminBadge {
|
|
|
128
136
|
* Envuelve un `<button>` nativo: mantiene teclado, foco y submit de formulario.
|
|
129
137
|
* Como es un elemento personalizado, ningún atributo ARIA puesto en el host
|
|
130
138
|
* llega al `<button>` interno — por eso `disabled`, `type`, `ariaLabel`,
|
|
131
|
-
* `ariaExpanded` y `
|
|
139
|
+
* `ariaExpanded`, `ariaPressed` y `ariaHaspopup` se reenvían a mano.
|
|
132
140
|
*
|
|
133
141
|
* Seis variantes: `primary`, `secondary`, `ghost`, `outline`, `danger`,
|
|
134
142
|
* `surface`. Tres tamaños (`sm`/`md`/`lg`). `icon` agrega un glifo antes del
|
|
@@ -147,6 +155,15 @@ declare class AdminBadge {
|
|
|
147
155
|
*
|
|
148
156
|
* `(click)` no se reenvía: burbujea del botón interno al host solo.
|
|
149
157
|
*
|
|
158
|
+
* Objetivo táctil: el alto y el ancho mínimos del `<button>` interno salen
|
|
159
|
+
* de `--kf-button-min-height` y `--kf-button-min-width` (default `auto`,
|
|
160
|
+
* sin cambio). Un contenedor los sube (ej. a 44px en pantallas táctiles,
|
|
161
|
+
* sobre todo para un botón solo-ícono) declarando las variables en su
|
|
162
|
+
* propio CSS — heredan a través del límite de encapsulación.
|
|
163
|
+
*
|
|
164
|
+
* `focus()` enfoca el `<button>` interno: el consumidor no necesita
|
|
165
|
+
* buscarlo con `querySelector` en el DOM del componente.
|
|
166
|
+
*
|
|
150
167
|
* `loading` reemplaza el contenido proyectado por `kf-spinner` y fuerza
|
|
151
168
|
* `disabled`.
|
|
152
169
|
*
|
|
@@ -186,15 +203,23 @@ declare class Button {
|
|
|
186
203
|
* más fuerte para leerse activo, y así ningún consumidor tiene que
|
|
187
204
|
* acordarse de pedirlo aparte. */
|
|
188
205
|
readonly ariaPressed: _angular_core.InputSignal<boolean | undefined>;
|
|
206
|
+
/** Tipo de elemento emergente que abre el botón (ej. `'dialog'` para un
|
|
207
|
+
* panel de filtros, `'listbox'`) — mismo motivo de reenvío manual. */
|
|
208
|
+
readonly ariaHaspopup: _angular_core.InputSignal<"menu" | "dialog" | "listbox" | "true" | undefined>;
|
|
209
|
+
private readonly nativeButton;
|
|
210
|
+
/** Enfoca el `<button>` interno (mismas opciones que `HTMLElement.focus`). */
|
|
211
|
+
focus(options?: FocusOptions): void;
|
|
189
212
|
/** `ghost`/`outline`/`surface` no tienen fondo oscuro sólido — el anillo
|
|
190
213
|
* del spinner por defecto ya se lee bien ahí sin variante propia
|
|
191
214
|
* (`surface` es fondo claro con texto oscuro, mismo motivo que `outline`). */
|
|
192
215
|
protected readonly hasSolidFill: _angular_core.Signal<boolean>;
|
|
193
216
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Button, never>;
|
|
194
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Button, "kf-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "block": { "alias": "block"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "ariaExpanded": { "alias": "ariaExpanded"; "required": false; "isSignal": true; }; "ariaPressed": { "alias": "ariaPressed"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
217
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Button, "kf-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "block": { "alias": "block"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "ariaExpanded": { "alias": "ariaExpanded"; "required": false; "isSignal": true; }; "ariaPressed": { "alias": "ariaPressed"; "required": false; "isSignal": true; }; "ariaHaspopup": { "alias": "ariaHaspopup"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
195
218
|
}
|
|
196
219
|
|
|
197
220
|
type AlertTone = 'info' | 'ok' | 'warn' | 'error';
|
|
221
|
+
/** Forma del aviso: `card` (default, con borde y esquinas) o `bar` (franja compacta de ancho completo). */
|
|
222
|
+
type AlertVariant = 'card' | 'bar';
|
|
198
223
|
/**
|
|
199
224
|
* Banner contextual que vive dentro del flujo: validaciones, avisos de
|
|
200
225
|
* vencimiento, confirmaciones. Persiste hasta que se descarta o hasta que la
|
|
@@ -206,9 +231,21 @@ type AlertTone = 'info' | 'ok' | 'warn' | 'error';
|
|
|
206
231
|
*
|
|
207
232
|
* <kf-alert tone="warn" title="SOAT por vencer">Vence el 15/08.</kf-alert>
|
|
208
233
|
* <kf-alert tone="ok" [(open)]="saved" dismissible>Pago registrado.</kf-alert>
|
|
234
|
+
*
|
|
235
|
+
* `variant="bar"` es una franja compacta de ancho completo, sin tarjeta: sin
|
|
236
|
+
* esquinas ni bordes laterales (solo la línea superior e inferior del tono),
|
|
237
|
+
* ícono, título y mensaje en una sola línea que envuelve si no entra. Mismos
|
|
238
|
+
* tonos y mismo `role` (`alert` para `error`/`warn`, `status` para el resto)
|
|
239
|
+
* que la variante `card`. Pensada para el borde de una página o de un panel
|
|
240
|
+
* (ej. "Estás viendo datos de otro cliente"), donde una tarjeta con margen
|
|
241
|
+
* sobra.
|
|
242
|
+
*
|
|
243
|
+
* <kf-alert variant="bar" tone="warn" title="Modo suplantación">Viendo como Ana Pérez.</kf-alert>
|
|
209
244
|
*/
|
|
210
245
|
declare class Alert {
|
|
211
246
|
readonly tone: _angular_core.InputSignal<AlertTone>;
|
|
247
|
+
/** `card` (default) o `bar` (franja compacta de ancho completo). */
|
|
248
|
+
readonly variant: _angular_core.InputSignal<AlertVariant>;
|
|
212
249
|
/** Línea en negrita arriba del mensaje. Vacío deja solo el contenido proyectado. */
|
|
213
250
|
readonly title: _angular_core.InputSignal<string>;
|
|
214
251
|
readonly dismissible: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
@@ -221,7 +258,7 @@ declare class Alert {
|
|
|
221
258
|
protected readonly ariaRole: _angular_core.Signal<"alert" | "status">;
|
|
222
259
|
protected readonly toneIcon: _angular_core.Signal<IconName>;
|
|
223
260
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Alert, never>;
|
|
224
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Alert, "kf-alert", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["*"], true, never>;
|
|
261
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Alert, "kf-alert", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["*"], true, never>;
|
|
225
262
|
}
|
|
226
263
|
|
|
227
264
|
type AlertRowTone = 'warn' | 'error';
|
|
@@ -279,13 +316,24 @@ declare class Avatar {
|
|
|
279
316
|
* punto (`dot`) usa el color BASE de cada tono, no `-strong` — ese último
|
|
280
317
|
* está pensado para texto legible sobre el fondo pastel de `soft` y se ve
|
|
281
318
|
* apagado sobre una superficie translúcida/oscura.
|
|
319
|
+
*
|
|
320
|
+
* `truncate` corta un texto largo con elipsis (ej. un estado de SAP como
|
|
321
|
+
* "WF Aprobación Política descuento") en vez de ensanchar la fila que lo
|
|
322
|
+
* contiene: el badge se limita al ancho de su contenedor (`max-width: 100%`,
|
|
323
|
+
* `min-width: 0`) y el punto no se recorta. El texto completo lo pone el
|
|
324
|
+
* consumidor en `title` (el badge no puede leer su propio contenido
|
|
325
|
+
* proyectado para generarlo):
|
|
326
|
+
*
|
|
327
|
+
* <kf-badge tone="warn" dot truncate [title]="q.statusLabel">{{ q.statusLabel }}</kf-badge>
|
|
282
328
|
*/
|
|
283
329
|
declare class Badge {
|
|
284
|
-
readonly tone: _angular_core.InputSignal<"
|
|
330
|
+
readonly tone: _angular_core.InputSignal<"info" | "neutral" | "ok" | "warn" | "error" | "service">;
|
|
285
331
|
readonly variant: _angular_core.InputSignal<"soft" | "glass">;
|
|
286
332
|
readonly dot: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
333
|
+
/** Corta el texto con elipsis al ancho del contenedor. Ver JSDoc de la clase. */
|
|
334
|
+
readonly truncate: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
287
335
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Badge, never>;
|
|
288
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Badge, "kf-badge", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "dot": { "alias": "dot"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
336
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Badge, "kf-badge", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "dot": { "alias": "dot"; "required": false; "isSignal": true; }; "truncate": { "alias": "truncate"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
289
337
|
}
|
|
290
338
|
|
|
291
339
|
interface BreadcrumbItem {
|
|
@@ -512,14 +560,26 @@ declare class Calendar {
|
|
|
512
560
|
* <kf-button>Guardar</kf-button>
|
|
513
561
|
* </div>
|
|
514
562
|
* </kf-card>
|
|
563
|
+
*
|
|
564
|
+
* `loading` (default `false`): cubre el cuerpo con un bloque de carga animado
|
|
565
|
+
* sin sacar el contenido del layout (queda invisible y fuera del foco y de
|
|
566
|
+
* lectores de pantalla), así la card conserva exactamente sus dimensiones. Los
|
|
567
|
+
* slots `[kf-card-media]` y `[kf-card-actions]` también se ocultan. Marca el
|
|
568
|
+
* host con `aria-busy="true"`. Para una forma más fiel (líneas separadas) usa
|
|
569
|
+
* `kf-skeleton` dentro de la card, o la card propia del dominio con su
|
|
570
|
+
* `loading` (`kf-stat-card`, `kf-metric-card`).
|
|
571
|
+
*
|
|
572
|
+
* <kf-card [loading]="isLoading()"><h3>{{ title() }}</h3><p>{{ text() }}</p></kf-card>
|
|
515
573
|
*/
|
|
516
574
|
declare class Card {
|
|
517
575
|
/** Quita la sombra — para cards anidadas dentro de otra superficie ya elevada. */
|
|
518
576
|
readonly flush: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
519
577
|
/** Espacio entre los hijos directos del cuerpo. `md` es el default. */
|
|
520
578
|
readonly gap: _angular_core.InputSignal<"sm" | "md" | "lg" | "xs" | "xl">;
|
|
579
|
+
/** Cubre el cuerpo con un bloque de carga conservando las dimensiones. */
|
|
580
|
+
readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
521
581
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Card, never>;
|
|
522
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Card, "kf-card", never, { "flush": { "alias": "flush"; "required": false; "isSignal": true; }; "gap": { "alias": "gap"; "required": false; "isSignal": true; }; }, {}, never, ["[kf-card-media]", "*", "[kf-card-actions]"], true, never>;
|
|
582
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Card, "kf-card", never, { "flush": { "alias": "flush"; "required": false; "isSignal": true; }; "gap": { "alias": "gap"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, {}, never, ["[kf-card-media]", "*", "[kf-card-actions]"], true, never>;
|
|
523
583
|
}
|
|
524
584
|
|
|
525
585
|
/**
|
|
@@ -735,99 +795,6 @@ declare class ContentSlot {
|
|
|
735
795
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContentSlot, "kf-content-slot", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
736
796
|
}
|
|
737
797
|
|
|
738
|
-
/** En qué estado está la sección. */
|
|
739
|
-
type ContentStateKind = 'ready' | 'loading' | 'empty' | 'error';
|
|
740
|
-
/** Cómo se dibuja `loading`. Default `'skeleton'`. */
|
|
741
|
-
type ContentStateLoad = 'skeleton' | 'spinner';
|
|
742
|
-
/**
|
|
743
|
-
* Wrapper de los cuatro estados que toda sección tiene: cargando, con datos,
|
|
744
|
-
* vacía y con error. Un componente en vez de tres `@if` sueltos, porque es
|
|
745
|
-
* siempre el mismo slot el que va rotando entre los cuatro.
|
|
746
|
-
*
|
|
747
|
-
* Con `state="ready"` proyecta el contenido real y desaparece; en los otros
|
|
748
|
-
* tres dibuja el placeholder correspondiente y el contenido no se instancia.
|
|
749
|
-
* No inventa visuales propios: `loading` usa `kf-skeleton` (o `kf-spinner` con
|
|
750
|
-
* `load="spinner"`), y `empty`/`error` usan `kf-empty-state`.
|
|
751
|
-
*
|
|
752
|
-
* Las acciones (reintentar, crear) van en el slot `actions` — se ignoran
|
|
753
|
-
* mientras carga, porque no hay nada que reintentar todavía.
|
|
754
|
-
*
|
|
755
|
-
* <kf-content-state [state]="state()" title="No pudimos cargar tus vehículos"
|
|
756
|
-
* subtitle="Revisá tu conexión e intentá de nuevo.">
|
|
757
|
-
* <kf-button actions (click)="retry()">Reintentar</kf-button>
|
|
758
|
-
* <kf-data-table [columns]="cols" [rows]="rows()" />
|
|
759
|
-
* </kf-content-state>
|
|
760
|
-
*/
|
|
761
|
-
declare class ContentState {
|
|
762
|
-
readonly state: _angular_core.InputSignal<ContentStateKind>;
|
|
763
|
-
/** Forma del estado de carga: silueta (default) o spinner. */
|
|
764
|
-
readonly load: _angular_core.InputSignal<ContentStateLoad>;
|
|
765
|
-
/** Título de `empty`/`error`. Ignorado mientras carga. */
|
|
766
|
-
readonly title: _angular_core.InputSignal<string>;
|
|
767
|
-
readonly subtitle: _angular_core.InputSignal<string>;
|
|
768
|
-
/** Texto al lado del spinner cuando `load="spinner"`. */
|
|
769
|
-
readonly loadingLabel: _angular_core.InputSignal<string>;
|
|
770
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentState, never>;
|
|
771
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContentState, "kf-content-state", never, { "state": { "alias": "state"; "required": true; "isSignal": true; }; "load": { "alias": "load"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; "loadingLabel": { "alias": "loadingLabel"; "required": false; "isSignal": true; }; }, {}, never, ["*", "[actions]"], true, never>;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
type ContentViewerType = 'image' | 'video' | 'pdf';
|
|
775
|
-
/**
|
|
776
|
-
* Visor a pantalla completa para ampliar una pieza de contenido: imagen,
|
|
777
|
-
* video o PDF (`type="pdf"`, renderizado por el visor nativo del navegador).
|
|
778
|
-
* Mismo mecanismo que `kf-modal` (el `<dialog>` nativo resuelve backdrop,
|
|
779
|
-
* atrapado de foco, top-layer y `Escape`), pero sin panel/título/footer:
|
|
780
|
-
* el contenido ocupa toda la pantalla sobre un backdrop oscuro.
|
|
781
|
-
*
|
|
782
|
-
* `src` acepta lo que venga del backend sin que el consumidor tenga que
|
|
783
|
-
* normalizarlo primero: una URL (`http(s)://`), un data URI ya armado
|
|
784
|
-
* (`data:...`), o base64 crudo (se le antepone el prefijo `data:` según
|
|
785
|
-
* `type`, asumiendo JPEG para imagen, MP4 para video y PDF para pdf). Un PDF
|
|
786
|
-
* solo acepta contenido local (`blob:`, data URI o base64), nunca una URL remota.
|
|
787
|
-
*
|
|
788
|
-
* Lo proyectado con el atributo `actions` (p. ej. un botón de descarga) va en
|
|
789
|
-
* la barra superior, junto al título.
|
|
790
|
-
*
|
|
791
|
-
* <kf-content-viewer [(open)]="viewerOpen" [src]="viewerSrc()" alt="Foto del vehículo" />
|
|
792
|
-
* <kf-content-viewer [(open)]="viewerOpen" type="video" [src]="viewerSrc()" title="Inspección" />
|
|
793
|
-
* <kf-content-viewer [(open)]="viewerOpen" type="pdf" [src]="blobUrl()" title="Contrato">
|
|
794
|
-
* <kf-button actions variant="surface" icon="download" (click)="save()">Descargar</kf-button>
|
|
795
|
-
* </kf-content-viewer>
|
|
796
|
-
*/
|
|
797
|
-
declare class ContentViewer {
|
|
798
|
-
readonly type: _angular_core.InputSignal<ContentViewerType>;
|
|
799
|
-
/** URL, data URI, o base64 crudo — ver JSDoc de la clase. */
|
|
800
|
-
readonly src: _angular_core.InputSignal<string | null>;
|
|
801
|
-
/** Texto alternativo cuando `type="image"`. */
|
|
802
|
-
readonly alt: _angular_core.InputSignal<string>;
|
|
803
|
-
readonly title: _angular_core.InputSignal<string>;
|
|
804
|
-
/** Visibilidad, two-way: `[(open)]="viewerOpen"`. */
|
|
805
|
-
readonly open: _angular_core.ModelSignal<boolean>;
|
|
806
|
-
/** Permite cerrar con el botón, `Escape` o clic en el backdrop. */
|
|
807
|
-
readonly dismissible: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
808
|
-
protected readonly titleId: string;
|
|
809
|
-
/** Detecta si `src` ya es una URL o un data URI armado; si no, asume
|
|
810
|
-
* base64 crudo y le antepone el prefijo `data:` correspondiente a `type`
|
|
811
|
-
* — el backend a veces manda una cosa, a veces la otra. */
|
|
812
|
-
protected readonly resolvedSrc: _angular_core.Signal<string | null>;
|
|
813
|
-
protected readonly pdfSrc: _angular_core.Signal<SafeResourceUrl | null>;
|
|
814
|
-
protected readonly fallbackLabel: _angular_core.Signal<string>;
|
|
815
|
-
private readonly dialog;
|
|
816
|
-
private readonly document;
|
|
817
|
-
private readonly sanitizer;
|
|
818
|
-
constructor();
|
|
819
|
-
/** `Escape` dispara `cancel`; cancelarlo lo deja abierto. */
|
|
820
|
-
protected onCancel(event: Event): void;
|
|
821
|
-
/**
|
|
822
|
-
* Clic en el backdrop. Un clic en la zona del backdrop tiene como `target` al
|
|
823
|
-
* propio `<dialog>` (el contenido vive en el panel de adentro), así que basta
|
|
824
|
-
* comparar contra él — no hace falta cortar la propagación en el panel.
|
|
825
|
-
*/
|
|
826
|
-
protected onHostClick(event: MouseEvent): void;
|
|
827
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentViewer, never>;
|
|
828
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContentViewer, "kf-content-viewer", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "src": { "alias": "src"; "required": false; "isSignal": true; }; "alt": { "alias": "alt"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["[actions]"], true, never>;
|
|
829
|
-
}
|
|
830
|
-
|
|
831
798
|
/**
|
|
832
799
|
* Zona que ocupa la columna en la vista de cards. La vista de tabla ignora
|
|
833
800
|
* esto (salvo `media`, que igual se rinde como thumbnail en vez de imprimir
|
|
@@ -836,10 +803,14 @@ declare class ContentViewer {
|
|
|
836
803
|
* usa como `src` salvo que la columna traiga su `cellTemplates`.
|
|
837
804
|
* - `title`: título del encabezado (ej. la patente/unidad).
|
|
838
805
|
* - `status`: chip/estado al lado del título.
|
|
839
|
-
* - `field` (default): par label/valor en el cuerpo.
|
|
806
|
+
* - `field` (default): par label/valor en el cuerpo. Con `cardClamp`, el
|
|
807
|
+
* valor ocupa el ancho completo (sin label visible) recortado a N líneas.
|
|
808
|
+
* - `meta`: dato secundario corto (fecha, monto) en una fila inferior de la
|
|
809
|
+
* tarjeta, rótulo chico arriba y valor abajo; con `emphasis` se destaca
|
|
810
|
+
* (ej. el precio) y se alinea al final.
|
|
840
811
|
* - `action`: va al pie, separado del cuerpo por una línea.
|
|
841
812
|
*/
|
|
842
|
-
type DataTableCardRole = 'media' | 'title' | 'status' | 'field' | 'action';
|
|
813
|
+
type DataTableCardRole = 'media' | 'title' | 'status' | 'field' | 'meta' | 'action';
|
|
843
814
|
interface DataTableColumn {
|
|
844
815
|
key: string;
|
|
845
816
|
label: string;
|
|
@@ -862,7 +833,65 @@ interface DataTableColumn {
|
|
|
862
833
|
* corto) se comprima más de la cuenta cuando hay poco espacio y otras
|
|
863
834
|
* columnas compiten por él. */
|
|
864
835
|
minWidth?: string;
|
|
836
|
+
/** Ancho fijo de la columna (ej. `'56px'` para una columna de acciones
|
|
837
|
+
* solo ícono, `'9rem'` para una fecha). En la tabla va como `width` de la
|
|
838
|
+
* celda; en `kf-quote-picker` (`modalLayout="list"`), como el ancho de su
|
|
839
|
+
* pista en la grilla. */
|
|
840
|
+
width?: string;
|
|
841
|
+
/** Techo de ancho. En la tabla, junto con `truncate`, reemplaza al
|
|
842
|
+
* techo automático (ver `truncate`). En una tabla con `grow` admite
|
|
843
|
+
* unidades de contenedor relativas al ancho de la tabla, ej.
|
|
844
|
+
* `'min(14rem, 22cqw)'`: el techo baja solo cuando la tabla es angosta. */
|
|
845
|
+
maxWidth?: string;
|
|
846
|
+
/** Peso con el que la columna se reparte TODO el espacio sobrante de la
|
|
847
|
+
* tabla (ej. `1`; con dos columnas `grow: 2` y `grow: 1`, la primera
|
|
848
|
+
* recibe el doble). Con al menos una columna `grow` la tabla pasa a
|
|
849
|
+
* reparto de anchos: las columnas con `width` mantienen ese ancho, las que
|
|
850
|
+
* no traen `width` ni `grow` se ajustan a su contenido (con `maxWidth` como
|
|
851
|
+
* techo) y las `grow` absorben el resto. Se combina con `truncate` para
|
|
852
|
+
* que el texto largo ocupe el espacio sin empujar a las demás. Sin ninguna
|
|
853
|
+
* columna `grow`, el reparto es el de siempre. */
|
|
854
|
+
grow?: number;
|
|
855
|
+
/** Texto largo en UNA línea con elipsis y el valor completo en `title`
|
|
856
|
+
* (ej. el modelo de un vehículo). La columna deja de imponer su ancho
|
|
857
|
+
* mínimo: cede espacio para que las demás (y la de acciones) entren en
|
|
858
|
+
* pantalla sin scroll horizontal. Con `maxWidth`, se corta en ese ancho. */
|
|
859
|
+
truncate?: boolean;
|
|
860
|
+
/** Alineación horizontal. `'end'` equivale a `right: true` (que se
|
|
861
|
+
* mantiene por compatibilidad). */
|
|
862
|
+
align?: 'start' | 'center' | 'end';
|
|
863
|
+
/** Oculta el rótulo del encabezado a la vista (queda para lectores de
|
|
864
|
+
* pantalla) — ej. una columna de acciones solo ícono. */
|
|
865
|
+
hideLabel?: boolean;
|
|
866
|
+
/** Valor en tipografía monoespaciada (ej. un identificador "COT-2026-0042"),
|
|
867
|
+
* en la celda de la tabla y como título de la tarjeta. */
|
|
868
|
+
mono?: boolean;
|
|
869
|
+
/** Vista tarjetas, columna `field`: el valor va a ancho completo (rótulo
|
|
870
|
+
* solo para lectores de pantalla), recortado a este número de líneas con
|
|
871
|
+
* el texto completo en `title` — ej. el modelo del vehículo con `2`. */
|
|
872
|
+
cardClamp?: number;
|
|
873
|
+
/** Destaca el valor (peso y color de tinta) — ej. el monto. En la vista
|
|
874
|
+
* tarjetas, una columna `meta` con `emphasis` va al final de su fila. */
|
|
875
|
+
emphasis?: boolean;
|
|
876
|
+
/** Celda interactiva: su contenido (texto, `cellTemplates` o `render`) se
|
|
877
|
+
* renderiza dentro de un `<button type="button">` real —enfocable con Tab,
|
|
878
|
+
* con foco visible y activable con Enter o Espacio—, tanto en la vista de
|
|
879
|
+
* tabla como en la de tarjetas. Al activarla emite `cellClick`
|
|
880
|
+
* (`{ row, column, index }`) y NO emite `rowClick`. El contenido de un
|
|
881
|
+
* `cellTemplates` en una columna interactiva debe ser fraseo no interactivo
|
|
882
|
+
* (texto, íconos, indicadores): un enlace o botón dentro de otro botón es
|
|
883
|
+
* HTML inválido. El nombre accesible sale del contenido o, si no alcanza
|
|
884
|
+
* (un indicador sin texto), de `cellAriaLabel`. */
|
|
885
|
+
interactive?: boolean;
|
|
886
|
+
}
|
|
887
|
+
/** Payload de `cellClick`: la fila, la columna interactiva y el índice de la fila renderizada. */
|
|
888
|
+
interface DataTableCellClick<T = unknown> {
|
|
889
|
+
row: T;
|
|
890
|
+
column: DataTableColumn;
|
|
891
|
+
index: number;
|
|
865
892
|
}
|
|
893
|
+
/** Tope de filas (o tarjetas) esqueleto: con `loading`, una página de 50 no pinta 50. */
|
|
894
|
+
declare const DATA_TABLE_MAX_SKELETON_ROWS = 12;
|
|
866
895
|
/** Vistas disponibles cuando `cardable` está activo. */
|
|
867
896
|
type DataTableView = 'table' | 'cards';
|
|
868
897
|
/** Opciones de "filas por página" estándar del portal — 10 como default
|
|
@@ -910,12 +939,21 @@ type DataTableSort = `${string}:${'asc' | 'desc'}`;
|
|
|
910
939
|
* <kf-data-table [columns]="columns" [rows]="rows" [cardable]="true" defaultView="cards" />
|
|
911
940
|
*
|
|
912
941
|
* Loading nativo: con `loading` en `true`, la tabla se reemplaza por un
|
|
913
|
-
* placeholder (`kf-skeleton` por celda/card) —
|
|
914
|
-
* `pageSize`, o 5 si no hay paginación activa.
|
|
942
|
+
* placeholder (`kf-skeleton` por celda/card) — `skeletonRows` filas si se
|
|
943
|
+
* pasa; si no, las de `pageSize`, o 5 si no hay paginación activa. Nunca más
|
|
944
|
+
* de 12 (`DATA_TABLE_MAX_SKELETON_ROWS`): con una página de 50 no se pintan
|
|
945
|
+
* 50 placeholders. Ignora `rows()`/el slot
|
|
915
946
|
* `[empty]` mientras dura (no sabemos aún si el resultado real estará
|
|
916
947
|
* vacío), y respeta la vista activa (tabla o cards) para no cambiar el
|
|
917
948
|
* layout de golpe cuando los datos reales lleguen. El toggle tabla/cards y
|
|
918
|
-
* el header de columnas siguen visibles — solo el cuerpo se reemplaza
|
|
949
|
+
* el header de columnas siguen visibles — solo el cuerpo se reemplaza.
|
|
950
|
+
*
|
|
951
|
+
* El placeholder respeta la columna: en la tabla cada celda conserva su
|
|
952
|
+
* `align`, `width`, `minWidth` y `maxWidth` (una columna numérica lleva una
|
|
953
|
+
* barra corta alineada al final, una de acciones un cuadrado chico, el resto
|
|
954
|
+
* barras de anchos distintos) y la fila reserva el alto de una línea de texto.
|
|
955
|
+
* En tarjetas reproduce la estructura según `cardRole`: encabezado (miniatura,
|
|
956
|
+
* título y estado), campos con su rótulo, fila de `meta` y pie de acciones:
|
|
919
957
|
*
|
|
920
958
|
* <kf-data-table [columns]="columns" [rows]="rows()" [loading]="isLoading()">
|
|
921
959
|
* <kf-empty-state empty>No hay resultados para mostrar.</kf-empty-state>
|
|
@@ -940,6 +978,12 @@ type DataTableSort = `${string}:${'asc' | 'desc'}`;
|
|
|
940
978
|
* <kf-data-table [columns]="columns" [rows]="rows" [pageSize]="25" itemLabel="beneficios" />
|
|
941
979
|
* <kf-data-table [columns]="columns" [rows]="rows" [pageSize]="25" [pageSizeOptions]="[]" />
|
|
942
980
|
*
|
|
981
|
+
* La página es `[(page)]` (el consumidor puede llevarla a la URL) y se
|
|
982
|
+
* corrige sola si queda fuera de rango. Por defecto un cambio de `rows` la
|
|
983
|
+
* devuelve a 1; con `keepPageOnRowsChange` la conserva (el consumidor decide
|
|
984
|
+
* cuándo volver a 1). Un `pageSize` nuevo del consumidor pisa el elegido en
|
|
985
|
+
* el selector, y `pageSizeChange` avisa cuando el usuario lo cambia.
|
|
986
|
+
*
|
|
943
987
|
* Ordenamiento por columna: cada `DataTableColumn` con `sortable: true`
|
|
944
988
|
* vuelve su header clickeable, con el mismo formato `key:direction` que
|
|
945
989
|
* usa `sort` de `kf-quote-picker` (two-way manual, no `model()` — el
|
|
@@ -953,6 +997,79 @@ type DataTableSort = `${string}:${'asc' | 'desc'}`;
|
|
|
953
997
|
*
|
|
954
998
|
* Densidad: `density="compact"` reduce el padding vertical de cada fila,
|
|
955
999
|
* para priorizar cantidad de filas visibles sobre aire entre ellas.
|
|
1000
|
+
*
|
|
1001
|
+
* Listados largos con textos largos (ej. cotizaciones con el modelo del
|
|
1002
|
+
* vehículo): la columna de texto largo lleva `truncate` (elipsis + `title`),
|
|
1003
|
+
* las de dato corto `width`/`align: 'end'`, y la de acciones solo ícono
|
|
1004
|
+
* `width` angosto + `hideLabel` + `sticky: 'right'`. Así la acción queda
|
|
1005
|
+
* siempre a la vista sin scroll horizontal:
|
|
1006
|
+
*
|
|
1007
|
+
* columns = [
|
|
1008
|
+
* { key: 'id', label: 'Cotización', width: '9rem' },
|
|
1009
|
+
* { key: 'model', label: 'Vehículo', truncate: true, minWidth: '10rem' },
|
|
1010
|
+
* { key: 'amount', label: 'Monto', align: 'end', width: '8rem' },
|
|
1011
|
+
* { key: 'open', label: 'Abrir', hideLabel: true, width: '56px', sticky: 'right' },
|
|
1012
|
+
* ];
|
|
1013
|
+
* <kf-data-table [columns]="columns" [rows]="quotes" [rowClickable]="true"
|
|
1014
|
+
* (rowClick)="open($event.row)" [cellTemplates]="{ open: openCell }" />
|
|
1015
|
+
*
|
|
1016
|
+
* Reparto de anchos: con `grow` en alguna columna, esa(s) se reparten TODO el
|
|
1017
|
+
* espacio sobrante según su peso, las de `width` lo mantienen y las que no
|
|
1018
|
+
* traen `width` ni `grow` se ajustan a su contenido (con `maxWidth` como
|
|
1019
|
+
* techo). Así una columna de dato corto (estado, precio, fecha) no acapara
|
|
1020
|
+
* espacio y el texto largo (el vehículo) lo aprovecha:
|
|
1021
|
+
*
|
|
1022
|
+
* columns = [
|
|
1023
|
+
* { key: 'id', label: 'Cotización', width: '8.5rem', mono: true },
|
|
1024
|
+
* { key: 'model', label: 'Vehículo', grow: 1, truncate: true },
|
|
1025
|
+
* { key: 'issuedAt', label: 'Emisión' },
|
|
1026
|
+
* { key: 'price', label: 'Precio', align: 'end', emphasis: true },
|
|
1027
|
+
* { key: 'status', label: 'Estado', truncate: true, maxWidth: '14rem' },
|
|
1028
|
+
* ];
|
|
1029
|
+
*
|
|
1030
|
+
* Listado completo con vista tarjetas (ej. cotizaciones): la vista es
|
|
1031
|
+
* two-way (`[(view)]`) y el toggle interno se oculta con
|
|
1032
|
+
* `[showViewToggle]="false"` cuando el consumidor lo pone en su barra. En
|
|
1033
|
+
* tarjetas: título (`mono`) y estado en una fila, el campo principal a
|
|
1034
|
+
* ancho completo en 2 líneas (`cardClamp: 2`), y fecha/monto en una fila
|
|
1035
|
+
* inferior (`cardRole: 'meta'`, el monto con `emphasis`). Las tarjetas de
|
|
1036
|
+
* una fila miden lo mismo; `cardMinWidth` fija el ancho mínimo. Con
|
|
1037
|
+
* `rowClickable` la tarjeta entera es un botón (Enter/Espacio):
|
|
1038
|
+
*
|
|
1039
|
+
* columns = [
|
|
1040
|
+
* { key: 'id', label: 'Cotización', cardRole: 'title', mono: true },
|
|
1041
|
+
* { key: 'status', label: 'Estado', cardRole: 'status' },
|
|
1042
|
+
* { key: 'model', label: 'Vehículo', truncate: true, cardClamp: 2 },
|
|
1043
|
+
* { key: 'date', label: 'Fecha', cardRole: 'meta', width: '7rem' },
|
|
1044
|
+
* { key: 'amount', label: 'Monto', cardRole: 'meta', align: 'end', emphasis: true },
|
|
1045
|
+
* ];
|
|
1046
|
+
* <kf-data-table [columns]="columns" [rows]="quotes" cardable [(view)]="view"
|
|
1047
|
+
* [showViewToggle]="false" cardMinWidth="300px" [rowClickable]="true"
|
|
1048
|
+
* (rowClick)="open($event.row)" />
|
|
1049
|
+
*
|
|
1050
|
+
* Celdas interactivas (modo aditivo, ej. una matriz unidad × etapa donde cada
|
|
1051
|
+
* celda de etapa es un indicador de estado): una columna con
|
|
1052
|
+
* `interactive: true` renderiza su contenido dentro de un `<button>` real
|
|
1053
|
+
* —focusable, con foco visible y activación con Enter o Espacio— en la vista
|
|
1054
|
+
* de tabla y en la de tarjetas, y emite `cellClick` con `{ row, column, index }`.
|
|
1055
|
+
* `cellAriaLabel` da el nombre accesible de cada celda cuando el contenido no
|
|
1056
|
+
* lo aporta por sí solo (un indicador sin texto); en tarjetas conviene incluir
|
|
1057
|
+
* el contexto de la fila, porque no hay encabezado de columna que lo dé:
|
|
1058
|
+
*
|
|
1059
|
+
* columns = [
|
|
1060
|
+
* { key: 'unit', label: 'Unidad', cardRole: 'title', sticky: 'left' },
|
|
1061
|
+
* { key: 'stage1', label: 'Recepción', interactive: true, align: 'center' },
|
|
1062
|
+
* { key: 'stage2', label: 'Entrega', interactive: true, align: 'center' },
|
|
1063
|
+
* ];
|
|
1064
|
+
* <kf-data-table [columns]="columns" [rows]="units" cardable [rowKey]="unitId"
|
|
1065
|
+
* [cellTemplates]="{ stage1: stageCell, stage2: stageCell }"
|
|
1066
|
+
* [cellAriaLabel]="stageLabel" (cellClick)="openStage($event.row, $event.column)" />
|
|
1067
|
+
*
|
|
1068
|
+
* Convive con `rowClick`: la fila sigue emitiéndolo desde cualquier punto que
|
|
1069
|
+
* no sea una celda interactiva. En tarjetas, la tarjeta deja de ser un botón
|
|
1070
|
+
* (un botón dentro de un `role="button"` es inválido) salvo que se fuerce con
|
|
1071
|
+
* `[rowClickable]="true"`. `sticky`, `cellTemplates`, `currentRowKey`, la
|
|
1072
|
+
* ordenación y la paginación no cambian.
|
|
956
1073
|
*/
|
|
957
1074
|
declare class DataTable<T = unknown> {
|
|
958
1075
|
readonly columns: _angular_core.InputSignal<DataTableColumn[]>;
|
|
@@ -960,6 +1077,10 @@ declare class DataTable<T = unknown> {
|
|
|
960
1077
|
/** Placeholder nativo (`kf-skeleton`) mientras los datos reales cargan —
|
|
961
1078
|
* ver el doc-comment de la clase para el detalle. */
|
|
962
1079
|
readonly loading: _angular_core.InputSignal<boolean>;
|
|
1080
|
+
/** Filas (o tarjetas) esqueleto mientras `loading` es `true`. Sin valor: el
|
|
1081
|
+
* `pageSize` con paginación activa, o 5. Máximo
|
|
1082
|
+
* {@link DATA_TABLE_MAX_SKELETON_ROWS}. */
|
|
1083
|
+
readonly skeletonRows: _angular_core.InputSignal<number | undefined>;
|
|
963
1084
|
private readonly scrollEl;
|
|
964
1085
|
private readonly destroyRef;
|
|
965
1086
|
/**
|
|
@@ -972,6 +1093,13 @@ declare class DataTable<T = unknown> {
|
|
|
972
1093
|
*/
|
|
973
1094
|
protected readonly canScrollLeft: _angular_core.WritableSignal<boolean>;
|
|
974
1095
|
protected readonly canScrollRight: _angular_core.WritableSignal<boolean>;
|
|
1096
|
+
/**
|
|
1097
|
+
* Hay contenido oculto por scroll horizontal. Solo entonces el contenedor
|
|
1098
|
+
* es una región nombrada y enfocable (`tabindex="0"`, `role="region"`):
|
|
1099
|
+
* sin foco, quien navega con teclado no puede desplazarlo (WCAG 2.1.1).
|
|
1100
|
+
* Una tabla que entra completa no suma una parada de Tab vacía.
|
|
1101
|
+
*/
|
|
1102
|
+
protected readonly hasOverflow: _angular_core.WritableSignal<boolean>;
|
|
975
1103
|
constructor();
|
|
976
1104
|
private updateScrollState;
|
|
977
1105
|
/** Default: índice de la fila dentro de `rows`. */
|
|
@@ -979,17 +1107,26 @@ declare class DataTable<T = unknown> {
|
|
|
979
1107
|
/** Sin borde/sombra de card — para tablas anidadas dentro de otra card. */
|
|
980
1108
|
readonly flush: _angular_core.InputSignal<boolean>;
|
|
981
1109
|
/** Habilita el toggle de vista tabla/cards. */
|
|
982
|
-
readonly cardable: _angular_core.
|
|
1110
|
+
readonly cardable: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
983
1111
|
readonly defaultView: _angular_core.InputSignal<DataTableView>;
|
|
1112
|
+
/** Muestra el toggle tabla/tarjetas interno (con `cardable`). En `false`,
|
|
1113
|
+
* el consumidor controla la vista con `[(view)]` desde su propio control. */
|
|
1114
|
+
readonly showViewToggle: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1115
|
+
/** Ancho mínimo de cada tarjeta en la grilla (default `220px`, histórico).
|
|
1116
|
+
* Nunca supera el ancho disponible: en pantallas angostas, una columna. */
|
|
1117
|
+
readonly cardMinWidth: _angular_core.InputSignal<string>;
|
|
984
1118
|
/**
|
|
985
1119
|
* Formateo simple de celda como texto: `(row) => string`. Para marcado
|
|
986
1120
|
* real (badges, links, botones) usar `cellTemplates`.
|
|
987
1121
|
*/
|
|
988
1122
|
readonly render: _angular_core.InputSignal<((row: T) => string) | undefined>;
|
|
989
|
-
/** Mapa `columnKey -> TemplateRef` para celdas con contenido custom.
|
|
1123
|
+
/** Mapa `columnKey -> TemplateRef` para celdas con contenido custom. El
|
|
1124
|
+
* contexto trae `$implicit` (la fila), `index` y `column` (la columna), así
|
|
1125
|
+
* que un mismo template puede servir a varias columnas. */
|
|
990
1126
|
readonly cellTemplates: _angular_core.InputSignal<Record<string, TemplateRef<{
|
|
991
1127
|
$implicit: T;
|
|
992
1128
|
index: number;
|
|
1129
|
+
column?: DataTableColumn;
|
|
993
1130
|
}>> | undefined>;
|
|
994
1131
|
/** Densidad de fila — ver `DataTableDensity`. */
|
|
995
1132
|
readonly density: _angular_core.InputSignal<DataTableDensity>;
|
|
@@ -1000,6 +1137,27 @@ declare class DataTable<T = unknown> {
|
|
|
1000
1137
|
row: T;
|
|
1001
1138
|
index: number;
|
|
1002
1139
|
}>;
|
|
1140
|
+
/**
|
|
1141
|
+
* Se emite al activar (clic, Enter o Espacio) una celda de una columna
|
|
1142
|
+
* `interactive`. `index` es el de la fila dentro de las filas mostradas
|
|
1143
|
+
* (misma convención que `rowClick`). No emite `rowClick`.
|
|
1144
|
+
*/
|
|
1145
|
+
readonly cellClick: _angular_core.OutputEmitterRef<DataTableCellClick<T>>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Nombre accesible (`aria-label`) del botón de cada celda interactiva:
|
|
1148
|
+
* `(row, column, index) => string`. Sin esta función, el botón se nombra
|
|
1149
|
+
* por su contenido. Se usa solo en columnas `interactive`.
|
|
1150
|
+
*/
|
|
1151
|
+
readonly cellAriaLabel: _angular_core.InputSignal<((row: T, column: DataTableColumn, index: number) => string) | undefined>;
|
|
1152
|
+
/** Nombre accesible del contenedor con scroll horizontal (solo se aplica cuando hay overflow). */
|
|
1153
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
1154
|
+
/**
|
|
1155
|
+
* Clave (la misma que devuelve `rowKey`, o el índice sin él) de la fila
|
|
1156
|
+
* "actual" — ej. el registro que se está viendo en un selector. Esa fila
|
|
1157
|
+
* o card lleva `aria-current="true"` y la clase `--current` (fondo
|
|
1158
|
+
* `primary-soft`). `null` (default): ninguna.
|
|
1159
|
+
*/
|
|
1160
|
+
readonly currentRowKey: _angular_core.InputSignal<string | number | null>;
|
|
1003
1161
|
/**
|
|
1004
1162
|
* Paginación interna opcional — sin `pageSize`, cero cambio de
|
|
1005
1163
|
* comportamiento (el consumidor sigue paginando afuera si quiere, vía el
|
|
@@ -1014,7 +1172,16 @@ declare class DataTable<T = unknown> {
|
|
|
1014
1172
|
* portal) — pasar `[]` explícitamente desactiva el selector de tamaño
|
|
1015
1173
|
* aunque `pageSize` esté activo (paginación sin selector). */
|
|
1016
1174
|
readonly pageSizeOptions: _angular_core.InputSignal<number[]>;
|
|
1017
|
-
|
|
1175
|
+
/** Página actual (desde 1), bidireccional: `[(page)]="page"`. El consumidor
|
|
1176
|
+
* puede llevarla fuera de la tabla (ej. en la URL) y la tabla la corrige
|
|
1177
|
+
* si queda fuera de rango. `pageChange` emite en cada cambio, también los
|
|
1178
|
+
* automáticos (volver a 1 al cambiar de tamaño de página). */
|
|
1179
|
+
readonly page: _angular_core.ModelSignal<number>;
|
|
1180
|
+
/** Con `true`, un cambio de `rows` NO devuelve la página a 1: el
|
|
1181
|
+
* consumidor decide cuándo (ej. al filtrar) y la tabla solo la corrige si
|
|
1182
|
+
* queda fuera de rango. Default `false`: vuelve a 1, como siempre. */
|
|
1183
|
+
readonly keepPageOnRowsChange: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1184
|
+
/** Emite el tamaño elegido en el selector de la paginación interna. */
|
|
1018
1185
|
readonly pageSizeChange: _angular_core.OutputEmitterRef<number>;
|
|
1019
1186
|
/** Nombre de la entidad listada (ej. "beneficios", "facturas"), en
|
|
1020
1187
|
* plural — se agrega al final del texto informativo de la paginación
|
|
@@ -1022,16 +1189,27 @@ declare class DataTable<T = unknown> {
|
|
|
1022
1189
|
* números ("1–5 de 7"): la librería no impone un idioma ni un nombre
|
|
1023
1190
|
* fijo, cada consumidor decide el suyo. */
|
|
1024
1191
|
readonly itemLabel: _angular_core.InputSignal<string>;
|
|
1025
|
-
protected readonly page: _angular_core.WritableSignal<number>;
|
|
1026
1192
|
private readonly internalPageSize;
|
|
1027
1193
|
/** Tamaño de página efectivo: el que el usuario elija en el selector
|
|
1028
1194
|
* (si `pageSizeOptions` está activo), o el `pageSize` del consumidor. */
|
|
1029
1195
|
protected readonly effectivePageSize: _angular_core.Signal<number | null>;
|
|
1030
1196
|
/** Cantidad de filas/cards placeholder mientras `loading` es true — el
|
|
1031
|
-
* `
|
|
1032
|
-
* "adivina" cuántas filas reales
|
|
1033
|
-
* o 5
|
|
1197
|
+
* `skeletonRows` explícito; si no hay, el `pageSize` efectivo con
|
|
1198
|
+
* paginación activa (así el placeholder ya "adivina" cuántas filas reales
|
|
1199
|
+
* van a aparecer, sin salto de layout) o 5 sin paginación. Siempre entre 1 y
|
|
1200
|
+
* {@link DATA_TABLE_MAX_SKELETON_ROWS}: con una página de 50 filas no se
|
|
1201
|
+
* pintan 50 placeholders. */
|
|
1034
1202
|
protected readonly skeletonRowIndexes: _angular_core.Signal<number[]>;
|
|
1203
|
+
/** Las tarjetas esqueleto llevan encabezado cuando la real lo tendría. */
|
|
1204
|
+
protected readonly skeletonCardHeader: _angular_core.Signal<boolean>;
|
|
1205
|
+
/**
|
|
1206
|
+
* Ancho (%) de la barra de una celda esqueleto: no todas iguales — una
|
|
1207
|
+
* columna numérica (alineada al final) es corta, un identificador
|
|
1208
|
+
* (`mono`) mediano, una de acciones (`hideLabel`) un cuadrado chico, y el
|
|
1209
|
+
* resto alterna entre tres anchos según su posición para que la tabla no
|
|
1210
|
+
* parezca un patrón repetido.
|
|
1211
|
+
*/
|
|
1212
|
+
protected skeletonBarWidth(column: DataTableColumn, row: number, index: number): string;
|
|
1035
1213
|
protected readonly totalPages: _angular_core.Signal<number>;
|
|
1036
1214
|
/** Texto informativo del footer de paginación interna ("1–5 de 7
|
|
1037
1215
|
* beneficios") — se recalcula con cada cambio de página/tamaño/dataset,
|
|
@@ -1055,27 +1233,68 @@ declare class DataTable<T = unknown> {
|
|
|
1055
1233
|
protected toggleSort(column: DataTableColumn): void;
|
|
1056
1234
|
protected goToPage(target: number): void;
|
|
1057
1235
|
protected setPageSize(size: number | null): void;
|
|
1236
|
+
/**
|
|
1237
|
+
* Reparto de anchos activo: hay al menos una columna `grow`. Sin ella, los
|
|
1238
|
+
* anchos son los de siempre (`width`/`minWidth`/`maxWidth` tal cual).
|
|
1239
|
+
*/
|
|
1240
|
+
protected readonly weighted: _angular_core.Signal<boolean>;
|
|
1241
|
+
/** Porción (%) del espacio sobrante de cada columna `grow`, según su peso. */
|
|
1242
|
+
private readonly growShares;
|
|
1243
|
+
private growWeight;
|
|
1244
|
+
/**
|
|
1245
|
+
* `width` de la celda. En reparto de anchos: la columna `grow` toma su
|
|
1246
|
+
* porción en porcentaje (las porciones suman 100% y el navegador las escala
|
|
1247
|
+
* al espacio que dejan las demás), la de `width` conserva su ancho y la que
|
|
1248
|
+
* no trae ni `width` ni `grow` pide 1% — con `nowrap` queda en el ancho de
|
|
1249
|
+
* su contenido.
|
|
1250
|
+
*/
|
|
1251
|
+
protected widthFor(column: DataTableColumn): string | null;
|
|
1252
|
+
/**
|
|
1253
|
+
* `min-width` de la celda. En reparto de anchos, el `width` de una columna
|
|
1254
|
+
* (también de una `grow`) funciona como piso: ni las porciones en
|
|
1255
|
+
* porcentaje ni el contenido de las demás pueden comprimirla.
|
|
1256
|
+
*/
|
|
1257
|
+
protected minWidthFor(column: DataTableColumn): string | null;
|
|
1258
|
+
/**
|
|
1259
|
+
* `max-width` de la celda. En reparto de anchos, una columna que se ajusta
|
|
1260
|
+
* a su contenido y es `truncate` SIN `maxWidth` no debe heredar el techo de
|
|
1261
|
+
* 0 de `truncate` (quedaría sin ancho): se libera con `none`.
|
|
1262
|
+
*/
|
|
1263
|
+
protected maxWidthFor(column: DataTableColumn): string | null;
|
|
1058
1264
|
/** Columnas fijas del lado izquierdo/derecho, con el offset acumulado
|
|
1059
1265
|
* (medido en runtime, ver `measureStickyOffsets`) para `position: sticky`. */
|
|
1060
1266
|
protected readonly stickyLeftColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1061
1267
|
protected readonly stickyRightColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1062
1268
|
protected readonly stickyOffsets: _angular_core.WritableSignal<Map<string, number>>;
|
|
1063
1269
|
protected stickyStyle(column: DataTableColumn): Record<string, string> | null;
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1270
|
+
/**
|
|
1271
|
+
* Vista elegida, two-way: `[(view)]="view"`. Sin valor (default) manda
|
|
1272
|
+
* `defaultView`; el toggle interno la escribe. Para controlarla desde
|
|
1273
|
+
* afuera (ej. con el toggle en `kf-list-toolbar` y el estado en la URL),
|
|
1274
|
+
* enlazar `[(view)]` y ocultar el interno con `[showViewToggle]="false"`.
|
|
1275
|
+
* La vista efectivamente renderizada es `activeView()`.
|
|
1276
|
+
*/
|
|
1277
|
+
readonly view: _angular_core.ModelSignal<DataTableView | undefined>;
|
|
1278
|
+
/** Vista activa: `view` si está definida, si no `defaultView`. */
|
|
1279
|
+
readonly activeView: _angular_core.Signal<DataTableView>;
|
|
1067
1280
|
/** Primera columna de cada rol único; el resto se ignora en el encabezado. */
|
|
1068
1281
|
readonly cardMediaColumn: _angular_core.Signal<DataTableColumn | undefined>;
|
|
1069
1282
|
readonly cardTitleColumn: _angular_core.Signal<DataTableColumn | undefined>;
|
|
1070
1283
|
readonly cardStatusColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1071
1284
|
readonly cardActionColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1072
1285
|
readonly cardFieldColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1286
|
+
/** Campos a ancho completo y recortados (`cardClamp`), antes del resto. */
|
|
1287
|
+
readonly cardLeadColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1288
|
+
/** Fila inferior de datos secundarios (`cardRole: 'meta'`). */
|
|
1289
|
+
readonly cardMetaColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1073
1290
|
/**
|
|
1074
1291
|
* La card entera es clickeable solo si no tiene acciones propias: un
|
|
1075
1292
|
* `role="button"` con botones adentro es inválido y deja el foco ambiguo.
|
|
1076
1293
|
* Con columnas `action`, la interacción la manejan esos botones.
|
|
1077
1294
|
*/
|
|
1078
1295
|
readonly cardInteractive: _angular_core.Signal<boolean>;
|
|
1296
|
+
/** Hay al menos una columna `interactive` (celdas con botón propio). */
|
|
1297
|
+
protected readonly hasInteractiveColumns: _angular_core.Signal<boolean>;
|
|
1079
1298
|
/**
|
|
1080
1299
|
* Mismo criterio que `cardInteractive`, para la vista de tabla: la fila
|
|
1081
1300
|
* entera dispara `rowClick` solo si no hay una columna `action` que ya
|
|
@@ -1087,8 +1306,32 @@ declare class DataTable<T = unknown> {
|
|
|
1087
1306
|
readonly rowInteractive: _angular_core.Signal<boolean>;
|
|
1088
1307
|
setView(next: DataTableView): void;
|
|
1089
1308
|
trackRow(row: T, index: number): string | number;
|
|
1309
|
+
/** Alineada al final: `align: 'end'` o el histórico `right: true`. */
|
|
1310
|
+
protected isEndAligned(column: DataTableColumn): boolean;
|
|
1311
|
+
/** `title` de una celda `truncate`: el valor completo como texto. */
|
|
1312
|
+
protected truncateTitle(row: T, column: DataTableColumn): string | null;
|
|
1090
1313
|
cellValue(row: T, column: DataTableColumn): string;
|
|
1091
|
-
|
|
1314
|
+
protected isCurrentRow(row: T, index: number): boolean;
|
|
1315
|
+
/**
|
|
1316
|
+
* Espacio activa la fila/card igual que Enter, como un botón. Solo si el
|
|
1317
|
+
* foco está en la fila misma (no en un control dentro de ella): ahí
|
|
1318
|
+
* `preventDefault` evita el scroll de página; en cualquier otro caso
|
|
1319
|
+
* Espacio conserva su comportamiento nativo.
|
|
1320
|
+
*/
|
|
1321
|
+
protected onRowSpace(event: Event, row: T, index: number): void;
|
|
1322
|
+
/**
|
|
1323
|
+
* Emite `rowClick` salvo que el evento nazca dentro de un control
|
|
1324
|
+
* interactivo de la celda (enlace, botón, campo…): ese control ya resuelve
|
|
1325
|
+
* su propia acción. Así una celda con un `<a href>` real (clic derecho →
|
|
1326
|
+
* "abrir en nueva pestaña", Ctrl/Cmd+clic) no navega dos veces. El parámetro
|
|
1327
|
+
* `event` es opcional para no romper llamadas programáticas existentes.
|
|
1328
|
+
*/
|
|
1329
|
+
onRowClick(row: T, index: number, event?: Event): void;
|
|
1330
|
+
/** Activación de una celda interactiva (clic, o Enter/Espacio sobre su botón). */
|
|
1331
|
+
protected onCellClick(row: T, column: DataTableColumn, index: number): void;
|
|
1332
|
+
/** `aria-label` del botón de una celda interactiva, o `null` si lo da su contenido. */
|
|
1333
|
+
protected cellLabel(row: T, column: DataTableColumn, index: number): string | null;
|
|
1334
|
+
private originatesInInteractiveControl;
|
|
1092
1335
|
/**
|
|
1093
1336
|
* Ancho real de cada columna `sticky` — se mide después de cada render
|
|
1094
1337
|
* porque el ancho de una columna depende de su contenido, no hay forma
|
|
@@ -1099,7 +1342,185 @@ declare class DataTable<T = unknown> {
|
|
|
1099
1342
|
*/
|
|
1100
1343
|
protected measureStickyOffsets(): void;
|
|
1101
1344
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataTable<any>, never>;
|
|
1102
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTable<any>, "kf-data-table", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "rowKey": { "alias": "rowKey"; "required": false; "isSignal": true; }; "flush": { "alias": "flush"; "required": false; "isSignal": true; }; "cardable": { "alias": "cardable"; "required": false; "isSignal": true; }; "defaultView": { "alias": "defaultView"; "required": false; "isSignal": true; }; "render": { "alias": "render"; "required": false; "isSignal": true; }; "cellTemplates": { "alias": "cellTemplates"; "required": false; "isSignal": true; }; "density": { "alias": "density"; "required": false; "isSignal": true; }; "rowClickable": { "alias": "rowClickable"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "itemLabel": { "alias": "itemLabel"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; }, { "rowClick": "rowClick"; "
|
|
1345
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTable<any>, "kf-data-table", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "skeletonRows": { "alias": "skeletonRows"; "required": false; "isSignal": true; }; "rowKey": { "alias": "rowKey"; "required": false; "isSignal": true; }; "flush": { "alias": "flush"; "required": false; "isSignal": true; }; "cardable": { "alias": "cardable"; "required": false; "isSignal": true; }; "defaultView": { "alias": "defaultView"; "required": false; "isSignal": true; }; "showViewToggle": { "alias": "showViewToggle"; "required": false; "isSignal": true; }; "cardMinWidth": { "alias": "cardMinWidth"; "required": false; "isSignal": true; }; "render": { "alias": "render"; "required": false; "isSignal": true; }; "cellTemplates": { "alias": "cellTemplates"; "required": false; "isSignal": true; }; "density": { "alias": "density"; "required": false; "isSignal": true; }; "rowClickable": { "alias": "rowClickable"; "required": false; "isSignal": true; }; "cellAriaLabel": { "alias": "cellAriaLabel"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "currentRowKey": { "alias": "currentRowKey"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "page": { "alias": "page"; "required": false; "isSignal": true; }; "keepPageOnRowsChange": { "alias": "keepPageOnRowsChange"; "required": false; "isSignal": true; }; "itemLabel": { "alias": "itemLabel"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "view": { "alias": "view"; "required": false; "isSignal": true; }; }, { "rowClick": "rowClick"; "cellClick": "cellClick"; "page": "pageChange"; "pageSizeChange": "pageSizeChange"; "sortChange": "sortChange"; "view": "viewChange"; }, never, ["[empty]", "[footer]"], true, never>;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/** Forma de contenido que reproduce el preset. */
|
|
1349
|
+
type SkeletonPresetVariant = 'kpi-grid' | 'card-grid' | 'form' | 'list' | 'table' | 'timeline' | 'detail-header';
|
|
1350
|
+
/** Tope de elementos: un `count` mayor se acota, no tiene sentido pintar más. */
|
|
1351
|
+
declare const SKELETON_PRESET_MAX_COUNT = 12;
|
|
1352
|
+
/**
|
|
1353
|
+
* Esqueletos listos para usar que reproducen la FORMA del contenido real, para
|
|
1354
|
+
* que al llegar los datos nada se mueva. Cada variante se arma con la misma
|
|
1355
|
+
* geometría que su equivalente cargado (mismos cascarones, alturas, radios y
|
|
1356
|
+
* gaps, todo por tokens):
|
|
1357
|
+
*
|
|
1358
|
+
* | `variant` | Equivalente cargado | `count` | `columns` |
|
|
1359
|
+
* | ---------------- | ---------------------------- | -------------- | ------------------ |
|
|
1360
|
+
* | `kpi-grid` | `kf-stat-card` | tarjetas (4) | columnas de la grilla |
|
|
1361
|
+
* | `card-grid` | `kf-card` | tarjetas (6) | columnas de la grilla |
|
|
1362
|
+
* | `form` | `kf-input` con label | campos (4) | `1` o `2` |
|
|
1363
|
+
* | `list` | `kf-document-row` | filas (4) | — |
|
|
1364
|
+
* | `table` | `kf-data-table` | filas (5) | columnas (4) |
|
|
1365
|
+
* | `timeline` | `kf-milestone-timeline` | etapas (4) | — |
|
|
1366
|
+
* | `detail-header` | `kf-page-header` con ícono | — | — |
|
|
1367
|
+
*
|
|
1368
|
+
* Sin `columns`, las grillas (`kpi-grid`, `card-grid`) se reparten solas con un
|
|
1369
|
+
* ancho mínimo por tarjeta. `count` se acota a 12.
|
|
1370
|
+
*
|
|
1371
|
+
* El preset es decorativo (`aria-hidden` por dentro) y marca su contenedor con
|
|
1372
|
+
* `aria-busy="true"`. Con `label` agrega un texto visualmente oculto con
|
|
1373
|
+
* `role="status"` que lo anuncia a lectores de pantalla; dentro de
|
|
1374
|
+
* `kf-content-state` no hace falta (ya lo anuncia él).
|
|
1375
|
+
*
|
|
1376
|
+
* <kf-skeleton-preset variant="kpi-grid" [count]="4" />
|
|
1377
|
+
* <kf-skeleton-preset variant="form" [count]="3" [columns]="2" label="Cargando formulario" />
|
|
1378
|
+
* <kf-content-state [state]="state()" loadingPreset="table">…</kf-content-state>
|
|
1379
|
+
*/
|
|
1380
|
+
declare class SkeletonPreset {
|
|
1381
|
+
readonly variant: _angular_core.InputSignal<SkeletonPresetVariant>;
|
|
1382
|
+
/** Cantidad de elementos. Sin valor, el de la variante. Máximo 12. */
|
|
1383
|
+
readonly count: _angular_core.InputSignal<number | undefined>;
|
|
1384
|
+
/** Columnas: de la grilla (`kpi-grid`, `card-grid`), del formulario (`1`|`2`) o de la tabla. */
|
|
1385
|
+
readonly columns: _angular_core.InputSignal<number | undefined>;
|
|
1386
|
+
/** Texto accesible (visualmente oculto, `role="status"`). Vacío, no se emite. */
|
|
1387
|
+
readonly label: _angular_core.InputSignal<string>;
|
|
1388
|
+
protected readonly total: _angular_core.Signal<number>;
|
|
1389
|
+
protected readonly items: _angular_core.Signal<number[]>;
|
|
1390
|
+
/** Columnas de la tabla sintética (encabezados en blanco: lo real aún no llegó). */
|
|
1391
|
+
protected readonly tableColumns: _angular_core.Signal<DataTableColumn[]>;
|
|
1392
|
+
protected readonly formColumns: _angular_core.Signal<2 | 1>;
|
|
1393
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonPreset, never>;
|
|
1394
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonPreset, "kf-skeleton-preset", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "count": { "alias": "count"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
/** En qué estado está la sección. */
|
|
1398
|
+
type ContentStateKind = 'ready' | 'loading' | 'empty' | 'error';
|
|
1399
|
+
/** Cómo se dibuja `loading`. Default `'skeleton'`. */
|
|
1400
|
+
type ContentStateLoad = 'skeleton' | 'spinner';
|
|
1401
|
+
/**
|
|
1402
|
+
* Marca el `ng-template` que reemplaza el esqueleto genérico de
|
|
1403
|
+
* `kf-content-state` mientras carga (`state="loading"`, `load="skeleton"`).
|
|
1404
|
+
*
|
|
1405
|
+
* <kf-content-state [state]="state()">
|
|
1406
|
+
* <ng-template kfContentStateLoading><kf-skeleton-preset variant="kpi-grid" /></ng-template>
|
|
1407
|
+
* …
|
|
1408
|
+
* </kf-content-state>
|
|
1409
|
+
*/
|
|
1410
|
+
declare class ContentStateLoading {
|
|
1411
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentStateLoading, never>;
|
|
1412
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ContentStateLoading, "ng-template[kfContentStateLoading]", never, {}, {}, never, never, true, never>;
|
|
1413
|
+
}
|
|
1414
|
+
/**
|
|
1415
|
+
* Wrapper de los cuatro estados que toda sección tiene: cargando, con datos,
|
|
1416
|
+
* vacía y con error. Un componente en vez de tres `@if` sueltos, porque es
|
|
1417
|
+
* siempre el mismo slot el que va rotando entre los cuatro.
|
|
1418
|
+
*
|
|
1419
|
+
* Con `state="ready"` proyecta el contenido real y desaparece; en los otros
|
|
1420
|
+
* tres dibuja el placeholder correspondiente y el contenido no se instancia.
|
|
1421
|
+
* No inventa visuales propios: `loading` usa `kf-skeleton` (o `kf-spinner` con
|
|
1422
|
+
* `load="spinner"`), y `empty`/`error` usan `kf-empty-state`.
|
|
1423
|
+
*
|
|
1424
|
+
* Las acciones (reintentar, crear) van en el slot `actions` — se ignoran
|
|
1425
|
+
* mientras carga, porque no hay nada que reintentar todavía.
|
|
1426
|
+
*
|
|
1427
|
+
* <kf-content-state [state]="state()" title="No pudimos cargar tus vehículos"
|
|
1428
|
+
* subtitle="Revisá tu conexión e intentá de nuevo.">
|
|
1429
|
+
* <kf-button actions (click)="retry()">Reintentar</kf-button>
|
|
1430
|
+
* <kf-data-table [columns]="cols" [rows]="rows()" />
|
|
1431
|
+
* </kf-content-state>
|
|
1432
|
+
*
|
|
1433
|
+
* Esqueleto de carga: por defecto son tres líneas genéricas. Para que la
|
|
1434
|
+
* carga se parezca a lo que va a aparecer, hay tres vías (de la más corta a la
|
|
1435
|
+
* más libre): `loadingPreset` (una variante de `kf-skeleton-preset`), el input
|
|
1436
|
+
* `loadingTemplate` (un `TemplateRef`) o un `ng-template` marcado con
|
|
1437
|
+
* `kfContentStateLoading` dentro del contenido. Si hay más de una, gana la
|
|
1438
|
+
* plantilla proyectada, luego `loadingTemplate` y por último `loadingPreset`.
|
|
1439
|
+
*
|
|
1440
|
+
* <kf-content-state [state]="state()" loadingPreset="kpi-grid">…</kf-content-state>
|
|
1441
|
+
*
|
|
1442
|
+
* Accesibilidad: en modo skeleton el contenedor lleva `aria-busy="true"` y un
|
|
1443
|
+
* texto visualmente oculto con `role="status"` (`loadingLabel`, "Cargando…" por
|
|
1444
|
+
* defecto) que anuncia el estado una vez. Con `load="spinner"` el texto es el
|
|
1445
|
+
* del propio `kf-spinner`. El contenedor reserva un ancho mínimo, así que el
|
|
1446
|
+
* esqueleto no colapsa a 0 dentro de un padre que se ajusta a su contenido.
|
|
1447
|
+
*/
|
|
1448
|
+
declare class ContentState {
|
|
1449
|
+
readonly state: _angular_core.InputSignal<ContentStateKind>;
|
|
1450
|
+
/** Forma del estado de carga: silueta (default) o spinner. */
|
|
1451
|
+
readonly load: _angular_core.InputSignal<ContentStateLoad>;
|
|
1452
|
+
/** Título de `empty`/`error`. Ignorado mientras carga. */
|
|
1453
|
+
readonly title: _angular_core.InputSignal<string>;
|
|
1454
|
+
readonly subtitle: _angular_core.InputSignal<string>;
|
|
1455
|
+
/** Texto de carga: al lado del spinner con `load="spinner"` y, en modo skeleton,
|
|
1456
|
+
* texto visualmente oculto con `role="status"` para lectores de pantalla. */
|
|
1457
|
+
readonly loadingLabel: _angular_core.InputSignal<string>;
|
|
1458
|
+
/** Plantilla propia del esqueleto (reemplaza las tres líneas genéricas). */
|
|
1459
|
+
readonly loadingTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
|
|
1460
|
+
/** Variante de `kf-skeleton-preset` como esqueleto de carga. */
|
|
1461
|
+
readonly loadingPreset: _angular_core.InputSignal<SkeletonPresetVariant | null>;
|
|
1462
|
+
/** `ng-template[kfContentStateLoading]` proyectado como contenido. */
|
|
1463
|
+
protected readonly projectedLoading: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
1464
|
+
protected readonly customLoading: _angular_core.Signal<TemplateRef<any> | null>;
|
|
1465
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentState, never>;
|
|
1466
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContentState, "kf-content-state", never, { "state": { "alias": "state"; "required": true; "isSignal": true; }; "load": { "alias": "load"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; "loadingLabel": { "alias": "loadingLabel"; "required": false; "isSignal": true; }; "loadingTemplate": { "alias": "loadingTemplate"; "required": false; "isSignal": true; }; "loadingPreset": { "alias": "loadingPreset"; "required": false; "isSignal": true; }; }, {}, ["projectedLoading"], ["*", "[actions]"], true, never>;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
type ContentViewerType = 'image' | 'video' | 'pdf';
|
|
1470
|
+
/**
|
|
1471
|
+
* Visor a pantalla completa para ampliar una pieza de contenido: imagen,
|
|
1472
|
+
* video o PDF (`type="pdf"`, renderizado por el visor nativo del navegador).
|
|
1473
|
+
* Mismo mecanismo que `kf-modal` (el `<dialog>` nativo resuelve backdrop,
|
|
1474
|
+
* atrapado de foco, top-layer y `Escape`), pero sin panel/título/footer:
|
|
1475
|
+
* el contenido ocupa toda la pantalla sobre un backdrop oscuro.
|
|
1476
|
+
*
|
|
1477
|
+
* `src` acepta lo que venga del backend sin que el consumidor tenga que
|
|
1478
|
+
* normalizarlo primero: una URL (`http(s)://`), un data URI ya armado
|
|
1479
|
+
* (`data:...`), o base64 crudo (se le antepone el prefijo `data:` según
|
|
1480
|
+
* `type`, asumiendo JPEG para imagen, MP4 para video y PDF para pdf). Un PDF
|
|
1481
|
+
* solo acepta contenido local (`blob:`, data URI o base64), nunca una URL remota.
|
|
1482
|
+
*
|
|
1483
|
+
* Lo proyectado con el atributo `actions` (p. ej. un botón de descarga) va en
|
|
1484
|
+
* la barra superior, junto al título.
|
|
1485
|
+
*
|
|
1486
|
+
* <kf-content-viewer [(open)]="viewerOpen" [src]="viewerSrc()" alt="Foto del vehículo" />
|
|
1487
|
+
* <kf-content-viewer [(open)]="viewerOpen" type="video" [src]="viewerSrc()" title="Inspección" />
|
|
1488
|
+
* <kf-content-viewer [(open)]="viewerOpen" type="pdf" [src]="blobUrl()" title="Contrato">
|
|
1489
|
+
* <kf-button actions variant="surface" icon="download" (click)="save()">Descargar</kf-button>
|
|
1490
|
+
* </kf-content-viewer>
|
|
1491
|
+
*/
|
|
1492
|
+
declare class ContentViewer {
|
|
1493
|
+
readonly type: _angular_core.InputSignal<ContentViewerType>;
|
|
1494
|
+
/** URL, data URI, o base64 crudo — ver JSDoc de la clase. */
|
|
1495
|
+
readonly src: _angular_core.InputSignal<string | null>;
|
|
1496
|
+
/** Texto alternativo cuando `type="image"`. */
|
|
1497
|
+
readonly alt: _angular_core.InputSignal<string>;
|
|
1498
|
+
readonly title: _angular_core.InputSignal<string>;
|
|
1499
|
+
/** Visibilidad, two-way: `[(open)]="viewerOpen"`. */
|
|
1500
|
+
readonly open: _angular_core.ModelSignal<boolean>;
|
|
1501
|
+
/** Permite cerrar con el botón, `Escape` o clic en el backdrop. */
|
|
1502
|
+
readonly dismissible: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1503
|
+
protected readonly titleId: string;
|
|
1504
|
+
/** Detecta si `src` ya es una URL o un data URI armado; si no, asume
|
|
1505
|
+
* base64 crudo y le antepone el prefijo `data:` correspondiente a `type`
|
|
1506
|
+
* — el backend a veces manda una cosa, a veces la otra. */
|
|
1507
|
+
protected readonly resolvedSrc: _angular_core.Signal<string | null>;
|
|
1508
|
+
protected readonly pdfSrc: _angular_core.Signal<SafeResourceUrl | null>;
|
|
1509
|
+
protected readonly fallbackLabel: _angular_core.Signal<string>;
|
|
1510
|
+
private readonly dialog;
|
|
1511
|
+
private readonly document;
|
|
1512
|
+
private readonly sanitizer;
|
|
1513
|
+
constructor();
|
|
1514
|
+
/** `Escape` dispara `cancel`; cancelarlo lo deja abierto. */
|
|
1515
|
+
protected onCancel(event: Event): void;
|
|
1516
|
+
/**
|
|
1517
|
+
* Clic en el backdrop. Un clic en la zona del backdrop tiene como `target` al
|
|
1518
|
+
* propio `<dialog>` (el contenido vive en el panel de adentro), así que basta
|
|
1519
|
+
* comparar contra él — no hace falta cortar la propagación en el panel.
|
|
1520
|
+
*/
|
|
1521
|
+
protected onHostClick(event: MouseEvent): void;
|
|
1522
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentViewer, never>;
|
|
1523
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContentViewer, "kf-content-viewer", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "src": { "alias": "src"; "required": false; "isSignal": true; }; "alt": { "alias": "alt"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["[actions]"], true, never>;
|
|
1103
1524
|
}
|
|
1104
1525
|
|
|
1105
1526
|
/**
|
|
@@ -1145,6 +1566,14 @@ type DocumentRowTone = 'neutral' | 'ok' | 'warn' | 'error' | 'info';
|
|
|
1145
1566
|
* título, metadata y la acción de descarga al final. Sin `href` rinde
|
|
1146
1567
|
* `pendingLabel` en vez de un link roto. El contenido proyectado cae entre
|
|
1147
1568
|
* la metadata y la acción, como slot para un `kf-badge` de estado.
|
|
1569
|
+
*
|
|
1570
|
+
* `loading` (default `false`): dibuja el esqueleto de la fila — chip, título,
|
|
1571
|
+
* metadata y acción como bloques del alto real de cada texto — con el mismo
|
|
1572
|
+
* cascarón, así que al llegar los datos no hay salto de layout. Pasa los
|
|
1573
|
+
* mismos inputs que usarás cargada (`meta` incluido, para reservar su línea).
|
|
1574
|
+
* Marca el host con `aria-busy="true"` y oculta el contenido proyectado.
|
|
1575
|
+
*
|
|
1576
|
+
* <kf-document-row title="Factura" meta="PDF · 120 KB" [loading]="isLoading()" />
|
|
1148
1577
|
*/
|
|
1149
1578
|
declare class DocumentRow {
|
|
1150
1579
|
readonly icon: _angular_core.InputSignal<IconName>;
|
|
@@ -1160,11 +1589,20 @@ declare class DocumentRow {
|
|
|
1160
1589
|
readonly downloadLabel: _angular_core.InputSignal<string>;
|
|
1161
1590
|
/** Qué se dice cuando no hay `href`. */
|
|
1162
1591
|
readonly pendingLabel: _angular_core.InputSignal<string>;
|
|
1592
|
+
/** Dibuja el esqueleto en lugar del contenido, conservando las dimensiones. */
|
|
1593
|
+
readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1163
1594
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DocumentRow, never>;
|
|
1164
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DocumentRow, "kf-document-row", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "meta": { "alias": "meta"; "required": false; "isSignal": true; }; "href": { "alias": "href"; "required": false; "isSignal": true; }; "downloadLabel": { "alias": "downloadLabel"; "required": false; "isSignal": true; }; "pendingLabel": { "alias": "pendingLabel"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1595
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DocumentRow, "kf-document-row", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "meta": { "alias": "meta"; "required": false; "isSignal": true; }; "href": { "alias": "href"; "required": false; "isSignal": true; }; "downloadLabel": { "alias": "downloadLabel"; "required": false; "isSignal": true; }; "pendingLabel": { "alias": "pendingLabel"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, {}, never, ["*", "*"], true, never>;
|
|
1165
1596
|
}
|
|
1166
1597
|
|
|
1167
|
-
|
|
1598
|
+
/** Borde de anclaje del panel. `bottom` es una hoja inferior (bottom sheet). */
|
|
1599
|
+
type DrawerSide = 'left' | 'right' | 'bottom';
|
|
1600
|
+
/**
|
|
1601
|
+
* Rol del panel. `navigation` (default) es el menú lateral histórico;
|
|
1602
|
+
* `dialog` es un panel modal de tarea (filtros, resumen) con
|
|
1603
|
+
* `aria-modal="true"`.
|
|
1604
|
+
*/
|
|
1605
|
+
type DrawerRole = 'navigation' | 'dialog';
|
|
1168
1606
|
/**
|
|
1169
1607
|
* Panel lateral genérico, agnóstico de contenido — no sabe qué es navegación
|
|
1170
1608
|
* ni qué es sesión, solo da tres lugares para proyectar contenido
|
|
@@ -1197,28 +1635,98 @@ type DrawerSide = 'left' | 'right';
|
|
|
1197
1635
|
* <a href="/">Home</a>
|
|
1198
1636
|
* <a href="/vehiculos">Vehículos</a>
|
|
1199
1637
|
* </kf-drawer>
|
|
1638
|
+
*
|
|
1639
|
+
* ## Panel de tarea (`role="dialog"`)
|
|
1640
|
+
*
|
|
1641
|
+
* Para un panel modal que no es navegación (filtros de un listado, resumen
|
|
1642
|
+
* de un registro): `role="dialog"` expone `role="dialog"` + `aria-modal`,
|
|
1643
|
+
* `title` dibuja una barra clara con el título (que nombra el diálogo vía
|
|
1644
|
+
* `aria-labelledby`) y un botón de cierre con `closeLabel`. En pantallas de
|
|
1645
|
+
* hasta 640px el panel ocupa el ancho completo; arriba de eso mide
|
|
1646
|
+
* `--kf-drawer-width` (default 480px). El pie (`[kf-drawer-footer]`) queda
|
|
1647
|
+
* fijo abajo mientras el cuerpo hace scroll.
|
|
1648
|
+
*
|
|
1649
|
+
* <kf-drawer [(open)]="filtersOpen" role="dialog" side="right"
|
|
1650
|
+
* title="Filtros" closeLabel="Cerrar filtros">
|
|
1651
|
+
* <kf-option-list label="Estado" ... />
|
|
1652
|
+
* <div kf-drawer-footer> ...Limpiar / Ver 12 resultados... </div>
|
|
1653
|
+
* </kf-drawer>
|
|
1654
|
+
*
|
|
1655
|
+
* `side="bottom"` lo convierte en hoja inferior (grip, esquinas superiores
|
|
1656
|
+
* redondeadas, alto máximo 80vh) — pensado para un resumen en mobile.
|
|
1657
|
+
*
|
|
1658
|
+
* Escape cierra el panel salvo que un control interno ya haya consumido la
|
|
1659
|
+
* tecla (`event.defaultPrevented`): un `kf-select`, `kf-multi-select` o
|
|
1660
|
+
* `kf-dropdown` abierto dentro del drawer cierra primero su propio panel y
|
|
1661
|
+
* un segundo Escape cierra el drawer.
|
|
1662
|
+
*
|
|
1663
|
+
* Nombres por defecto: con `role="navigation"` el panel se llama "Menú" y
|
|
1664
|
+
* el cierre "Cerrar menú" (comportamiento histórico). Con `role="dialog"`
|
|
1665
|
+
* los defaults son neutros ("Diálogo" / "Cerrar") y en modo desarrollo se
|
|
1666
|
+
* avisa por consola si no hay `title` ni `ariaLabel`: un diálogo sin nombre
|
|
1667
|
+
* propio no le dice nada al lector de pantalla.
|
|
1668
|
+
*
|
|
1669
|
+
* ## Selectores y otros paneles flotantes dentro del drawer
|
|
1670
|
+
*
|
|
1671
|
+
* `kf-select`, `kf-multi-select` y `kf-dropdown` funcionan
|
|
1672
|
+
* dentro de un drawer (incluido el pie `[kf-drawer-footer]`): sus paneles
|
|
1673
|
+
* quedan por encima del drawer, se abren hacia arriba si abajo no hay lugar
|
|
1674
|
+
* y no se cortan con el borde del panel ni con el scroll del cuerpo. Con
|
|
1675
|
+
* `role="dialog"` el contenedor de overlays de CDK se reubica dentro del
|
|
1676
|
+
* panel mientras está abierto: el listbox queda dentro del diálogo
|
|
1677
|
+
* `aria-modal`, no fuera de él, y el atrapado de foco lo incluye. Al cerrar
|
|
1678
|
+
* el drawer vuelve a `<body>`. Escape cierra primero el panel flotante
|
|
1679
|
+
* (devolviendo el foco a su disparador) y el siguiente cierra el drawer.
|
|
1680
|
+
*
|
|
1681
|
+
* <kf-drawer [(open)]="open" role="dialog" side="right" title="Unidad VIN-1003">
|
|
1682
|
+
* ...
|
|
1683
|
+
* <div kf-drawer-footer>
|
|
1684
|
+
* <kf-select label="Saltar a otra unidad" width="full"
|
|
1685
|
+
* [options]="units" [value]="unit()" (valueChange)="unit.set($event)" />
|
|
1686
|
+
* </div>
|
|
1687
|
+
* </kf-drawer>
|
|
1688
|
+
*
|
|
1689
|
+
* Al cerrar, el foco vuelve al elemento que lo tenía al abrir solo si sigue
|
|
1690
|
+
* en el documento (`isConnected`); si fue desmontado mientras el drawer
|
|
1691
|
+
* estaba abierto, no se fuerza ningún destino.
|
|
1200
1692
|
*/
|
|
1201
1693
|
declare class Drawer {
|
|
1202
1694
|
/** Visibilidad del panel, two-way: `[(open)]="menuOpen"`. */
|
|
1203
1695
|
readonly open: _angular_core.ModelSignal<boolean>;
|
|
1204
1696
|
/** Borde de anclaje del panel. `left` (default) es la convención dominante
|
|
1205
1697
|
* (Material/iOS/Android): el botón que abre el drawer y el propio panel
|
|
1206
|
-
* quedan del mismo lado. */
|
|
1698
|
+
* quedan del mismo lado. `bottom` lo convierte en hoja inferior. */
|
|
1207
1699
|
readonly side: _angular_core.InputSignal<DrawerSide>;
|
|
1208
|
-
/** `
|
|
1209
|
-
|
|
1210
|
-
|
|
1700
|
+
/** `navigation` (default, menú) o `dialog` (panel modal de tarea). Ver JSDoc de la clase. */
|
|
1701
|
+
readonly role: _angular_core.InputSignal<DrawerRole>;
|
|
1702
|
+
/** `aria-label` del panel — describe su propósito para lectores de
|
|
1703
|
+
* pantalla (ej. "Menú de navegación"). Ignorado cuando hay `title`, que
|
|
1704
|
+
* nombra el panel con su texto visible. Default: "Menú" (`navigation`) o
|
|
1705
|
+
* "Diálogo" (`dialog`). */
|
|
1706
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
1707
|
+
/** Título visible en una barra clara arriba del panel, con botón de cierre. Sin él no hay barra (comportamiento histórico). */
|
|
1708
|
+
readonly title: _angular_core.InputSignal<string | undefined>;
|
|
1709
|
+
/** Nombre accesible del botón de cierre de la barra de título y del
|
|
1710
|
+
* overlay. Default: "Cerrar menú" (`navigation`) o "Cerrar" (`dialog`). */
|
|
1711
|
+
readonly closeLabel: _angular_core.InputSignal<string | undefined>;
|
|
1712
|
+
/** `ariaLabel` o, sin él, el default según el rol. */
|
|
1713
|
+
protected readonly resolvedAriaLabel: _angular_core.Signal<string>;
|
|
1714
|
+
/** `closeLabel` o, sin él, el default según el rol. */
|
|
1715
|
+
protected readonly resolvedCloseLabel: _angular_core.Signal<string>;
|
|
1716
|
+
protected readonly titleId: string;
|
|
1211
1717
|
private readonly panelRef;
|
|
1212
1718
|
private readonly focusTrapFactory;
|
|
1213
1719
|
private readonly document;
|
|
1720
|
+
private readonly overlayContainer;
|
|
1721
|
+
private registeredPanel;
|
|
1214
1722
|
private focusTrap;
|
|
1215
1723
|
private lastFocusedElement;
|
|
1216
1724
|
constructor();
|
|
1217
1725
|
/** Cierra el drawer con Escape — mismo patrón que `Dropdown`/`Modal`. */
|
|
1218
|
-
protected onEscape(): void;
|
|
1726
|
+
protected onEscape(event: Event): void;
|
|
1219
1727
|
private getOrCreateFocusTrap;
|
|
1220
1728
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Drawer, never>;
|
|
1221
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Drawer, "kf-drawer", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "side": { "alias": "side"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["[kf-drawer-header]", "*", "[kf-drawer-footer]"], true, never>;
|
|
1729
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Drawer, "kf-drawer", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "side": { "alias": "side"; "required": false; "isSignal": true; }; "role": { "alias": "role"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "closeLabel": { "alias": "closeLabel"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["[kf-drawer-header]", "*", "[kf-drawer-footer]"], true, never>;
|
|
1222
1730
|
}
|
|
1223
1731
|
|
|
1224
1732
|
/**
|
|
@@ -1266,9 +1774,12 @@ declare class Dropdown {
|
|
|
1266
1774
|
* Respaldo de `overlayRef.keydownEvents()`: ese observable del CDK solo
|
|
1267
1775
|
* ve teclas con el foco DENTRO del panel. Si el foco queda en el botón
|
|
1268
1776
|
* disparador (caso común), `keydownEvents()` nunca dispara — este
|
|
1269
|
-
* listener a nivel de documento cubre ese caso.
|
|
1777
|
+
* listener a nivel de documento cubre ese caso. Va en fase de captura
|
|
1778
|
+
* (ver `listenEscapeCapture`) y consume la tecla solo si había un menú
|
|
1779
|
+
* abierto, así un `kf-drawer`/`kf-modal` contenedor no se cierra con el
|
|
1780
|
+
* mismo Escape. Devuelve si cerró algo.
|
|
1270
1781
|
*/
|
|
1271
|
-
onDocumentEscape():
|
|
1782
|
+
onDocumentEscape(): boolean;
|
|
1272
1783
|
private attach;
|
|
1273
1784
|
/**
|
|
1274
1785
|
* El trigger real (el `anchor`, o el propio host si no se pasó ninguno —
|
|
@@ -1334,6 +1845,8 @@ declare class DropdownPanel {
|
|
|
1334
1845
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DropdownPanel, "kf-dropdown-panel", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1335
1846
|
}
|
|
1336
1847
|
|
|
1848
|
+
/** Tono del estado. `warn`/`info` solo cambian el chip del ícono. */
|
|
1849
|
+
type EmptyStateTone = 'neutral' | 'error' | 'warn' | 'info';
|
|
1337
1850
|
/**
|
|
1338
1851
|
* Placeholder para una sección sin contenido. Dos tonos, con anatomía
|
|
1339
1852
|
* distinta (páginas 27-28 del design system, que los trata como piezas
|
|
@@ -1353,13 +1866,45 @@ declare class DropdownPanel {
|
|
|
1353
1866
|
* No pudimos cargar tus vehículos
|
|
1354
1867
|
* <kf-button (click)="retry()">Reintentar</kf-button>
|
|
1355
1868
|
* </kf-empty-state>
|
|
1869
|
+
*
|
|
1870
|
+
* ## Variante `card`
|
|
1871
|
+
* Tarjeta centrada (fondo blanco, borde, sombra, ancho máximo 480px) para
|
|
1872
|
+
* un estado que REEMPLAZA a un contenido grande — ej. un iframe que no
|
|
1873
|
+
* cargó o un documento que aún no existe. Ícono en un círculo tonal de
|
|
1874
|
+
* 56px según `tone` (`warn`, `info`, `error` o `neutral`), `title` como
|
|
1875
|
+
* título, el contenido proyectado como texto (puede incluir una lista de
|
|
1876
|
+
* pasos) y `[kf-empty-state-actions]` para los botones. Los roles
|
|
1877
|
+
* (`role="alert"` para un error) los pone el consumidor en el host: no
|
|
1878
|
+
* todo estado de esta forma debe interrumpir al lector de pantalla.
|
|
1879
|
+
*
|
|
1880
|
+
* <kf-empty-state variant="card" tone="warn" icon="alert-triangle"
|
|
1881
|
+
* title="No pudimos cargar la propuesta" role="alert">
|
|
1882
|
+
* <p>Este contenido solo está disponible dentro de la red de la empresa.</p>
|
|
1883
|
+
* <ol>…pasos…</ol>
|
|
1884
|
+
* <div kf-empty-state-actions>
|
|
1885
|
+
* <kf-button (click)="retry()">Reintentar</kf-button>
|
|
1886
|
+
* </div>
|
|
1887
|
+
* </kf-empty-state>
|
|
1888
|
+
*
|
|
1889
|
+
* `[kf-empty-state-footer]` va DESPUÉS de las acciones, para pistas y
|
|
1890
|
+
* metadatos debajo de los botones ("¿Ya estás conectado? …", "Intento 2 ·
|
|
1891
|
+
* 10:42"). Vacío, no ocupa lugar.
|
|
1892
|
+
*
|
|
1893
|
+
* `title` se dibuja como texto destacado, no como encabezado (`<h*>`): el
|
|
1894
|
+
* nivel de encabezado depende de la página que lo contiene, y un estado
|
|
1895
|
+
* vacío no debe alterar su estructura.
|
|
1356
1896
|
*/
|
|
1357
1897
|
declare class EmptyState {
|
|
1358
1898
|
readonly icon: _angular_core.InputSignal<IconName | undefined>;
|
|
1359
|
-
/** `neutral` (default): cero resultados. `error`: fallo real de carga. */
|
|
1360
|
-
readonly tone: _angular_core.InputSignal<
|
|
1899
|
+
/** `neutral` (default): cero resultados. `error`: fallo real de carga. `warn`/`info`: tiñen el chip del ícono. */
|
|
1900
|
+
readonly tone: _angular_core.InputSignal<EmptyStateTone>;
|
|
1901
|
+
/** `inline` (default, histórico) o `card` (tarjeta centrada). Ver JSDoc de la clase. */
|
|
1902
|
+
readonly variant: _angular_core.InputSignal<"card" | "inline">;
|
|
1903
|
+
/** Título destacado sobre el contenido. Opcional en ambas variantes. */
|
|
1904
|
+
readonly title: _angular_core.InputSignal<string | undefined>;
|
|
1905
|
+
protected readonly iconSize: _angular_core.Signal<IconSize>;
|
|
1361
1906
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EmptyState, never>;
|
|
1362
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EmptyState, "kf-empty-state", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1907
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EmptyState, "kf-empty-state", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; }, {}, never, ["*", "[kf-empty-state-actions]", "[kf-empty-state-footer]"], true, never>;
|
|
1363
1908
|
}
|
|
1364
1909
|
|
|
1365
1910
|
/** Color del marcador. Distingue la CLASE de evento de un vistazo en un log
|
|
@@ -1474,6 +2019,128 @@ declare class FieldLabel {
|
|
|
1474
2019
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldLabel, "kf-field-label", never, { "for": { "alias": "for"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1475
2020
|
}
|
|
1476
2021
|
|
|
2022
|
+
/** Por qué se descartó un archivo: formato fuera de `accept` o más grande que `maxSize`. */
|
|
2023
|
+
type FileRejectionReason = 'type' | 'size';
|
|
2024
|
+
/** Un archivo descartado y el motivo. */
|
|
2025
|
+
interface FileRejection {
|
|
2026
|
+
file: File;
|
|
2027
|
+
reason: FileRejectionReason;
|
|
2028
|
+
}
|
|
2029
|
+
/** Tamaño en bytes como texto (`5 MB`, `120 KB`), base 1024. */
|
|
2030
|
+
declare function formatFileSize(bytes: number): string;
|
|
2031
|
+
/**
|
|
2032
|
+
* Selector de archivo accesible, con la misma apariencia y contrato de campo
|
|
2033
|
+
* que `kf-input`: label arriba, ayuda y error debajo, `invalid`.
|
|
2034
|
+
*
|
|
2035
|
+
* El control real es un `<input type="file">` nativo, visualmente oculto pero
|
|
2036
|
+
* enfocable: se llega con Tab, se abre con Enter o Espacio y el anillo de foco
|
|
2037
|
+
* se dibuja sobre el botón visible. Su nombre accesible es el `label` (o
|
|
2038
|
+
* `ariaLabel`); la ayuda, el archivo elegido y el error lo describen
|
|
2039
|
+
* (`aria-describedby`).
|
|
2040
|
+
*
|
|
2041
|
+
* **Ayuda antes de elegir.** `hint` es texto libre; si no se pasa, se arma sola
|
|
2042
|
+
* con los formatos de `accept` y el tamaño de `maxSize` (`PDF, JPG · máx. 5 MB`),
|
|
2043
|
+
* para que el usuario sepa qué sirve ANTES de abrir el selector.
|
|
2044
|
+
*
|
|
2045
|
+
* **Validación.** Cada archivo se revisa contra `accept` (extensiones `.pdf`,
|
|
2046
|
+
* tipos `image/png` o comodines `image/*`) y `maxSize` (bytes). Los válidos
|
|
2047
|
+
* quedan elegidos y se emiten en `fileChange` (siempre `File[]`, vacío al
|
|
2048
|
+
* quitar); los descartados se emiten uno a uno en `fileRejected` con su
|
|
2049
|
+
* motivo (`'type'` o `'size'`) y se muestran como error bajo el campo
|
|
2050
|
+
* (`rejectedTypeText` / `rejectedSizeText`); la ayuda sigue visible bajo ese
|
|
2051
|
+
* mensaje, para que se vea qué sí sirve. Un `error` del consumidor tiene
|
|
2052
|
+
* prioridad sobre ese mensaje y reemplaza a la ayuda, igual que `errorMessage`
|
|
2053
|
+
* sobre `hint` en `kf-input`. La validación del navegador no reemplaza la del servidor.
|
|
2054
|
+
*
|
|
2055
|
+
* **Archivo elegido.** Su nombre y tamaño aparecen UNA vez, con un botón para
|
|
2056
|
+
* quitarlo (`removeLabel`, con el nombre del archivo en su `aria-label`); el
|
|
2057
|
+
* nombre del `<input>` nativo queda oculto. Con `multiple` se listan todos y
|
|
2058
|
+
* cada uno se quita por separado. Elegir de nuevo reemplaza la selección.
|
|
2059
|
+
*
|
|
2060
|
+
* `dropzone` agrega arrastrar y soltar sobre el área; el botón y el teclado
|
|
2061
|
+
* siguen siendo la vía principal.
|
|
2062
|
+
*
|
|
2063
|
+
* Es un `ControlValueAccessor`: con `[(ngModel)]`/`formControl` el valor es
|
|
2064
|
+
* `File | null` (o `File[]` con `multiple`); `writeValue(null)` limpia.
|
|
2065
|
+
*
|
|
2066
|
+
* <kf-file-input label="Comprobante" accept=".pdf,.jpg,.png" [maxSize]="5242880"
|
|
2067
|
+
* (fileChange)="onFiles($event)" (fileRejected)="onRejected($event)" />
|
|
2068
|
+
* <kf-file-input label="Fotos" accept="image/*" multiple dropzone formControlName="photos" />
|
|
2069
|
+
* <kf-file-input label="Contrato" error="Adjunta el contrato firmado." formControlName="contract" />
|
|
2070
|
+
*/
|
|
2071
|
+
declare class FileInput implements ControlValueAccessor {
|
|
2072
|
+
private readonly nativeInput;
|
|
2073
|
+
readonly label: _angular_core.InputSignal<string | undefined>;
|
|
2074
|
+
readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2075
|
+
/** Texto de ayuda. Sin valor, se arma con `accept` y `maxSize`. */
|
|
2076
|
+
readonly hint: _angular_core.InputSignal<string | undefined>;
|
|
2077
|
+
/** Formatos admitidos, como el `accept` nativo: `.pdf,.jpg`, `image/png`, `image/*`. */
|
|
2078
|
+
readonly accept: _angular_core.InputSignal<string | undefined>;
|
|
2079
|
+
/** Tamaño máximo por archivo, en bytes. Sin valor, sin límite. */
|
|
2080
|
+
readonly maxSize: _angular_core.InputSignal<number | undefined>;
|
|
2081
|
+
readonly multiple: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2082
|
+
/** Agrega arrastrar y soltar sobre el área del control. */
|
|
2083
|
+
readonly dropzone: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2084
|
+
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2085
|
+
/** Borde rojo y `aria-invalid`. Se activa solo con `error`; úsalo para marcar un error sin mensaje. */
|
|
2086
|
+
readonly invalid: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2087
|
+
/** Mensaje de error del consumidor (`role="alert"`); reemplaza a la ayuda y al motivo de rechazo, como `errorMessage` en `kf-input`. */
|
|
2088
|
+
readonly error: _angular_core.InputSignal<string | undefined>;
|
|
2089
|
+
/** Nombre accesible cuando no hay `label` visible. */
|
|
2090
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
2091
|
+
/** Texto del botón cuando no hay archivo elegido. */
|
|
2092
|
+
readonly buttonLabel: _angular_core.InputSignal<string>;
|
|
2093
|
+
/** Texto del botón con `multiple` o cuando ya hay un archivo (cambiar). */
|
|
2094
|
+
readonly changeLabel: _angular_core.InputSignal<string>;
|
|
2095
|
+
/** Nombre accesible del botón de quitar; se le agrega el nombre del archivo. */
|
|
2096
|
+
readonly removeLabel: _angular_core.InputSignal<string>;
|
|
2097
|
+
/** Texto de arrastrar y soltar (solo con `dropzone`). */
|
|
2098
|
+
readonly dropzoneText: _angular_core.InputSignal<string>;
|
|
2099
|
+
readonly rejectedTypeText: _angular_core.InputSignal<string>;
|
|
2100
|
+
readonly rejectedSizeText: _angular_core.InputSignal<string>;
|
|
2101
|
+
/** Selección vigente (`File[]`, vacío al quitar todo). */
|
|
2102
|
+
readonly fileChange: _angular_core.OutputEmitterRef<File[]>;
|
|
2103
|
+
/** Un archivo descartado y su motivo. */
|
|
2104
|
+
readonly fileRejected: _angular_core.OutputEmitterRef<FileRejection>;
|
|
2105
|
+
protected readonly inputId: string;
|
|
2106
|
+
protected readonly hintId: string;
|
|
2107
|
+
protected readonly errorId: string;
|
|
2108
|
+
protected readonly filesId: string;
|
|
2109
|
+
protected readonly files: _angular_core.WritableSignal<File[]>;
|
|
2110
|
+
protected readonly rejection: _angular_core.WritableSignal<FileRejectionReason | null>;
|
|
2111
|
+
protected readonly dragging: _angular_core.WritableSignal<boolean>;
|
|
2112
|
+
private readonly disabledByForm;
|
|
2113
|
+
protected readonly isDisabled: _angular_core.Signal<boolean>;
|
|
2114
|
+
private onChange;
|
|
2115
|
+
private onTouched;
|
|
2116
|
+
/** Mensaje visible: el del consumidor, o el motivo del último rechazo. */
|
|
2117
|
+
protected readonly message: _angular_core.Signal<string | null>;
|
|
2118
|
+
/** Ayuda efectiva: la del consumidor o la armada con formatos y tamaño. */
|
|
2119
|
+
protected readonly effectiveHint: _angular_core.Signal<string>;
|
|
2120
|
+
protected readonly isInvalid: _angular_core.Signal<boolean>;
|
|
2121
|
+
protected readonly describedBy: _angular_core.Signal<string | null>;
|
|
2122
|
+
protected readonly triggerText: _angular_core.Signal<string>;
|
|
2123
|
+
/** Enfoca el `<input>` nativo. */
|
|
2124
|
+
focus(options?: FocusOptions): void;
|
|
2125
|
+
writeValue(value: File | File[] | null): void;
|
|
2126
|
+
registerOnChange(fn: (value: File | File[] | null) => void): void;
|
|
2127
|
+
registerOnTouched(fn: () => void): void;
|
|
2128
|
+
setDisabledState(isDisabled: boolean): void;
|
|
2129
|
+
protected onPick(event: Event): void;
|
|
2130
|
+
protected onDragOver(event: DragEvent): void;
|
|
2131
|
+
protected onDragLeave(): void;
|
|
2132
|
+
protected onDrop(event: DragEvent): void;
|
|
2133
|
+
protected remove(index: number): void;
|
|
2134
|
+
protected formatSize(file: File): string;
|
|
2135
|
+
/** Valida lo recibido, emite los rechazos y reemplaza la selección si hay algo válido. */
|
|
2136
|
+
private receive;
|
|
2137
|
+
private reject;
|
|
2138
|
+
private matchesAccept;
|
|
2139
|
+
private commit;
|
|
2140
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FileInput, never>;
|
|
2141
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FileInput, "kf-file-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "maxSize": { "alias": "maxSize"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "dropzone": { "alias": "dropzone"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "buttonLabel": { "alias": "buttonLabel"; "required": false; "isSignal": true; }; "changeLabel": { "alias": "changeLabel"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "dropzoneText": { "alias": "dropzoneText"; "required": false; "isSignal": true; }; "rejectedTypeText": { "alias": "rejectedTypeText"; "required": false; "isSignal": true; }; "rejectedSizeText": { "alias": "rejectedSizeText"; "required": false; "isSignal": true; }; }, { "fileChange": "fileChange"; "fileRejected": "fileRejected"; }, never, never, true, never>;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
1477
2144
|
interface MultiSelectOption {
|
|
1478
2145
|
value: string;
|
|
1479
2146
|
label: string;
|
|
@@ -1567,7 +2234,13 @@ declare class MultiSelect {
|
|
|
1567
2234
|
/** Mueve `activeIndex` sobre las opciones YA FILTRADAS visibles. Clamp simple, sin wraparound. */
|
|
1568
2235
|
moveActive(delta: number): void;
|
|
1569
2236
|
toggleActive(): void;
|
|
1570
|
-
|
|
2237
|
+
/**
|
|
2238
|
+
* Escape con el panel abierto, en fase de captura sobre `document` (ver
|
|
2239
|
+
* `listenEscapeCapture`): consume la tecla solo si había un panel que
|
|
2240
|
+
* cerrar, así un `kf-drawer`/`kf-modal` contenedor no se cierra con el
|
|
2241
|
+
* mismo Escape. Devuelve si cerró algo.
|
|
2242
|
+
*/
|
|
2243
|
+
onEscape(): boolean;
|
|
1571
2244
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MultiSelect, never>;
|
|
1572
2245
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MultiSelect, "kf-multi-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "values": { "alias": "values"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchThreshold": { "alias": "searchThreshold"; "required": false; "isSignal": true; }; }, { "valuesChange": "valuesChange"; }, never, never, true, never>;
|
|
1573
2246
|
}
|
|
@@ -1627,43 +2300,63 @@ declare class Filter {
|
|
|
1627
2300
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Filter, "kf-filter", never, { "fields": { "alias": "fields"; "required": true; "isSignal": true; }; "values": { "alias": "values"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "mobileTitle": { "alias": "mobileTitle"; "required": false; "isSignal": true; }; }, { "fieldChange": "fieldChange"; }, never, never, true, never>;
|
|
1628
2301
|
}
|
|
1629
2302
|
|
|
1630
|
-
/**
|
|
2303
|
+
/**
|
|
2304
|
+
* Opción en forma de objeto. `count` es opcional: cuando está presente se
|
|
2305
|
+
* muestra a la derecha del label (ej. "Pendientes 3"), con cifras tabulares
|
|
2306
|
+
* para que el ancho del chip no salte al cambiar el número.
|
|
2307
|
+
*/
|
|
1631
2308
|
interface FilterChipOption {
|
|
1632
2309
|
value: string;
|
|
1633
2310
|
label: string;
|
|
2311
|
+
count?: number;
|
|
1634
2312
|
}
|
|
1635
2313
|
/**
|
|
1636
2314
|
* Fila de chips tipo "pill" para filtros de una sola selección.
|
|
1637
2315
|
*
|
|
1638
2316
|
* Cada opción puede pasarse como string simple (se usa como value y label
|
|
1639
|
-
* a la vez) o como objeto { value, label } cuando el texto
|
|
1640
|
-
* del valor interno.
|
|
2317
|
+
* a la vez) o como objeto `{ value, label, count? }` cuando el texto
|
|
2318
|
+
* mostrado difiere del valor interno o cuando cada chip lleva un contador.
|
|
1641
2319
|
*
|
|
1642
2320
|
* El chip activo se resalta con `--kf-color-primary` — mismo color de marca
|
|
1643
2321
|
* que `kf-tabs`/`kf-select` para su propio estado activo, así el filtro
|
|
1644
2322
|
* seleccionado se lee con el color del tema activo, no un negro fijo que
|
|
1645
2323
|
* no cambia entre marcas.
|
|
1646
2324
|
*
|
|
2325
|
+
* Densidad: el padding horizontal de cada chip sale de
|
|
2326
|
+
* `--kf-filter-chips-padding-inline` (default `--kf-space-md`). Un
|
|
2327
|
+
* contenedor puede reducirlo sin tocar este componente — `kf-list-toolbar`
|
|
2328
|
+
* lo baja a 12px en su modo compacto.
|
|
2329
|
+
*
|
|
1647
2330
|
* <kf-filter-chips [options]="['Todos', 'Activos', 'Archivados']"
|
|
1648
2331
|
* [value]="filtro"
|
|
1649
2332
|
* (valueChange)="filtro = $event" />
|
|
1650
2333
|
*
|
|
1651
|
-
*
|
|
2334
|
+
* `layout="scroll"` deja todos los chips en UNA línea con desplazamiento
|
|
2335
|
+
* horizontal (para mobile: los filtros no ocupan más alto que una fila); el
|
|
2336
|
+
* default `wrap` los reparte en varias líneas. `deselectable` permite
|
|
2337
|
+
* quitar el filtro volviendo a tocar el chip activo (emite `''`), para el
|
|
2338
|
+
* caso "ningún chip = sin filtro".
|
|
2339
|
+
*
|
|
2340
|
+
* <kf-filter-chips ariaLabel="Filtrar por estado"
|
|
2341
|
+
* [options]="[{ value: '', label: 'Todas', count: 12 }]"
|
|
1652
2342
|
* [value]="filtro"
|
|
1653
2343
|
* (valueChange)="filtro = $event" />
|
|
1654
2344
|
*/
|
|
1655
2345
|
declare class FilterChips {
|
|
1656
|
-
readonly options: _angular_core.InputSignal<(string |
|
|
1657
|
-
value: string;
|
|
1658
|
-
label: string;
|
|
1659
|
-
})[]>;
|
|
2346
|
+
readonly options: _angular_core.InputSignal<(string | FilterChipOption)[]>;
|
|
1660
2347
|
readonly value: _angular_core.InputSignal<string>;
|
|
2348
|
+
/** Nombre accesible del grupo (ej. "Filtrar por estado"). Sin él, el grupo se anuncia sin nombre. */
|
|
2349
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
2350
|
+
/** `wrap` (default): varias líneas. `scroll`: una sola línea con desplazamiento horizontal. */
|
|
2351
|
+
readonly layout: _angular_core.InputSignal<"scroll" | "wrap">;
|
|
2352
|
+
/** Tocar el chip activo lo desactiva y emite `''`. Default `false` (comportamiento histórico). */
|
|
2353
|
+
readonly deselectable: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1661
2354
|
readonly valueChange: _angular_core.OutputEmitterRef<string>;
|
|
1662
|
-
/** Normaliza cada opción string/objeto a la forma { value, label }
|
|
2355
|
+
/** Normaliza cada opción string/objeto a la forma `{ value, label, count? }`. */
|
|
1663
2356
|
readonly normalizedOptions: _angular_core.Signal<FilterChipOption[]>;
|
|
1664
2357
|
select(value: string): void;
|
|
1665
2358
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FilterChips, never>;
|
|
1666
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FilterChips, "kf-filter-chips", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
2359
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FilterChips, "kf-filter-chips", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "deselectable": { "alias": "deselectable"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
1667
2360
|
}
|
|
1668
2361
|
|
|
1669
2362
|
/** Un link del pie — legales, contacto, soporte. */
|
|
@@ -1698,6 +2391,8 @@ declare class Footer {
|
|
|
1698
2391
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Footer, "kf-footer", never, { "logoSrc": { "alias": "logoSrc"; "required": false; "isSignal": true; }; "logoAlt": { "alias": "logoAlt"; "required": false; "isSignal": true; }; "copyright": { "alias": "copyright"; "required": true; "isSignal": true; }; "links": { "alias": "links"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1699
2392
|
}
|
|
1700
2393
|
|
|
2394
|
+
/** Valor de `min`/`max`/`step`: número, o texto cuando el tipo lo pide (una fecha `'2026-01-31'`, un mes, una hora). */
|
|
2395
|
+
type InputBound = string | number | null | undefined;
|
|
1701
2396
|
/**
|
|
1702
2397
|
* Input de formulario apilado: label arriba (en mayúsculas vía CSS), campo con
|
|
1703
2398
|
* fondo gris que pasa a blanco con anillo de foco azul al enfocar.
|
|
@@ -1740,6 +2435,41 @@ declare class Footer {
|
|
|
1740
2435
|
* está en vuelo).
|
|
1741
2436
|
*
|
|
1742
2437
|
* <kf-input label="DNI" readonly formControlName="documentId" />
|
|
2438
|
+
*
|
|
2439
|
+
* Buscador sin label visible: `ariaLabel` da el nombre accesible del
|
|
2440
|
+
* `<input>` (el placeholder no lo reemplaza: desaparece al escribir) y
|
|
2441
|
+
* `clearable` agrega un botón "×" mientras haya texto. Borrar limpia el
|
|
2442
|
+
* valor, notifica al formulario (`ngModel`/`formControl`), dispara un
|
|
2443
|
+
* evento `input` nativo (para quien escucha `(input)`), emite `cleared` y
|
|
2444
|
+
* devuelve el foco al campo.
|
|
2445
|
+
*
|
|
2446
|
+
* <kf-input type="search" icon="search" ariaLabel="Buscar cotizaciones"
|
|
2447
|
+
* placeholder="Buscar cotización" clearable [(ngModel)]="query" />
|
|
2448
|
+
*
|
|
2449
|
+
* `focus()` enfoca el `<input>` nativo, sin que el consumidor busque el
|
|
2450
|
+
* control interno con `querySelector`.
|
|
2451
|
+
*
|
|
2452
|
+
* `autocomplete`, `name` e `inputmode` se reenvían al `<input>` nativo (un
|
|
2453
|
+
* atributo en el host no llega adentro) para que el navegador y los gestores
|
|
2454
|
+
* de contraseñas identifiquen el campo; sin valor no se renderiza ningún
|
|
2455
|
+
* atributo. Funcionan igual con `type="password"` y `toggleable`.
|
|
2456
|
+
*
|
|
2457
|
+
* <kf-input label="RUT" autocomplete="username" name="rut" inputmode="text" formControlName="rut" />
|
|
2458
|
+
* <kf-input type="password" label="Contraseña" toggleable autocomplete="current-password" name="password" formControlName="password" />
|
|
2459
|
+
*
|
|
2460
|
+
* `min`, `max`, `step` y `maxlength` se reenvían al `<input>` nativo (mismo
|
|
2461
|
+
* motivo: un atributo en el host no llega adentro) y sin valor no se
|
|
2462
|
+
* renderiza ningún atributo. `min`/`max`/`step` aceptan número o texto según
|
|
2463
|
+
* el `type` (`number`, `range`, `date`, `time`, `month`…): con `type="date"` el
|
|
2464
|
+
* límite es una fecha ISO. `maxlength` es un entero positivo y aplica a los
|
|
2465
|
+
* tipos de texto (`text`, `search`, `email`, `tel`, `url`, `password`). El
|
|
2466
|
+
* navegador usa los límites para la validación nativa (`:invalid`,
|
|
2467
|
+
* `validity.rangeUnderflow`) y para el selector de fechas; no reemplazan la
|
|
2468
|
+
* validación del formulario ni el `errorMessage`.
|
|
2469
|
+
*
|
|
2470
|
+
* <kf-input type="date" label="Fecha de entrega" min="2026-01-01" max="2026-12-31" />
|
|
2471
|
+
* <kf-input type="number" label="Cantidad" [min]="1" [max]="20" [step]="1" />
|
|
2472
|
+
* <kf-input label="Placa" [maxlength]="7" />
|
|
1743
2473
|
*/
|
|
1744
2474
|
declare class Input implements ControlValueAccessor, AfterViewInit {
|
|
1745
2475
|
private static nextId;
|
|
@@ -1766,11 +2496,37 @@ declare class Input implements ControlValueAccessor, AfterViewInit {
|
|
|
1766
2496
|
readonly readonly: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1767
2497
|
readonly type: _angular_core.InputSignal<string>;
|
|
1768
2498
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
1769
|
-
/**
|
|
1770
|
-
*
|
|
1771
|
-
|
|
2499
|
+
/** Token de autocompletado HTML (`username`, `email`, `current-password`,
|
|
2500
|
+
* `new-password`, `off`, etc.) que se reenvía al `<input>` nativo para que
|
|
2501
|
+
* el navegador y los gestores de contraseñas identifiquen el propósito del
|
|
2502
|
+
* campo (WCAG 1.3.5 y 3.3.8). Sin valor, el atributo no se renderiza. */
|
|
2503
|
+
readonly autocomplete: _angular_core.InputSignal<string | null | undefined>;
|
|
2504
|
+
/** `name` del `<input>` nativo; los gestores de contraseñas y el envío
|
|
2505
|
+
* nativo de formularios lo usan para identificar el campo. Sin valor, el
|
|
2506
|
+
* atributo no se renderiza. */
|
|
2507
|
+
readonly name: _angular_core.InputSignal<string | null | undefined>;
|
|
2508
|
+
/** Sugiere el teclado virtual (`numeric`, `email`, `tel`, etc.) sin cambiar
|
|
2509
|
+
* el `type`. Sin valor, el atributo no se renderiza. */
|
|
2510
|
+
readonly inputmode: _angular_core.InputSignal<string | null | undefined>;
|
|
2511
|
+
/** Límite inferior del control (`min` nativo): número, o texto para fechas/horas (`'2026-01-01'`). */
|
|
2512
|
+
readonly min: _angular_core.InputSignalWithTransform<string | number | null, InputBound>;
|
|
2513
|
+
/** Límite superior del control (`max` nativo). Ver `min`. */
|
|
2514
|
+
readonly max: _angular_core.InputSignalWithTransform<string | number | null, InputBound>;
|
|
2515
|
+
/** Paso del control (`step` nativo): número o `'any'`. */
|
|
2516
|
+
readonly step: _angular_core.InputSignalWithTransform<string | number | null, InputBound>;
|
|
2517
|
+
/** Largo máximo del texto (`maxlength` nativo), entero positivo. Solo aplica a tipos de texto. */
|
|
2518
|
+
readonly maxlength: _angular_core.InputSignalWithTransform<number | null, string | number | null | undefined>;
|
|
1772
2519
|
/** Agrega el botón de mostrar/ocultar — sin efecto si `type` no es `"password"`. */
|
|
1773
2520
|
readonly toggleable: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2521
|
+
/** Nombre accesible del `<input>` cuando no hay `label` visible. Ignorado
|
|
2522
|
+
* si hay `label`: un `aria-label` pisaría al `<label for>` visible. */
|
|
2523
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
2524
|
+
/** Agrega un botón "×" para borrar el valor mientras haya texto (sin efecto con `disabled`/`readonly`). */
|
|
2525
|
+
readonly clearable: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2526
|
+
/** Nombre accesible del botón de borrar. */
|
|
2527
|
+
readonly clearLabel: _angular_core.InputSignal<string>;
|
|
2528
|
+
/** Emitido después de borrar el valor con el botón "×". */
|
|
2529
|
+
readonly cleared: _angular_core.OutputEmitterRef<void>;
|
|
1774
2530
|
protected readonly inputId: string;
|
|
1775
2531
|
protected readonly hintId: string;
|
|
1776
2532
|
protected readonly errorId: string;
|
|
@@ -1784,6 +2540,8 @@ declare class Input implements ControlValueAccessor, AfterViewInit {
|
|
|
1784
2540
|
protected readonly passwordVisible: _angular_core.WritableSignal<boolean>;
|
|
1785
2541
|
/** El botón solo tiene sentido si el campo realmente es de contraseña. */
|
|
1786
2542
|
protected readonly showPasswordToggle: _angular_core.Signal<boolean>;
|
|
2543
|
+
/** El botón de borrar solo aparece con texto y con el campo editable. */
|
|
2544
|
+
protected readonly showClear: _angular_core.Signal<boolean>;
|
|
1787
2545
|
/**
|
|
1788
2546
|
* `type` real que recibe el `<input>` nativo: igual a `type()` salvo
|
|
1789
2547
|
* cuando el toggle está activo y visible, donde pasa a `text` para
|
|
@@ -1794,12 +2552,22 @@ declare class Input implements ControlValueAccessor, AfterViewInit {
|
|
|
1794
2552
|
private onChange;
|
|
1795
2553
|
private onTouched;
|
|
1796
2554
|
ngAfterViewInit(): void;
|
|
2555
|
+
/** Enfoca el `<input>` nativo (mismas opciones que `HTMLElement.focus`). */
|
|
2556
|
+
focus(options?: FocusOptions): void;
|
|
1797
2557
|
writeValue(value: string): void;
|
|
1798
2558
|
registerOnChange(fn: (value: string) => void): void;
|
|
1799
2559
|
registerOnTouched(fn: () => void): void;
|
|
1800
2560
|
setDisabledState(isDisabled: boolean): void;
|
|
1801
2561
|
protected onInput(rawValue: string): void;
|
|
1802
2562
|
protected onBlur(): void;
|
|
2563
|
+
/**
|
|
2564
|
+
* Borra el valor reutilizando el mismo camino que el tipeo: un evento
|
|
2565
|
+
* `input` nativo pasa por `onInput` (notifica al formulario) y además
|
|
2566
|
+
* llega a cualquier `(input)` del consumidor. Con el mouse no hay blur:
|
|
2567
|
+
* el `mousedown` del botón hace `preventDefault` (ver Input.html), así el
|
|
2568
|
+
* campo no se marca `touched` por usar su propio "×".
|
|
2569
|
+
*/
|
|
2570
|
+
protected onClear(): void;
|
|
1803
2571
|
/**
|
|
1804
2572
|
* Alterna la visibilidad del valor. No dispara `onBlur`/pierde el foco:
|
|
1805
2573
|
* el botón vive dentro del mismo `.kf-input__field`, así que un click acá
|
|
@@ -1807,7 +2575,7 @@ declare class Input implements ControlValueAccessor, AfterViewInit {
|
|
|
1807
2575
|
*/
|
|
1808
2576
|
protected onTogglePasswordVisibility(): void;
|
|
1809
2577
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Input, never>;
|
|
1810
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Input, "kf-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "inputmode": { "alias": "inputmode"; "required": false; "isSignal": true; }; "toggleable": { "alias": "toggleable"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2578
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Input, "kf-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "inputmode": { "alias": "inputmode"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "maxlength": { "alias": "maxlength"; "required": false; "isSignal": true; }; "toggleable": { "alias": "toggleable"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "clearLabel": { "alias": "clearLabel"; "required": false; "isSignal": true; }; }, { "cleared": "cleared"; }, never, never, true, never>;
|
|
1811
2579
|
}
|
|
1812
2580
|
|
|
1813
2581
|
type JourneyStepStatus = 'done' | 'current' | 'delayed' | 'pending';
|
|
@@ -1900,6 +2668,205 @@ declare class Link {
|
|
|
1900
2668
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Link, "kf-link", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "href": { "alias": "href"; "required": false; "isSignal": true; }; "showArrow": { "alias": "showArrow"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1901
2669
|
}
|
|
1902
2670
|
|
|
2671
|
+
/**
|
|
2672
|
+
* Modo de `kf-list-toolbar` según el ancho REAL disponible:
|
|
2673
|
+
* - `full`: todo en una fila con la densidad normal.
|
|
2674
|
+
* - `compact`: todo en una fila, con los chips más angostos (`data-density="compact"`).
|
|
2675
|
+
* - `panel`: solo el buscador y un botón "Filtros"; filtros y acciones finales se ocultan.
|
|
2676
|
+
*/
|
|
2677
|
+
type ListToolbarMode = 'full' | 'compact' | 'panel';
|
|
2678
|
+
/** Anchos medidos (px): disponible en la barra y requerido por cada densidad. */
|
|
2679
|
+
interface ListToolbarWidths {
|
|
2680
|
+
available: number;
|
|
2681
|
+
full: number;
|
|
2682
|
+
compact: number;
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Margen de histéresis (px) para SUBIR de modo. Bajar es inmediato (si no
|
|
2686
|
+
* cabe, no cabe); subir exige este margen extra, así un ancho que oscila
|
|
2687
|
+
* justo en el umbral (scrollbar que aparece y desaparece, un contador que
|
|
2688
|
+
* pasa de 9 a 10) no hace parpadear la barra entre dos modos.
|
|
2689
|
+
*/
|
|
2690
|
+
declare const LIST_TOOLBAR_HYSTERESIS = 24;
|
|
2691
|
+
/**
|
|
2692
|
+
* Decide el modo a partir del modo actual y los anchos medidos. Función pura
|
|
2693
|
+
* para poder probar la histéresis sin layout real.
|
|
2694
|
+
*/
|
|
2695
|
+
declare function resolveListToolbarMode(widths: ListToolbarWidths, current: ListToolbarMode, hysteresis?: number): ListToolbarMode;
|
|
2696
|
+
|
|
2697
|
+
/**
|
|
2698
|
+
* Barra de herramientas de un listado: buscador, filtros y acciones finales
|
|
2699
|
+
* (orden, cambio de vista) en UNA fila, que se adapta al ancho REAL que
|
|
2700
|
+
* tiene disponible — no al del viewport. El mismo listado puede renderizarse
|
|
2701
|
+
* con el menú lateral abierto o cerrado, dentro de un panel o a pantalla
|
|
2702
|
+
* completa, y una `@media` no distingue esos casos; la barra mide su propio
|
|
2703
|
+
* ancho con `ResizeObserver`.
|
|
2704
|
+
*
|
|
2705
|
+
* ## Cuándo usarla y cuándo `kf-filter`
|
|
2706
|
+
* - `kf-list-toolbar`: chips con contador (`kf-filter-chips`) + orden + cambio
|
|
2707
|
+
* de vista + panel de filtros en modo estrecho, fija al hacer scroll y
|
|
2708
|
+
* guiada por el ancho del contenedor.
|
|
2709
|
+
* - `kf-filter`: selects, multi-select y buscador de texto en una fila de
|
|
2710
|
+
* formulario, que se pliega en un `kf-collapsible` a ≤768px de viewport.
|
|
2711
|
+
* Si el listado se filtra con campos, usar `kf-filter`; no se combinan ni
|
|
2712
|
+
* se reimplementan entre sí.
|
|
2713
|
+
*
|
|
2714
|
+
* ## Slots
|
|
2715
|
+
* - `[kf-toolbar-search]`: el buscador (ej. `kf-input icon="search"`). Siempre visible; ocupa el espacio libre.
|
|
2716
|
+
* - `[kf-toolbar-filters]`: filtros rápidos (ej. `kf-filter-chips`).
|
|
2717
|
+
* - `[kf-toolbar-end]`: acciones al final de la fila (ej. `kf-select` de orden, `kf-view-toggle`).
|
|
2718
|
+
*
|
|
2719
|
+
* Cada slot acepta VARIOS elementos con el mismo atributo y los ubica en
|
|
2720
|
+
* fila con `gap`; marcar cada control (no un `<div>` envoltorio sin
|
|
2721
|
+
* `display: flex`, que apilaría sus hijos en bloque).
|
|
2722
|
+
*
|
|
2723
|
+
* La barra ocupa el ancho de su contenedor (`display: block`). Dentro de un
|
|
2724
|
+
* contenedor flex que ajusta su ancho al contenido, darle un ancho
|
|
2725
|
+
* explícito: si el contenedor mide lo que la barra pide, la barra mide lo
|
|
2726
|
+
* que el contenedor le da y el modo nunca puede subir de `panel`.
|
|
2727
|
+
* - default: contenido no visual que debe quedar SIEMPRE presente, como una
|
|
2728
|
+
* región `aria-live` con el conteo de resultados (nunca dentro de un slot
|
|
2729
|
+
* que se oculta).
|
|
2730
|
+
*
|
|
2731
|
+
* ## Modos (`mode`, `modeChange`, atributo `data-mode`)
|
|
2732
|
+
* - `full`: todo cabe en una fila.
|
|
2733
|
+
* - `compact`: cabe en una fila solo con chips más angostos. El host expone
|
|
2734
|
+
* `data-density="compact"` y redefine `--kf-filter-chips-padding-inline`
|
|
2735
|
+
* (12px), que `kf-filter-chips` adopta sin configuración extra.
|
|
2736
|
+
* - `panel`: no cabe. Se ocultan `filters` y `end` y aparece, junto al
|
|
2737
|
+
* buscador, un botón "Filtros" (`filtersLabel`) con un badge de
|
|
2738
|
+
* `activeCount` (filtros/orden distintos del valor por defecto) que emite
|
|
2739
|
+
* `filtersClick` — el consumidor abre su propio panel (típicamente
|
|
2740
|
+
* `kf-drawer role="dialog"` con `kf-option-list`).
|
|
2741
|
+
*
|
|
2742
|
+
* Contrato con el panel de filtros: el consumidor DEBE pasar
|
|
2743
|
+
* `[filtersExpanded]` con el estado de su panel y DEBE cerrarlo al recibir
|
|
2744
|
+
* un `modeChange` distinto de `'panel'`. Al salir de `panel` con el panel
|
|
2745
|
+
* abierto, la barra mueve el foco al primer filtro visible (el botón
|
|
2746
|
+
* "Filtros" ya no existe para recibirlo); si el panel modal siguiera
|
|
2747
|
+
* abierto, ese foco quedaría fuera del diálogo.
|
|
2748
|
+
*
|
|
2749
|
+
* El modo sale de comparar el ancho disponible con el ancho natural de los
|
|
2750
|
+
* slots en cada densidad (más `searchMinWidth` para el buscador), con
|
|
2751
|
+
* histéresis al subir de modo (`LIST_TOOLBAR_HYSTERESIS`) para que no
|
|
2752
|
+
* parpadee en el umbral. Los slots ocultos en modo `panel` se siguen
|
|
2753
|
+
* midiendo (quedan fuera de vista con `visibility: hidden`, sin foco ni
|
|
2754
|
+
* árbol de accesibilidad), así un contador que crece se refleja igual.
|
|
2755
|
+
*
|
|
2756
|
+
* ## Fija (`sticky`)
|
|
2757
|
+
* Con `sticky`, la barra queda pegada arriba al hacer scroll (`stickyTop`
|
|
2758
|
+
* compensa una cabecera fija del shell). Cuando efectivamente queda pegada,
|
|
2759
|
+
* el host recibe la clase `kf-list-toolbar--stuck`: sombra más marcada y
|
|
2760
|
+
* menos alto. "Pegada" = el contenedor con scroll (el ancestro más cercano
|
|
2761
|
+
* con `overflow-y: auto|scroll`, o la ventana) ya se desplazó Y la barra
|
|
2762
|
+
* está en su posición fija. Sin centinela: un centinela por encima de la
|
|
2763
|
+
* barra quedaría recortado cuando la barra es el primer elemento del
|
|
2764
|
+
* contenedor, y la marcaría pegada en reposo. El fondo alrededor de
|
|
2765
|
+
* la barra fija sale de `--kf-list-toolbar-backdrop` (default
|
|
2766
|
+
* `--kf-color-surface`, el fondo habitual del área de contenido).
|
|
2767
|
+
*
|
|
2768
|
+
* Foco tapado (WCAG 2.4.11): una barra fija puede quedar encima del control
|
|
2769
|
+
* que recibe el foco al tabular hacia arriba. El consumidor debe aplicar
|
|
2770
|
+
* `scroll-padding-top` = `stickyTop` + alto de la barra al contenedor que
|
|
2771
|
+
* hace scroll (o a `html` si es la ventana), así el navegador deja ese
|
|
2772
|
+
* margen al llevar un elemento enfocado a la vista. El alto vigente se
|
|
2773
|
+
* publica como señal `height` (px), output `heightChange` y variable CSS
|
|
2774
|
+
* `--kf-list-toolbar-height` en el host (esta última solo la heredan los
|
|
2775
|
+
* descendientes; un ancestro debe usar la señal):
|
|
2776
|
+
*
|
|
2777
|
+
* <main class="content" [style.scroll-padding-top.px]="56 + toolbar.height()">
|
|
2778
|
+
* <kf-list-toolbar #toolbar sticky [stickyTop]="56" ... />
|
|
2779
|
+
* </main>
|
|
2780
|
+
*
|
|
2781
|
+
* <kf-list-toolbar sticky ariaLabel="Filtrar cotizaciones" [activeCount]="activeFilters()"
|
|
2782
|
+
* (filtersClick)="filtersOpen.set(true)" (modeChange)="mode.set($event)">
|
|
2783
|
+
* <span class="sr-only" aria-live="polite">{{ resultsLabel() }}</span>
|
|
2784
|
+
* <kf-input kf-toolbar-search icon="search" ... />
|
|
2785
|
+
* <kf-filter-chips kf-toolbar-filters ... />
|
|
2786
|
+
* <kf-select kf-toolbar-end variant="compact" icon="sort" ariaLabel="Ordenar por" ... />
|
|
2787
|
+
* <kf-view-toggle kf-toolbar-end ... />
|
|
2788
|
+
* </kf-list-toolbar>
|
|
2789
|
+
*/
|
|
2790
|
+
declare class ListToolbar {
|
|
2791
|
+
/** Nombre accesible del landmark de búsqueda (`role="search"`). */
|
|
2792
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
2793
|
+
/** Fija la barra arriba al hacer scroll. */
|
|
2794
|
+
readonly sticky: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2795
|
+
/** Offset superior de la barra fija: número (px) o longitud CSS (ej. `'var(--shell-header-height)'`). */
|
|
2796
|
+
readonly stickyTop: _angular_core.InputSignal<string | number>;
|
|
2797
|
+
/** Ancho mínimo útil del buscador (px) — entra en el cálculo de si todo cabe en una fila. */
|
|
2798
|
+
readonly searchMinWidth: _angular_core.InputSignal<number>;
|
|
2799
|
+
/** Texto del botón del modo `panel`. */
|
|
2800
|
+
readonly filtersLabel: _angular_core.InputSignal<string>;
|
|
2801
|
+
/** Cantidad de filtros/orden distintos del valor por defecto; se muestra como badge en el botón del modo `panel`. */
|
|
2802
|
+
readonly activeCount: _angular_core.InputSignal<number>;
|
|
2803
|
+
/**
|
|
2804
|
+
* `aria-expanded` del botón del modo `panel`: el estado del panel que abre
|
|
2805
|
+
* el consumidor. Además, si es `true` al salir de `panel`, el foco pasa al
|
|
2806
|
+
* primer filtro visible — por eso el consumidor DEBE cerrar su panel en
|
|
2807
|
+
* ese mismo `modeChange` (ver "Contrato con el panel de filtros").
|
|
2808
|
+
*/
|
|
2809
|
+
readonly filtersExpanded: _angular_core.InputSignal<boolean | undefined>;
|
|
2810
|
+
readonly filtersClick: _angular_core.OutputEmitterRef<void>;
|
|
2811
|
+
/**
|
|
2812
|
+
* Nuevo modo. Al recibir un valor distinto de `'panel'`, el consumidor
|
|
2813
|
+
* DEBE cerrar su panel de filtros (ver "Contrato con el panel de filtros").
|
|
2814
|
+
*/
|
|
2815
|
+
readonly modeChange: _angular_core.OutputEmitterRef<ListToolbarMode>;
|
|
2816
|
+
/** Alto del host (px) cada vez que cambia — ver "Foco tapado" en el JSDoc de la clase. */
|
|
2817
|
+
readonly heightChange: _angular_core.OutputEmitterRef<number>;
|
|
2818
|
+
private readonly modeState;
|
|
2819
|
+
/** Modo vigente (también disponible como `data-mode` en el host). */
|
|
2820
|
+
readonly mode: _angular_core.Signal<ListToolbarMode>;
|
|
2821
|
+
private readonly stuckState;
|
|
2822
|
+
/** `true` mientras la barra fija está efectivamente pegada arriba. */
|
|
2823
|
+
readonly stuck: _angular_core.Signal<boolean>;
|
|
2824
|
+
private readonly heightState;
|
|
2825
|
+
/** Alto vigente del host en px (barra + padding de la variante fija). */
|
|
2826
|
+
readonly height: _angular_core.Signal<number>;
|
|
2827
|
+
protected readonly stickyTopCss: _angular_core.Signal<string>;
|
|
2828
|
+
protected readonly filtersAriaLabel: _angular_core.Signal<string | undefined>;
|
|
2829
|
+
private readonly hostRef;
|
|
2830
|
+
private readonly document;
|
|
2831
|
+
private readonly destroyRef;
|
|
2832
|
+
private readonly barRef;
|
|
2833
|
+
private readonly filtersRef;
|
|
2834
|
+
private readonly endRef;
|
|
2835
|
+
private readonly filtersButtonRef;
|
|
2836
|
+
/** A dónde mover el foco tras un cambio de modo que desmonta/oculta el elemento enfocado. */
|
|
2837
|
+
private pendingFocus;
|
|
2838
|
+
/** `requestAnimationFrame` pendiente de `measure()` (coalesce de notificaciones). */
|
|
2839
|
+
private measureFrame;
|
|
2840
|
+
private stuckFrame;
|
|
2841
|
+
private removeScrollListener;
|
|
2842
|
+
constructor();
|
|
2843
|
+
protected onFiltersClick(): void;
|
|
2844
|
+
/**
|
|
2845
|
+
* Mide el ancho disponible y el natural de cada slot en ambas
|
|
2846
|
+
* densidades, y actualiza el modo. La densidad de medición se fuerza con
|
|
2847
|
+
* `data-measure` (que gana sobre `data-density` en el CSS) y se retira en
|
|
2848
|
+
* el mismo frame: el navegador nunca pinta ese estado intermedio.
|
|
2849
|
+
*/
|
|
2850
|
+
private measure;
|
|
2851
|
+
private updateHeight;
|
|
2852
|
+
private applyMode;
|
|
2853
|
+
private slotsContain;
|
|
2854
|
+
private restorePendingFocus;
|
|
2855
|
+
private observeSize;
|
|
2856
|
+
private scheduleMeasure;
|
|
2857
|
+
/** Engancha (o suelta) el cálculo de `stuck` al scroll del contenedor. */
|
|
2858
|
+
private watchScroll;
|
|
2859
|
+
/**
|
|
2860
|
+
* Pegada = el contenedor ya se desplazó Y la barra está en su posición
|
|
2861
|
+
* fija (`top` resuelto, con medio píxel de tolerancia por subpíxeles).
|
|
2862
|
+
* Sin la primera condición, una barra que es el primer elemento del
|
|
2863
|
+
* contenedor se leería pegada en reposo.
|
|
2864
|
+
*/
|
|
2865
|
+
private updateStuck;
|
|
2866
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ListToolbar, never>;
|
|
2867
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ListToolbar, "kf-list-toolbar", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "sticky": { "alias": "sticky"; "required": false; "isSignal": true; }; "stickyTop": { "alias": "stickyTop"; "required": false; "isSignal": true; }; "searchMinWidth": { "alias": "searchMinWidth"; "required": false; "isSignal": true; }; "filtersLabel": { "alias": "filtersLabel"; "required": false; "isSignal": true; }; "activeCount": { "alias": "activeCount"; "required": false; "isSignal": true; }; "filtersExpanded": { "alias": "filtersExpanded"; "required": false; "isSignal": true; }; }, { "filtersClick": "filtersClick"; "modeChange": "modeChange"; "heightChange": "heightChange"; }, never, ["*", "[kf-toolbar-search]", "[kf-toolbar-filters]", "[kf-toolbar-end]"], true, never>;
|
|
2868
|
+
}
|
|
2869
|
+
|
|
1903
2870
|
/**
|
|
1904
2871
|
* Card de estadística/KPI: label, valor grande, ícono opcional en la esquina
|
|
1905
2872
|
* superior derecha, badge de esquina opcional (pegado al valor) y una nota
|
|
@@ -1921,6 +2888,14 @@ declare class Link {
|
|
|
1921
2888
|
* <kf-metric-card label="Saldo Pendiente" value="$45,000">
|
|
1922
2889
|
* <kf-button actions variant="primary" size="sm">Pagar Ahora</kf-button>
|
|
1923
2890
|
* </kf-metric-card>
|
|
2891
|
+
*
|
|
2892
|
+
* `loading` (default `false`): dibuja el esqueleto de la card — etiqueta,
|
|
2893
|
+
* ícono, valor y `foot` como bloques del alto real de cada línea — dentro del
|
|
2894
|
+
* mismo `kf-card`, y reserva (sin mostrar) el espacio de las acciones, así que
|
|
2895
|
+
* al llegar los datos no hay salto de layout. Pasa los mismos inputs que
|
|
2896
|
+
* usarás cargada. Marca el host con `aria-busy="true"`.
|
|
2897
|
+
*
|
|
2898
|
+
* <kf-metric-card label="Tickets abiertos" value="11" foot="+2 hoy" [loading]="isLoading()" />
|
|
1924
2899
|
*/
|
|
1925
2900
|
declare class MetricCard {
|
|
1926
2901
|
readonly label: _angular_core.InputSignal<string>;
|
|
@@ -1933,8 +2908,132 @@ declare class MetricCard {
|
|
|
1933
2908
|
readonly valueColor: _angular_core.InputSignal<string | undefined>;
|
|
1934
2909
|
/** Badge de esquina opcional, pegado al valor (ej. "+2%"). */
|
|
1935
2910
|
readonly badge: _angular_core.InputSignal<string | undefined>;
|
|
2911
|
+
/** Dibuja el esqueleto en lugar del contenido, conservando las dimensiones. */
|
|
2912
|
+
readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1936
2913
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MetricCard, never>;
|
|
1937
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MetricCard, "kf-metric-card", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "unit": { "alias": "unit"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "foot": { "alias": "foot"; "required": false; "isSignal": true; }; "valueColor": { "alias": "valueColor"; "required": false; "isSignal": true; }; "badge": { "alias": "badge"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
|
|
2914
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MetricCard, "kf-metric-card", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "unit": { "alias": "unit"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "foot": { "alias": "foot"; "required": false; "isSignal": true; }; "valueColor": { "alias": "valueColor"; "required": false; "isSignal": true; }; "badge": { "alias": "badge"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
/** Estado de avance de una etapa o hito; nunca se comunica solo con color. */
|
|
2918
|
+
type ProgressStatus = 'done' | 'current' | 'pending';
|
|
2919
|
+
declare const PROGRESS_STATUS: {
|
|
2920
|
+
readonly DONE: "done";
|
|
2921
|
+
readonly CURRENT: "current";
|
|
2922
|
+
readonly PENDING: "pending";
|
|
2923
|
+
};
|
|
2924
|
+
/**
|
|
2925
|
+
* Texto por defecto (español) de cada estado: el estado nunca se comunica solo
|
|
2926
|
+
* con color. Los componentes que lo muestran aceptan sus propios textos.
|
|
2927
|
+
*/
|
|
2928
|
+
declare const PROGRESS_STATUS_LABEL: {
|
|
2929
|
+
readonly done: "Completado";
|
|
2930
|
+
readonly current: "En curso";
|
|
2931
|
+
readonly pending: "Pendiente";
|
|
2932
|
+
};
|
|
2933
|
+
|
|
2934
|
+
/**
|
|
2935
|
+
* Hito de una etapa. `date` llega ya formateada; `exception` excluye el hito
|
|
2936
|
+
* del avance (se muestra en un bloque aparte y solo si ocurrió).
|
|
2937
|
+
*/
|
|
2938
|
+
interface MilestoneItem {
|
|
2939
|
+
id: string;
|
|
2940
|
+
label: string;
|
|
2941
|
+
done: boolean;
|
|
2942
|
+
date?: string;
|
|
2943
|
+
exception?: boolean;
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Etapa expandible de la línea de tiempo. `date` llega ya formateada y solo
|
|
2947
|
+
* aplica si la etapa está completada. Una etapa sin `items` no es expandible.
|
|
2948
|
+
*/
|
|
2949
|
+
interface MilestoneGroup {
|
|
2950
|
+
id: string;
|
|
2951
|
+
label: string;
|
|
2952
|
+
status: ProgressStatus;
|
|
2953
|
+
icon: IconName;
|
|
2954
|
+
date?: string;
|
|
2955
|
+
items: readonly MilestoneItem[];
|
|
2956
|
+
}
|
|
2957
|
+
/** Textos de `kf-milestone-timeline`; todos tienen valor por defecto en español. */
|
|
2958
|
+
interface MilestoneTimelineLabels {
|
|
2959
|
+
heading: string;
|
|
2960
|
+
expandAll: string;
|
|
2961
|
+
collapseAll: string;
|
|
2962
|
+
statusDone: string;
|
|
2963
|
+
statusPending: string;
|
|
2964
|
+
/** Texto de una etapa en curso; recibe los hitos completados y el total que cuenta en el avance. */
|
|
2965
|
+
currentMeta: (done: number, total: number) => string;
|
|
2966
|
+
/** Insignia del hito destacado como el siguiente a completar. */
|
|
2967
|
+
next: string;
|
|
2968
|
+
exceptionsTitle: string;
|
|
2969
|
+
noExceptions: string;
|
|
2970
|
+
/** Texto solo para lectores de pantalla tras un hito completado. */
|
|
2971
|
+
itemDone: string;
|
|
2972
|
+
/** Texto solo para lectores de pantalla tras un hito pendiente. */
|
|
2973
|
+
itemPending: string;
|
|
2974
|
+
}
|
|
2975
|
+
declare const DEFAULT_MILESTONE_TIMELINE_LABELS: MilestoneTimelineLabels;
|
|
2976
|
+
|
|
2977
|
+
/**
|
|
2978
|
+
* Línea de tiempo de etapas con hitos. Cada etapa es un encabezado expandible
|
|
2979
|
+
* (`aria-expanded`/`aria-controls`) con un panel de hitos y, si la etapa tiene
|
|
2980
|
+
* hitos de excepción, un bloque aparte que no cuenta en el avance. Una etapa
|
|
2981
|
+
* sin hitos es solo informativa (no es un botón).
|
|
2982
|
+
*
|
|
2983
|
+
* El estado nunca se comunica solo con color: cada etapa y cada hito llevan su
|
|
2984
|
+
* estado en texto (visible o solo para lectores de pantalla) y los nodos y
|
|
2985
|
+
* marcas lo dibujan también con la forma. Todos los textos salen de `labels`
|
|
2986
|
+
* (español por defecto) y las fechas llegan ya formateadas.
|
|
2987
|
+
*
|
|
2988
|
+
* El conector entre etapas se deriva del tamaño del nodo
|
|
2989
|
+
* (`--kf-status-node-size`, default `2.125rem`) y de la separación del
|
|
2990
|
+
* encabezado: cambiar el tamaño del nodo mueve la línea con él.
|
|
2991
|
+
*
|
|
2992
|
+
* <kf-milestone-timeline
|
|
2993
|
+
* [groups]="stages()"
|
|
2994
|
+
* [(expandedIds)]="expanded"
|
|
2995
|
+
* nextItemId="stage2-docs"
|
|
2996
|
+
* ariaLabel="Avance de la entrega"
|
|
2997
|
+
* [labels]="{ heading: 'Progress', expandAll: 'Expand all' }"
|
|
2998
|
+
* />
|
|
2999
|
+
*/
|
|
3000
|
+
declare class MilestoneTimeline {
|
|
3001
|
+
private readonly host;
|
|
3002
|
+
private readonly instanceId;
|
|
3003
|
+
readonly groups: _angular_core.InputSignal<readonly MilestoneGroup[]>;
|
|
3004
|
+
/** Ids de las etapas expandidas, two-way: `[(expandedIds)]`. El padre controla el estado inicial. */
|
|
3005
|
+
readonly expandedIds: _angular_core.ModelSignal<readonly string[]>;
|
|
3006
|
+
/** Id del hito que se destaca como el siguiente a completar. */
|
|
3007
|
+
readonly nextItemId: _angular_core.InputSignal<string | undefined>;
|
|
3008
|
+
/** Textos; los que no se pasen usan el español por defecto. */
|
|
3009
|
+
readonly labels: _angular_core.InputSignal<Partial<MilestoneTimelineLabels>>;
|
|
3010
|
+
/** Nombre accesible de la lista de etapas. */
|
|
3011
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
3012
|
+
/** Nivel (2-6) del título "Avance por etapa", para respetar el esquema de títulos de la página. */
|
|
3013
|
+
readonly headingLevel: _angular_core.InputSignal<2 | 3 | 4 | 5 | 6>;
|
|
3014
|
+
protected readonly text: _angular_core.Signal<MilestoneTimelineLabels>;
|
|
3015
|
+
protected readonly rows: _angular_core.Signal<{
|
|
3016
|
+
group: MilestoneGroup;
|
|
3017
|
+
main: MilestoneItem[];
|
|
3018
|
+
exceptions: MilestoneItem[];
|
|
3019
|
+
happened: MilestoneItem[];
|
|
3020
|
+
expandable: boolean;
|
|
3021
|
+
meta: string;
|
|
3022
|
+
}[]>;
|
|
3023
|
+
private readonly expandableIds;
|
|
3024
|
+
protected readonly hasExpandable: _angular_core.Signal<boolean>;
|
|
3025
|
+
protected readonly allExpanded: _angular_core.Signal<boolean>;
|
|
3026
|
+
protected isExpanded(groupId: string): boolean;
|
|
3027
|
+
protected headId(groupId: string): string;
|
|
3028
|
+
protected panelId(groupId: string): string;
|
|
3029
|
+
protected itemStatus(item: MilestoneItem): 'done' | 'pending';
|
|
3030
|
+
protected toggle(groupId: string): void;
|
|
3031
|
+
protected toggleAll(): void;
|
|
3032
|
+
/** Lleva el foco al encabezado de una etapa expandible; devuelve el elemento, o `null` si no existe o no es expandible. */
|
|
3033
|
+
focusGroup(groupId: string): HTMLElement | null;
|
|
3034
|
+
private metaOf;
|
|
3035
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MilestoneTimeline, never>;
|
|
3036
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MilestoneTimeline, "kf-milestone-timeline", never, { "groups": { "alias": "groups"; "required": true; "isSignal": true; }; "expandedIds": { "alias": "expandedIds"; "required": false; "isSignal": true; }; "nextItemId": { "alias": "nextItemId"; "required": false; "isSignal": true; }; "labels": { "alias": "labels"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "headingLevel": { "alias": "headingLevel"; "required": false; "isSignal": true; }; }, { "expandedIds": "expandedIdsChange"; }, never, never, true, never>;
|
|
1938
3037
|
}
|
|
1939
3038
|
|
|
1940
3039
|
/**
|
|
@@ -1974,6 +3073,27 @@ declare class MetricCard {
|
|
|
1974
3073
|
*
|
|
1975
3074
|
* <kf-link footer class="kf-modal__footer-start" disabled>Ver documento</kf-link>
|
|
1976
3075
|
* <kf-button footer (click)="open.set(false)">Cerrar</kf-button>
|
|
3076
|
+
*
|
|
3077
|
+
* ## Modal de listado (alto acotado, filtros fijos)
|
|
3078
|
+
* Para un diálogo con mucho contenido (ej. elegir un ítem entre cientos):
|
|
3079
|
+
* - `maxHeight` (ej. `"85vh"`) acota el panel; solo `.kf-modal__body` se
|
|
3080
|
+
* desplaza, el encabezado, la zona `[kf-modal-toolbar]` y el footer
|
|
3081
|
+
* quedan fijos.
|
|
3082
|
+
* - `[kf-modal-toolbar]`: zona FIJA entre el encabezado y el cuerpo, para
|
|
3083
|
+
* buscador y filtros.
|
|
3084
|
+
* - `[kf-modal-meta]`: dato corto junto al título (ej. "12 de 86").
|
|
3085
|
+
* - `fullscreenOnMobile`: hasta 640px de viewport ocupa toda la pantalla
|
|
3086
|
+
* (`100dvh`, sin radio).
|
|
3087
|
+
* - `initialFocus`: selector CSS del elemento que recibe el foco al abrir
|
|
3088
|
+
* (si apunta a un contenedor, se enfoca su primer control). Sin él, el
|
|
3089
|
+
* `<dialog>` nativo decide (`autofocus` o el primer control).
|
|
3090
|
+
*
|
|
3091
|
+
* <kf-modal [(open)]="open" title="Cambiar cotización" width="1040px"
|
|
3092
|
+
* maxHeight="85vh" fullscreenOnMobile initialFocus=".search">
|
|
3093
|
+
* <span kf-modal-meta aria-live="polite">12 de 86</span>
|
|
3094
|
+
* <div kf-modal-toolbar><kf-input class="search" … /></div>
|
|
3095
|
+
* <ul>…</ul>
|
|
3096
|
+
* </kf-modal>
|
|
1977
3097
|
*/
|
|
1978
3098
|
declare class Modal {
|
|
1979
3099
|
readonly title: _angular_core.InputSignal<string>;
|
|
@@ -1986,11 +3106,26 @@ declare class Modal {
|
|
|
1986
3106
|
* más, ej. `width="720px"` — sigue topeado por `100vw` en pantallas
|
|
1987
3107
|
* angostas, mismo `min()` de siempre. */
|
|
1988
3108
|
readonly width: _angular_core.InputSignal<string | null>;
|
|
3109
|
+
/** Alto máximo del panel (ej. `"85vh"`); con valor, solo el cuerpo se
|
|
3110
|
+
* desplaza. Sin valor (default) el panel crece con su contenido. */
|
|
3111
|
+
readonly maxHeight: _angular_core.InputSignal<string | null>;
|
|
3112
|
+
/** Hasta 640px de viewport, ocupa toda la pantalla (100dvh, sin radio). */
|
|
3113
|
+
readonly fullscreenOnMobile: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
3114
|
+
/** Selector CSS (dentro del panel) del elemento a enfocar al abrir. */
|
|
3115
|
+
readonly initialFocus: _angular_core.InputSignal<string | null>;
|
|
1989
3116
|
protected readonly titleId: string;
|
|
1990
3117
|
private readonly dialog;
|
|
3118
|
+
private readonly panel;
|
|
1991
3119
|
private readonly document;
|
|
1992
3120
|
private readonly overlayContainer;
|
|
1993
3121
|
constructor();
|
|
3122
|
+
/**
|
|
3123
|
+
* Enfoca `initialFocus` DESPUÉS de `showModal()` (que ya movió el foco al
|
|
3124
|
+
* primer control): un elemento dentro de un `<dialog>` cerrado no se puede
|
|
3125
|
+
* enfocar. Si el selector apunta a un host (ej. `kf-input`), se enfoca su
|
|
3126
|
+
* primer control interno.
|
|
3127
|
+
*/
|
|
3128
|
+
private focusInitial;
|
|
1994
3129
|
/** `Escape` dispara `cancel`; cancelarlo lo deja abierto. */
|
|
1995
3130
|
protected onCancel(event: Event): void;
|
|
1996
3131
|
/**
|
|
@@ -2004,7 +3139,7 @@ declare class Modal {
|
|
|
2004
3139
|
*/
|
|
2005
3140
|
protected onHostClick(event: MouseEvent): void;
|
|
2006
3141
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Modal, never>;
|
|
2007
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Modal, "kf-modal", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["*", "[footer]"], true, never>;
|
|
3142
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Modal, "kf-modal", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "fullscreenOnMobile": { "alias": "fullscreenOnMobile"; "required": false; "isSignal": true; }; "initialFocus": { "alias": "initialFocus"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["[kf-modal-meta]", "[kf-modal-toolbar]", "*", "[footer]"], true, never>;
|
|
2008
3143
|
}
|
|
2009
3144
|
|
|
2010
3145
|
/** Color de la franja izquierda y del fondo. */
|
|
@@ -2026,6 +3161,84 @@ declare class NoteBlock {
|
|
|
2026
3161
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NoteBlock, "kf-note-block", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; "signature": { "alias": "signature"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
2027
3162
|
}
|
|
2028
3163
|
|
|
3164
|
+
/** Opción de `kf-option-list`. `count` se muestra alineado a la derecha. */
|
|
3165
|
+
interface OptionListOption {
|
|
3166
|
+
value: string;
|
|
3167
|
+
label: string;
|
|
3168
|
+
count?: number;
|
|
3169
|
+
}
|
|
3170
|
+
/**
|
|
3171
|
+
* Lista vertical de opciones de UNA sola selección para paneles (ej. las
|
|
3172
|
+
* secciones "Estado", "Ordenar por" y "Vista" de un panel de filtros): una
|
|
3173
|
+
* fila de al menos 44px por opción, contador opcional a la derecha y la
|
|
3174
|
+
* opción elegida resaltada con `--kf-color-primary-soft`.
|
|
3175
|
+
*
|
|
3176
|
+
* Es la contraparte en panel de `kf-filter-chips`: misma función (filtrar u
|
|
3177
|
+
* ordenar lo que se muestra) cuando no hay ancho para una fila de chips. No
|
|
3178
|
+
* es `kf-selectable-card-group`: aquel responde una pregunta de un flujo
|
|
3179
|
+
* ("¿con qué método pagas?") con affordance de radio y cards grandes; esta
|
|
3180
|
+
* lista ajusta una vista, con filas densas y contador.
|
|
3181
|
+
*
|
|
3182
|
+
* Semántica: `role="radiogroup"` + `role="radio"` con `aria-checked`, no
|
|
3183
|
+
* botones con `aria-pressed`. Las opciones son mutuamente excluyentes (eso
|
|
3184
|
+
* es un radio; `aria-pressed` describe toggles independientes), el lector
|
|
3185
|
+
* de pantalla anuncia la posición ("2 de 4") y cada grupo es UNA sola
|
|
3186
|
+
* parada de Tab: un panel con tres secciones se recorre con 3 Tabs en vez
|
|
3187
|
+
* de uno por opción. Dentro del grupo, flechas arriba/abajo y Home/End
|
|
3188
|
+
* mueven el foco y seleccionan (`handleArrowKeyNavigation`, mismo helper que
|
|
3189
|
+
* `kf-tabs`/`kf-selectable-card-group`).
|
|
3190
|
+
*
|
|
3191
|
+
* La opción elegida lleva además un check (no solo color), para que el
|
|
3192
|
+
* estado no dependa de distinguir el tinte `primary-soft` (WCAG 1.4.1).
|
|
3193
|
+
*
|
|
3194
|
+
* El `@for` hace `track` por índice: cuando el padre re-renderiza (ej. los
|
|
3195
|
+
* contadores cambian al elegir), los botones existentes se reutilizan y el
|
|
3196
|
+
* foco no se pierde. Por índice y no por `value` para no fallar (NG0955)
|
|
3197
|
+
* si dos opciones repiten `value`; aun así los values deben ser únicos:
|
|
3198
|
+
* con repetidos, ambas filas se marcan elegidas.
|
|
3199
|
+
*
|
|
3200
|
+
* `label` dibuja el título de la sección (chico, en mayúsculas) y nombra el
|
|
3201
|
+
* grupo vía `aria-labelledby`; sin título visible, pasar `ariaLabel`.
|
|
3202
|
+
*
|
|
3203
|
+
* <kf-option-list label="Estado"
|
|
3204
|
+
* [options]="[{ value: '', label: 'Todas', count: 12 },
|
|
3205
|
+
* { value: 'pending', label: 'Pendientes', count: 3 }]"
|
|
3206
|
+
* [value]="status()"
|
|
3207
|
+
* (valueChange)="status.set($event)" />
|
|
3208
|
+
*/
|
|
3209
|
+
declare class OptionList {
|
|
3210
|
+
readonly options: _angular_core.InputSignal<(string | OptionListOption)[]>;
|
|
3211
|
+
readonly value: _angular_core.InputSignal<string>;
|
|
3212
|
+
/** Título visible de la sección; nombra el grupo. */
|
|
3213
|
+
readonly label: _angular_core.InputSignal<string | undefined>;
|
|
3214
|
+
/** Nombre accesible del grupo cuando no hay `label` visible. */
|
|
3215
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
3216
|
+
readonly valueChange: _angular_core.OutputEmitterRef<string>;
|
|
3217
|
+
private readonly instanceId;
|
|
3218
|
+
protected readonly labelId: string;
|
|
3219
|
+
/**
|
|
3220
|
+
* Prefijo de id de cada opción — único por instancia (dos listas con los
|
|
3221
|
+
* mismos values no colisionan). El id termina en el ÍNDICE, no en el
|
|
3222
|
+
* value: un value con espacios u otros caracteres daría un id inválido.
|
|
3223
|
+
*/
|
|
3224
|
+
protected readonly optionIdPrefix: string;
|
|
3225
|
+
readonly normalizedOptions: _angular_core.Signal<OptionListOption[]>;
|
|
3226
|
+
/**
|
|
3227
|
+
* Opción que recibe `tabindex="0"`: la seleccionada o, si ninguna lo
|
|
3228
|
+
* está, la primera — el grupo siempre debe ser alcanzable con Tab.
|
|
3229
|
+
*/
|
|
3230
|
+
protected readonly tabStopValue: _angular_core.Signal<string>;
|
|
3231
|
+
select(value: string): void;
|
|
3232
|
+
/**
|
|
3233
|
+
* `handleArrowKeyNavigation` ubica el botón destino por `idPrefix + value`;
|
|
3234
|
+
* como los ids usan el índice, se le pasa la lista con el índice como
|
|
3235
|
+
* value y se traduce de vuelta al value real al seleccionar.
|
|
3236
|
+
*/
|
|
3237
|
+
protected onKeydown(event: KeyboardEvent, index: number): void;
|
|
3238
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OptionList, never>;
|
|
3239
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OptionList, "kf-option-list", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
3240
|
+
}
|
|
3241
|
+
|
|
2029
3242
|
type TextAs = 'h1' | 'h2' | 'h3' | 'p' | 'span';
|
|
2030
3243
|
type TextVariant = 'title-xxl' | 'title-xl' | 'title-lg' | 'title-md' | 'title-sm' | 'body' | 'body-muted' | 'caption' | 'overline' | 'overline-strong';
|
|
2031
3244
|
type TextTone = 'neutral' | 'ok' | 'warn' | 'error' | 'info';
|
|
@@ -2217,6 +3430,140 @@ declare class Panel {
|
|
|
2217
3430
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Panel, "kf-panel", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "actionLabel": { "alias": "actionLabel"; "required": false; "isSignal": true; }; "actionHref": { "alias": "actionHref"; "required": false; "isSignal": true; }; }, { "actionClick": "actionClick"; }, never, ["*"], true, never>;
|
|
2218
3431
|
}
|
|
2219
3432
|
|
|
3433
|
+
type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
3434
|
+
/**
|
|
3435
|
+
* Popover de contenido enriquecido anclado a un elemento — la contraparte de
|
|
3436
|
+
* `kfTooltip` para cuando el texto plano no alcanza (varias líneas, énfasis,
|
|
3437
|
+
* un desglose, enlaces). Mismo mecanismo de `@angular/cdk/overlay`. El host
|
|
3438
|
+
* sigue siendo el elemento que recibe el foco: la directiva no lo hace
|
|
3439
|
+
* focusable, así que va sobre un `<button>`, un `<a>` o un elemento con
|
|
3440
|
+
* `tabindex="0"`.
|
|
3441
|
+
*
|
|
3442
|
+
* <button [kfPopover]="detail" kfPopoverPlacement="top">Etapa</button>
|
|
3443
|
+
* <ng-template #detail><strong>Recepción</strong><p>Completada el 12/05.</p></ng-template>
|
|
3444
|
+
*
|
|
3445
|
+
* Apertura: puntero (hover, tras `kfPopoverShowDelay` ms; NO se abre con puntero
|
|
3446
|
+
* táctil) y foco de teclado (al instante, solo si el foco es visible: un
|
|
3447
|
+
* clic con el mouse no lo abre). Cierre: Escape (descarta el panel hasta que
|
|
3448
|
+
* el puntero y el foco salgan y vuelvan), salida del puntero tras
|
|
3449
|
+
* `kfPopoverHideDelay` ms, pérdida de foco, scroll de cualquier contenedor y
|
|
3450
|
+
* redimensionado de la ventana. El panel se reposiciona dentro del viewport
|
|
3451
|
+
* (invierte el lado si no cabe).
|
|
3452
|
+
*
|
|
3453
|
+
* Con `kfPopoverInteractive`, el puntero puede entrar al panel sin cerrarlo y
|
|
3454
|
+
* el panel es un `dialog` no modal: Tab desde el anfitrión entra al primer
|
|
3455
|
+
* control del panel y Mayús+Tab desde ese control vuelve al anfitrión. Sin
|
|
3456
|
+
* `kfPopoverInteractive` (default), el panel es un `tooltip` que no captura
|
|
3457
|
+
* el puntero y no debe contener controles.
|
|
3458
|
+
*
|
|
3459
|
+
* Si el anfitrión no es interactivo pero vive dentro de un control (un botón,
|
|
3460
|
+
* un enlace, un elemento con `tabindex`), los eventos de puntero, foco y
|
|
3461
|
+
* teclado se escuchan en ese control y el panel se ancla al anfitrión. Es el
|
|
3462
|
+
* caso de un indicador dentro de una celda interactiva de `kf-data-table`:
|
|
3463
|
+
*
|
|
3464
|
+
* <ng-template #stageCell let-row>
|
|
3465
|
+
* <span [kfPopover]="detail"><kf-status-mark [status]="row.status" /></span>
|
|
3466
|
+
* </ng-template>
|
|
3467
|
+
*
|
|
3468
|
+
* Accesibilidad: mientras está abierto, el elemento que recibe el foco
|
|
3469
|
+
* referencia el panel con `aria-describedby` (se conserva cualquier valor
|
|
3470
|
+
* previo).
|
|
3471
|
+
*/
|
|
3472
|
+
declare class PopoverDirective implements OnDestroy {
|
|
3473
|
+
/** Contenido del popover (un `ng-template`). `null`/`undefined` = no se abre. */
|
|
3474
|
+
readonly kfPopover: _angular_core.InputSignal<TemplateRef<unknown> | null | undefined>;
|
|
3475
|
+
/** Lado preferido; si no cabe en el viewport, se invierte. Default `bottom`. */
|
|
3476
|
+
readonly kfPopoverPlacement: _angular_core.InputSignal<PopoverPlacement>;
|
|
3477
|
+
/** Retardo (ms) antes de abrir con el puntero. El foco de teclado abre sin retardo. */
|
|
3478
|
+
readonly kfPopoverShowDelay: _angular_core.InputSignalWithTransform<number, unknown>;
|
|
3479
|
+
/** Retardo (ms) antes de cerrar al salir el puntero. */
|
|
3480
|
+
readonly kfPopoverHideDelay: _angular_core.InputSignalWithTransform<number, unknown>;
|
|
3481
|
+
/** Desactiva el popover (y lo cierra si estaba abierto). */
|
|
3482
|
+
readonly kfPopoverDisabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
3483
|
+
/** Permite que el puntero entre al panel sin cerrarlo y que el teclado llegue a sus controles. */
|
|
3484
|
+
readonly kfPopoverInteractive: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
3485
|
+
/** Nombre accesible del panel cuando es `interactive` (rol `dialog`). */
|
|
3486
|
+
readonly kfPopoverLabel: _angular_core.InputSignal<string | null>;
|
|
3487
|
+
/** Emite `true` al abrirse y `false` al cerrarse. */
|
|
3488
|
+
readonly kfPopoverOpenChange: _angular_core.OutputEmitterRef<boolean>;
|
|
3489
|
+
private readonly host;
|
|
3490
|
+
private readonly overlayService;
|
|
3491
|
+
private readonly viewContainerRef;
|
|
3492
|
+
private readonly injector;
|
|
3493
|
+
private readonly document;
|
|
3494
|
+
private readonly destroyRef;
|
|
3495
|
+
private readonly panelId;
|
|
3496
|
+
private readonly openState;
|
|
3497
|
+
/** `true` mientras el panel está abierto. */
|
|
3498
|
+
readonly isOpen: _angular_core.Signal<boolean>;
|
|
3499
|
+
/**
|
|
3500
|
+
* Elemento que recibe los eventos de puntero, foco y teclado: el propio
|
|
3501
|
+
* anfitrión o, si este no es interactivo pero vive dentro de un control
|
|
3502
|
+
* (botón, enlace, `tabindex`), ese control. `aria-describedby` va en él.
|
|
3503
|
+
*/
|
|
3504
|
+
private trigger;
|
|
3505
|
+
private overlayRef;
|
|
3506
|
+
private panelElement;
|
|
3507
|
+
private showTimer;
|
|
3508
|
+
private hideTimer;
|
|
3509
|
+
private openedAt;
|
|
3510
|
+
private teardownGlobalListeners;
|
|
3511
|
+
private destroyed;
|
|
3512
|
+
private pointerOnHost;
|
|
3513
|
+
private pointerOnPanel;
|
|
3514
|
+
private focusOnHost;
|
|
3515
|
+
private focusOnPanel;
|
|
3516
|
+
/** Escape lo descartó: no reabre hasta que puntero y foco hayan salido. */
|
|
3517
|
+
private dismissed;
|
|
3518
|
+
constructor();
|
|
3519
|
+
ngOnDestroy(): void;
|
|
3520
|
+
/** Cierra el panel de inmediato, sin retardo. */
|
|
3521
|
+
close(): void;
|
|
3522
|
+
private readonly onHostPointerEnter;
|
|
3523
|
+
private readonly onHostPointerLeave;
|
|
3524
|
+
private readonly onHostFocusIn;
|
|
3525
|
+
private readonly onHostFocusOut;
|
|
3526
|
+
private readonly onHostKeydown;
|
|
3527
|
+
private get wanted();
|
|
3528
|
+
/** Abre o cierra según los cuatro orígenes (puntero/foco × anfitrión/panel). */
|
|
3529
|
+
private reevaluate;
|
|
3530
|
+
private scheduleOpen;
|
|
3531
|
+
private scheduleClose;
|
|
3532
|
+
private open;
|
|
3533
|
+
private dispose;
|
|
3534
|
+
private onPanelFocusOut;
|
|
3535
|
+
/** Mayús+Tab desde el primer control del panel devuelve el foco al anfitrión. */
|
|
3536
|
+
private readonly onPanelKeydown;
|
|
3537
|
+
private focusHost;
|
|
3538
|
+
/**
|
|
3539
|
+
* Escape, scroll y resize mientras el panel está abierto. En fase de captura
|
|
3540
|
+
* y sobre `document`: `scroll` no burbujea (hay que capturarlo para ver el
|
|
3541
|
+
* de cualquier contenedor) y Escape debe cerrar primero el popover sin
|
|
3542
|
+
* llegar al modal o drawer que lo contenga.
|
|
3543
|
+
*/
|
|
3544
|
+
private listenGlobal;
|
|
3545
|
+
private resolveTrigger;
|
|
3546
|
+
/** Foco de teclado (`:focus-visible`); sin soporte del selector, se asume teclado. */
|
|
3547
|
+
private isKeyboardFocus;
|
|
3548
|
+
private addDescribedBy;
|
|
3549
|
+
private removeDescribedBy;
|
|
3550
|
+
private describedByTokens;
|
|
3551
|
+
private clearShowTimer;
|
|
3552
|
+
private clearHideTimer;
|
|
3553
|
+
private clearTimers;
|
|
3554
|
+
/**
|
|
3555
|
+
* Posiciones en orden de preferencia: el lado pedido (centrado, luego
|
|
3556
|
+
* alineado al inicio y al final del anfitrión), el lado opuesto con las
|
|
3557
|
+
* mismas tres alineaciones y, por último, los dos lados perpendiculares.
|
|
3558
|
+
* Así un anfitrión pegado a una esquina encuentra una posición que cabe
|
|
3559
|
+
* entera en vez de depender solo del empuje al viewport.
|
|
3560
|
+
*/
|
|
3561
|
+
private positionsFor;
|
|
3562
|
+
private positionFor;
|
|
3563
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PopoverDirective, never>;
|
|
3564
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<PopoverDirective, "[kfPopover]", ["kfPopover"], { "kfPopover": { "alias": "kfPopover"; "required": true; "isSignal": true; }; "kfPopoverPlacement": { "alias": "kfPopoverPlacement"; "required": false; "isSignal": true; }; "kfPopoverShowDelay": { "alias": "kfPopoverShowDelay"; "required": false; "isSignal": true; }; "kfPopoverHideDelay": { "alias": "kfPopoverHideDelay"; "required": false; "isSignal": true; }; "kfPopoverDisabled": { "alias": "kfPopoverDisabled"; "required": false; "isSignal": true; }; "kfPopoverInteractive": { "alias": "kfPopoverInteractive"; "required": false; "isSignal": true; }; "kfPopoverLabel": { "alias": "kfPopoverLabel"; "required": false; "isSignal": true; }; }, { "kfPopoverOpenChange": "kfPopoverOpenChange"; }, never, never, true, never>;
|
|
3565
|
+
}
|
|
3566
|
+
|
|
2220
3567
|
/** Un ítem de navegación de la barra de marca. `icon` es opcional y solo se
|
|
2221
3568
|
* usa en el drawer mobile (columna, ver template) — el `<nav>` horizontal de
|
|
2222
3569
|
* escritorio se mantiene solo texto, sin ícono ni chevron. */
|
|
@@ -2351,9 +3698,12 @@ declare class PortalHeader {
|
|
|
2351
3698
|
* que no aplican a un valor de progreso): `neutral` es el color de marca
|
|
2352
3699
|
* por defecto (sin implicar buen/mal estado), `primary` es el color
|
|
2353
3700
|
* primario para un avance de proceso (ej. una carga), y `ok`/`warn`/`error`
|
|
2354
|
-
* sí comunican severidad.
|
|
3701
|
+
* sí comunican severidad. `purple` es el acento morado de marca, igual al tono
|
|
3702
|
+
* `purple` de `kf-stat-card`. La librería no conoce el dominio que produce ese
|
|
2355
3703
|
* valor (SLA, storage, lo que sea) — el consumidor decide qué tone usar. */
|
|
2356
|
-
type ProgressTone = 'neutral' | 'primary' | 'ok' | 'warn' | 'error';
|
|
3704
|
+
type ProgressTone = 'neutral' | 'primary' | 'ok' | 'warn' | 'error' | 'purple';
|
|
3705
|
+
/** Grosor de la pista: `sm` 4px (el histórico), `md` 8px, `lg` 12px. */
|
|
3706
|
+
type ProgressSize = 'sm' | 'md' | 'lg';
|
|
2357
3707
|
/**
|
|
2358
3708
|
* Barra de progreso de un solo valor (0-100%) con color por severidad —
|
|
2359
3709
|
* para un porcentaje simple, a diferencia de `kf-bucket-progress`, que
|
|
@@ -2364,16 +3714,24 @@ type ProgressTone = 'neutral' | 'primary' | 'ok' | 'warn' | 'error';
|
|
|
2364
3714
|
*
|
|
2365
3715
|
* `value` se clampea a [0, 100] — un consumidor que calcule un ratio fuera
|
|
2366
3716
|
* de rango (ej. tiempo transcurrido sobre un SLA ya vencido) no rompe el
|
|
2367
|
-
* ancho de la barra. `
|
|
3717
|
+
* ancho de la barra. `size` cambia el grosor de la pista (`sm` 4px, `md` 8px,
|
|
3718
|
+
* `lg` 12px; sin él, 4px como siempre); el `role="progressbar"` y sus valores
|
|
3719
|
+
* accesibles no cambian. `label` es texto libre opcional sobre la barra (ej.
|
|
2368
3720
|
* "80%"); sin él, no se renderiza ningún texto, solo la barra.
|
|
2369
3721
|
*/
|
|
2370
3722
|
declare class Progress {
|
|
2371
3723
|
readonly value: _angular_core.InputSignal<number>;
|
|
2372
3724
|
readonly tone: _angular_core.InputSignal<ProgressTone>;
|
|
3725
|
+
/** Grosor de la pista. Default `sm` (4px). */
|
|
3726
|
+
readonly size: _angular_core.InputSignal<ProgressSize>;
|
|
2373
3727
|
readonly label: _angular_core.InputSignal<string | undefined>;
|
|
3728
|
+
/** Nombre accesible de la barra (`aria-label`). Sin él, el `progressbar`
|
|
3729
|
+
* queda sin nombre: dalo siempre que el contexto no lo nombre ya (por
|
|
3730
|
+
* ejemplo con un `label` visible asociado). */
|
|
3731
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
2374
3732
|
protected readonly clampedValue: _angular_core.Signal<number>;
|
|
2375
3733
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Progress, never>;
|
|
2376
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Progress, "kf-progress", never, { "value": { "alias": "value"; "required": true; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
3734
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Progress, "kf-progress", never, { "value": { "alias": "value"; "required": true; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2377
3735
|
}
|
|
2378
3736
|
|
|
2379
3737
|
/**
|
|
@@ -2632,12 +3990,16 @@ declare class Segmented {
|
|
|
2632
3990
|
* Opción en forma de objeto. `tag` se muestra como `kf-badge` a la derecha
|
|
2633
3991
|
* del label (en el panel y en el trigger) y `detail` como línea secundaria
|
|
2634
3992
|
* atenuada debajo, solo en el panel. Ambos entran en la búsqueda.
|
|
3993
|
+
* `shortLabel` reemplaza al label SOLO en el trigger (ej. panel "Más
|
|
3994
|
+
* recientes primero", trigger "Más recientes") — para triggers compactos
|
|
3995
|
+
* donde el label completo se truncaría.
|
|
2635
3996
|
*/
|
|
2636
3997
|
interface SelectOption {
|
|
2637
3998
|
value: string;
|
|
2638
3999
|
label: string;
|
|
2639
4000
|
tag?: string;
|
|
2640
4001
|
detail?: string;
|
|
4002
|
+
shortLabel?: string;
|
|
2641
4003
|
}
|
|
2642
4004
|
/**
|
|
2643
4005
|
* Dropdown de selección simple con panel propio — NUNCA usa el `<select>`
|
|
@@ -2667,6 +4029,25 @@ interface SelectOption {
|
|
|
2667
4029
|
* layouts flex/grid donde el ancho fijo de `md` no encaja.
|
|
2668
4030
|
*
|
|
2669
4031
|
* <kf-select width="full" [options]="branches" [value]="branch()" (valueChange)="..." />
|
|
4032
|
+
*
|
|
4033
|
+
* Control de orden de una barra de herramientas (ícono + valor + caret, sin
|
|
4034
|
+
* label visible): `icon` agrega un glifo `sm` a la izquierda del valor,
|
|
4035
|
+
* `ariaLabel` da el nombre accesible (el trigger se anuncia como
|
|
4036
|
+
* `"<ariaLabel>: <valor actual>"`), `panelTitle` agrega un título chico en
|
|
4037
|
+
* mayúsculas dentro del panel (decorativo, `aria-hidden`) y
|
|
4038
|
+
* `panelWidth="content"` deja que el panel crezca hasta el ancho de sus
|
|
4039
|
+
* opciones en vez de truncarlas al ancho del trigger compacto.
|
|
4040
|
+
*
|
|
4041
|
+
* <kf-select variant="compact" icon="sort" ariaLabel="Ordenar por"
|
|
4042
|
+
* panelTitle="Ordenar por" panelWidth="content"
|
|
4043
|
+
* [options]="sortOptions" [value]="sort()" (valueChange)="sort.set($event)" />
|
|
4044
|
+
*
|
|
4045
|
+
* Teclado (patrón listbox de WAI-ARIA): ArrowDown/ArrowUp sobre el trigger
|
|
4046
|
+
* cerrado lo abren; al abrir, el foco pasa a la opción seleccionada (o al
|
|
4047
|
+
* buscador, si está visible). En el panel, flechas y Home/End mueven el
|
|
4048
|
+
* foco, Enter/Espacio eligen, Escape cierra y devuelve el foco al trigger,
|
|
4049
|
+
* y Tab cierra el panel y continúa la tabulación desde el trigger. Las
|
|
4050
|
+
* opciones nunca son paradas de Tab (`tabindex="-1"`).
|
|
2670
4051
|
*/
|
|
2671
4052
|
declare class Select {
|
|
2672
4053
|
readonly label: _angular_core.InputSignal<string | undefined>;
|
|
@@ -2694,6 +4075,26 @@ declare class Select {
|
|
|
2694
4075
|
*/
|
|
2695
4076
|
readonly searchable: _angular_core.InputSignal<boolean | undefined>;
|
|
2696
4077
|
readonly searchThreshold: _angular_core.InputSignal<number>;
|
|
4078
|
+
/**
|
|
4079
|
+
* Nombre accesible del control cuando no hay `label` visible (ej. "Ordenar
|
|
4080
|
+
* por"). El trigger se anuncia como `"<ariaLabel>: <valor visible>"` (el
|
|
4081
|
+
* mismo texto que muestra el trigger, `shortLabel` si la opción lo trae),
|
|
4082
|
+
* así el nombre contiene el texto visible (WCAG 2.5.3) y además dice qué se
|
|
4083
|
+
* está eligiendo. Ignorado si hay `label`: un `aria-label` pisaría al
|
|
4084
|
+
* `<label for>` visible.
|
|
4085
|
+
*/
|
|
4086
|
+
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
4087
|
+
/** Ícono `sm` a la izquierda del valor en el trigger (ej. `'sort'`). */
|
|
4088
|
+
readonly icon: _angular_core.InputSignal<IconName | undefined>;
|
|
4089
|
+
/** Título chico en mayúsculas dentro del panel, sobre las opciones. Decorativo (`aria-hidden`): el nombre del listbox ya lo da `ariaLabel`/`label`. */
|
|
4090
|
+
readonly panelTitle: _angular_core.InputSignal<string | undefined>;
|
|
4091
|
+
/**
|
|
4092
|
+
* `'trigger'` (default): el panel mide lo mismo que el trigger.
|
|
4093
|
+
* `'content'`: el trigger es el ancho mínimo y el panel crece hasta el
|
|
4094
|
+
* ancho de la opción más larga — para triggers compactos cuyas opciones
|
|
4095
|
+
* son más largas que el valor resumido.
|
|
4096
|
+
*/
|
|
4097
|
+
readonly panelWidth: _angular_core.InputSignal<"content" | "trigger">;
|
|
2697
4098
|
readonly valueChange: _angular_core.OutputEmitterRef<string>;
|
|
2698
4099
|
private readonly instanceId;
|
|
2699
4100
|
readonly triggerId: string;
|
|
@@ -2705,22 +4106,68 @@ declare class Select {
|
|
|
2705
4106
|
/** Resolves `string | SelectOption` entries into a single shape for the template. */
|
|
2706
4107
|
readonly normalizedOptions: _angular_core.Signal<SelectOption[]>;
|
|
2707
4108
|
readonly selectedOption: _angular_core.Signal<SelectOption | undefined>;
|
|
4109
|
+
/** Texto que muestra el trigger: `shortLabel` o `label` de la opción elegida, o el placeholder. */
|
|
4110
|
+
readonly triggerText: _angular_core.Signal<string>;
|
|
4111
|
+
/**
|
|
4112
|
+
* `aria-label` del trigger: solo con `ariaLabel` y SIN `label` visible. Un
|
|
4113
|
+
* `aria-label` tiene prioridad sobre el `<label for>` en el cálculo del
|
|
4114
|
+
* nombre accesible, así que con label visible no se emite.
|
|
4115
|
+
*/
|
|
4116
|
+
readonly triggerAriaLabel: _angular_core.Signal<string | null>;
|
|
2708
4117
|
readonly showSearch: _angular_core.Signal<boolean>;
|
|
2709
4118
|
/** Opciones visibles tras aplicar el filtro de búsqueda (case/acento-insensitive). */
|
|
2710
4119
|
readonly filteredOptions: _angular_core.Signal<SelectOption[]>;
|
|
2711
4120
|
private readonly triggerRef;
|
|
2712
4121
|
private readonly panelTemplate;
|
|
2713
4122
|
private readonly searchInputRef;
|
|
4123
|
+
private readonly panelRef;
|
|
4124
|
+
private readonly document;
|
|
2714
4125
|
private readonly overlay;
|
|
2715
4126
|
constructor();
|
|
2716
4127
|
/**
|
|
2717
|
-
*
|
|
2718
|
-
*
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
4128
|
+
* Escape con el panel abierto, escuchado en fase de captura sobre
|
|
4129
|
+
* `document` (ver `listenEscapeCapture`). Respaldo de
|
|
4130
|
+
* `overlayRef.keydownEvents()`: ese observable del CDK solo ve teclas
|
|
4131
|
+
* presionadas con el foco DENTRO del pane del overlay; si el foco sigue en
|
|
4132
|
+
* el trigger (o en cualquier otro lado) mientras el panel está abierto,
|
|
4133
|
+
* nunca dispara. Consume la tecla (`preventDefault`) solo si había un
|
|
4134
|
+
* panel que cerrar, así un `kf-drawer`/`kf-modal` que contenga al select
|
|
4135
|
+
* no se cierra con el mismo Escape. Devuelve si cerró algo.
|
|
2721
4136
|
*/
|
|
2722
|
-
onDocumentEscape():
|
|
4137
|
+
onDocumentEscape(): boolean;
|
|
2723
4138
|
toggle(): void;
|
|
4139
|
+
/** Abre el panel con la opción seleccionada como activa (o la primera). */
|
|
4140
|
+
open(): void;
|
|
4141
|
+
/**
|
|
4142
|
+
* Cierra el panel. `restoreFocus` (default: solo si el foco está dentro
|
|
4143
|
+
* del panel) devuelve el foco al trigger ANTES de desmontar el panel —
|
|
4144
|
+
* si no, el elemento enfocado desaparece y el foco cae al `<body>`. Un
|
|
4145
|
+
* click afuera no lo restaura: el foco ya se fue a donde se hizo click.
|
|
4146
|
+
*/
|
|
4147
|
+
close(restoreFocus?: boolean): void;
|
|
4148
|
+
/** ArrowDown/ArrowUp con el panel cerrado lo abren (patrón listbox). */
|
|
4149
|
+
onTriggerKeydown(event: KeyboardEvent): void;
|
|
4150
|
+
/**
|
|
4151
|
+
* Teclado con el foco en una opción del panel. Las flechas parten SIEMPRE
|
|
4152
|
+
* de la opción que recibió el evento (`index`), no de `activeIndex`: el
|
|
4153
|
+
* `mouseenter` mueve `activeIndex` sin mover el foco, y sin esto, con el
|
|
4154
|
+
* foco en la opción 1 y el mouse sobre la 4, ArrowDown saltaría a la 5.
|
|
4155
|
+
*/
|
|
4156
|
+
onOptionKeydown(event: KeyboardEvent, option: SelectOption, index: number): void;
|
|
4157
|
+
/** Teclas de salida del buscador: Escape y Tab, igual que desde una opción. */
|
|
4158
|
+
onSearchKeydown(event: KeyboardEvent): void;
|
|
4159
|
+
/**
|
|
4160
|
+
* Escape cierra y devuelve el foco al trigger; `preventDefault` le avisa a
|
|
4161
|
+
* un contenedor que también escucha Escape (ej. `kf-drawer`) que la tecla
|
|
4162
|
+
* ya se consumió. Tab cierra y mueve el foco al trigger SIN
|
|
4163
|
+
* `preventDefault`: la tabulación nativa continúa desde el trigger, así
|
|
4164
|
+
* Tab/Shift+Tab salen del panel hacia el control siguiente/anterior.
|
|
4165
|
+
*/
|
|
4166
|
+
private handleExitKeys;
|
|
4167
|
+
private focusOption;
|
|
4168
|
+
private isFocusInPanel;
|
|
4169
|
+
/** Id de cada opción, para `aria-activedescendant` del buscador. */
|
|
4170
|
+
optionId(index: number): string;
|
|
2724
4171
|
/** Nombre accesible explícito solo para opciones con `tag`/`detail`, para separar las partes al leerlas. */
|
|
2725
4172
|
optionAriaLabel(option: SelectOption): string | null;
|
|
2726
4173
|
select(option: SelectOption): void;
|
|
@@ -2732,9 +4179,16 @@ declare class Select {
|
|
|
2732
4179
|
* cuando se combina con un buscador que puede reducir la lista a 1 opción.
|
|
2733
4180
|
*/
|
|
2734
4181
|
moveActive(delta: number): void;
|
|
4182
|
+
/**
|
|
4183
|
+
* Con el foco en el buscador, la opción activa se marca con
|
|
4184
|
+
* `aria-activedescendant` pero no recibe foco, así que el navegador no la
|
|
4185
|
+
* desplaza a la vista: se hace a mano. (`scrollIntoView` puede no existir
|
|
4186
|
+
* en entornos sin layout.)
|
|
4187
|
+
*/
|
|
4188
|
+
private scrollActiveIntoView;
|
|
2735
4189
|
selectActive(): void;
|
|
2736
4190
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Select, never>;
|
|
2737
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Select, "kf-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchThreshold": { "alias": "searchThreshold"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
4191
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Select, "kf-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchThreshold": { "alias": "searchThreshold"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "panelTitle": { "alias": "panelTitle"; "required": false; "isSignal": true; }; "panelWidth": { "alias": "panelWidth"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
2738
4192
|
}
|
|
2739
4193
|
|
|
2740
4194
|
interface SelectableCardOption {
|
|
@@ -2921,7 +4375,7 @@ declare class Spinner {
|
|
|
2921
4375
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Spinner, "kf-spinner", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "onDark": { "alias": "onDark"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2922
4376
|
}
|
|
2923
4377
|
|
|
2924
|
-
type StatCardTone = 'primary' | 'success' | 'error' | 'purple';
|
|
4378
|
+
type StatCardTone = 'primary' | 'success' | 'error' | 'purple' | 'warn' | 'info' | 'neutral';
|
|
2925
4379
|
/**
|
|
2926
4380
|
* Card de estadística horizontal: ícono circular grande a la izquierda,
|
|
2927
4381
|
* valor + label + nota apilados al centro, chevron opcional al final si es
|
|
@@ -2930,6 +4384,31 @@ type StatCardTone = 'primary' | 'success' | 'error' | 'purple';
|
|
|
2930
4384
|
* otorgados", "Cortesías otorgadas"), no una variante de la misma card.
|
|
2931
4385
|
*
|
|
2932
4386
|
* <kf-stat-card icon="gift" tone="purple" value="4" label="Bonos otorgados" note="$15,000.00 en beneficios" (cardClick)="onNavigate('beneficios')" />
|
|
4387
|
+
*
|
|
4388
|
+
* Extensiones opcionales (la card sin ellas se ve y se comporta como siempre):
|
|
4389
|
+
* - `tone`: además de `primary|success|error|purple`, `warn`, `info` y `neutral`.
|
|
4390
|
+
* - `bar` (0-100): barra de progreso accesible (`kf-progress`, `role="progressbar"`
|
|
4391
|
+
* con `aria-valuenow`/`min`/`max` y el `label` como nombre) bajo la nota. Se
|
|
4392
|
+
* acota a [0, 100]; `null`/`undefined` no la dibuja. Es un refuerzo visual:
|
|
4393
|
+
* el valor exacto conviene darlo también en texto (`hint`), porque el relleno
|
|
4394
|
+
* de algunos tonos de `kf-progress` tiene poco contraste con su pista.
|
|
4395
|
+
* - `hint`: texto secundario bajo la barra (ej. "12 de 20 completadas").
|
|
4396
|
+
* - `pressed` (`boolean | null`): con `clickable`, la card es un botón de
|
|
4397
|
+
* alternancia (`aria-pressed`), útil como filtro. `null` (default) = no
|
|
4398
|
+
* aplica y no emite el atributo. Sin `clickable` no tiene efecto.
|
|
4399
|
+
*
|
|
4400
|
+
* <kf-stat-card icon="clock" tone="warn" value="7" label="Por vencer" [bar]="35" hint="7 de 20"
|
|
4401
|
+
* clickable [pressed]="filter() === 'due'" (cardClick)="toggle('due')" />
|
|
4402
|
+
*
|
|
4403
|
+
* `loading` (default `false`): mientras es `true` la card dibuja su esqueleto
|
|
4404
|
+
* en vez del contenido, con el MISMO cascarón (borde, padding, ícono de 50px)
|
|
4405
|
+
* y líneas del alto real de cada texto — valor, etiqueta y, si se pasaron,
|
|
4406
|
+
* nota, barra y `hint` —, así que al llegar los datos no hay salto de
|
|
4407
|
+
* layout. Pasa los mismos inputs que usarás cargada para que el esqueleto
|
|
4408
|
+
* reserve las mismas líneas. Marca la card con `aria-busy="true"`, no es
|
|
4409
|
+
* clicable ni expone su texto a lectores de pantalla mientras carga.
|
|
4410
|
+
*
|
|
4411
|
+
* <kf-stat-card icon="clock" value="7" label="Por vencer" note="Esta semana" [loading]="isLoading()" />
|
|
2933
4412
|
*/
|
|
2934
4413
|
declare class StatCard {
|
|
2935
4414
|
readonly icon: _angular_core.InputSignal<IconName>;
|
|
@@ -2937,11 +4416,24 @@ declare class StatCard {
|
|
|
2937
4416
|
readonly value: _angular_core.InputSignal<string | number>;
|
|
2938
4417
|
readonly label: _angular_core.InputSignal<string>;
|
|
2939
4418
|
readonly note: _angular_core.InputSignal<string | undefined>;
|
|
4419
|
+
/** Avance 0-100 (barra de progreso accesible); `null`/`undefined` = sin barra. */
|
|
4420
|
+
readonly bar: _angular_core.InputSignal<number | null | undefined>;
|
|
4421
|
+
/** Texto secundario bajo la barra (o bajo la nota si no hay barra). */
|
|
4422
|
+
readonly hint: _angular_core.InputSignal<string | undefined>;
|
|
4423
|
+
/**
|
|
4424
|
+
* Estado de alternancia (`aria-pressed`) cuando la card es `clickable`.
|
|
4425
|
+
* `null` (default) = no aplica: el atributo no se emite.
|
|
4426
|
+
*/
|
|
4427
|
+
readonly pressed: _angular_core.InputSignal<boolean | null>;
|
|
4428
|
+
/** Dibuja el esqueleto en lugar del contenido, conservando las dimensiones. */
|
|
4429
|
+
readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2940
4430
|
/** Si se escucha `cardClick`, la card se renderiza como botón clickeable con chevron. */
|
|
2941
4431
|
readonly clickable: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
2942
4432
|
readonly cardClick: _angular_core.OutputEmitterRef<void>;
|
|
4433
|
+
protected readonly barTone: _angular_core.Signal<ProgressTone>;
|
|
4434
|
+
protected readonly hasBar: _angular_core.Signal<boolean>;
|
|
2943
4435
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<StatCard, never>;
|
|
2944
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<StatCard, "kf-stat-card", never, { "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "note": { "alias": "note"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, never, true, never>;
|
|
4436
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<StatCard, "kf-stat-card", never, { "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "note": { "alias": "note"; "required": false; "isSignal": true; }; "bar": { "alias": "bar"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "pressed": { "alias": "pressed"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, never, true, never>;
|
|
2945
4437
|
}
|
|
2946
4438
|
|
|
2947
4439
|
/** Vocabulario semántico único de tono, compartido con `TextTone`. */
|
|
@@ -2999,6 +4491,57 @@ declare class StatTile {
|
|
|
2999
4491
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<StatTile, "kf-stat-tile", never, { "cta": { "alias": "cta"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "note": { "alias": "note"; "required": false; "isSignal": true; }; "notePlaceholder": { "alias": "notePlaceholder"; "required": false; "isSignal": true; }; "valueMissing": { "alias": "valueMissing"; "required": false; "isSignal": true; }; "hasProjectedValue": { "alias": "hasProjectedValue"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "actionLabel": { "alias": "actionLabel"; "required": false; "isSignal": true; }; "actionHref": { "alias": "actionHref"; "required": false; "isSignal": true; }; }, { "actionClick": "actionClick"; }, never, ["[valueContent]"], true, never>;
|
|
3000
4492
|
}
|
|
3001
4493
|
|
|
4494
|
+
/**
|
|
4495
|
+
* Marca pequeña de estado para leyendas y listas de hitos: círculo relleno
|
|
4496
|
+
* con check (completado), anillo con punto (en curso) o anillo vacío
|
|
4497
|
+
* (pendiente). La forma comunica el estado y el color solo lo refuerza.
|
|
4498
|
+
* `exception` la pinta con borde discontinuo y tono de aviso.
|
|
4499
|
+
*
|
|
4500
|
+
* Es decorativa por defecto (`aria-hidden`): el texto del estado va en el
|
|
4501
|
+
* contexto que la usa. Para usarla suelta (ej. una leyenda sin texto al lado),
|
|
4502
|
+
* `label` la expone como imagen con ese nombre.
|
|
4503
|
+
*
|
|
4504
|
+
* <kf-status-mark status="done" small />
|
|
4505
|
+
* <kf-status-mark status="current" label="En curso" />
|
|
4506
|
+
*
|
|
4507
|
+
* Tamaño: variables CSS `--kf-status-mark-size` y `--kf-status-mark-size-sm`.
|
|
4508
|
+
*/
|
|
4509
|
+
declare class StatusMark {
|
|
4510
|
+
readonly status: _angular_core.InputSignal<ProgressStatus>;
|
|
4511
|
+
/** Versión reducida, para listas de hitos. */
|
|
4512
|
+
readonly small: _angular_core.InputSignal<boolean>;
|
|
4513
|
+
/** Hito de excepción: borde discontinuo y tono de aviso. */
|
|
4514
|
+
readonly exception: _angular_core.InputSignal<boolean>;
|
|
4515
|
+
/** Nombre accesible; sin él la marca es decorativa. */
|
|
4516
|
+
readonly label: _angular_core.InputSignal<string | null>;
|
|
4517
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<StatusMark, never>;
|
|
4518
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<StatusMark, "kf-status-mark", never, { "status": { "alias": "status"; "required": true; "isSignal": true; }; "small": { "alias": "small"; "required": false; "isSignal": true; }; "exception": { "alias": "exception"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
/**
|
|
4522
|
+
* Nodo circular de una etapa: ícono de la etapa más una insignia de estado.
|
|
4523
|
+
* La forma comunica el estado (relleno con check, anillo con punto, anillo
|
|
4524
|
+
* vacío) y el color solo lo refuerza.
|
|
4525
|
+
*
|
|
4526
|
+
* Es decorativo por defecto (`aria-hidden`): el texto del estado debe estar en
|
|
4527
|
+
* el contexto que lo usa. Para usarlo suelto, `label` lo expone como imagen
|
|
4528
|
+
* con ese nombre.
|
|
4529
|
+
*
|
|
4530
|
+
* <kf-status-node status="current" icon="truck" />
|
|
4531
|
+
* <kf-status-node status="done" icon="check" size="sm" label="Entrega completada" />
|
|
4532
|
+
*
|
|
4533
|
+
* Tamaño: variables CSS `--kf-status-node-size` y `--kf-status-node-size-sm`.
|
|
4534
|
+
*/
|
|
4535
|
+
declare class StatusNode {
|
|
4536
|
+
readonly status: _angular_core.InputSignal<ProgressStatus>;
|
|
4537
|
+
readonly icon: _angular_core.InputSignal<IconName>;
|
|
4538
|
+
readonly size: _angular_core.InputSignal<"sm" | "md">;
|
|
4539
|
+
/** Nombre accesible; sin él el nodo es decorativo. */
|
|
4540
|
+
readonly label: _angular_core.InputSignal<string | null>;
|
|
4541
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<StatusNode, never>;
|
|
4542
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<StatusNode, "kf-status-node", never, { "status": { "alias": "status"; "required": true; "isSignal": true; }; "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
4543
|
+
}
|
|
4544
|
+
|
|
3002
4545
|
/**
|
|
3003
4546
|
* Pill con borde, en mayúsculas y con letter-spacing, pensada para indicadores
|
|
3004
4547
|
* de estado únicos y prominentes (ej. "ESTADO TÉCNICO"). El fondo es siempre
|
|
@@ -3272,7 +4815,12 @@ interface ToastAction {
|
|
|
3272
4815
|
interface ToastOptions {
|
|
3273
4816
|
/** Color tone. Defaults to `'info'`. */
|
|
3274
4817
|
tone?: ToastTone;
|
|
3275
|
-
/**
|
|
4818
|
+
/**
|
|
4819
|
+
* Milliseconds before auto-dismiss. Ignored when `tone` is `'loading'`. When
|
|
4820
|
+
* omitted it depends on the tone (see {@link TOAST_DEFAULT_DURATION_MS}):
|
|
4821
|
+
* `2800` for `success`/`info`, `5000` for `warning`, `8000` for `error`. An
|
|
4822
|
+
* explicit value always wins over the per-tone default.
|
|
4823
|
+
*/
|
|
3276
4824
|
duration?: number;
|
|
3277
4825
|
/** Botón de acción opcional, ej. ir al registro sobre el que avisa el toast. */
|
|
3278
4826
|
action?: ToastAction;
|
|
@@ -3292,6 +4840,13 @@ interface ToastState {
|
|
|
3292
4840
|
leaving: boolean;
|
|
3293
4841
|
action?: ToastAction;
|
|
3294
4842
|
}
|
|
4843
|
+
/**
|
|
4844
|
+
* Auto-dismiss time per tone when the caller doesn't pass `duration`. Errors and
|
|
4845
|
+
* warnings stay longer than confirmations: they carry something to read and
|
|
4846
|
+
* act on, while a success only has to be noticed. `success`/`info` keep the
|
|
4847
|
+
* historical 2800ms. `loading` never auto-dismisses.
|
|
4848
|
+
*/
|
|
4849
|
+
declare const TOAST_DEFAULT_DURATION_MS: Readonly<Record<Exclude<ToastTone, 'loading'>, number>>;
|
|
3295
4850
|
/** What's currently holding the auto-dismiss timer paused. Tracked as a set so hover and
|
|
3296
4851
|
* focus can overlap (e.g. mouse leaves while focus is still on the action button) without
|
|
3297
4852
|
* resuming the timer early. */
|
|
@@ -3300,6 +4855,11 @@ type ToastPauseSource = 'hover' | 'focus';
|
|
|
3300
4855
|
* Shows one toast at a time — a new `show()` call replaces whatever is
|
|
3301
4856
|
* currently up (this mirrors a global status line, not a notification stack).
|
|
3302
4857
|
*
|
|
4858
|
+
* Duration by tone (when `duration` isn't passed): `success`/`info` 2800ms,
|
|
4859
|
+
* `warning` 5000ms, `error` 8000ms (`TOAST_DEFAULT_DURATION_MS`); an explicit
|
|
4860
|
+
* `duration` always wins. The countdown pauses while the pointer or focus is
|
|
4861
|
+
* on the toast. Error toasts also get a larger, always-opaque close button.
|
|
4862
|
+
*
|
|
3303
4863
|
* Angular has no global function that can mount UI on its own, so the
|
|
3304
4864
|
* imperative `showToast(...)` of the reference design system becomes a
|
|
3305
4865
|
* root-provided service holding signal state: `ToastService.show(...)` sets
|
|
@@ -3452,17 +5012,31 @@ type ViewToggleOption = 'table' | 'cards';
|
|
|
3452
5012
|
* navegación con flechas izquierda/derecha, igual que un <input type="radio">
|
|
3453
5013
|
* nativo agrupado.
|
|
3454
5014
|
*
|
|
5015
|
+
* Con `iconOnly` cada opción muestra solo su ícono (`list` / `grid`); el
|
|
5016
|
+
* nombre accesible y el tooltip salen de `tableLabel` / `cardsLabel`. El
|
|
5017
|
+
* objetivo táctil mide 32px en escritorio y 44px en pantallas táctiles o de
|
|
5018
|
+
* hasta 640px.
|
|
5019
|
+
*
|
|
3455
5020
|
* <kf-view-toggle [view]="view" (viewChange)="view = $event" />
|
|
5021
|
+
* <kf-view-toggle iconOnly [view]="view" (viewChange)="view = $event" />
|
|
3456
5022
|
*/
|
|
3457
5023
|
declare class ViewToggle {
|
|
3458
5024
|
readonly view: _angular_core.InputSignal<ViewToggleOption>;
|
|
5025
|
+
/** Solo íconos (el rótulo queda como nombre accesible y `title`). */
|
|
5026
|
+
readonly iconOnly: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
5027
|
+
/** Rótulo de la opción de tabla. */
|
|
5028
|
+
readonly tableLabel: _angular_core.InputSignal<string>;
|
|
5029
|
+
/** Rótulo de la opción de tarjetas. */
|
|
5030
|
+
readonly cardsLabel: _angular_core.InputSignal<string>;
|
|
5031
|
+
/** Nombre accesible del grupo. */
|
|
5032
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
3459
5033
|
readonly viewChange: _angular_core.OutputEmitterRef<ViewToggleOption>;
|
|
3460
5034
|
select(next: ViewToggleOption): void;
|
|
3461
5035
|
/** Navegación estándar de ARIA radiogroup: flechas mueven foco y seleccionan. */
|
|
3462
5036
|
onKeydown(event: KeyboardEvent): void;
|
|
3463
5037
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ViewToggle, never>;
|
|
3464
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ViewToggle, "kf-view-toggle", never, { "view": { "alias": "view"; "required": true; "isSignal": true; }; }, { "viewChange": "viewChange"; }, never, never, true, never>;
|
|
5038
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ViewToggle, "kf-view-toggle", never, { "view": { "alias": "view"; "required": true; "isSignal": true; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "tableLabel": { "alias": "tableLabel"; "required": false; "isSignal": true; }; "cardsLabel": { "alias": "cardsLabel"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "viewChange": "viewChange"; }, never, never, true, never>;
|
|
3465
5039
|
}
|
|
3466
5040
|
|
|
3467
|
-
export { ActionTile, AdminBadge, Alert, AlertRow, Avatar, Badge, Breadcrumb, BucketProgress, Button, Calendar, Card, Carousel, CarouselSlide, Checkbox, Chip, Collapsible, ContactPopover, ContentSlot, ContentState, ContentViewer, DEFAULT_PAGE_SIZE_OPTIONS, DataTable, Divider, DocumentRow, Drawer, Dropdown, DropdownItem, DropdownPanel, EmptyState, EventTimeline, FeatureCard, Field, FieldLabel, Filter, FilterChips, FolderTabs, FolderTabsPanel, Footer, FormatInputDirective, Icon, Input, JourneyStepper, Link, MetricCard, Modal, MultiSelect, NoteBlock, PageHeader, Pagination, Panel, PortalHeader, Progress, PulseDot, RowActions, SectionHeader, SectionNav, SectionNavItem, SectionNavSubsection, Segmented, Select, SelectableCardGroup, SidebarShell, Skeleton, Spinner, StatCard, StatTile, StatusPill, Tabs, Text, Textarea, TileGrid, TimeSlotPicker, ToastHost, ToastService, TooltipDirective, ViewToggle, dataTableViewSignal };
|
|
3468
|
-
export type { AlertRowTone, AlertTone, BreadcrumbItem, BucketProgressItem, CalendarDay, ContentStateKind, ContentStateLoad, ContentViewerType, DataTableCardRole, DataTableColumn, DataTableDensity, DataTableSort, DataTableView, DividerOrientation, DocumentRowTone, DrawerSide, DropdownItemTone, DropdownPanelVariant, EventTimelineItem, EventTimelineTone, FilterFieldChange, FilterFieldConfig, FilterFieldType, FilterValue, FolderTabOption, FooterLink, IconName, IconRotation, IconSize, JourneyStep, JourneyStepStatus, JourneyStepperColorScheme, JourneyStepperSurface, LinkVariant, MultiSelectOption, NoteBlockTone, PageHeaderTitleSize, PaginationItem, PortalHeaderAdminAction, PortalHeaderNavItem, ProgressTone, RowAction, RowActionKind, RowActionsMode, SectionNavSubsectionData, SegmentedOption, SelectOption, SelectableCardOption, SidebarNavItemData, SkeletonVariant, SpinnerSize, StatCardTone, StatTileTone, StatTileVariant, TabOption, TextAs, TextTone, TextVariant, TimeSlot, ToastAction, ToastOptions, ToastPromiseMessages, ToastState, ToastTone, TooltipPosition, ViewToggleOption };
|
|
5041
|
+
export { ActionTile, AdminBadge, Alert, AlertRow, Avatar, Badge, Breadcrumb, BucketProgress, Button, Calendar, Card, Carousel, CarouselSlide, Checkbox, Chip, Collapsible, ContactPopover, ContentSlot, ContentState, ContentStateLoading, ContentViewer, DATA_TABLE_MAX_SKELETON_ROWS, DEFAULT_MILESTONE_TIMELINE_LABELS, DEFAULT_PAGE_SIZE_OPTIONS, DataTable, Divider, DocumentRow, Drawer, Dropdown, DropdownItem, DropdownPanel, EmptyState, EventTimeline, FeatureCard, Field, FieldLabel, FileInput, Filter, FilterChips, FolderTabs, FolderTabsPanel, Footer, FormatInputDirective, Icon, Input, JourneyStepper, LIST_TOOLBAR_HYSTERESIS, Link, ListToolbar, MetricCard, MilestoneTimeline, Modal, MultiSelect, NoteBlock, OptionList, PROGRESS_STATUS, PROGRESS_STATUS_LABEL, PageHeader, Pagination, Panel, PopoverDirective, PortalHeader, Progress, PulseDot, RowActions, SKELETON_PRESET_MAX_COUNT, SectionHeader, SectionNav, SectionNavItem, SectionNavSubsection, Segmented, Select, SelectableCardGroup, SidebarShell, Skeleton, SkeletonPreset, Spinner, StatCard, StatTile, StatusMark, StatusNode, StatusPill, TOAST_DEFAULT_DURATION_MS, Tabs, Text, Textarea, TileGrid, TimeSlotPicker, ToastHost, ToastService, TooltipDirective, ViewToggle, dataTableViewSignal, formatFileSize, resolveListToolbarMode };
|
|
5042
|
+
export type { AlertRowTone, AlertTone, AlertVariant, BreadcrumbItem, BucketProgressItem, CalendarDay, ContentStateKind, ContentStateLoad, ContentViewerType, DataTableCardRole, DataTableCellClick, DataTableColumn, DataTableDensity, DataTableSort, DataTableView, DividerOrientation, DocumentRowTone, DrawerRole, DrawerSide, DropdownItemTone, DropdownPanelVariant, EmptyStateTone, EventTimelineItem, EventTimelineTone, FileRejection, FileRejectionReason, FilterChipOption, FilterFieldChange, FilterFieldConfig, FilterFieldType, FilterValue, FolderTabOption, FooterLink, IconName, IconRotation, IconSize, InputBound, JourneyStep, JourneyStepStatus, JourneyStepperColorScheme, JourneyStepperSurface, LinkVariant, ListToolbarMode, MilestoneGroup, MilestoneItem, MilestoneTimelineLabels, MultiSelectOption, NoteBlockTone, OptionListOption, PageHeaderTitleSize, PaginationItem, PopoverPlacement, PortalHeaderAdminAction, PortalHeaderNavItem, ProgressSize, ProgressStatus, ProgressTone, RowAction, RowActionKind, RowActionsMode, SectionNavSubsectionData, SegmentedOption, SelectOption, SelectableCardOption, SidebarNavItemData, SkeletonPresetVariant, SkeletonVariant, SpinnerSize, StatCardTone, StatTileTone, StatTileVariant, TabOption, TextAs, TextTone, TextVariant, TimeSlot, ToastAction, ToastOptions, ToastPromiseMessages, ToastState, ToastTone, TooltipPosition, ViewToggleOption };
|