@kaufmann-lab/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1499 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { AfterContentInit, TemplateRef, AfterViewInit } from '@angular/core';
3
+ import { ControlValueAccessor } from '@angular/forms';
4
+
5
+ /** Nombre de cada uno de los 59 íconos del design system (página 5). */
6
+ 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' | 'download' | 'edit' | 'external-link' | 'eye' | 'file' | 'filter' | 'gauge' | 'gift' | 'grid' | 'history' | 'inbox' | 'layers' | 'list' | 'map' | 'map-pin' | 'menu' | 'mic' | 'mic-off' | 'more-vertical' | 'pause' | 'phone' | 'play' | 'plus' | 'search' | 'settings' | 'shield-check' | 'sort' | 'star' | 'ticket' | 'tool' | 'trash' | 'truck' | 'upload-cloud' | 'user' | 'user-search' | 'video' | 'x';
7
+ type IconSize = 'sm' | 'md' | 'lg';
8
+ /**
9
+ * Ícono de trazo del design system — 59 glyphs (página 5), grilla 24×24,
10
+ * grosor de trazo 1.9px. Referencia un sprite SVG embebido (ver
11
+ * `icon-sprite.ts`) vía `<use>`, así que no hay peso de red adicional por
12
+ * cada instancia: el sprite se inyecta al DOM una única vez, la primera
13
+ * vez que se renderiza cualquier `<kf-icon>` de toda la aplicación.
14
+ *
15
+ * El tamaño se controla con `size` (página 6: "el tamaño se controla con la
16
+ * prop size"): `sm` (16px), `md` (20px, default) o `lg` (24px). El color
17
+ * sigue siempre `currentColor` — se hereda del texto del elemento
18
+ * contenedor, nunca se fija en el propio ícono.
19
+ *
20
+ * <kf-icon name="alert-triangle" size="sm" />
21
+ * <kf-button icon="calendar">Reservar hora</kf-button> <!-- ver Button -->
22
+ */
23
+ declare class Icon {
24
+ readonly name: _angular_core.InputSignal<IconName>;
25
+ readonly size: _angular_core.InputSignal<IconSize>;
26
+ private readonly document;
27
+ protected readonly pixelSize: _angular_core.Signal<string>;
28
+ constructor();
29
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Icon, never>;
30
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Icon, "kf-icon", never, { "name": { "alias": "name"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
31
+ }
32
+
33
+ /**
34
+ * Dos variantes del mismo concepto — acceso rápido a una sección (página
35
+ * 35): "Tile de acceso destacado" (`variant="tile"`, default) es un bloque
36
+ * centrado con ícono grande arriba y título abajo, pensado para una
37
+ * cuadrícula de accesos (ej. "Todos los certificados"). "Fila de documento"
38
+ * (`variant="row"`) es horizontal, con ícono a la izquierda y
39
+ * título+descripción a la derecha, pensada para listas verticales dentro de
40
+ * un `kf-panel` (ej. "Pagos" / "Revisa tu estado de cuenta y realiza pagos.").
41
+ *
42
+ * <kf-action-tile icon="shield-check" title="Todos los certificados" />
43
+ * <kf-action-tile variant="row" icon="download" title="Pagos"
44
+ * description="Revisa tu estado de cuenta y realiza pagos." />
45
+ */
46
+ declare class ActionTile {
47
+ readonly variant: _angular_core.InputSignal<"tile" | "row">;
48
+ readonly icon: _angular_core.InputSignal<IconName>;
49
+ readonly title: _angular_core.InputSignal<string>;
50
+ readonly description: _angular_core.InputSignal<string | undefined>;
51
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ActionTile, never>;
52
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ActionTile, "kf-action-tile", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
53
+ }
54
+
55
+ /**
56
+ * Marca la barra superior como chrome exclusivo de administradores (página
57
+ * 18) — acento ámbar para diferenciar contexto privilegiado del resto del
58
+ * portal. Dos variantes: etiqueta aislada (pill), o `inline` para usarse
59
+ * dentro de la franja de `kf-portal-header` (fondo oscuro, texto ámbar).
60
+ *
61
+ * <kf-admin-badge />
62
+ * <kf-admin-badge inline />
63
+ */
64
+ declare class AdminBadge {
65
+ /** Para usarse dentro de una superficie oscura (ej. la franja de `kf-portal-header`). */
66
+ readonly inline: _angular_core.InputSignalWithTransform<boolean, unknown>;
67
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AdminBadge, never>;
68
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AdminBadge, "kf-admin-badge", never, { "inline": { "alias": "inline"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
69
+ }
70
+
71
+ /**
72
+ * Wraps a native `<button>`, so keyboard handling, focus and form submission
73
+ * keep working. The cost of the wrapper is forwarding `disabled` and `type` by
74
+ * hand: as attributes on a custom element they have no native effect.
75
+ *
76
+ * Five variants (page 9 of the design system): `primary` (main action, blue),
77
+ * `secondary` (service actions, orange), `ghost` (low-emphasis, no fill),
78
+ * `outline` (medium-emphasis, bordered) and `danger` (destructive
79
+ * confirmations — red, see the Confirmation Modal pattern on page 30). Three
80
+ * sizes (`sm`/`md`/`lg`). `icon` renders a leading glyph (`kf-icon`) before
81
+ * the projected label; `block` stretches the button to the full width of its
82
+ * container.
83
+ *
84
+ * `(click)` is not forwarded — it bubbles from the inner button to the host.
85
+ *
86
+ * <kf-button (click)="save()">Save</kf-button>
87
+ * <kf-button variant="ghost" disabled>Cancel</kf-button>
88
+ * <kf-button variant="danger" (click)="remove()">Delete</kf-button>
89
+ * <kf-button size="sm" icon="calendar" block>Reservar hora</kf-button>
90
+ */
91
+ declare class Button {
92
+ readonly variant: _angular_core.InputSignal<"primary" | "secondary" | "ghost" | "outline" | "danger">;
93
+ readonly size: _angular_core.InputSignal<"sm" | "md" | "lg">;
94
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
95
+ /** Matches the native default: submits when inside a `<form>`. */
96
+ readonly type: _angular_core.InputSignal<"button" | "submit" | "reset">;
97
+ /** Leading icon, rendered via `kf-icon` before the projected label. */
98
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
99
+ /** Stretches the button to the full width of its container. */
100
+ readonly block: _angular_core.InputSignalWithTransform<boolean, unknown>;
101
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Button, never>;
102
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Button, "kf-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "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; }; }, {}, never, ["*"], true, never>;
103
+ }
104
+
105
+ type AlertTone = 'info' | 'ok' | 'warn' | 'error';
106
+ /**
107
+ * Banner contextual que vive dentro del flujo: validaciones, avisos de
108
+ * vencimiento, confirmaciones. Persiste hasta que se descarta o hasta que la
109
+ * condición que lo causó desaparece — para feedback efímero está el toast.
110
+ *
111
+ * `open` es two-way: el botón de cerrar lo pone en `false` y el componente
112
+ * deja de renderizar. El consumidor puede volver a abrirlo poniéndolo en
113
+ * `true` (ej. cuando la validación falla otra vez).
114
+ *
115
+ * ponytail: los glifos van inline en vez de venir de un componente Icon —
116
+ * son 4 paths fijos, uno por tono, y no existe todavía `kf-icon` en la
117
+ * librería. Cuando exista, se reemplaza este `@switch` por `<kf-icon>`.
118
+ *
119
+ * <kf-alert tone="warn" title="SOAT por vencer">Vence el 15/08.</kf-alert>
120
+ * <kf-alert tone="ok" [(open)]="saved" dismissible>Pago registrado.</kf-alert>
121
+ */
122
+ declare class Alert {
123
+ readonly tone: _angular_core.InputSignal<AlertTone>;
124
+ /** Línea en negrita arriba del mensaje. Vacío deja solo el contenido proyectado. */
125
+ readonly title: _angular_core.InputSignal<string>;
126
+ readonly dismissible: _angular_core.InputSignalWithTransform<boolean, unknown>;
127
+ /** Visibilidad, two-way: `[(open)]="hasError"`. */
128
+ readonly open: _angular_core.ModelSignal<boolean>;
129
+ /**
130
+ * `alert` interrumpe al lector de pantalla; se reserva para error/warn.
131
+ * Los avisos informativos se anuncian sin cortar lo que se esté leyendo.
132
+ */
133
+ protected readonly ariaRole: _angular_core.Signal<"alert" | "status">;
134
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Alert, never>;
135
+ 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>;
136
+ }
137
+
138
+ /**
139
+ * Avatar de usuario: muestra una foto (`src`) o, si no hay foto, las
140
+ * iniciales (`initials`) sobre un fondo con gradiente de marca. `round`
141
+ * controla la forma: circular (por defecto) o cuadrada con radio.
142
+ *
143
+ * Con `pill`, el avatar se envuelve en una pastilla azul con un chevron a la
144
+ * derecha — la "pill de usuario (header)" de la página 18 del design system,
145
+ * usada en la barra de sesión del Portal Header.
146
+ *
147
+ * <kf-avatar initials="JD" />
148
+ * <kf-avatar src="https://…/foto.jpg" [round]="false" />
149
+ * <kf-avatar initials="TS" pill />
150
+ *
151
+ * Pendiente: si en el futuro se agrega un ícono de fallback (persona
152
+ * genérica) para cuando no hay ni `src` ni `initials`, depende del
153
+ * componente Icon / sprite SVG que todavía no existe en esta librería.
154
+ */
155
+ declare class Avatar {
156
+ readonly initials: _angular_core.InputSignal<string | undefined>;
157
+ readonly src: _angular_core.InputSignal<string | undefined>;
158
+ readonly round: _angular_core.InputSignal<boolean>;
159
+ /** Envuelve el avatar en la pastilla de sesión del header, con chevron. */
160
+ readonly pill: _angular_core.InputSignalWithTransform<boolean, unknown>;
161
+ /** Limita a 2 caracteres para que quepan cómodos dentro del círculo. */
162
+ readonly displayInitials: _angular_core.Signal<string>;
163
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Avatar, never>;
164
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Avatar, "kf-avatar", never, { "initials": { "alias": "initials"; "required": false; "isSignal": true; }; "src": { "alias": "src"; "required": false; "isSignal": true; }; "round": { "alias": "round"; "required": false; "isSignal": true; }; "pill": { "alias": "pill"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
165
+ }
166
+
167
+ /**
168
+ * Pill chica de fondo suave (soft) para un conteo, tag o estado liviano
169
+ * puntual (no un proceso en vivo — para eso existe `kf-status-pill`, que usa
170
+ * borde en vez de relleno). El color de fondo/texto/punto depende de `tone`.
171
+ *
172
+ * El PDF (página 10) fija seis tonos con fondo soft y texto del tono fuerte
173
+ * — nunca fondo saturado con texto blanco, que es más apto para un botón
174
+ * que para una etiqueta de lectura rápida en una lista densa.
175
+ *
176
+ * <kf-badge tone="ok" dot>Al día</kf-badge>
177
+ * <kf-badge tone="error">3</kf-badge>
178
+ *
179
+ * Mapeo de `tone` a los seis conceptos de la página 10 y sus tokens
180
+ * semánticos en projects/ui/src/tokens/base.css:
181
+ * neutral -> Neutral (border/text-muted), info -> Información (info-soft/-strong),
182
+ * ok -> Activo (success-soft/-strong), warn -> Pendiente (warning-soft/-strong),
183
+ * error -> Vencido (error-soft/-strong), service -> Servicio (secondary-soft,
184
+ * no existe un `-strong` para secondary todavía — usa el color base).
185
+ */
186
+ declare class Badge {
187
+ readonly tone: _angular_core.InputSignal<"info" | "ok" | "warn" | "error" | "neutral" | "service">;
188
+ readonly dot: _angular_core.InputSignalWithTransform<boolean, unknown>;
189
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Badge, never>;
190
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Badge, "kf-badge", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "dot": { "alias": "dot"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
191
+ }
192
+
193
+ interface BreadcrumbItem {
194
+ label: string;
195
+ /** Destino del link. Sin `href` el nivel se rinde como texto plano. */
196
+ href?: string;
197
+ }
198
+ /**
199
+ * Ruta de navegación de las vistas internas. El último nivel es la página
200
+ * actual: nunca es link y lleva `aria-current="page"`, aunque traiga `href`.
201
+ *
202
+ * Se rinde como `<nav><ol>` — es una lista ordenada de ancestros, y eso es lo
203
+ * que los lectores de pantalla anuncian ("navegación, lista de 3 elementos").
204
+ *
205
+ * Para apps con router: escuchar `itemClick` y llamar
206
+ * `event.preventDefault()` antes de `router.navigate(...)`. El `href` se
207
+ * mantiene igual para que click-medio, "abrir en pestaña nueva" y el hover
208
+ * de la barra de estado sigan funcionando.
209
+ *
210
+ * <kf-breadcrumb [items]="[{ label: 'Inicio', href: '/' }, { label: 'Mis vehículos' }]" />
211
+ */
212
+ declare class Breadcrumb {
213
+ readonly items: _angular_core.InputSignal<BreadcrumbItem[]>;
214
+ /**
215
+ * Click en un nivel con `href`. Incluye el `MouseEvent` para que un
216
+ * consumidor con router pueda cortar la navegación nativa.
217
+ *
218
+ * ponytail: no dependemos de `@angular/router` acá — sería un peer dep
219
+ * nuevo en la librería para lo que el consumidor resuelve en una línea.
220
+ */
221
+ readonly itemClick: _angular_core.OutputEmitterRef<{
222
+ item: BreadcrumbItem;
223
+ index: number;
224
+ event: MouseEvent;
225
+ }>;
226
+ protected readonly lastIndex: _angular_core.Signal<number>;
227
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Breadcrumb, never>;
228
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Breadcrumb, "kf-breadcrumb", never, { "items": { "alias": "items"; "required": true; "isSignal": true; }; }, { "itemClick": "itemClick"; }, never, never, true, never>;
229
+ }
230
+
231
+ /**
232
+ * Contenedor base con esquinas redondeadas y sombra sutil — la base visual
233
+ * de paneles, tarjetas de métrica, tablas y bloques de contenido de todo el
234
+ * portal (ver página 14 del design system).
235
+ *
236
+ * Piensa este componente como el "cimiento": no impone estructura interna
237
+ * más allá de dos slots opcionales alrededor del contenido libre —
238
+ * `[media]` para una imagen/ícono destacado arriba, y `[actions]` para una
239
+ * fila de botones al pie, separada por una línea. El contenido por defecto
240
+ * (sin selector) queda en el medio, sin ningún layout forzado, para que
241
+ * cualquier composición (una métrica, una lista, un formulario) pueda vivir
242
+ * dentro sin pelear con estilos propios del `Card`.
243
+ *
244
+ * <kf-card>Contenido simple</kf-card>
245
+ * <kf-card flush>Sin sombra — para superficies ya delimitadas por otra card</kf-card>
246
+ * <kf-card>
247
+ * <img kf-card-media src="..." alt="" />
248
+ * <h3>Título</h3>
249
+ * <p>Descripción</p>
250
+ * <div kf-card-actions>
251
+ * <kf-button variant="ghost">Cancelar</kf-button>
252
+ * <kf-button>Guardar</kf-button>
253
+ * </div>
254
+ * </kf-card>
255
+ */
256
+ declare class Card {
257
+ /** Quita la sombra — para cards anidadas dentro de otra superficie ya elevada. */
258
+ readonly flush: _angular_core.InputSignalWithTransform<boolean, unknown>;
259
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Card, never>;
260
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Card, "kf-card", never, { "flush": { "alias": "flush"; "required": false; "isSignal": true; }; }, {}, never, ["[kf-card-media]", "*", "[kf-card-actions]"], true, never>;
261
+ }
262
+
263
+ /**
264
+ * Slide individual de un `kf-carousel`. Es un contenedor mínimo: solo existe
265
+ * para que el carrusel pueda detectar, vía `contentChildren`, cuántos slides
266
+ * se proyectaron y en qué orden — el contenido real es responsabilidad total
267
+ * de quien lo consume.
268
+ *
269
+ * <kf-carousel-slide>...</kf-carousel-slide>
270
+ */
271
+ declare class CarouselSlide {
272
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<CarouselSlide, never>;
273
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CarouselSlide, "kf-carousel-slide", never, {}, {}, never, ["*"], true, never>;
274
+ }
275
+ /**
276
+ * Carrusel de slides con flechas, dots y autoplay opcional.
277
+ *
278
+ * La spec original de React recibe `slides` como un array de nodos React.
279
+ * En Angular eso no tiene equivalente directo: en vez de forzar un array de
280
+ * datos crudos, cada slide se proyecta como contenido declarativo mediante
281
+ * un `kf-carousel-slide` hijo, y el carrusel los detecta con
282
+ * `contentChildren(CarouselSlide)`. Esto evita depender de un renderer de
283
+ * nodos y deja que cada slide use plantillas Angular normales (bindings,
284
+ * `@if`, `@for`, etc.) tal como se espera en este ecosistema.
285
+ *
286
+ * <kf-carousel [autoplay]="true" [interval]="4000" (indexChange)="onIndex($event)">
287
+ * <kf-carousel-slide>...</kf-carousel-slide>
288
+ * <kf-carousel-slide>...</kf-carousel-slide>
289
+ * </kf-carousel>
290
+ */
291
+ declare class Carousel implements AfterContentInit {
292
+ readonly autoplay: _angular_core.InputSignal<boolean>;
293
+ readonly interval: _angular_core.InputSignalWithTransform<number, unknown>;
294
+ readonly indexChange: _angular_core.OutputEmitterRef<number>;
295
+ readonly slides: _angular_core.Signal<readonly CarouselSlide[]>;
296
+ private readonly activeIndexSignal;
297
+ readonly activeIndex: _angular_core.Signal<number>;
298
+ private readonly destroyRef;
299
+ private timer;
300
+ private autoplayPaused;
301
+ ngAfterContentInit(): void;
302
+ next(): void;
303
+ previous(): void;
304
+ goTo(index: number): void;
305
+ pauseAutoplay(): void;
306
+ resumeAutoplay(): void;
307
+ private startAutoplay;
308
+ private stopAutoplay;
309
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Carousel, never>;
310
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Carousel, "kf-carousel", never, { "autoplay": { "alias": "autoplay"; "required": false; "isSignal": true; }; "interval": { "alias": "interval"; "required": false; "isSignal": true; }; }, { "indexChange": "indexChange"; }, ["slides"], ["*"], true, never>;
311
+ }
312
+
313
+ /**
314
+ * Checkbox accesible con soporte de estado "indeterminate".
315
+ *
316
+ * `indeterminate` no existe como atributo HTML: el navegador solo lo expone
317
+ * como propiedad del elemento nativo, así que se aplica a mano sobre el
318
+ * `<input>` interno vía `viewChild` + `effect` cada vez que cambia el input.
319
+ *
320
+ * Implementa `ControlValueAccessor` para poder usarse con `formControlName` /
321
+ * `ngModel` igual que un checkbox nativo. En ese modo, `writeValue` controla
322
+ * el DOM directamente y el input `checked` (pensado para binding manual sin
323
+ * forms) queda en su valor por defecto — igual que `disabled` combina el
324
+ * input signal con `setDisabledState` en el resto de la librería.
325
+ *
326
+ * <kf-checkbox label="Aceptar términos" [(checked)]="accepted" />
327
+ * <kf-checkbox label="Seleccionar todo" [indeterminate]="isPartial()" />
328
+ * <kf-checkbox label="Notificaciones" formControlName="notifications" />
329
+ */
330
+ declare class Checkbox implements ControlValueAccessor {
331
+ readonly label: _angular_core.InputSignal<string | undefined>;
332
+ readonly checked: _angular_core.InputSignalWithTransform<boolean, unknown>;
333
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
334
+ readonly indeterminate: _angular_core.InputSignalWithTransform<boolean, unknown>;
335
+ readonly checkedChange: _angular_core.OutputEmitterRef<boolean>;
336
+ private readonly inputRef;
337
+ /** Callbacks registrados por Forms; no-op hasta que registerOnChange/Touched las reemplacen. */
338
+ private onChangeFn;
339
+ private onTouchedFn;
340
+ constructor();
341
+ onChange(event: Event): void;
342
+ onTouched(): void;
343
+ writeValue(value: boolean): void;
344
+ registerOnChange(fn: (value: boolean) => void): void;
345
+ registerOnTouched(fn: () => void): void;
346
+ setDisabledState?(isDisabled: boolean): void;
347
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Checkbox, never>;
348
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Checkbox, "kf-checkbox", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "indeterminate": { "alias": "indeterminate"; "required": false; "isSignal": true; }; }, { "checkedChange": "checkedChange"; }, never, never, true, never>;
349
+ }
350
+
351
+ /**
352
+ * Chip de fondo suave con un punto líder que indica estado. Pensado
353
+ * principalmente para celdas de tabla (estado de fila), pero utilizable
354
+ * en cualquier lugar donde se necesite una etiqueta de estado compacta.
355
+ *
356
+ * <kf-chip tone="warn">Pendiente</kf-chip>
357
+ * <kf-chip tone="ok">Aprobado</kf-chip>
358
+ *
359
+ * Nota: la spec original define la unión de tonos como "ok" | "warn" |
360
+ * "error" | "neutral". Internamente se mapean a los tokens semánticos de
361
+ * projects/ui/src/tokens/base.css: ok -> success, warn -> warning,
362
+ * error -> error, neutral -> surface/border/text-muted (no existe un
363
+ * token "neutral" dedicado en base.css, así que se arma con los tokens
364
+ * de superficie/borde/texto-muted más cercanos).
365
+ */
366
+ declare class Chip {
367
+ readonly tone: _angular_core.InputSignal<"ok" | "warn" | "error" | "neutral">;
368
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Chip, never>;
369
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Chip, "kf-chip", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
370
+ }
371
+
372
+ /** Metadato clave mostrado junto al selector (RUC, identificación, sucursal). */
373
+ interface CompanySelectorMeta {
374
+ label: string;
375
+ value: string;
376
+ }
377
+ /**
378
+ * Conmutador de empresa activa con metadatos clave (página 32) — encabeza
379
+ * la pantalla de inicio del portal. Compone `kf-select` para el propio
380
+ * selector (mismo panel propio, sin `<select>` nativo) y proyecta hasta 3
381
+ * pares label/valor (RUC, Identificación, Sucursal en el ejemplo del PDF).
382
+ *
383
+ * <kf-company-selector
384
+ * label="Selecciona empresa"
385
+ * [companies]="['TRANSPORTES DEL SUR S.A.C.', 'ANDES MAQ LTDA.']"
386
+ * [value]="activeCompany()"
387
+ * (valueChange)="activeCompany.set($event)"
388
+ * [meta]="[
389
+ * { label: 'RUC', value: '20448712359' },
390
+ * { label: 'Identificación', value: '0004002232' },
391
+ * { label: 'Sucursal', value: 'Sucursal Norte' },
392
+ * ]"
393
+ * />
394
+ */
395
+ declare class CompanySelector {
396
+ readonly label: _angular_core.InputSignal<string>;
397
+ readonly companies: _angular_core.InputSignal<string[]>;
398
+ readonly value: _angular_core.InputSignal<string | undefined>;
399
+ readonly meta: _angular_core.InputSignal<CompanySelectorMeta[]>;
400
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
401
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<CompanySelector, never>;
402
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CompanySelector, "kf-company-selector", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "companies": { "alias": "companies"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "meta": { "alias": "meta"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
403
+ }
404
+
405
+ /**
406
+ * Marcador genérico para contenido aún por definir (página 38) — comunica
407
+ * "contenido disponible para uso" sin parecer un error, a diferencia de
408
+ * `kf-empty-state` (que comunica ausencia real de datos del usuario).
409
+ * Pensado para secciones del portal que un negocio todavía no completó.
410
+ *
411
+ * `compact` reduce el tamaño de la imagen placeholder y omite el badge de
412
+ * pie (segunda variante de la página 38, sin la etiqueta "Contenido
413
+ * disponible para uso" al final).
414
+ *
415
+ * <kf-content-slot title="Contenido disponible"
416
+ * description="Espacio reservado para contenido de Divemotor Perú. Disponible para uso." />
417
+ * <kf-content-slot compact icon="star" title="Contenido disponible"
418
+ * description="Espacio reservado para contenido de Divemotor Perú." />
419
+ */
420
+ declare class ContentSlot {
421
+ readonly title: _angular_core.InputSignal<string>;
422
+ readonly description: _angular_core.InputSignal<string | undefined>;
423
+ readonly icon: _angular_core.InputSignal<IconName>;
424
+ readonly compact: _angular_core.InputSignalWithTransform<boolean, unknown>;
425
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentSlot, never>;
426
+ 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>;
427
+ }
428
+
429
+ /** En qué estado está la sección. */
430
+ type ContentStateKind = 'ready' | 'loading' | 'empty' | 'error';
431
+ /** Cómo se dibuja `loading`. Default `'skeleton'`. */
432
+ type ContentStateLoad = 'skeleton' | 'spinner';
433
+ /**
434
+ * Wrapper de los cuatro estados que toda sección tiene: cargando, con datos,
435
+ * vacía y con error. Un componente en vez de tres `@if` sueltos, porque es
436
+ * siempre el mismo slot el que va rotando entre los cuatro.
437
+ *
438
+ * Con `state="ready"` proyecta el contenido real y desaparece; en los otros
439
+ * tres dibuja el placeholder correspondiente y el contenido no se instancia.
440
+ * No inventa visuales propios: `loading` usa `kf-skeleton` (o `kf-spinner` con
441
+ * `load="spinner"`), y `empty`/`error` usan `kf-empty-state`.
442
+ *
443
+ * Las acciones (reintentar, crear) van en el slot `actions` — se ignoran
444
+ * mientras carga, porque no hay nada que reintentar todavía.
445
+ *
446
+ * <kf-content-state [state]="state()" title="No pudimos cargar tus vehículos"
447
+ * subtitle="Revisá tu conexión e intentá de nuevo.">
448
+ * <kf-button actions (click)="retry()">Reintentar</kf-button>
449
+ * <kf-data-table [columns]="cols" [rows]="rows()" />
450
+ * </kf-content-state>
451
+ */
452
+ declare class ContentState {
453
+ readonly state: _angular_core.InputSignal<ContentStateKind>;
454
+ /** Forma del estado de carga: silueta (default) o spinner. */
455
+ readonly load: _angular_core.InputSignal<ContentStateLoad>;
456
+ /** Título de `empty`/`error`. Ignorado mientras carga. */
457
+ readonly title: _angular_core.InputSignal<string>;
458
+ readonly subtitle: _angular_core.InputSignal<string>;
459
+ /** Texto al lado del spinner cuando `load="spinner"`. */
460
+ readonly loadingLabel: _angular_core.InputSignal<string>;
461
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContentState, never>;
462
+ 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>;
463
+ }
464
+
465
+ /**
466
+ * Zona que ocupa la columna en la vista de cards. La vista de tabla ignora
467
+ * esto (salvo `media`, que igual se rinde como thumbnail en vez de imprimir
468
+ * la URL):
469
+ * - `media`: thumbnail a la izquierda del encabezado; el valor de la celda se
470
+ * usa como `src` salvo que la columna traiga su `cellTemplates`.
471
+ * - `title`: título del encabezado (ej. la patente/unidad).
472
+ * - `status`: chip/estado al lado del título.
473
+ * - `field` (default): par label/valor en el cuerpo.
474
+ * - `action`: va al pie, separado del cuerpo por una línea.
475
+ */
476
+ type DataTableCardRole = 'media' | 'title' | 'status' | 'field' | 'action';
477
+ interface DataTableColumn {
478
+ key: string;
479
+ label: string;
480
+ right?: boolean;
481
+ className?: string;
482
+ cardRole?: DataTableCardRole;
483
+ }
484
+ /** Vistas disponibles cuando `cardable` está activo. */
485
+ type DataTableView = 'table' | 'cards';
486
+ /**
487
+ * Tabla estandarizada con soporte opcional de toggle tabla/cards.
488
+ *
489
+ * El "render" custom por columna de la spec original (una función que
490
+ * devuelve JSX) se resuelve acá de dos formas, de la más simple a la más
491
+ * flexible:
492
+ * - `render`: función `(row) => string` para el caso típico de mostrar un
493
+ * valor derivado/formateado de la fila como texto plano.
494
+ * - `cellTemplates`: mapa `key -> TemplateRef` para cuando un consumidor
495
+ * necesita marcado real dentro de una celda (badges, links, botones). Se
496
+ * proyecta con `ngTemplateOutlet` y recibe `{ $implicit: row, index }`.
497
+ * Se eligió esta combinación en vez de content-projection por columna
498
+ * (ng-content con selector) porque las columnas son dinámicas (vienen de
499
+ * `columns()`), y `ngTemplateOutlet` es el mecanismo estándar de Angular
500
+ * para "insertar esta plantilla por cada fila de este array".
501
+ *
502
+ * En la vista de cards, `cardRole` por columna reparte el contenido en zonas
503
+ * — encabezado (thumbnail + título + estado), cuerpo (pares label/valor) y
504
+ * pie separado por una línea para las acciones. Sin `cardRole`, todas las
505
+ * columnas caen en el cuerpo, igual que antes.
506
+ *
507
+ * El modo `cards` no depende de un componente ViewToggle separado: expone
508
+ * un control de segmentos mínimo inline (mismo patrón visual que
509
+ * kf-segmented) para no acoplarse a un componente que otro agente puede
510
+ * estar construyendo en paralelo — ver nota en el resumen de la tarea.
511
+ *
512
+ * <kf-data-table [columns]="columns" [rows]="rows" (rowClick)="onRowClick($event)">
513
+ * <kf-empty-state empty>No hay resultados para mostrar.</kf-empty-state>
514
+ * </kf-data-table>
515
+ *
516
+ * <kf-data-table [columns]="columns" [rows]="rows" [cardable]="true" defaultView="cards" />
517
+ *
518
+ * El slot `[footer]` (página 15: "slot de pie para paginación") va siempre
519
+ * al final, en ambas vistas, separado por una línea — pensado para proyectar
520
+ * `<kf-pagination>`, que sigue siendo un componente independiente.
521
+ *
522
+ * <kf-data-table [columns]="columns" [rows]="rows">
523
+ * <kf-pagination footer [page]="page()" [total]="total()" (pageChange)="page.set($event)" />
524
+ * </kf-data-table>
525
+ */
526
+ declare class DataTable<T = unknown> {
527
+ readonly columns: _angular_core.InputSignal<DataTableColumn[]>;
528
+ readonly rows: _angular_core.InputSignal<T[]>;
529
+ /** Default: índice de la fila dentro de `rows`. */
530
+ readonly rowKey: _angular_core.InputSignal<((row: T, index: number) => string | number) | undefined>;
531
+ /** Sin borde/sombra de card — para tablas anidadas dentro de otra card. */
532
+ readonly flush: _angular_core.InputSignal<boolean>;
533
+ /** Habilita el toggle de vista tabla/cards. */
534
+ readonly cardable: _angular_core.InputSignal<boolean>;
535
+ readonly defaultView: _angular_core.InputSignal<DataTableView>;
536
+ /**
537
+ * Formateo simple de celda como texto: `(row) => string`. Para marcado
538
+ * real (badges, links, botones) usar `cellTemplates`.
539
+ */
540
+ readonly render: _angular_core.InputSignal<((row: T) => string) | undefined>;
541
+ /** Mapa `columnKey -> TemplateRef` para celdas con contenido custom. */
542
+ readonly cellTemplates: _angular_core.InputSignal<Record<string, TemplateRef<{
543
+ $implicit: T;
544
+ index: number;
545
+ }>> | undefined>;
546
+ readonly rowClick: _angular_core.OutputEmitterRef<{
547
+ row: T;
548
+ index: number;
549
+ }>;
550
+ private readonly internalView;
551
+ /** Vista activa: la elegida por el usuario, o `defaultView` si no tocó el toggle. */
552
+ readonly view: _angular_core.Signal<DataTableView>;
553
+ /** Primera columna de cada rol único; el resto se ignora en el encabezado. */
554
+ readonly cardMediaColumn: _angular_core.Signal<DataTableColumn | undefined>;
555
+ readonly cardTitleColumn: _angular_core.Signal<DataTableColumn | undefined>;
556
+ readonly cardStatusColumns: _angular_core.Signal<DataTableColumn[]>;
557
+ readonly cardActionColumns: _angular_core.Signal<DataTableColumn[]>;
558
+ readonly cardFieldColumns: _angular_core.Signal<DataTableColumn[]>;
559
+ /**
560
+ * La card entera es clickeable solo si no tiene acciones propias: un
561
+ * `role="button"` con botones adentro es inválido y deja el foco ambiguo.
562
+ * Con columnas `action`, la interacción la manejan esos botones.
563
+ */
564
+ readonly cardInteractive: _angular_core.Signal<boolean>;
565
+ setView(next: DataTableView): void;
566
+ trackRow(row: T, index: number): string | number;
567
+ cellValue(row: T, column: DataTableColumn): string;
568
+ onRowClick(row: T, index: number): void;
569
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataTable<any>, never>;
570
+ 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; }; "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; }; }, { "rowClick": "rowClick"; }, never, ["[empty]", "[footer]"], true, never>;
571
+ }
572
+
573
+ /**
574
+ * Placeholder para una sección sin contenido. Dos tonos, con anatomía
575
+ * distinta (páginas 27-28 del design system, que los trata como piezas
576
+ * separadas — "Error State" no es una variante de color de "Empty State",
577
+ * es un estado semánticamente distinto):
578
+ *
579
+ * - `neutral` (default): "cero resultados" — cuadro con borde punteado
580
+ * discreto, para listas vacías o búsquedas sin coincidencias. No es un
581
+ * error, es la ausencia normal de datos.
582
+ * - `error`: fallo real de carga — sin borde punteado, con un ícono de
583
+ * alerta más prominente y texto en el tono de error. Pensado para usarse
584
+ * junto a un botón "Reintentar" en el slot por defecto.
585
+ *
586
+ * <kf-empty-state>No se encontraron resultados.</kf-empty-state>
587
+ * <kf-empty-state icon="search">Sin coincidencias para tu búsqueda.</kf-empty-state>
588
+ * <kf-empty-state tone="error" icon="alert-triangle">
589
+ * No pudimos cargar tus vehículos
590
+ * <kf-button (click)="retry()">Reintentar</kf-button>
591
+ * </kf-empty-state>
592
+ */
593
+ declare class EmptyState {
594
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
595
+ /** `neutral` (default): cero resultados. `error`: fallo real de carga. */
596
+ readonly tone: _angular_core.InputSignal<"error" | "neutral">;
597
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EmptyState, never>;
598
+ 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>;
599
+ }
600
+
601
+ /**
602
+ * Bloque promocional sobre fondo oscuro de marca (página 37) — campañas,
603
+ * accesos directos o el portal de autoatención. Usa `--kf-color-tertiary-deep`
604
+ * como base del degradado, el mismo azul profundo que el slide destacado de
605
+ * `kf-carousel` y la barra de `kf-portal-header`.
606
+ *
607
+ * <kf-feature-card badge="Autoatención" badgeIcon="tool" title="Portal de Autoatención"
608
+ * description="Con tu patente o VIN accede a soluciones para tu vehículo: mantenciones, repuestos y conectividad en un solo lugar."
609
+ * actionLabel="Ir al portal" actionHref="/autoatencion" />
610
+ */
611
+ declare class FeatureCard {
612
+ readonly badge: _angular_core.InputSignal<string | undefined>;
613
+ readonly badgeIcon: _angular_core.InputSignal<IconName | undefined>;
614
+ readonly title: _angular_core.InputSignal<string>;
615
+ readonly description: _angular_core.InputSignal<string | undefined>;
616
+ readonly actionLabel: _angular_core.InputSignal<string | undefined>;
617
+ readonly actionHref: _angular_core.InputSignal<string | undefined>;
618
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FeatureCard, never>;
619
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FeatureCard, "kf-feature-card", never, { "badge": { "alias": "badge"; "required": false; "isSignal": true; }; "badgeIcon": { "alias": "badgeIcon"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "actionLabel": { "alias": "actionLabel"; "required": false; "isSignal": true; }; "actionHref": { "alias": "actionHref"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
620
+ }
621
+
622
+ /**
623
+ * Chip de solo-lectura inline (label/valor) dentro de una caja bordeada.
624
+ * Se usa en barras de filtro y filas de resumen para mostrar información,
625
+ * NO para entrada de datos — para eso existe `Input`.
626
+ *
627
+ * El valor admite dos formas, igual que en el design system de referencia:
628
+ * - `value` (string): caso simple, ej. `[value]="'Jul 2026'"`.
629
+ * - contenido proyectado (`<ng-content>`): cuando se necesita algo más rico
630
+ * que un string (un badge, texto con formato, etc.).
631
+ * `value` tiene prioridad cuando está definido; si no se pasa `value`, se
632
+ * renderiza el contenido proyectado y, si tampoco hay contenido, `placeholder`.
633
+ *
634
+ * <kf-field icon="calendar" label="Periodo" value="Jul 2026" [select]="true" />
635
+ * <kf-field label="Sucursal"><strong>Casa Central</strong></kf-field>
636
+ */
637
+ declare class Field {
638
+ readonly label: _angular_core.InputSignal<string | undefined>;
639
+ readonly value: _angular_core.InputSignal<string | undefined>;
640
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
641
+ readonly placeholder: _angular_core.InputSignal<string | undefined>;
642
+ readonly select: _angular_core.InputSignalWithTransform<boolean, unknown>;
643
+ /** Estilos inline opcionales aplicados directamente al host. */
644
+ readonly style: _angular_core.InputSignal<string | undefined>;
645
+ /**
646
+ * El placeholder solo tiene sentido cuando no hay `value` ni contenido
647
+ * proyectado. Angular no expone de forma simple si `<ng-content>` recibió
648
+ * hijos reales, así que la regla adoptada es puramente declarativa: se
649
+ * muestra el placeholder cuando hay texto de placeholder y no hay `value`
650
+ * (ver comentario de clase sobre la prioridad value > proyectado > placeholder).
651
+ */
652
+ protected isPlaceholderVisible(): boolean;
653
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Field, never>;
654
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Field, "kf-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "select": { "alias": "select"; "required": false; "isSignal": true; }; "style": { "alias": "style"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
655
+ }
656
+
657
+ /**
658
+ * Label superior compartido por todos los campos de formulario del design
659
+ * system (páginas 11-12: Text Field, Select, Multiselect) — uppercase,
660
+ * chico, gris, con letter-spacing amplio. El PDF fija un único tratamiento
661
+ * ("PATENTE O VIN", "SUCURSAL", "SUCURSALES" usan exactamente el mismo
662
+ * estilo), así que este componente es la única fuente de verdad: antes vivía
663
+ * copiado por separado en `Input`, `Select`, `SelectMenu` y `MultiSelect`,
664
+ * y dos de esas copias ya habían divergido del estilo real del PDF.
665
+ *
666
+ * No reemplaza al `<label>` nativo — lo envuelve, para no perder la
667
+ * asociación de accesibilidad `for`/`id` con el control real.
668
+ *
669
+ * <kf-field-label [for]="inputId">Patente o VIN</kf-field-label>
670
+ */
671
+ declare class FieldLabel {
672
+ /** `id` del control asociado — se refleja como `for` en el `<label>` interno. */
673
+ readonly for: _angular_core.InputSignal<string | undefined>;
674
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldLabel, never>;
675
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldLabel, "kf-field-label", never, { "for": { "alias": "for"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
676
+ }
677
+
678
+ /** Forma normalizada interna de cada opción, ya resuelta a value/label. */
679
+ interface FilterChipOption {
680
+ value: string;
681
+ label: string;
682
+ }
683
+ /**
684
+ * Fila de chips tipo "pill" para filtros de una sola selección.
685
+ *
686
+ * Cada opción puede pasarse como string simple (se usa como value y label
687
+ * a la vez) o como objeto { value, label } cuando el texto mostrado difiere
688
+ * del valor interno.
689
+ *
690
+ * El chip activo se resalta con el color "ink" oscuro (--kf-color-ink), no
691
+ * con el color primario de marca: así lo define el sistema de diseño de
692
+ * referencia para este componente en particular.
693
+ *
694
+ * <kf-filter-chips [options]="['Todos', 'Activos', 'Archivados']"
695
+ * [value]="filtro"
696
+ * (valueChange)="filtro = $event" />
697
+ *
698
+ * <kf-filter-chips [options]="[{ value: 'all', label: 'Todos' }]"
699
+ * [value]="filtro"
700
+ * (valueChange)="filtro = $event" />
701
+ */
702
+ declare class FilterChips {
703
+ readonly options: _angular_core.InputSignal<(string | {
704
+ value: string;
705
+ label: string;
706
+ })[]>;
707
+ readonly value: _angular_core.InputSignal<string>;
708
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
709
+ /** Normaliza cada opción string/objeto a la forma { value, label }. */
710
+ readonly normalizedOptions: _angular_core.Signal<FilterChipOption[]>;
711
+ select(value: string): void;
712
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FilterChips, never>;
713
+ 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>;
714
+ }
715
+
716
+ interface FolderTabOption {
717
+ value: string;
718
+ label: string;
719
+ icon?: IconName;
720
+ }
721
+ /**
722
+ * Tabs con forma de "carpeta": el borde superior queda redondeado y el borde
723
+ * inferior de la pestaña activa se funde visualmente con el panel de
724
+ * contenido que va debajo (misma superficie, sin línea divisoria).
725
+ *
726
+ * Al cambiar de pestaña, la que se activa se "abre": gira sobre su borde
727
+ * inferior (hinge 3D) y sube con un pequeño rebote. Es CSS solo: la clase
728
+ * `--active` se mueve de un botón a otro, y eso vuelve a disparar el keyframe
729
+ * sin tocar JS.
730
+ *
731
+ * El consumidor es responsable de renderizar el panel de contenido debajo;
732
+ * este componente solo resuelve la fila de pestañas y emite `valueChange`.
733
+ *
734
+ * <kf-folder-tabs [options]="tabs" [value]="active" (valueChange)="active = $event" />
735
+ */
736
+ declare class FolderTabs {
737
+ readonly options: _angular_core.InputSignal<FolderTabOption[]>;
738
+ readonly value: _angular_core.InputSignal<string>;
739
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
740
+ select(value: string): void;
741
+ /** Navegación estándar de ARIA tabs: flechas mueven el foco y activan la pestaña. */
742
+ onKeydown(event: KeyboardEvent, currentValue: string): void;
743
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FolderTabs, never>;
744
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FolderTabs, "kf-folder-tabs", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
745
+ }
746
+
747
+ /**
748
+ * Input de formulario apilado: label arriba (en mayúsculas vía CSS), campo con
749
+ * fondo gris que pasa a blanco con anillo de foco azul al enfocar.
750
+ *
751
+ * Implementa ControlValueAccessor, así que funciona con [(ngModel)] y con
752
+ * Reactive Forms (formControl / formControlName), no es solo un wrapper visual.
753
+ *
754
+ * <kf-input label="Placa" icon="car" placeholder="ABC-123" hint="Formato: 3 letras + 3 números" />
755
+ * <input kf-input formControlName="email" type="email" />
756
+ *
757
+ * Nota sobre "icon": todavía no existe un componente Icon / sprite SVG en esta
758
+ * librería. El prop se acepta igual para no romper el contrato de la spec,
759
+ * pero por ahora solo reserva el espacio visual (placeholder vacío) — no
760
+ * renderiza ningún glyph real.
761
+ */
762
+ declare class Input implements ControlValueAccessor, AfterViewInit {
763
+ private static nextId;
764
+ private readonly nativeInput;
765
+ readonly label: _angular_core.InputSignal<string | undefined>;
766
+ /** Nombre de ícono líder. Ver nota de clase: sin componente Icon todavía. */
767
+ readonly icon: _angular_core.InputSignal<string | undefined>;
768
+ readonly suffix: _angular_core.InputSignal<string | undefined>;
769
+ readonly hint: _angular_core.InputSignal<string | undefined>;
770
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
771
+ readonly type: _angular_core.InputSignal<string>;
772
+ readonly placeholder: _angular_core.InputSignal<string>;
773
+ protected readonly inputId: string;
774
+ protected readonly hintId: string;
775
+ protected readonly value: _angular_core.WritableSignal<string>;
776
+ protected readonly focused: _angular_core.WritableSignal<boolean>;
777
+ /** Deshabilitado por Reactive Forms (formControl.disable()). */
778
+ private readonly disabledByForm;
779
+ /** Disabled real: por input() directo o por el FormControl asociado. */
780
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
781
+ private onChange;
782
+ private onTouched;
783
+ ngAfterViewInit(): void;
784
+ writeValue(value: string): void;
785
+ registerOnChange(fn: (value: string) => void): void;
786
+ registerOnTouched(fn: () => void): void;
787
+ setDisabledState(isDisabled: boolean): void;
788
+ protected onInput(rawValue: string): void;
789
+ protected onBlur(): void;
790
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Input, never>;
791
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Input, "kf-input", never, { "label": { "alias": "label"; "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; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
792
+ }
793
+
794
+ /**
795
+ * Card de estadística/KPI: label, valor grande, ícono opcional en la esquina
796
+ * superior derecha, badge de esquina opcional (pegado al valor) y una nota
797
+ * al pie. Pensada para tableros de resumen (ej. "11 Tickets abiertos").
798
+ *
799
+ * Compone sobre `kf-card` en vez de duplicar su estilo de contenedor — así
800
+ * el look de "card" (radio, sombra, borde) tiene una única fuente de verdad
801
+ * en toda la librería, tal como pide el design system (página 14: "Card...
802
+ * es la base de paneles, tarjetas de métrica, tablas...").
803
+ *
804
+ * <kf-metric-card label="Tickets abiertos" value="11" icon="ticket" foot="+2 hoy" />
805
+ * <kf-metric-card label="Tasa de resolución" value="94%" badge="+2%" value-color="var(--kf-color-success)" />
806
+ */
807
+ declare class MetricCard {
808
+ readonly label: _angular_core.InputSignal<string>;
809
+ readonly value: _angular_core.InputSignal<string | number>;
810
+ readonly unit: _angular_core.InputSignal<string | undefined>;
811
+ /** Ícono en la esquina superior derecha, renderizado vía `kf-icon`. */
812
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
813
+ readonly foot: _angular_core.InputSignal<string | undefined>;
814
+ /** Tinte opcional para el valor grande (ej. un color semántico de estado). */
815
+ readonly valueColor: _angular_core.InputSignal<string | undefined>;
816
+ /** Badge de esquina opcional, pegado al valor (ej. "+2%"). */
817
+ readonly badge: _angular_core.InputSignal<string | undefined>;
818
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MetricCard, never>;
819
+ 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, never, true, never>;
820
+ }
821
+
822
+ /**
823
+ * Diálogo centrado sobre un backdrop: confirmaciones destructivas, formularios
824
+ * cortos, decisiones que bloquean el flujo.
825
+ *
826
+ * Se apoya en el `<dialog>` nativo (`showModal()`), así que el atrapado de
827
+ * foco, el backdrop, el orden en el top-layer y el cierre con `Escape` los
828
+ * resuelve el navegador — no hay trampa de foco escrita a mano acá. Lo único
829
+ * que se agrega es el lock de scroll del body, que `<dialog>` no hace.
830
+ *
831
+ * `open` es two-way. Con `dismissible` en `false` (ej. mientras una acción
832
+ * destructiva está en vuelo) se cancelan `Escape` y el clic en el backdrop:
833
+ * solo cierra el consumidor poniendo `open` en `false`.
834
+ *
835
+ * Las acciones van en el slot `footer`.
836
+ *
837
+ * <kf-modal [(open)]="confirmOpen" title="Eliminar unidad">
838
+ * <p>Esta acción no se puede deshacer.</p>
839
+ * <div footer>
840
+ * <kf-button variant="ghost" (click)="confirmOpen.set(false)">Cancelar</kf-button>
841
+ * <kf-button (click)="remove()">Eliminar</kf-button>
842
+ * </div>
843
+ * </kf-modal>
844
+ */
845
+ declare class Modal {
846
+ readonly title: _angular_core.InputSignal<string>;
847
+ /** Visibilidad, two-way: `[(open)]="confirmOpen"`. */
848
+ readonly open: _angular_core.ModelSignal<boolean>;
849
+ /** Permite cerrar con el botón, `Escape` o clic en el backdrop. */
850
+ readonly dismissible: _angular_core.InputSignalWithTransform<boolean, unknown>;
851
+ protected readonly titleId: string;
852
+ private readonly dialog;
853
+ private readonly document;
854
+ constructor();
855
+ /** `Escape` dispara `cancel`; cancelarlo lo deja abierto. */
856
+ protected onCancel(event: Event): void;
857
+ /**
858
+ * Clic en el backdrop. Un clic en la zona del backdrop tiene como `target` al
859
+ * propio `<dialog>` (el contenido vive en el panel de adentro), así que basta
860
+ * comparar contra él — no hace falta cortar la propagación en el panel.
861
+ *
862
+ * Va como HostListener y no como binding en el template porque un `(click)`
863
+ * sobre el `<dialog>` dispara las reglas a11y de click-sin-teclado; acá el
864
+ * equivalente de teclado es `Escape`, que el `<dialog>` nativo ya maneja.
865
+ */
866
+ protected onHostClick(event: MouseEvent): void;
867
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Modal, never>;
868
+ 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; }; }, { "open": "openChange"; }, never, ["*", "[footer]"], true, never>;
869
+ }
870
+
871
+ interface MultiSelectOption {
872
+ value: string;
873
+ label: string;
874
+ }
875
+ /**
876
+ * Dropdown de selección múltiple con checkboxes internos, siguiendo el mismo
877
+ * patrón de panel flotante que `SelectMenu` (panel con `position: absolute`
878
+ * sobre el host, sin Angular CDK Overlay, que no es dependencia del proyecto).
879
+ * Se abre y cierra por click en el disparador, y se cierra al hacer click
880
+ * afuera o al presionar Escape.
881
+ *
882
+ * A diferencia de `SelectMenu`, el disparador no muestra un único valor sino
883
+ * los nombres seleccionados junto a un badge circular con el conteo (página
884
+ * 12: "Sucursal Norte, Lima Centro" + badge "2"), y cada opción del panel se
885
+ * marca/desmarca con un checkbox sin cerrar el panel. Incluye una opción
886
+ * "Todas" al inicio de la lista, con estado `indeterminate` cuando hay
887
+ * selección parcial — el mismo patrón de "seleccionar todos" de `Checkbox`.
888
+ *
889
+ * <kf-multi-select
890
+ * label="Sucursales"
891
+ * [options]="branches"
892
+ * [values]="selectedBranches()"
893
+ * (valuesChange)="selectedBranches.set($event)"
894
+ * />
895
+ *
896
+ * Pendiente: el prop `icon` de otros componentes del design system requiere
897
+ * un componente Icon / sprite SVG que esta librería todavía no tiene — este
898
+ * componente no usa iconos, así que no aplica acá.
899
+ */
900
+ declare class MultiSelect {
901
+ readonly label: _angular_core.InputSignal<string | undefined>;
902
+ readonly options: _angular_core.InputSignal<MultiSelectOption[]>;
903
+ readonly values: _angular_core.InputSignal<string[]>;
904
+ readonly placeholder: _angular_core.InputSignal<string>;
905
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
906
+ readonly valuesChange: _angular_core.OutputEmitterRef<string[]>;
907
+ private readonly instanceId;
908
+ readonly triggerId: string;
909
+ readonly listboxId: string;
910
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
911
+ readonly selectedCount: _angular_core.Signal<number>;
912
+ readonly allSelected: _angular_core.Signal<boolean>;
913
+ readonly isPartiallySelected: _angular_core.Signal<boolean>;
914
+ /**
915
+ * Texto del disparador: placeholder si no hay selección, o los nombres
916
+ * seleccionados unidos por coma (el conteo va aparte, en el badge). Con
917
+ * muchas opciones el `text-overflow: ellipsis` del `.kf-multi-select__value`
918
+ * corta el texto — el badge de conteo siempre queda visible al lado.
919
+ */
920
+ readonly summaryText: _angular_core.Signal<string>;
921
+ private readonly host;
922
+ isSelected(value: string): boolean;
923
+ toggle(): void;
924
+ toggleOption(value: string): void;
925
+ /** Alterna entre "todas seleccionadas" y "ninguna seleccionada". */
926
+ toggleAll(): void;
927
+ onDocumentClick(event: MouseEvent): void;
928
+ onEscape(): void;
929
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MultiSelect, never>;
930
+ 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; }; }, { "valuesChange": "valuesChange"; }, never, never, true, never>;
931
+ }
932
+
933
+ /**
934
+ * Bloque de título al tope de una página: chip de ícono opcional, título (h1),
935
+ * subtítulo opcional y un área de acciones opcional proyectada vía
936
+ * `<ng-content select="[actions]">`, para no acoplar el componente a un set
937
+ * fijo de botones.
938
+ *
939
+ * <kf-page-header title="Vehículos" subtitle="Gestión de la flota activa">
940
+ * <button actions>Nuevo vehículo</button>
941
+ * </kf-page-header>
942
+ *
943
+ * <kf-page-header icon="settings" title="Configuración" />
944
+ */
945
+ declare class PageHeader {
946
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
947
+ readonly title: _angular_core.InputSignal<string>;
948
+ readonly subtitle: _angular_core.InputSignal<string | undefined>;
949
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PageHeader, never>;
950
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PageHeader, "kf-page-header", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
951
+ }
952
+
953
+ /** Un número de página clickeable o un separador "…" no interactivo. */
954
+ type PaginationItem = {
955
+ type: 'page';
956
+ page: number;
957
+ } | {
958
+ type: 'ellipsis';
959
+ };
960
+ /**
961
+ * Paginador numerado con elipsis + prev/next.
962
+ *
963
+ * Algoritmo de elipsis estándar: siempre se muestran la primera página, la
964
+ * última, la página actual y un par de vecinas alrededor de la actual; el
965
+ * resto de los huecos se colapsa en un separador "…". Cuando el hueco entre
966
+ * dos números visibles es de exactamente una página, se muestra ese número
967
+ * en vez de un "…" (no tiene sentido colapsar un solo elemento).
968
+ *
969
+ * El contenido proyectado (`<ng-content>`) es para el texto informativo
970
+ * opcional (ej. "21–40 de 273"), a la izquierda de los controles.
971
+ *
972
+ * <kf-pagination [page]="page" [pages]="totalPages" (pageChange)="page = $event">
973
+ * 21–40 de 273
974
+ * </kf-pagination>
975
+ */
976
+ declare class Pagination {
977
+ readonly page: _angular_core.InputSignal<number>;
978
+ readonly pages: _angular_core.InputSignal<number>;
979
+ readonly pageChange: _angular_core.OutputEmitterRef<number>;
980
+ /** Lista de números de página y separadores a renderizar, ya resuelta por el algoritmo de elipsis. */
981
+ readonly items: _angular_core.Signal<PaginationItem[]>;
982
+ goTo(target: number): void;
983
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Pagination, never>;
984
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Pagination, "kf-pagination", never, { "page": { "alias": "page"; "required": false; "isSignal": true; }; "pages": { "alias": "pages"; "required": false; "isSignal": true; }; }, { "pageChange": "pageChange"; }, never, ["*"], true, never>;
985
+ }
986
+
987
+ /**
988
+ * Tarjeta contenedora con título, enlace de acción opcional a la derecha, y
989
+ * cuerpo con contenido libre — página 33: "Base de la mayoría de bloques del
990
+ * portal". Compone sobre `kf-card` para compartir la misma superficie
991
+ * (radio, sombra, borde) que el resto de la librería.
992
+ *
993
+ * <kf-panel title="Mis documentos por pagar" actionLabel="Ir a pagos" actionHref="/pagos">
994
+ * <kf-action-tile-row icon="download" title="Pagos" description="Revisa tu estado de cuenta y realiza pagos." />
995
+ * </kf-panel>
996
+ */
997
+ declare class Panel {
998
+ readonly title: _angular_core.InputSignal<string>;
999
+ readonly actionLabel: _angular_core.InputSignal<string | undefined>;
1000
+ readonly actionHref: _angular_core.InputSignal<string | undefined>;
1001
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Panel, never>;
1002
+ 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; }; }, {}, never, ["*"], true, never>;
1003
+ }
1004
+
1005
+ /** Un ítem de navegación de la barra de marca. */
1006
+ interface PortalHeaderNavItem {
1007
+ label: string;
1008
+ href: string;
1009
+ active?: boolean;
1010
+ }
1011
+ /** Una acción de la franja de administrador (ej. "Consultar deuda clientes"). */
1012
+ interface PortalHeaderAdminAction {
1013
+ label: string;
1014
+ href: string;
1015
+ }
1016
+ /**
1017
+ * Cabecera completa del portal (página 31) — franja de administrador
1018
+ * (acento ámbar, solo admins), barra de marca con logo, navegación y
1019
+ * pastilla de sesión. Compone `kf-admin-badge` para la franja y `kf-avatar
1020
+ * pill` para la sesión, en vez de reimplementar ambos.
1021
+ *
1022
+ * Es distinto de `kf-page-header`/`kf-page-head` (título de una vista
1023
+ * interna) — este es el chrome global del portal, se monta una sola vez.
1024
+ *
1025
+ * <kf-portal-header
1026
+ * [isAdmin]="true"
1027
+ * [adminActions]="[{ label: 'Consultar deuda clientes', href: '/deuda' }, { label: 'Cambiar DNI', href: '/dni' }]"
1028
+ * [navItems]="[{ label: 'Home', href: '/', active: true }, { label: 'Vehículos', href: '/vehiculos' }]"
1029
+ * userInitials="TS"
1030
+ * />
1031
+ */
1032
+ declare class PortalHeader {
1033
+ readonly brand: _angular_core.InputSignal<string>;
1034
+ readonly isAdmin: _angular_core.InputSignalWithTransform<boolean, unknown>;
1035
+ readonly adminActions: _angular_core.InputSignal<PortalHeaderAdminAction[]>;
1036
+ readonly navItems: _angular_core.InputSignal<PortalHeaderNavItem[]>;
1037
+ readonly userInitials: _angular_core.InputSignal<string>;
1038
+ readonly sessionClick: _angular_core.OutputEmitterRef<void>;
1039
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PortalHeader, never>;
1040
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PortalHeader, "kf-portal-header", never, { "brand": { "alias": "brand"; "required": false; "isSignal": true; }; "isAdmin": { "alias": "isAdmin"; "required": false; "isSignal": true; }; "adminActions": { "alias": "adminActions"; "required": false; "isSignal": true; }; "navItems": { "alias": "navItems"; "required": false; "isSignal": true; }; "userInitials": { "alias": "userInitials"; "required": true; "isSignal": true; }; }, { "sessionClick": "sessionClick"; }, never, never, true, never>;
1041
+ }
1042
+
1043
+ /**
1044
+ * Estado vacío de reservas en taller con llamada a agendar (página 36):
1045
+ * barra de estado vacío arriba ("No tienes reservas de taller"), panel de
1046
+ * invitación al medio (ícono en círculo azul, título, descripción, link) y
1047
+ * una fila de dos acciones al pie — un slot `[actions]` proyectado, para no
1048
+ * acoplar el componente a botones fijos.
1049
+ *
1050
+ * Distinto de `kf-empty-state` genérico: este combina la barra + la
1051
+ * invitación + las acciones como un bloque compuesto propio del dominio
1052
+ * "taller", no un placeholder de una sola pieza.
1053
+ *
1054
+ * <kf-reserve-block emptyLabel="No tienes reservas de taller"
1055
+ * title="¿Necesitas mantención?" description="Tenemos la mejor red de talleres."
1056
+ * actionLabel="Agenda tu reserva aquí" actionHref="/taller/agendar">
1057
+ * <kf-button actions icon="calendar">Reservar hora</kf-button>
1058
+ * <kf-button actions variant="outline" icon="list">Ver agenda</kf-button>
1059
+ * </kf-reserve-block>
1060
+ */
1061
+ declare class ReserveBlock {
1062
+ readonly emptyLabel: _angular_core.InputSignal<string>;
1063
+ readonly title: _angular_core.InputSignal<string>;
1064
+ readonly description: _angular_core.InputSignal<string | undefined>;
1065
+ readonly actionLabel: _angular_core.InputSignal<string | undefined>;
1066
+ readonly actionHref: _angular_core.InputSignal<string | undefined>;
1067
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ReserveBlock, never>;
1068
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ReserveBlock, "kf-reserve-block", never, { "emptyLabel": { "alias": "emptyLabel"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "actionLabel": { "alias": "actionLabel"; "required": false; "isSignal": true; }; "actionHref": { "alias": "actionHref"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
1069
+ }
1070
+
1071
+ /**
1072
+ * Título de sub-sección con chip de ícono, pensado para anidarse dentro de
1073
+ * cards o paneles (a diferencia de `PageHeader`, que encabeza una página
1074
+ * completa). Un área de acciones opcional se proyecta vía
1075
+ * `<ng-content select="[actions]">` para no acoplar el componente a un set
1076
+ * fijo de botones.
1077
+ *
1078
+ * `size="sm"` reduce tipografía y espaciado para usarse dentro de cards ya
1079
+ * compactas. `solid` rellena el chip de ícono con el color primario sólido
1080
+ * en vez del tratamiento "soft" (fondo tenue) — pensado para superficies que
1081
+ * ya tienen un tinte de color propio, donde el chip "soft" perdería contraste.
1082
+ *
1083
+ * <kf-section-header icon="settings" title="Preferencias"
1084
+ * subtitle="Configuración general de la cuenta">
1085
+ * <button actions>Editar</button>
1086
+ * </kf-section-header>
1087
+ *
1088
+ * <kf-section-header title="Detalle" size="sm" [solid]="true" />
1089
+ */
1090
+ declare class SectionHeader {
1091
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
1092
+ readonly title: _angular_core.InputSignal<string>;
1093
+ readonly subtitle: _angular_core.InputSignal<string | undefined>;
1094
+ readonly size: _angular_core.InputSignal<"sm" | undefined>;
1095
+ readonly solid: _angular_core.InputSignalWithTransform<boolean, unknown>;
1096
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SectionHeader, never>;
1097
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SectionHeader, "kf-section-header", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": true; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "solid": { "alias": "solid"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
1098
+ }
1099
+
1100
+ interface SegmentedOption {
1101
+ value: string;
1102
+ label: string;
1103
+ }
1104
+ /**
1105
+ * Control de segmentos relleno, tipo "iOS segmented control": 2-3 opciones
1106
+ * con un thumb que se desliza detrás de la opción activa.
1107
+ *
1108
+ * La posición del thumb se resuelve con una variable CSS (--kf-segmented-index)
1109
+ * y `transform: translateX()`, así la transición queda a cargo de CSS puro
1110
+ * (mismo criterio que Tabs), sin medir el DOM desde TypeScript.
1111
+ *
1112
+ * <kf-segmented [options]="options" [value]="value" (valueChange)="onChange($event)" />
1113
+ */
1114
+ declare class Segmented {
1115
+ readonly options: _angular_core.InputSignal<SegmentedOption[]>;
1116
+ readonly value: _angular_core.InputSignal<string>;
1117
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
1118
+ /** Índice de la opción activa; -1 si `value` no matchea ninguna opción. */
1119
+ readonly selectedIndex: _angular_core.Signal<number>;
1120
+ select(nextValue: string): void;
1121
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Segmented, never>;
1122
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Segmented, "kf-segmented", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
1123
+ }
1124
+
1125
+ /** Normalized shape used internally once `options` (string[] or object[]) is resolved. */
1126
+ interface SelectOption {
1127
+ value: string;
1128
+ label: string;
1129
+ }
1130
+ /**
1131
+ * Dropdown de selección simple con panel propio — NUNCA usa el `<select>`
1132
+ * nativo del navegador. Un `<select>` real siempre delega el popup de
1133
+ * opciones al sistema operativo, y ningún CSS puede controlar cómo se ve
1134
+ * ese popup (ver el mismo problema ya resuelto en `SelectMenu`, del que
1135
+ * este componente reutiliza el patrón completo: trigger + panel flotante
1136
+ * propio, cerrado con click-afuera y Escape).
1137
+ *
1138
+ * Pensado para sets simples y cortos. Para listas más ricas o con más
1139
+ * opciones, es el mismo componente que `SelectMenu` — la diferencia es
1140
+ * solo de estilo (label uppercase, fondo gris que pasa a blanco al foco,
1141
+ * a tono con `Input`) y que acepta `options` como `string[]` además de
1142
+ * `{ value, label }[]`.
1143
+ *
1144
+ * <kf-select label="Sede" [options]="['Lima', 'Arequipa', 'Trujillo']" placeholder="Selecciona…" />
1145
+ * <kf-select [options]="[{ value: 'pe', label: 'Perú' }]" (valueChange)="onCountry($event)" />
1146
+ */
1147
+ declare class Select {
1148
+ readonly label: _angular_core.InputSignal<string | undefined>;
1149
+ readonly options: _angular_core.InputSignal<string[] | SelectOption[]>;
1150
+ readonly value: _angular_core.InputSignal<string | undefined>;
1151
+ readonly placeholder: _angular_core.InputSignal<string>;
1152
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
1153
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
1154
+ private readonly instanceId;
1155
+ readonly triggerId: string;
1156
+ readonly listboxId: string;
1157
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
1158
+ /** Resolves the union (`string[] | { value; label }[]`) into a single shape for the template. */
1159
+ readonly normalizedOptions: _angular_core.Signal<SelectOption[]>;
1160
+ readonly selectedOption: _angular_core.Signal<SelectOption | undefined>;
1161
+ private readonly host;
1162
+ toggle(): void;
1163
+ select(option: SelectOption): void;
1164
+ onDocumentClick(event: MouseEvent): void;
1165
+ onEscape(): void;
1166
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Select, never>;
1167
+ 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; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
1168
+ }
1169
+
1170
+ interface SelectMenuOption {
1171
+ value: string;
1172
+ label: string;
1173
+ }
1174
+ /**
1175
+ * Dropdown de selección simple pero con panel propio (no usa `<select>` nativo),
1176
+ * para cuando se necesita más control visual que un `<select>` estándar permite.
1177
+ *
1178
+ * El panel flotante se implementa con `position: absolute` sobre el host
1179
+ * (sin Angular CDK Overlay, que no es dependencia del proyecto). Se abre y
1180
+ * cierra por click en el disparador, y se cierra al hacer click afuera o al
1181
+ * presionar Escape.
1182
+ *
1183
+ * <kf-select-menu
1184
+ * label="País"
1185
+ * [options]="countries"
1186
+ * [value]="selectedCountry()"
1187
+ * (valueChange)="selectedCountry.set($event)"
1188
+ * />
1189
+ *
1190
+ * Pendiente: el prop `icon` de otros componentes del design system requiere
1191
+ * un componente Icon / sprite SVG que esta librería todavía no tiene — este
1192
+ * componente no usa iconos, así que no aplica acá.
1193
+ */
1194
+ declare class SelectMenu {
1195
+ readonly label: _angular_core.InputSignal<string | undefined>;
1196
+ readonly options: _angular_core.InputSignal<SelectMenuOption[]>;
1197
+ readonly value: _angular_core.InputSignal<string | undefined>;
1198
+ readonly placeholder: _angular_core.InputSignal<string>;
1199
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
1200
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
1201
+ private readonly instanceId;
1202
+ readonly triggerId: string;
1203
+ readonly listboxId: string;
1204
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
1205
+ readonly selectedOption: _angular_core.Signal<SelectMenuOption | undefined>;
1206
+ private readonly host;
1207
+ toggle(): void;
1208
+ select(option: SelectMenuOption): void;
1209
+ onDocumentClick(event: MouseEvent): void;
1210
+ onEscape(): void;
1211
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SelectMenu, never>;
1212
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SelectMenu, "kf-select-menu", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
1213
+ }
1214
+
1215
+ /** Forma del placeholder. */
1216
+ type SkeletonVariant = 'text' | 'circle' | 'rect';
1217
+ /**
1218
+ * Bloque placeholder con shimmer para contenido que todavía carga: una línea
1219
+ * de texto, un avatar o un área de card/imagen, según `variant`.
1220
+ *
1221
+ * Es decorativo (`aria-hidden`): quien lo usa debería marcar el contenedor con
1222
+ * `aria-busy="true"` mientras carga, así el lector de pantalla anuncia el
1223
+ * estado una vez en vez de leer N placeholders vacíos.
1224
+ *
1225
+ * `circle` usa `aspect-ratio`, así que alcanza con darle `width`.
1226
+ *
1227
+ * <kf-skeleton />
1228
+ * <kf-skeleton variant="circle" width="40px" />
1229
+ * <kf-skeleton variant="rect" width="100%" height="120px" />
1230
+ */
1231
+ declare class Skeleton {
1232
+ readonly variant: _angular_core.InputSignal<SkeletonVariant>;
1233
+ /** Ancho CSS. Default `'100%'`. */
1234
+ readonly width: _angular_core.InputSignal<string>;
1235
+ /** Alto CSS. Vacío deja el alto/aspect-ratio propio de la variante. */
1236
+ readonly height: _angular_core.InputSignal<string>;
1237
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Skeleton, never>;
1238
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Skeleton, "kf-skeleton", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1239
+ }
1240
+
1241
+ type SpinnerSize = 'sm' | 'md' | 'lg';
1242
+ /**
1243
+ * Indicador de carga indeterminado: inline, dentro de un botón, o como único
1244
+ * contenido de una sección mientras llega la data.
1245
+ *
1246
+ * Cuando se conoce la forma del contenido que viene, preferir `kf-skeleton`
1247
+ * (dibuja la silueta). El spinner es para "algo está pasando" sin forma
1248
+ * conocida — guardar, enviar, reintentar.
1249
+ *
1250
+ * Lleva `role="status"`, así que el lector de pantalla anuncia el `label`
1251
+ * cuando aparece. Sin `label` cae en un texto accesible por defecto.
1252
+ *
1253
+ * <kf-spinner />
1254
+ * <kf-spinner size="sm" label="Cargando…" />
1255
+ * <kf-spinner onDark />
1256
+ */
1257
+ declare class Spinner {
1258
+ readonly size: _angular_core.InputSignal<SpinnerSize>;
1259
+ /** Texto al lado del anillo. Vacío deja solo el anillo (y el texto para lectores). */
1260
+ readonly label: _angular_core.InputSignal<string>;
1261
+ /** Invierte los colores para fondos oscuros. */
1262
+ readonly onDark: _angular_core.InputSignalWithTransform<boolean, unknown>;
1263
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Spinner, never>;
1264
+ 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>;
1265
+ }
1266
+
1267
+ /**
1268
+ * Indicador numérico compacto (página 34): label + valor grande, con un
1269
+ * ícono a la derecha del label — más chico y sin badge de esquina que
1270
+ * `kf-metric-card`, pensado para grillas densas de KPIs simples ("Total
1271
+ * vehículos: 4", "En taller: 1"), no para dashboards con tendencia.
1272
+ *
1273
+ * Con `cta` en vez de `value`, se convierte en la variante de llamada a la
1274
+ * acción: un bloque de fondo suave con título, descripción y un link — sin
1275
+ * número, para promover el siguiente paso (ej. "¿Necesitas mantención?").
1276
+ *
1277
+ * <kf-stat-tile label="Total vehículos" value="4" icon="car" />
1278
+ * <kf-stat-tile cta title="¿Necesitas mantención?"
1279
+ * description="Tenemos la mejor red de talleres."
1280
+ * actionLabel="Agenda aquí" actionHref="/taller/agendar" />
1281
+ */
1282
+ declare class StatTile {
1283
+ readonly cta: _angular_core.InputSignalWithTransform<boolean, unknown>;
1284
+ readonly label: _angular_core.InputSignal<string | undefined>;
1285
+ readonly value: _angular_core.InputSignal<string | number | undefined>;
1286
+ readonly icon: _angular_core.InputSignal<IconName | undefined>;
1287
+ readonly title: _angular_core.InputSignal<string | undefined>;
1288
+ readonly description: _angular_core.InputSignal<string | undefined>;
1289
+ readonly actionLabel: _angular_core.InputSignal<string | undefined>;
1290
+ readonly actionHref: _angular_core.InputSignal<string | undefined>;
1291
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<StatTile, never>;
1292
+ 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; }; "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; }; }, {}, never, never, true, never>;
1293
+ }
1294
+
1295
+ /**
1296
+ * Pill con borde, en mayúsculas y con letter-spacing, pensada para indicadores
1297
+ * de estado únicos y prominentes (ej. "ESTADO TÉCNICO"). El fondo es siempre
1298
+ * transparente; el color de borde/texto/punto depende de `tone`.
1299
+ *
1300
+ * <kf-status-pill tone="ok">Operativo</kf-status-pill>
1301
+ * <kf-status-pill tone="error" dot>Fuera de servicio</kf-status-pill>
1302
+ */
1303
+ declare class StatusPill {
1304
+ readonly tone: _angular_core.InputSignal<"ok" | "warn" | "error" | "blue">;
1305
+ readonly dot: _angular_core.InputSignalWithTransform<boolean, unknown>;
1306
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<StatusPill, never>;
1307
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<StatusPill, "kf-status-pill", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "dot": { "alias": "dot"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1308
+ }
1309
+
1310
+ interface TabOption {
1311
+ value: string;
1312
+ label: string;
1313
+ icon?: IconName;
1314
+ }
1315
+ /**
1316
+ * Barra de tabs subrayada: un único indicador se desliza horizontalmente hasta
1317
+ * la pestaña activa. Como las pestañas tienen ancho de contenido (labels de
1318
+ * largo distinto), la posición no se puede resolver con CSS puro: se mide el
1319
+ * `offsetLeft`/`offsetWidth` de la pestaña activa después de cada render y la
1320
+ * transición del `transform`/`width` queda a cargo de CSS.
1321
+ *
1322
+ * <kf-tabs [options]="tabs" [value]="active" (valueChange)="active = $event" />
1323
+ */
1324
+ declare class Tabs {
1325
+ readonly options: _angular_core.InputSignal<TabOption[]>;
1326
+ readonly value: _angular_core.InputSignal<string>;
1327
+ readonly valueChange: _angular_core.OutputEmitterRef<string>;
1328
+ private readonly track;
1329
+ private readonly destroyRef;
1330
+ /** Geometría de la pestaña activa; `null` mientras no haya una medición válida. */
1331
+ private readonly activeRect;
1332
+ protected readonly indicatorTransform: _angular_core.Signal<string>;
1333
+ protected readonly indicatorWidth: _angular_core.Signal<number>;
1334
+ constructor();
1335
+ private measure;
1336
+ select(value: string): void;
1337
+ /** Navegación estándar de ARIA tabs: flechas mueven el foco y activan la pestaña. */
1338
+ onKeydown(event: KeyboardEvent, currentValue: string): void;
1339
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Tabs, never>;
1340
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Tabs, "kf-tabs", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
1341
+ }
1342
+
1343
+ /**
1344
+ * Visual tone of a toast. Maps to the state tokens in
1345
+ * projects/ui/src/tokens/base.css. `loading` has no auto-dismiss and shows an
1346
+ * indeterminate bar instead of a countdown — pair it with
1347
+ * {@link ToastService.promise}. It reuses the `info` tokens, the closest
1348
+ * semantic role to "work in progress".
1349
+ */
1350
+ type ToastTone = 'success' | 'error' | 'warning' | 'info' | 'loading';
1351
+ /** Options for {@link ToastService.show}. */
1352
+ interface ToastOptions {
1353
+ /** Color tone. Defaults to `'info'`. */
1354
+ tone?: ToastTone;
1355
+ /** Milliseconds before auto-dismiss. Ignored when `tone` is `'loading'`. Defaults to `2800`. */
1356
+ duration?: number;
1357
+ }
1358
+ /** Messages for each leg of {@link ToastService.promise}. */
1359
+ interface ToastPromiseMessages<T = unknown> {
1360
+ loading?: string;
1361
+ success?: string | ((value: T) => string);
1362
+ error?: string | ((error: unknown) => string);
1363
+ }
1364
+ /** The single active toast, as rendered by `kf-toast-host`. */
1365
+ interface ToastState {
1366
+ id: number;
1367
+ message: string;
1368
+ tone: ToastTone;
1369
+ duration: number;
1370
+ leaving: boolean;
1371
+ }
1372
+ /**
1373
+ * Shows one toast at a time — a new `show()` call replaces whatever is
1374
+ * currently up (this mirrors a global status line, not a notification stack).
1375
+ *
1376
+ * Angular has no global function that can mount UI on its own, so the
1377
+ * imperative `showToast(...)` of the reference design system becomes a
1378
+ * root-provided service holding signal state: `ToastService.show(...)` sets
1379
+ * the active toast and `ToastHost` (standalone, mounted once in the app
1380
+ * shell) renders it.
1381
+ *
1382
+ * @example
1383
+ * ```ts
1384
+ * // app.ts
1385
+ * imports: [ToastHost]
1386
+ * template: `<kf-toast-host />`
1387
+ *
1388
+ * // anywhere else
1389
+ * private readonly toast = inject(ToastService);
1390
+ * this.toast.show('Vehículo guardado', { tone: 'success' });
1391
+ *
1392
+ * // chains a `loading` toast into the promise's outcome:
1393
+ * this.toast.promise(this.api.save(vehicle), {
1394
+ * loading: 'Guardando…',
1395
+ * success: 'Vehículo guardado',
1396
+ * error: 'No se pudo guardar',
1397
+ * });
1398
+ * ```
1399
+ */
1400
+ declare class ToastService {
1401
+ private readonly _current;
1402
+ private nextId;
1403
+ private dismissTimer?;
1404
+ private removeTimer?;
1405
+ /** The single active toast, or `null`. */
1406
+ readonly current: _angular_core.Signal<ToastState | null>;
1407
+ /** Shows a toast, replacing whatever is currently shown. Returns its id. */
1408
+ show(message: string, options?: ToastOptions): number;
1409
+ /**
1410
+ * Starts the exit animation, then removes the toast. No-op when `id` is no
1411
+ * longer the active toast, so a stale timer never kills a newer toast.
1412
+ */
1413
+ dismiss(id?: number): void;
1414
+ /**
1415
+ * Shows a `loading` toast, then swaps it for a `success`/`error` toast once
1416
+ * `work` settles. Re-throws `work`'s rejection so callers can still react to
1417
+ * the failure.
1418
+ */
1419
+ promise<T>(work: Promise<T>, messages?: ToastPromiseMessages<T>): Promise<T>;
1420
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ToastService, never>;
1421
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<ToastService>;
1422
+ }
1423
+ /**
1424
+ * Renders whatever `ToastService` currently holds, fixed bottom-right. Mount
1425
+ * one instance in the app shell (e.g. next to the router outlet); it takes no
1426
+ * inputs and re-renders itself from the service state.
1427
+ *
1428
+ * <kf-toast-host />
1429
+ */
1430
+ declare class ToastHost {
1431
+ private readonly toastService;
1432
+ /** 0-or-1 wrapper so `@for track t.id` remounts the node on every new toast, restarting its animations. */
1433
+ protected readonly toastList: _angular_core.Signal<ToastState[]>;
1434
+ protected toastIcon(tone: ToastTone): IconName;
1435
+ protected dismiss(id: number): void;
1436
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ToastHost, never>;
1437
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ToastHost, "kf-toast-host", never, {}, {}, never, never, true, never>;
1438
+ }
1439
+
1440
+ /**
1441
+ * Estado puntual mostrado junto a la identidad del vehículo (ej. "En ruta",
1442
+ * "Mantenimiento", "Fuera de servicio"). `tone` define el color semántico:
1443
+ * "crit" no tiene token propio en base.css, se mapea a var(--kf-color-error).
1444
+ */
1445
+ interface VehicleHeaderStatus {
1446
+ label: string;
1447
+ tone?: 'ok' | 'warn' | 'crit';
1448
+ icon?: IconName;
1449
+ }
1450
+ /**
1451
+ * Header de identidad de un vehículo de flota: unidad (patente/id), modelo
1452
+ * (como badge, no texto plano — página 24: "ABC-123" junto a un badge
1453
+ * "TITAN 4X2"), VIN en fuente mono y un estado opcional. Un área de acciones
1454
+ * opcional se proyecta vía `<ng-content select="[actions]">` para no acoplar
1455
+ * el componente a un set fijo de botones — el patrón real de la spec es
1456
+ * `kf-button variant="outline"` (ej. "Llamar", con ícono) + un `primary`
1457
+ * (ej. "Crear Ticket", con ícono "+"):
1458
+ *
1459
+ * <kf-vehicle-header unit="AB123CD" model="Sprinter 415" vin="9BW..."
1460
+ * [status]="{ label: 'En ruta', tone: 'ok' }">
1461
+ * <kf-button actions variant="outline" icon="phone">Llamar</kf-button>
1462
+ * <kf-button actions icon="plus">Crear Ticket</kf-button>
1463
+ * </kf-vehicle-header>
1464
+ */
1465
+ declare class VehicleHeader {
1466
+ readonly unit: _angular_core.InputSignal<string>;
1467
+ readonly model: _angular_core.InputSignal<string | undefined>;
1468
+ readonly vin: _angular_core.InputSignal<string | undefined>;
1469
+ readonly status: _angular_core.InputSignal<VehicleHeaderStatus | undefined>;
1470
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<VehicleHeader, never>;
1471
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<VehicleHeader, "kf-vehicle-header", never, { "unit": { "alias": "unit"; "required": true; "isSignal": true; }; "model": { "alias": "model"; "required": false; "isSignal": true; }; "vin": { "alias": "vin"; "required": false; "isSignal": true; }; "status": { "alias": "status"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
1472
+ }
1473
+
1474
+ type ViewToggleOption = 'table' | 'cards';
1475
+ /**
1476
+ * Switch de dos posiciones para alternar entre vista de tabla y vista de
1477
+ * tarjetas. Pensado para usarse dentro de DataTable, pero es standalone e
1478
+ * independiente: no asume nada sobre el componente que lo contiene.
1479
+ *
1480
+ * Se implementa como un grupo de radio (role="radiogroup") en vez de dos
1481
+ * botones sueltos: semánticamente es una única selección excluyente entre
1482
+ * dos estados, no dos acciones independientes. Esto también habilita
1483
+ * navegación con flechas izquierda/derecha, igual que un <input type="radio">
1484
+ * nativo agrupado.
1485
+ *
1486
+ * <kf-view-toggle [view]="view" (viewChange)="view = $event" />
1487
+ */
1488
+ declare class ViewToggle {
1489
+ readonly view: _angular_core.InputSignal<ViewToggleOption>;
1490
+ readonly viewChange: _angular_core.OutputEmitterRef<ViewToggleOption>;
1491
+ select(next: ViewToggleOption): void;
1492
+ /** Navegación estándar de ARIA radiogroup: flechas mueven foco y seleccionan. */
1493
+ onKeydown(event: KeyboardEvent): void;
1494
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ViewToggle, never>;
1495
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ViewToggle, "kf-view-toggle", never, { "view": { "alias": "view"; "required": true; "isSignal": true; }; }, { "viewChange": "viewChange"; }, never, never, true, never>;
1496
+ }
1497
+
1498
+ export { ActionTile, AdminBadge, Alert, Avatar, Badge, Breadcrumb, Button, Card, Carousel, CarouselSlide, Checkbox, Chip, CompanySelector, ContentSlot, ContentState, DataTable, EmptyState, FeatureCard, Field, FieldLabel, FilterChips, FolderTabs, Icon, Input, MetricCard, Modal, MultiSelect, PageHeader, Pagination, Panel, PortalHeader, ReserveBlock, SectionHeader, Segmented, Select, SelectMenu, Skeleton, Spinner, StatTile, StatusPill, Tabs, ToastHost, ToastService, VehicleHeader, ViewToggle };
1499
+ export type { AlertTone, BreadcrumbItem, CompanySelectorMeta, ContentStateKind, ContentStateLoad, DataTableCardRole, DataTableColumn, DataTableView, FolderTabOption, IconName, IconSize, MultiSelectOption, PaginationItem, PortalHeaderAdminAction, PortalHeaderNavItem, SegmentedOption, SelectMenuOption, SkeletonVariant, SpinnerSize, TabOption, ToastOptions, ToastPromiseMessages, ToastState, ToastTone, VehicleHeaderStatus, ViewToggleOption };