@kaufmann-lab/ui 0.1.9 → 0.1.11
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.mjs +1842 -438
- package/fesm2022/kaufmann-lab-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/src/tokens/base.css +22 -0
- package/types/kaufmann-lab-ui.d.ts +617 -139
|
@@ -14,11 +14,11 @@ import { ControlValueAccessor } from '@angular/forms';
|
|
|
14
14
|
* reciba un `IconName` (`Button`, `MetricCard`, etc.) — no debería requerir
|
|
15
15
|
* importar el componente `Icon` completo solo para tipar una prop.
|
|
16
16
|
*/
|
|
17
|
-
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' | 'eye-off' | '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';
|
|
17
|
+
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' | 'eye-off' | 'file' | 'filter' | 'gauge' | 'gift' | 'grid' | 'history' | 'home' | 'inbox' | 'layers' | 'list' | 'log-out' | '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';
|
|
18
18
|
|
|
19
19
|
type IconSize = 'sm' | 'md' | 'lg';
|
|
20
20
|
/**
|
|
21
|
-
* Ícono de trazo del design system —
|
|
21
|
+
* Ícono de trazo del design system — 61 glyphs (59 de la página 5 + `eye-off` y `log-out`), grilla 24×24,
|
|
22
22
|
* grosor de trazo 1.9px. Referencia un sprite SVG embebido (ver
|
|
23
23
|
* `icon-sprite.ts`) vía `<use>`, así que no hay peso de red adicional por
|
|
24
24
|
* cada instancia: el sprite se inyecta al DOM una única vez, la primera
|
|
@@ -157,6 +157,71 @@ declare class Alert {
|
|
|
157
157
|
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>;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Layout a pantalla completa para cualquier pantalla de autenticación
|
|
162
|
+
* (login, recuperar contraseña, confirmación de envío) — split marca a la
|
|
163
|
+
* izquierda / contenido libre a la derecha en desktop, formulario a
|
|
164
|
+
* pantalla completa en mobile (el panel de marca completo se oculta, no se
|
|
165
|
+
* apila arriba: en una pantalla angosta el usuario vino a loguearse, no a
|
|
166
|
+
* leer la tagline). Un logo compacto (o wordmark de respaldo) sí se
|
|
167
|
+
* mantiene visible arriba del formulario en mobile — el usuario nunca
|
|
168
|
+
* pierde de vista qué portal está usando, mismo criterio que ya sigue el
|
|
169
|
+
* resto del ecosistema (ver la topbar mobile de `css/otd.css`, que muestra
|
|
170
|
+
* el logo aunque el sidebar completo se oculte).
|
|
171
|
+
*
|
|
172
|
+
* Este componente resuelve el "cascarón" — nunca el formulario en sí. Cada
|
|
173
|
+
* portal arma su propio `<form>` con los componentes de la librería
|
|
174
|
+
* (`kf-input`, `kf-checkbox`, `kf-button`, `kf-alert`) y lo proyecta en el
|
|
175
|
+
* slot por defecto. Es la misma separación de responsabilidad que ya usa
|
|
176
|
+
* `kf-card`: un componente da la estructura visual, el consumidor decide
|
|
177
|
+
* qué va adentro.
|
|
178
|
+
*
|
|
179
|
+
* Antes de este componente, cada portal (LATAM primero, ahora OTD) hubiera
|
|
180
|
+
* tenido que reimplementar este mismo split desde cero — la librería
|
|
181
|
+
* había pospuesto esta abstracción a propósito hasta tener un segundo
|
|
182
|
+
* consumidor real que confirmara qué parte es realmente compartida (el
|
|
183
|
+
* cascarón) y qué parte es de cada portal (el formulario). OTD es ese
|
|
184
|
+
* segundo consumidor.
|
|
185
|
+
*
|
|
186
|
+
* Ningún input tiene valor por defecto propio de ningún portal — `brand`
|
|
187
|
+
* es obligatorio (`input.required`) y el resto de props de marca son
|
|
188
|
+
* opcionales sin fallback hardcodeado, precisamente para que cada
|
|
189
|
+
* consumidor (LATAM, OTD, Star, o el ERP de Asistencia en Ruta con sus
|
|
190
|
+
* propios temas) traiga su propio logo/tagline sin que la librería asuma
|
|
191
|
+
* cuál.
|
|
192
|
+
*
|
|
193
|
+
* <kf-auth-layout
|
|
194
|
+
* brand="Mi Portal"
|
|
195
|
+
* brandLogoSrc="images/mi-portal-logo-white.png"
|
|
196
|
+
* brandLogoMobileSrc="images/mi-portal-logo-black.png"
|
|
197
|
+
* brandTagline="Frase corta de marca, propia de cada portal."
|
|
198
|
+
* >
|
|
199
|
+
* <form (ngSubmit)="onSubmit()">
|
|
200
|
+
* <kf-input label="Correo" type="email" />
|
|
201
|
+
* <kf-input label="Contraseña" type="password" toggleable />
|
|
202
|
+
* <kf-button type="submit">Ingresar</kf-button>
|
|
203
|
+
* </form>
|
|
204
|
+
* </kf-auth-layout>
|
|
205
|
+
*/
|
|
206
|
+
declare class AuthLayout {
|
|
207
|
+
/** Nombre de marca/portal, usado como wordmark de respaldo si no hay ningún logo, y como `alt` de ambos logos. */
|
|
208
|
+
readonly brand: _angular_core.InputSignal<string>;
|
|
209
|
+
/** Logo en blanco para el panel oscuro de desktop — si no se pasa, se muestra `brand()` como wordmark tipográfico. */
|
|
210
|
+
readonly brandLogoSrc: _angular_core.InputSignal<string | undefined>;
|
|
211
|
+
/** Frase corta bajo el logo — opcional, cada portal decide su propio texto de marca. */
|
|
212
|
+
readonly brandTagline: _angular_core.InputSignal<string | undefined>;
|
|
213
|
+
/**
|
|
214
|
+
* Logo compacto para mobile, sobre el fondo claro del panel de contenido
|
|
215
|
+
* — normalmente la variante oscura/negra del mismo logo, ya que
|
|
216
|
+
* `brandLogoSrc` suele ser la variante blanca pensada para el gradiente
|
|
217
|
+
* oscuro. Si no se pasa, reutiliza `brandLogoSrc`; si tampoco hay logo en
|
|
218
|
+
* absoluto, cae al wordmark tipográfico igual que en desktop.
|
|
219
|
+
*/
|
|
220
|
+
readonly brandLogoMobileSrc: _angular_core.InputSignal<string | undefined>;
|
|
221
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AuthLayout, never>;
|
|
222
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AuthLayout, "kf-auth-layout", never, { "brand": { "alias": "brand"; "required": true; "isSignal": true; }; "brandLogoSrc": { "alias": "brandLogoSrc"; "required": false; "isSignal": true; }; "brandTagline": { "alias": "brandTagline"; "required": false; "isSignal": true; }; "brandLogoMobileSrc": { "alias": "brandLogoMobileSrc"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
223
|
+
}
|
|
224
|
+
|
|
160
225
|
/**
|
|
161
226
|
* Avatar de usuario: muestra una foto (`src`) o, si no hay foto, las
|
|
162
227
|
* iniciales (`initials`) sobre un fondo con gradiente de marca. `round`
|
|
@@ -621,84 +686,209 @@ declare class Divider {
|
|
|
621
686
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Divider, "kf-divider", never, { "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
622
687
|
}
|
|
623
688
|
|
|
689
|
+
type DrawerSide = 'left' | 'right';
|
|
690
|
+
/**
|
|
691
|
+
* Panel lateral genérico, agnóstico de contenido — no sabe qué es navegación
|
|
692
|
+
* ni qué es sesión, solo da tres lugares para proyectar contenido
|
|
693
|
+
* (`[kf-drawer-header]`, default, `[kf-drawer-footer]`) y resuelve lo que
|
|
694
|
+
* cualquier drawer necesita resolver igual sin importar qué haya adentro:
|
|
695
|
+
* overlay con blur que cierra al click, `Escape`, atrapado de foco real y
|
|
696
|
+
* devolución de foco al cerrar.
|
|
697
|
+
*
|
|
698
|
+
* Extraído de `PortalHeader`, que hasta acá reimplementaba su propio drawer
|
|
699
|
+
* embebido (navegación hardcodeada + slot único al final). Cualquier
|
|
700
|
+
* consumidor que necesite un panel lateral — no solo `PortalHeader` — puede
|
|
701
|
+
* usar este componente directamente.
|
|
702
|
+
*
|
|
703
|
+
* `open` es two-way, mismo patrón que `Dropdown`/`Modal`: el consumidor
|
|
704
|
+
* decide qué dispara la apertura (un botón de hamburguesa, por ejemplo) y
|
|
705
|
+
* qué hace con el cierre.
|
|
706
|
+
*
|
|
707
|
+
* Foco: al abrir, se crea un `FocusTrap` del CDK sobre el panel (la misma
|
|
708
|
+
* pieza que usa Angular Material para `mat-sidenav`/`mat-dialog`) — Tab y
|
|
709
|
+
* Shift+Tab ciclan solo entre los elementos focuseables del drawer, sin
|
|
710
|
+
* escapar al contenido de fondo. Al cerrar, el foco vuelve al elemento que
|
|
711
|
+
* tenía el foco antes de abrir (guardado en `document.activeElement`), no
|
|
712
|
+
* se pierde en el `<body>`.
|
|
713
|
+
*
|
|
714
|
+
* `[kf-drawer-header]` tiene fondo oscuro propio (`--kf-color-tertiary-deep`),
|
|
715
|
+
* distinto del body (`--kf-color-white`) — pensado para contener
|
|
716
|
+
* `kf-drawer-session`, que asume ese fondo y no lo trae él mismo (ver
|
|
717
|
+
* `DrawerSession.ts`). Si el slot queda vacío, el contenedor colapsa
|
|
718
|
+
* (`display: none`) y no deja una franja oscura sin contenido.
|
|
719
|
+
*
|
|
720
|
+
* <kf-drawer [(open)]="menuOpen" ariaLabel="Menú de navegación">
|
|
721
|
+
* <div kf-drawer-header>
|
|
722
|
+
* <kf-drawer-session name="Tomás Soto" email="tomas@kaufmann.com" (logoutClick)="onLogout()" />
|
|
723
|
+
* </div>
|
|
724
|
+
* <a href="/">Home</a>
|
|
725
|
+
* <a href="/vehiculos">Vehículos</a>
|
|
726
|
+
* </kf-drawer>
|
|
727
|
+
*/
|
|
728
|
+
declare class Drawer {
|
|
729
|
+
/** Visibilidad del panel, two-way: `[(open)]="menuOpen"`. */
|
|
730
|
+
readonly open: _angular_core.ModelSignal<boolean>;
|
|
731
|
+
/** Borde de anclaje del panel. `left` (default) es la convención dominante
|
|
732
|
+
* (Material/iOS/Android): el botón que abre el drawer y el propio panel
|
|
733
|
+
* quedan del mismo lado. */
|
|
734
|
+
readonly side: _angular_core.InputSignal<DrawerSide>;
|
|
735
|
+
/** `aria-label` del `<nav>` interno — describe el propósito del panel para
|
|
736
|
+
* lectores de pantalla (ej. "Menú de navegación"). */
|
|
737
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
738
|
+
private readonly panelRef;
|
|
739
|
+
private readonly focusTrapFactory;
|
|
740
|
+
private readonly document;
|
|
741
|
+
private focusTrap;
|
|
742
|
+
private lastFocusedElement;
|
|
743
|
+
constructor();
|
|
744
|
+
/** Cierra el drawer con Escape — mismo patrón que `Dropdown`/`Modal`. */
|
|
745
|
+
protected onEscape(): void;
|
|
746
|
+
private getOrCreateFocusTrap;
|
|
747
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Drawer, never>;
|
|
748
|
+
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>;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Botón de cerrar sesión, pensado para proyectarse dentro de
|
|
753
|
+
* `[kf-drawer-footer]` de `kf-drawer`, o junto a `kf-drawer-session` dentro
|
|
754
|
+
* de `[kf-sidebar-footer]` de `kf-sidebar-shell` — separado de
|
|
755
|
+
* `kf-drawer-session` (que solo muestra identidad: brand, avatar, nombre,
|
|
756
|
+
* email), no anidado dentro de ella.
|
|
757
|
+
*
|
|
758
|
+
* Reproduce el mismo botón que antes vivía embebido en `DrawerSession`:
|
|
759
|
+
* ícono `log-out` + label, color `--kf-color-error` con hover en
|
|
760
|
+
* `--kf-color-error-soft` y foco visible con `--kf-shadow-focus`. Se separó
|
|
761
|
+
* en un componente propio porque identidad y logout son responsabilidades
|
|
762
|
+
* distintas — `kf-drawer-session` no debería saber que existe un botón de
|
|
763
|
+
* cerrar sesión, y el footer del drawer ya tiene su propio padding/borde
|
|
764
|
+
* superior (ver `Drawer.ts`) que reemplaza el borde que antes traía el botón
|
|
765
|
+
* mismo.
|
|
766
|
+
*
|
|
767
|
+
* No sabe nada de autenticación real — solo emite `logoutClick` cuando el
|
|
768
|
+
* consumidor debe cerrar la sesión real.
|
|
769
|
+
*
|
|
770
|
+
* `collapsed` oculta el label y centra el ícono, exponiéndolo vía `title`
|
|
771
|
+
* — mismo criterio que `SidebarNavItem.collapsed` y
|
|
772
|
+
* `DrawerSession.collapsed`, para cuando este botón vive dentro de un
|
|
773
|
+
* `kf-sidebar-shell` colapsado.
|
|
774
|
+
*
|
|
775
|
+
* <kf-drawer-logout kf-portal-header-footer (logoutClick)="onLogout()" />
|
|
776
|
+
*/
|
|
777
|
+
declare class DrawerLogout {
|
|
778
|
+
/** Label del botón, en español neutro por defecto. Input opcional por si
|
|
779
|
+
* algún consumidor futuro necesita otro texto. */
|
|
780
|
+
readonly label: _angular_core.InputSignal<string>;
|
|
781
|
+
/** Oculta el label y centra el ícono — ver comentario de la clase. */
|
|
782
|
+
readonly collapsed: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
783
|
+
readonly logoutClick: _angular_core.OutputEmitterRef<void>;
|
|
784
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DrawerLogout, never>;
|
|
785
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DrawerLogout, "kf-drawer-logout", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; }, { "logoutClick": "logoutClick"; }, never, never, true, never>;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Bloque de identidad para `[kf-drawer-header]` de `kf-drawer` o
|
|
790
|
+
* `[kf-sidebar-footer]` de `kf-sidebar-shell`: avatar + nombre + email,
|
|
791
|
+
* brand opcional arriba. Solo identidad — el logout vive aparte, en
|
|
792
|
+
* `kf-drawer-logout`.
|
|
793
|
+
*
|
|
794
|
+
* `collapsed` oculta brand/nombre/email y deja solo el avatar (para un
|
|
795
|
+
* `kf-sidebar-shell` colapsado). `interactive` convierte la tarjeta en un
|
|
796
|
+
* botón real que emite `cardClick`, para cuando la identidad es el
|
|
797
|
+
* disparador de un menú de acciones (ej. envuelta en `kf-dropdown`).
|
|
798
|
+
*
|
|
799
|
+
* <kf-dropdown [(open)]="menuOpen">
|
|
800
|
+
* <kf-drawer-session interactive name="Juan Pérez" email="juan@empresa.com" (cardClick)="menuOpen.set(!menuOpen())" />
|
|
801
|
+
* <kf-dropdown-panel variant="dark">
|
|
802
|
+
* <kf-dropdown-item icon="log-out" tone="error" (click)="onLogout()">Cerrar sesión</kf-dropdown-item>
|
|
803
|
+
* </kf-dropdown-panel>
|
|
804
|
+
* </kf-dropdown>
|
|
805
|
+
*/
|
|
806
|
+
declare class DrawerSession {
|
|
807
|
+
readonly name: _angular_core.InputSignal<string>;
|
|
808
|
+
readonly email: _angular_core.InputSignal<string>;
|
|
809
|
+
readonly initials: _angular_core.InputSignal<string>;
|
|
810
|
+
readonly avatarUrl: _angular_core.InputSignal<string>;
|
|
811
|
+
/** Label superior opcional, ej. "Portal Kaufmann LATAM". */
|
|
812
|
+
readonly brand: _angular_core.InputSignal<string>;
|
|
813
|
+
/** Oculta brand/nombre/email y centra el avatar — ver comentario de la clase. */
|
|
814
|
+
readonly collapsed: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
815
|
+
/** Convierte la tarjeta en un botón real con ícono de kebab — ver comentario de la clase. */
|
|
816
|
+
readonly interactive: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
817
|
+
/** Se emite al clickear la tarjeta, solo cuando `interactive` es `true`. */
|
|
818
|
+
readonly cardClick: _angular_core.OutputEmitterRef<void>;
|
|
819
|
+
/** Si no se pasa `initials`, se derivan de `name`: primera letra de cada
|
|
820
|
+
* una de las primeras 2 palabras, en mayúscula. */
|
|
821
|
+
protected readonly displayInitials: _angular_core.Signal<string>;
|
|
822
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DrawerSession, never>;
|
|
823
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DrawerSession, "kf-drawer-session", never, { "name": { "alias": "name"; "required": true; "isSignal": true; }; "email": { "alias": "email"; "required": false; "isSignal": true; }; "initials": { "alias": "initials"; "required": false; "isSignal": true; }; "avatarUrl": { "alias": "avatarUrl"; "required": false; "isSignal": true; }; "brand": { "alias": "brand"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, never, true, never>;
|
|
824
|
+
}
|
|
825
|
+
|
|
624
826
|
type DropdownItemTone = 'neutral' | 'error';
|
|
625
827
|
/**
|
|
626
828
|
* Ítem de acción dentro de un `kf-dropdown-panel`. Es un `<button>` nativo
|
|
627
|
-
*
|
|
628
|
-
* comportamiento en la pantalla actual (cerrar sesión, ejecutar un
|
|
629
|
-
* comando), no navegan a otra URL.
|
|
829
|
+
* (no un `<a>`): dispara comportamiento en la pantalla actual, no navega.
|
|
630
830
|
*
|
|
631
|
-
*
|
|
831
|
+
* `icon` es opcional — sin él, el ítem es solo texto.
|
|
832
|
+
*
|
|
833
|
+
* <kf-dropdown-item icon="log-out" (click)="onLogout()" tone="error">Cerrar sesión</kf-dropdown-item>
|
|
632
834
|
*/
|
|
633
835
|
declare class DropdownItem {
|
|
634
836
|
readonly tone: _angular_core.InputSignal<DropdownItemTone>;
|
|
837
|
+
/** Ícono opcional al inicio de la fila. */
|
|
838
|
+
readonly icon: _angular_core.InputSignal<IconName | undefined>;
|
|
635
839
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DropdownItem, never>;
|
|
636
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DropdownItem, "kf-dropdown-item", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
840
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DropdownItem, "kf-dropdown-item", never, { "tone": { "alias": "tone"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
637
841
|
}
|
|
842
|
+
type DropdownPanelVariant = 'solid' | 'dark';
|
|
638
843
|
/**
|
|
639
844
|
* Contenido del panel flotante de un `kf-dropdown`. Es solo una plantilla
|
|
640
|
-
* (`<ng-template
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
845
|
+
* (`<ng-template>`, capturada vía `TemplateRef`) — `Dropdown` la conecta al
|
|
846
|
+
* overlay real cuando `open` pasa a `true`, no la renderiza en su propio
|
|
847
|
+
* lugar del DOM. Esto permite que el panel aparezca pegado al host de
|
|
848
|
+
* `Dropdown` sin importar dónde esté ese host en la página.
|
|
849
|
+
*
|
|
850
|
+
* `variant`: `'solid'` (default, fondo blanco) o `'dark'` (fondo sólido
|
|
851
|
+
* oscuro, mismo tono que `[kf-drawer-header]`) para cuando el trigger vive
|
|
852
|
+
* sobre una superficie oscura de marca.
|
|
853
|
+
*
|
|
854
|
+
* `dark` es sólida a propósito, no semitransparente: el CDK Overlay
|
|
855
|
+
* reposiciona el panel según dónde entra en el viewport y puede terminar
|
|
856
|
+
* cayendo sobre fondo blanco en vez de sobre el rail oscuro — un color
|
|
857
|
+
* sólido se ve intencional sin importar dónde lo posicione el CDK.
|
|
650
858
|
*/
|
|
651
859
|
declare class DropdownPanel {
|
|
860
|
+
readonly variant: _angular_core.InputSignal<DropdownPanelVariant>;
|
|
652
861
|
readonly templateRef: _angular_core.Signal<TemplateRef<any>>;
|
|
653
862
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DropdownPanel, never>;
|
|
654
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DropdownPanel, "kf-dropdown-panel", never, {}, {}, never, ["*"], true, never>;
|
|
863
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DropdownPanel, "kf-dropdown-panel", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
655
864
|
}
|
|
656
865
|
/**
|
|
657
866
|
* Menú de acciones flotante, conectado a un elemento disparador vía
|
|
658
867
|
* `@angular/cdk/overlay` — la misma pieza que usa Angular Material para
|
|
659
|
-
* `mat-menu`/`mat-select`.
|
|
660
|
-
* mano en cada consumidor (ver el session-menu de `web-portal-latam-frontend`,
|
|
661
|
-
* ~80 líneas de HTML/TS/SCSS para toggle + click-afuera + Escape + animación
|
|
662
|
-
* de entrada, acopladas a una clase interna no pública de `PortalHeader`).
|
|
663
|
-
*
|
|
664
|
-
* Se apoya en el CDK en vez de un `position: absolute` casero (como sí hace
|
|
665
|
-
* `SelectMenu`, que puede permitírselo porque su trigger vive siempre dentro
|
|
666
|
-
* del propio componente) porque acá el disparador real puede vivir en OTRO
|
|
667
|
-
* componente por completo — ej. el avatar dentro de `kf-portal-header` — y
|
|
668
|
-
* el panel tiene que aparecer pegado a ESE elemento sin importar dónde el
|
|
669
|
-
* consumidor ubique al `Dropdown` en su HTML. El Overlay CDK calcula esa
|
|
670
|
-
* posición (con fallback si no entra en pantalla) en vez de que cada
|
|
671
|
-
* consumidor lo recalcule a mano.
|
|
672
|
-
*
|
|
673
|
-
* `open` es two-way, igual que `Alert`/`Modal`: el consumidor decide qué
|
|
674
|
-
* dispara la apertura (puede ser un `(click)` en un botón propio, o un
|
|
675
|
-
* evento de otro componente como `PortalHeader.sessionClick`) — `Dropdown`
|
|
676
|
-
* en sí no renderiza ningún trigger, su propio host es el punto de anclaje
|
|
677
|
-
* visual del panel.
|
|
868
|
+
* `mat-menu`/`mat-select`.
|
|
678
869
|
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
870
|
+
* Se apoya en el CDK en vez de un `position: absolute` casero (a diferencia
|
|
871
|
+
* de `SelectMenu`, que puede permitírselo porque su trigger vive siempre
|
|
872
|
+
* dentro del propio componente) porque acá el disparador real puede vivir
|
|
873
|
+
* en OTRO componente por completo — ej. el avatar dentro de
|
|
874
|
+
* `kf-portal-header` — y el panel tiene que aparecer pegado a ESE elemento
|
|
875
|
+
* sin importar dónde el consumidor ubique al `Dropdown` en su HTML.
|
|
876
|
+
*
|
|
877
|
+
* `open` es two-way: el consumidor decide qué dispara la apertura —
|
|
878
|
+
* `Dropdown` en sí no renderiza ningún trigger, su propio host es el punto
|
|
879
|
+
* de anclaje visual del panel.
|
|
880
|
+
*
|
|
881
|
+
* <kf-dropdown [(open)]="menuOpen"><kf-dropdown-panel>...</kf-dropdown-panel></kf-dropdown>
|
|
685
882
|
*/
|
|
686
883
|
declare class Dropdown {
|
|
687
884
|
/** Visibilidad del panel, two-way: `[(open)]="menuOpen"`. */
|
|
688
885
|
readonly open: _angular_core.ModelSignal<boolean>;
|
|
689
886
|
/**
|
|
690
887
|
* Elemento al que se conecta el overlay, si es distinto del propio host
|
|
691
|
-
* de `Dropdown`. Sin esto, `Dropdown` asume que ÉL MISMO es
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
* ensanchar el área de click a algo más grande que el botón (ej. el
|
|
696
|
-
* avatar de sesión dentro de `PortalHeader`, que convive con logo y
|
|
697
|
-
* navegación en el mismo host), `anchor` permite apuntar el overlay a la
|
|
698
|
-
* referencia real de ese componente en vez de al host vacío de
|
|
699
|
-
* `Dropdown`.
|
|
700
|
-
*
|
|
701
|
-
* <kf-dropdown [(open)]="menuOpen" [anchor]="headerRef()">
|
|
888
|
+
* de `Dropdown`. Sin esto, `Dropdown` asume que ÉL MISMO es el
|
|
889
|
+
* disparador. Útil cuando el disparador real vive dentro de OTRO
|
|
890
|
+
* componente que no se puede envolver sin ensanchar el área de click
|
|
891
|
+
* (ej. el avatar de sesión dentro de `PortalHeader`).
|
|
702
892
|
*/
|
|
703
893
|
readonly anchor: _angular_core.InputSignal<ElementRef<HTMLElement> | undefined>;
|
|
704
894
|
private readonly panel;
|
|
@@ -707,18 +897,41 @@ declare class Dropdown {
|
|
|
707
897
|
private readonly viewContainerRef;
|
|
708
898
|
private readonly destroyRef;
|
|
709
899
|
private overlayRef;
|
|
900
|
+
/**
|
|
901
|
+
* Suscripciones a `outsidePointerEvents()`/`keydownEvents()` del overlay
|
|
902
|
+
* ACTUALMENTE adjunto. `getOrCreateOverlayRef()` reutiliza el mismo
|
|
903
|
+
* `overlayRef` entre aperturas (no lo recrea cada vez) — sin esto,
|
|
904
|
+
* `attach()` se resuscribía a esos observables en cada apertura sin
|
|
905
|
+
* cancelar la suscripción de la vez anterior, acumulando N suscripciones
|
|
906
|
+
* activas sobre el mismo overlay persistente. Eso causaba el bug real de
|
|
907
|
+
* "clicks seguidos": al abrir de nuevo, el propio pointerdown que originó
|
|
908
|
+
* la apertura llegaba a más de una suscripción acumulada, disparando
|
|
909
|
+
* `open.set(false)` de forma errática en el mismo tick (patrón observado:
|
|
910
|
+
* abre cada 2 clicks, cierra cada 1). Se cancelan explícitamente en
|
|
911
|
+
* `detach()`, antes de la siguiente `attach()`.
|
|
912
|
+
*/
|
|
913
|
+
private overlaySubscription;
|
|
710
914
|
constructor();
|
|
711
915
|
/**
|
|
712
916
|
* Respaldo de `overlayRef.keydownEvents()`: ese observable del CDK solo
|
|
713
|
-
* ve teclas
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
* vive fuera del overlay), `keydownEvents()` nunca dispara. Este listener
|
|
717
|
-
* a nivel de documento cubre ese caso; el de `keydownEvents()` sigue
|
|
718
|
-
* activo para cuando el foco sí está dentro del panel.
|
|
917
|
+
* ve teclas con el foco DENTRO del panel. Si el foco queda en el botón
|
|
918
|
+
* disparador (caso común), `keydownEvents()` nunca dispara — este
|
|
919
|
+
* listener a nivel de documento cubre ese caso.
|
|
719
920
|
*/
|
|
720
921
|
onDocumentEscape(): void;
|
|
721
922
|
private attach;
|
|
923
|
+
/**
|
|
924
|
+
* El trigger real (el `anchor`, o el propio host si no se pasó ninguno —
|
|
925
|
+
* ver comentario de la clase) vive FUERA del overlay a propósito: el
|
|
926
|
+
* overlay recién se crea/adjunta cuando `open` pasa a `true`, así que el
|
|
927
|
+
* CDK no tiene forma de saber que ese elemento externo "es parte" de su
|
|
928
|
+
* disparador. Sin este filtro, el mismo `pointerdown` que abre el menú
|
|
929
|
+
* (el trigger no es hijo del overlay) también llega a
|
|
930
|
+
* `outsidePointerEvents()`, cerrando el panel en el mismo gesto que lo
|
|
931
|
+
* abrió — bug real reproducido con Playwright: "abre y cierra" en
|
|
932
|
+
* clicks consecutivos rápidos sobre la tarjeta de sesión del sidebar.
|
|
933
|
+
*/
|
|
934
|
+
private isEventOnTrigger;
|
|
722
935
|
private detach;
|
|
723
936
|
private getOrCreateOverlayRef;
|
|
724
937
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Dropdown, never>;
|
|
@@ -890,11 +1103,11 @@ interface FolderTabOption {
|
|
|
890
1103
|
* atributo porque el panel no necesita comportamiento propio, solo marcar
|
|
891
1104
|
* su presencia).
|
|
892
1105
|
*
|
|
893
|
-
* <div
|
|
1106
|
+
* <div kfFolderTabsPanel>...</div>
|
|
894
1107
|
*/
|
|
895
1108
|
declare class FolderTabsPanel {
|
|
896
1109
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FolderTabsPanel, never>;
|
|
897
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FolderTabsPanel, "[
|
|
1110
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FolderTabsPanel, "[kfFolderTabsPanel]", never, {}, {}, never, never, true, never>;
|
|
898
1111
|
}
|
|
899
1112
|
/**
|
|
900
1113
|
* Tabs con forma de "carpeta": el borde superior queda redondeado y el borde
|
|
@@ -936,7 +1149,7 @@ declare class FolderTabsPanel {
|
|
|
936
1149
|
* evita que cada consumidor repita esas reglas a mano.
|
|
937
1150
|
*
|
|
938
1151
|
* <kf-folder-tabs [options]="tabs" [value]="active" (valueChange)="active = $event">
|
|
939
|
-
* <div
|
|
1152
|
+
* <div kfFolderTabsPanel>contenido de la pestaña activa</div>
|
|
940
1153
|
* </kf-folder-tabs>
|
|
941
1154
|
*
|
|
942
1155
|
* <!-- o, sin contenido, como antes: -->
|
|
@@ -948,7 +1161,7 @@ declare class FolderTabs {
|
|
|
948
1161
|
readonly valueChange: _angular_core.OutputEmitterRef<string>;
|
|
949
1162
|
/**
|
|
950
1163
|
* Detecta si el consumidor proyectó contenido marcado con
|
|
951
|
-
* `
|
|
1164
|
+
* `kfFolderTabsPanel` — sin `.required`, así que es `undefined`
|
|
952
1165
|
* cuando no hay nada proyectado (mismo patrón que usa `kf-dropdown` con
|
|
953
1166
|
* `contentChild(DropdownPanel)` para saber si hay un panel que
|
|
954
1167
|
* attachear). `hasPanel()` decide si el wrapper del panel participa del
|
|
@@ -960,7 +1173,39 @@ declare class FolderTabs {
|
|
|
960
1173
|
/** Navegación estándar de ARIA tabs: flechas mueven el foco y activan la pestaña. */
|
|
961
1174
|
onKeydown(event: KeyboardEvent, currentValue: string): void;
|
|
962
1175
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FolderTabs, never>;
|
|
963
|
-
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"; }, ["projectedPanel"], ["[
|
|
1176
|
+
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"; }, ["projectedPanel"], ["[kfFolderTabsPanel]"], true, never>;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/** Un link del pie — legales, contacto, soporte. */
|
|
1180
|
+
interface FooterLink {
|
|
1181
|
+
label: string;
|
|
1182
|
+
href?: string;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Pie de página general del portal (página 38): logo + copyright a la
|
|
1186
|
+
* izquierda, links legales/soporte empujados a la derecha. Logo y copyright
|
|
1187
|
+
* son inputs (cada portal del ecosistema — LATAM, OTD, Star — trae su
|
|
1188
|
+
* propia marca y texto legal); `links` es la lista de accesos, típicamente
|
|
1189
|
+
* placeholders hasta que existan destinos reales.
|
|
1190
|
+
*
|
|
1191
|
+
* <kf-footer
|
|
1192
|
+
* logoSrc="images/logo-kaufmann-dark.png"
|
|
1193
|
+
* logoAlt="Grupo Kaufmann"
|
|
1194
|
+
* copyright="© 2026 Kaufmann LATAM · Todos los derechos reservados"
|
|
1195
|
+
* [links]="[
|
|
1196
|
+
* { label: 'Políticas de privacidad' },
|
|
1197
|
+
* { label: 'Contacto' },
|
|
1198
|
+
* { label: 'Sugerencias y reclamos' },
|
|
1199
|
+
* ]"
|
|
1200
|
+
* />
|
|
1201
|
+
*/
|
|
1202
|
+
declare class Footer {
|
|
1203
|
+
readonly logoSrc: _angular_core.InputSignal<string | undefined>;
|
|
1204
|
+
readonly logoAlt: _angular_core.InputSignal<string>;
|
|
1205
|
+
readonly copyright: _angular_core.InputSignal<string>;
|
|
1206
|
+
readonly links: _angular_core.InputSignal<FooterLink[]>;
|
|
1207
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Footer, never>;
|
|
1208
|
+
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>;
|
|
964
1209
|
}
|
|
965
1210
|
|
|
966
1211
|
/**
|
|
@@ -1165,18 +1410,25 @@ interface MultiSelectOption {
|
|
|
1165
1410
|
label: string;
|
|
1166
1411
|
}
|
|
1167
1412
|
/**
|
|
1168
|
-
* Dropdown de selección múltiple con checkboxes internos
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1171
|
-
*
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
*
|
|
1175
|
-
*
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1413
|
+
* Dropdown de selección múltiple con checkboxes internos. El panel flotante
|
|
1414
|
+
* se conecta al trigger vía `@angular/cdk/overlay` — el mismo mecanismo que
|
|
1415
|
+
* `Select` (ver `../select/Select.ts`) y `Dropdown` (`../dropdown/Dropdown.ts`).
|
|
1416
|
+
*
|
|
1417
|
+
* Hasta la `0.1.9` este panel vivía con `position: absolute` manual sobre el
|
|
1418
|
+
* propio host, sin depender del CDK Overlay. Se migró para unificar el
|
|
1419
|
+
* mecanismo de posicionamiento/cierre con el resto de los dropdowns flotantes
|
|
1420
|
+
* de la librería (4 posiciones de fallback, `withViewportMargin`, `withPush`,
|
|
1421
|
+
* cierre por `outsidePointerEvents()`/`keydownEvents()` en vez de un
|
|
1422
|
+
* `@HostListener('document:click')` manual).
|
|
1423
|
+
*
|
|
1424
|
+
* A diferencia de `Select`, el disparador no muestra un único valor sino los
|
|
1425
|
+
* nombres seleccionados junto a un badge circular con el conteo, y cada
|
|
1426
|
+
* opción del panel se marca/desmarca con un checkbox sin cerrar el panel.
|
|
1427
|
+
* Incluye una opción "Todas" al inicio de la lista, con estado
|
|
1428
|
+
* `indeterminate` cuando hay selección parcial — el mismo patrón de
|
|
1429
|
+
* "seleccionar todos" de `Checkbox`. "Todas" nunca se filtra por el buscador:
|
|
1430
|
+
* queda siempre visible y sigue actuando sobre el universo COMPLETO de
|
|
1431
|
+
* `options()`, no sobre el subconjunto filtrado (ver JSDoc de `toggleAll()`).
|
|
1180
1432
|
*
|
|
1181
1433
|
* <kf-multi-select
|
|
1182
1434
|
* label="Sucursales"
|
|
@@ -1195,14 +1447,27 @@ declare class MultiSelect {
|
|
|
1195
1447
|
readonly values: _angular_core.InputSignal<string[]>;
|
|
1196
1448
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
1197
1449
|
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1450
|
+
/**
|
|
1451
|
+
* Tri-state: si el consumidor no lo especifica (`undefined`), el buscador
|
|
1452
|
+
* se activa solo cuando `options().length` supera `searchThreshold()`. Si
|
|
1453
|
+
* el consumidor define `true`/`false` explícitamente, ese valor manda por
|
|
1454
|
+
* sobre el umbral automático. Mismo criterio que `Select`.
|
|
1455
|
+
*/
|
|
1456
|
+
readonly searchable: _angular_core.InputSignal<boolean | undefined>;
|
|
1457
|
+
readonly searchThreshold: _angular_core.InputSignal<number>;
|
|
1198
1458
|
readonly valuesChange: _angular_core.OutputEmitterRef<string[]>;
|
|
1199
1459
|
private readonly instanceId;
|
|
1200
1460
|
readonly triggerId: string;
|
|
1201
1461
|
readonly listboxId: string;
|
|
1202
1462
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
1463
|
+
readonly searchQuery: _angular_core.WritableSignal<string>;
|
|
1464
|
+
readonly activeIndex: _angular_core.WritableSignal<number>;
|
|
1203
1465
|
readonly selectedCount: _angular_core.Signal<number>;
|
|
1204
1466
|
readonly allSelected: _angular_core.Signal<boolean>;
|
|
1205
1467
|
readonly isPartiallySelected: _angular_core.Signal<boolean>;
|
|
1468
|
+
readonly showSearch: _angular_core.Signal<boolean>;
|
|
1469
|
+
/** Opciones visibles tras aplicar el filtro de búsqueda ("Todas" nunca se filtra). */
|
|
1470
|
+
readonly filteredOptions: _angular_core.Signal<MultiSelectOption[]>;
|
|
1206
1471
|
/**
|
|
1207
1472
|
* Texto del disparador: placeholder si no hay selección, o los nombres
|
|
1208
1473
|
* seleccionados unidos por coma (el conteo va aparte, en el badge). Con
|
|
@@ -1210,18 +1475,88 @@ declare class MultiSelect {
|
|
|
1210
1475
|
* corta el texto — el badge de conteo siempre queda visible al lado.
|
|
1211
1476
|
*/
|
|
1212
1477
|
readonly summaryText: _angular_core.Signal<string>;
|
|
1213
|
-
private readonly
|
|
1478
|
+
private readonly triggerRef;
|
|
1479
|
+
private readonly panelTemplate;
|
|
1480
|
+
private readonly searchInputRef;
|
|
1481
|
+
private readonly overlayService;
|
|
1482
|
+
private readonly viewContainerRef;
|
|
1483
|
+
private readonly destroyRef;
|
|
1484
|
+
private overlayRef;
|
|
1485
|
+
constructor();
|
|
1214
1486
|
isSelected(value: string): boolean;
|
|
1215
1487
|
toggle(): void;
|
|
1216
1488
|
toggleOption(value: string): void;
|
|
1217
|
-
/**
|
|
1489
|
+
/**
|
|
1490
|
+
* Alterna entre "todas seleccionadas" y "ninguna seleccionada". Actúa
|
|
1491
|
+
* siempre sobre el universo COMPLETO de `options()`, no sobre
|
|
1492
|
+
* `filteredOptions()` — con un buscador activo, "Todas" no se filtra ni
|
|
1493
|
+
* cambia de significado: seguir marcando/desmarcando únicamente lo visible
|
|
1494
|
+
* sería sorprendente para quien ya tenía otras opciones (no visibles en el
|
|
1495
|
+
* filtro actual) seleccionadas de antes.
|
|
1496
|
+
*/
|
|
1218
1497
|
toggleAll(): void;
|
|
1219
|
-
|
|
1498
|
+
onSearchInput(event: Event): void;
|
|
1499
|
+
/** Mueve `activeIndex` sobre las opciones YA FILTRADAS visibles. Clamp simple, sin wraparound. */
|
|
1500
|
+
moveActive(delta: number): void;
|
|
1501
|
+
toggleActive(): void;
|
|
1220
1502
|
onEscape(): void;
|
|
1503
|
+
private attach;
|
|
1504
|
+
private detach;
|
|
1505
|
+
private getOrCreateOverlayRef;
|
|
1221
1506
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MultiSelect, never>;
|
|
1222
|
-
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>;
|
|
1507
|
+
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; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchThreshold": { "alias": "searchThreshold"; "required": false; "isSignal": true; }; }, { "valuesChange": "valuesChange"; }, never, never, true, never>;
|
|
1223
1508
|
}
|
|
1224
1509
|
|
|
1510
|
+
type TextAs = 'h1' | 'h2' | 'h3' | 'p' | 'span';
|
|
1511
|
+
type TextVariant = 'title-xxl' | 'title-xl' | 'title-lg' | 'title-md' | 'title-sm' | 'body' | 'body-muted' | 'caption';
|
|
1512
|
+
type TextTone = 'neutral' | 'ok' | 'warn' | 'error' | 'info';
|
|
1513
|
+
/**
|
|
1514
|
+
* Tipografía unificada — separa la etiqueta semántica (`as`, qué es el
|
|
1515
|
+
* texto para el DOM/accesibilidad) del estilo visual (`variant`, cómo se
|
|
1516
|
+
* ve). Antes de este componente, cada pantalla que consume la librería
|
|
1517
|
+
* definía su propio `h1`/`p` con `font-size` suelto para el mismo rol
|
|
1518
|
+
* (título de página, subtítulo, texto secundario) — auditoría sobre
|
|
1519
|
+
* `web-portal-latam-frontend` encontró 9 tamaños distintos entre login y
|
|
1520
|
+
* home sin ningún paso de escala en común. `variant` resuelve eso contra
|
|
1521
|
+
* la escala de `tokens/base.css` (`--kf-font-size-*`).
|
|
1522
|
+
*
|
|
1523
|
+
* `tone` sigue la misma convención cerrada que `Alert`/`Badge`/`Chip`: sin
|
|
1524
|
+
* escape hatch de color libre. Si un caso necesita un color que `tone` no
|
|
1525
|
+
* cubre, es una discusión de design system, no una prop nueva acá.
|
|
1526
|
+
*
|
|
1527
|
+
* `title-xl`/`title-xxl` son un tier aparte de `title-lg|md|sm`: no vienen
|
|
1528
|
+
* de la auditoría de contenido de página (esa cerró en 2.125rem), son para
|
|
1529
|
+
* títulos protagonistas de pantalla completa (ej. bienvenida del home vía
|
|
1530
|
+
* `kf-page-header[size=xl|xxl]`) — ver tokens/base.css.
|
|
1531
|
+
*
|
|
1532
|
+
* <kf-text as="h1" variant="title-lg">Bienvenido de nuevo</kf-text>
|
|
1533
|
+
* <kf-text as="p" variant="body-muted">Ingresá con tu cuenta corporativa.</kf-text>
|
|
1534
|
+
* <kf-text as="span" variant="caption" tone="error">Campo obligatorio</kf-text>
|
|
1535
|
+
*/
|
|
1536
|
+
declare class Text {
|
|
1537
|
+
/** Etiqueta semántica real que se renderiza — nunca es solo un `div`. */
|
|
1538
|
+
readonly as: _angular_core.InputSignal<TextAs>;
|
|
1539
|
+
readonly variant: _angular_core.InputSignal<TextVariant>;
|
|
1540
|
+
readonly tone: _angular_core.InputSignal<TextTone>;
|
|
1541
|
+
/**
|
|
1542
|
+
* Copia de `as` para uso dentro del template: `as` es palabra reservada
|
|
1543
|
+
* en las expresiones de Angular (`@if (x; as y)`), así que `@switch (as())`
|
|
1544
|
+
* no parsea — NG5002. La prop pública sigue llamándose `as` (es solo un
|
|
1545
|
+
* atributo HTML ahí, `<kf-text as="h1">`, no una expresión).
|
|
1546
|
+
*/
|
|
1547
|
+
protected readonly tag: _angular_core.Signal<TextAs>;
|
|
1548
|
+
protected hostClass(): string;
|
|
1549
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Text, never>;
|
|
1550
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Text, "kf-text", never, { "as": { "alias": "as"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/**
|
|
1554
|
+
* Tamaño del título — `md` es el tamaño de siempre (no rompe a nadie que no
|
|
1555
|
+
* lo especifique). Cada valor mapea 1:1 a una variante `title-*` de
|
|
1556
|
+
* `kf-text` (ver `Text.ts`); `xl`/`xxl` son el tier "hero" de esa escala,
|
|
1557
|
+
* pensado para casos de un título más protagonista (ej. bienvenida del home).
|
|
1558
|
+
*/
|
|
1559
|
+
type PageHeaderTitleSize = 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
|
|
1225
1560
|
/**
|
|
1226
1561
|
* Bloque de título al tope de una página: chip de ícono opcional, título (h1),
|
|
1227
1562
|
* subtítulo opcional y un área de acciones opcional proyectada vía
|
|
@@ -1233,13 +1568,17 @@ declare class MultiSelect {
|
|
|
1233
1568
|
* </kf-page-header>
|
|
1234
1569
|
*
|
|
1235
1570
|
* <kf-page-header icon="settings" title="Configuración" />
|
|
1571
|
+
*
|
|
1572
|
+
* <kf-page-header size="xl" title="Bienvenido de nuevo" />
|
|
1236
1573
|
*/
|
|
1237
1574
|
declare class PageHeader {
|
|
1238
1575
|
readonly icon: _angular_core.InputSignal<IconName | undefined>;
|
|
1239
1576
|
readonly title: _angular_core.InputSignal<string>;
|
|
1240
1577
|
readonly subtitle: _angular_core.InputSignal<string | undefined>;
|
|
1578
|
+
readonly size: _angular_core.InputSignal<PageHeaderTitleSize>;
|
|
1579
|
+
protected readonly titleVariant: _angular_core.Signal<TextVariant>;
|
|
1241
1580
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PageHeader, never>;
|
|
1242
|
-
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>;
|
|
1581
|
+
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; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
|
|
1243
1582
|
}
|
|
1244
1583
|
|
|
1245
1584
|
/** Un número de página clickeable o un separador "…" no interactivo. */
|
|
@@ -1285,6 +1624,13 @@ declare class Pagination {
|
|
|
1285
1624
|
* <kf-panel title="Mis documentos por pagar" actionLabel="Ir a pagos" actionHref="/pagos">
|
|
1286
1625
|
* <kf-action-tile-row icon="download" title="Pagos" description="Revisa tu estado de cuenta y realiza pagos." />
|
|
1287
1626
|
* </kf-panel>
|
|
1627
|
+
*
|
|
1628
|
+
* El host y el `kf-card` interno son flex column con `flex:1` de punta a
|
|
1629
|
+
* punta — si un grid/flex externo estira `kf-panel` a la altura de un
|
|
1630
|
+
* hermano más alto, el contenido proyectado hereda esa altura en vez de
|
|
1631
|
+
* dejar un hueco vacío bajo el `kf-card`. Sin esa presión externa (altura
|
|
1632
|
+
* "auto" del contenedor), `flex:1` no tiene espacio extra que repartir y el
|
|
1633
|
+
* panel se comporta igual que antes.
|
|
1288
1634
|
*/
|
|
1289
1635
|
declare class Panel {
|
|
1290
1636
|
readonly title: _angular_core.InputSignal<string>;
|
|
@@ -1294,11 +1640,14 @@ declare class Panel {
|
|
|
1294
1640
|
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>;
|
|
1295
1641
|
}
|
|
1296
1642
|
|
|
1297
|
-
/** Un ítem de navegación de la barra de marca.
|
|
1643
|
+
/** Un ítem de navegación de la barra de marca. `icon` es opcional y solo se
|
|
1644
|
+
* usa en el drawer mobile (columna, ver template) — el `<nav>` horizontal de
|
|
1645
|
+
* escritorio se mantiene solo texto, sin ícono ni chevron. */
|
|
1298
1646
|
interface PortalHeaderNavItem {
|
|
1299
1647
|
label: string;
|
|
1300
1648
|
href: string;
|
|
1301
1649
|
active?: boolean;
|
|
1650
|
+
icon?: IconName;
|
|
1302
1651
|
}
|
|
1303
1652
|
/** Una acción de la franja de administrador (ej. "Consultar deuda clientes"). */
|
|
1304
1653
|
interface PortalHeaderAdminAction {
|
|
@@ -1321,21 +1670,43 @@ interface PortalHeaderAdminAction {
|
|
|
1321
1670
|
*
|
|
1322
1671
|
* Bajo los 768px, el `<nav>` deja de mostrarse en línea junto al logo y
|
|
1323
1672
|
* colapsa detrás de un botón de menú (ícono `menu`/`x`) que despliega un
|
|
1324
|
-
* drawer
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
*
|
|
1328
|
-
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1673
|
+
* `kf-drawer` (panel lateral genérico, ver `Drawer.ts`) anclado al borde
|
|
1674
|
+
* IZQUIERDO — mismo lado que el botón que lo abre, convención dominante
|
|
1675
|
+
* Material/iOS/Android — con los mismos `navItems` en columna dentro del
|
|
1676
|
+
* body (fondo claro) de ese drawer.
|
|
1677
|
+
*
|
|
1678
|
+
* `PortalHeader` expone dos slots propios pensados para que el consumidor
|
|
1679
|
+
* proyecte contenido que en escritorio vive en otro lugar:
|
|
1680
|
+
* - `<ng-content select="[kf-portal-header-extra]">`: identidad de sesión
|
|
1681
|
+
* (ej. `kf-drawer-session`). Cae en `[kf-drawer-header]` de `kf-drawer` —
|
|
1682
|
+
* el único contenedor con fondo oscuro (`--kf-color-tertiary-deep`, ver
|
|
1683
|
+
* `Drawer.ts`) que `kf-drawer-session` espera como fondo (no trae uno
|
|
1684
|
+
* propio, ver `DrawerSession.ts`).
|
|
1685
|
+
* - `<ng-content select="[kf-portal-header-footer]">`: acciones separadas del
|
|
1686
|
+
* resto (ej. `kf-drawer-logout`). Cae en `[kf-drawer-footer]` de
|
|
1687
|
+
* `kf-drawer`, mismo criterio de "no reimplementar nada del drawer": el
|
|
1688
|
+
* footer ya trae su propio padding/separador (ver `Drawer.ts`).
|
|
1689
|
+
*
|
|
1690
|
+
* `PortalHeader` no sabe qué es ninguno de los dos contenidos ni cómo se
|
|
1691
|
+
* abren, solo les da el lugar correcto dentro del drawer ya desplegado.
|
|
1692
|
+
* `kf-drawer` resuelve overlay con blur, cierre con click-afuera/`Escape`,
|
|
1693
|
+
* atrapado de foco real y devolución de foco al cerrar — `PortalHeader` no
|
|
1694
|
+
* reimplementa nada de eso, solo controla su `open` desde el botón de
|
|
1695
|
+
* hamburguesa.
|
|
1331
1696
|
*
|
|
1332
1697
|
* <kf-portal-header
|
|
1333
1698
|
* [isAdmin]="true"
|
|
1334
1699
|
* [adminActions]="[{ label: 'Consultar deuda clientes', href: '/deuda' }, { label: 'Cambiar DNI', href: '/dni' }]"
|
|
1335
|
-
* [navItems]="[{ label: 'Home', href: '/', active: true }, { label: 'Vehículos', href: '/vehiculos' }]"
|
|
1700
|
+
* [navItems]="[{ label: 'Home', href: '/', active: true, icon: 'grid' }, { label: 'Vehículos', href: '/vehiculos', icon: 'truck' }]"
|
|
1336
1701
|
* userInitials="TS"
|
|
1337
1702
|
* >
|
|
1338
|
-
* <
|
|
1703
|
+
* <kf-drawer-session
|
|
1704
|
+
* kf-portal-header-extra
|
|
1705
|
+
* brand="Portal Kaufmann LATAM"
|
|
1706
|
+
* name="Tomás Soto"
|
|
1707
|
+
* email="tomas.soto@kaufmann.com"
|
|
1708
|
+
* />
|
|
1709
|
+
* <kf-drawer-logout kf-portal-header-footer (logoutClick)="onLogout()" />
|
|
1339
1710
|
* </kf-portal-header>
|
|
1340
1711
|
*/
|
|
1341
1712
|
declare class PortalHeader {
|
|
@@ -1345,10 +1716,10 @@ declare class PortalHeader {
|
|
|
1345
1716
|
readonly navItems: _angular_core.InputSignal<PortalHeaderNavItem[]>;
|
|
1346
1717
|
readonly userInitials: _angular_core.InputSignal<string>;
|
|
1347
1718
|
readonly sessionClick: _angular_core.OutputEmitterRef<void>;
|
|
1348
|
-
/** Visibilidad del drawer de navegación mobile (bajo los 768px).
|
|
1719
|
+
/** Visibilidad del drawer de navegación mobile (bajo los 768px). Se pasa a
|
|
1720
|
+
* `kf-drawer` como `[(open)]` — `PortalHeader` ya no implementa overlay,
|
|
1721
|
+
* `Escape` ni atrapado de foco por su cuenta, eso vive en `Drawer`. */
|
|
1349
1722
|
protected readonly mobileMenuOpen: _angular_core.WritableSignal<boolean>;
|
|
1350
|
-
/** Cierra el drawer con Escape — mismo patrón que cualquier drawer/modal. */
|
|
1351
|
-
protected onEscape(): void;
|
|
1352
1723
|
/**
|
|
1353
1724
|
* `ElementRef` real del botón de sesión (el avatar en la esquina
|
|
1354
1725
|
* derecha), no de todo el header. Pensado para anclar un `kf-dropdown`
|
|
@@ -1361,7 +1732,7 @@ declare class PortalHeader {
|
|
|
1361
1732
|
*/
|
|
1362
1733
|
readonly sessionButtonRef: _angular_core.Signal<ElementRef<any>>;
|
|
1363
1734
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PortalHeader, never>;
|
|
1364
|
-
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, ["[kf-portal-header-extra]"], true, never>;
|
|
1735
|
+
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, ["[kf-portal-header-extra]", "[kf-portal-header-footer]"], true, never>;
|
|
1365
1736
|
}
|
|
1366
1737
|
|
|
1367
1738
|
/**
|
|
@@ -1375,7 +1746,12 @@ declare class PortalHeader {
|
|
|
1375
1746
|
* invitación + las acciones como un bloque compuesto propio del dominio
|
|
1376
1747
|
* "taller", no un placeholder de una sola pieza.
|
|
1377
1748
|
*
|
|
1378
|
-
*
|
|
1749
|
+
* `grow` estira el panel de invitación para llenar el espacio vertical
|
|
1750
|
+
* disponible — solo cuando el consumidor comparte fila con una tarjeta más
|
|
1751
|
+
* alta (ej. junto a "Total de vehículos"); en un lugar sin esa presión
|
|
1752
|
+
* (home, debajo del carousel) se deja en su alto natural.
|
|
1753
|
+
*
|
|
1754
|
+
* <kf-reserve-block emptyLabel="No tienes reservas de taller" grow
|
|
1379
1755
|
* title="¿Necesitas mantención?" description="Tenemos la mejor red de talleres."
|
|
1380
1756
|
* actionLabel="Agenda tu reserva aquí" actionHref="/taller/agendar">
|
|
1381
1757
|
* <kf-button actions icon="calendar">Reservar hora</kf-button>
|
|
@@ -1388,8 +1764,10 @@ declare class ReserveBlock {
|
|
|
1388
1764
|
readonly description: _angular_core.InputSignal<string | undefined>;
|
|
1389
1765
|
readonly actionLabel: _angular_core.InputSignal<string | undefined>;
|
|
1390
1766
|
readonly actionHref: _angular_core.InputSignal<string | undefined>;
|
|
1767
|
+
/** La invitación se estira para llenar la tarjeta (ej. junto a "Total de vehículos"). */
|
|
1768
|
+
readonly grow: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1391
1769
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ReserveBlock, never>;
|
|
1392
|
-
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>;
|
|
1770
|
+
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; }; "grow": { "alias": "grow"; "required": false; "isSignal": true; }; }, {}, never, ["[actions]"], true, never>;
|
|
1393
1771
|
}
|
|
1394
1772
|
|
|
1395
1773
|
/**
|
|
@@ -1490,16 +1868,30 @@ declare class Select {
|
|
|
1490
1868
|
readonly value: _angular_core.InputSignal<string | undefined>;
|
|
1491
1869
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
1492
1870
|
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1871
|
+
/**
|
|
1872
|
+
* Tri-state: si el consumidor no lo especifica (`undefined`), el buscador
|
|
1873
|
+
* se activa solo cuando `options().length` supera `searchThreshold()`. Si
|
|
1874
|
+
* el consumidor define `true`/`false` explícitamente, ese valor manda por
|
|
1875
|
+
* sobre el umbral automático.
|
|
1876
|
+
*/
|
|
1877
|
+
readonly searchable: _angular_core.InputSignal<boolean | undefined>;
|
|
1878
|
+
readonly searchThreshold: _angular_core.InputSignal<number>;
|
|
1493
1879
|
readonly valueChange: _angular_core.OutputEmitterRef<string>;
|
|
1494
1880
|
private readonly instanceId;
|
|
1495
1881
|
readonly triggerId: string;
|
|
1496
1882
|
readonly listboxId: string;
|
|
1497
1883
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
1884
|
+
readonly searchQuery: _angular_core.WritableSignal<string>;
|
|
1885
|
+
readonly activeIndex: _angular_core.WritableSignal<number>;
|
|
1498
1886
|
/** Resolves the union (`string[] | { value; label }[]`) into a single shape for the template. */
|
|
1499
1887
|
readonly normalizedOptions: _angular_core.Signal<SelectOption[]>;
|
|
1500
1888
|
readonly selectedOption: _angular_core.Signal<SelectOption | undefined>;
|
|
1889
|
+
readonly showSearch: _angular_core.Signal<boolean>;
|
|
1890
|
+
/** Opciones visibles tras aplicar el filtro de búsqueda (case/acento-insensitive). */
|
|
1891
|
+
readonly filteredOptions: _angular_core.Signal<SelectOption[]>;
|
|
1501
1892
|
private readonly triggerRef;
|
|
1502
1893
|
private readonly panelTemplate;
|
|
1894
|
+
private readonly searchInputRef;
|
|
1503
1895
|
private readonly overlayService;
|
|
1504
1896
|
private readonly viewContainerRef;
|
|
1505
1897
|
private readonly destroyRef;
|
|
@@ -1514,11 +1906,107 @@ declare class Select {
|
|
|
1514
1906
|
onDocumentEscape(): void;
|
|
1515
1907
|
toggle(): void;
|
|
1516
1908
|
select(option: SelectOption): void;
|
|
1909
|
+
onSearchInput(event: Event): void;
|
|
1910
|
+
/**
|
|
1911
|
+
* Mueve `activeIndex` sobre las opciones YA FILTRADAS visibles. Clamp
|
|
1912
|
+
* simple (sin wraparound): llegar al final o al principio de la lista se
|
|
1913
|
+
* queda ahí en vez de dar la vuelta — es el comportamiento más predecible
|
|
1914
|
+
* cuando se combina con un buscador que puede reducir la lista a 1 opción.
|
|
1915
|
+
*/
|
|
1916
|
+
moveActive(delta: number): void;
|
|
1917
|
+
selectActive(): void;
|
|
1517
1918
|
private attach;
|
|
1518
1919
|
private detach;
|
|
1519
1920
|
private getOrCreateOverlayRef;
|
|
1520
1921
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Select, never>;
|
|
1521
|
-
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>;
|
|
1922
|
+
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; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchThreshold": { "alias": "searchThreshold"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
/** Tipo que consume `kf-sidebar-shell.navItems`. `icon` es requerido: en el
|
|
1926
|
+
* sidebar persistente el ícono es parte permanente del diseño. */
|
|
1927
|
+
interface SidebarNavItemData {
|
|
1928
|
+
icon: IconName;
|
|
1929
|
+
label: string;
|
|
1930
|
+
href: string;
|
|
1931
|
+
active?: boolean;
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1934
|
+
* Ítem de navegación de `kf-sidebar-shell` — ícono + label en fila, estado
|
|
1935
|
+
* activo, sin agrupación. Es el equivalente vertical/persistente del `<a>`
|
|
1936
|
+
* que arma `kf-portal-header` para su `<nav>` horizontal.
|
|
1937
|
+
*
|
|
1938
|
+
* `collapsed` se recibe como input explícito (no vía `:host-context`): el
|
|
1939
|
+
* componente no necesita saber cómo funciona el estado de colapso del
|
|
1940
|
+
* shell, solo qué hacer cuando `collapsed` es `true`.
|
|
1941
|
+
*
|
|
1942
|
+
* No sabe nada de routing — emite `href` como cualquier link y deja que el
|
|
1943
|
+
* consumidor intercepte el click para integrarlo con el Router.
|
|
1944
|
+
*/
|
|
1945
|
+
declare class SidebarNavItem {
|
|
1946
|
+
readonly icon: _angular_core.InputSignal<IconName>;
|
|
1947
|
+
readonly label: _angular_core.InputSignal<string>;
|
|
1948
|
+
readonly href: _angular_core.InputSignal<string>;
|
|
1949
|
+
readonly active: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1950
|
+
/** Oculta el label y centra el ícono — lo controla `kf-sidebar-shell` según su propio estado de colapso. */
|
|
1951
|
+
readonly collapsed: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1952
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarNavItem, never>;
|
|
1953
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarNavItem, "kf-sidebar-nav-item", never, { "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "href": { "alias": "href"; "required": true; "isSignal": true; }; "active": { "alias": "active"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* Shell de layout con navegación lateral persistente — el complemento
|
|
1958
|
+
* vertical de `kf-portal-header` (navbar horizontal). Pensado para
|
|
1959
|
+
* portales tipo "aplicación interna" (Portal OTD, Servicio Star).
|
|
1960
|
+
*
|
|
1961
|
+
* `navItems` se recibe como array de datos (no como contenido proyectado):
|
|
1962
|
+
* el componente no sabe nada de routing, emite `navItemClick` con el ítem
|
|
1963
|
+
* clickeado y deja que el consumidor decida cómo navegar.
|
|
1964
|
+
*
|
|
1965
|
+
* Slots: `[kf-sidebar-brand]` (logo del rail expandido, visible en desktop
|
|
1966
|
+
* y en el panel mobile — es el MISMO rail), `[kf-sidebar-brand-collapsed]`
|
|
1967
|
+
* (reemplazo opcional cuando el rail está colapsado en desktop),
|
|
1968
|
+
* `[kf-sidebar-brand-mobile]` (logo de la topbar angosta de mobile, fondo
|
|
1969
|
+
* claro) y `[kf-sidebar-footer]` (tarjeta de usuario / acciones al pie).
|
|
1970
|
+
*
|
|
1971
|
+
* Botón de colapso: vive como último ítem de la propia lista de
|
|
1972
|
+
* navegación, no flotando en el borde del rail — mismo criterio de
|
|
1973
|
+
* tap-target grande y predecible que el resto de los ítems.
|
|
1974
|
+
*
|
|
1975
|
+
* Responsive: bajo los 900px el sidebar NO se reemplaza por un panel
|
|
1976
|
+
* distinto — es el MISMO rail el que pasa a `position: fixed` fuera de la
|
|
1977
|
+
* pantalla (`translateX(-100%)`) y se desliza a la vista (`translateX(0)`)
|
|
1978
|
+
* sobre un backdrop cuando `mobileOpen` es `true`. Una topbar angosta con
|
|
1979
|
+
* botón de hamburguesa reemplaza al rail en el flujo del documento
|
|
1980
|
+
* mientras el panel está cerrado.
|
|
1981
|
+
*
|
|
1982
|
+
* A propósito NO reutiliza `kf-drawer` (el panel lateral genérico de la
|
|
1983
|
+
* librería): `kf-drawer` tiene su propio fondo claro fijo y duplicaría el
|
|
1984
|
+
* árbol de navegación en un segundo lugar del DOM. Bug de contraste ya
|
|
1985
|
+
* corregido en el historial: los `kf-sidebar-nav-item`, con texto claro
|
|
1986
|
+
* pensado para el gradiente oscuro, quedaban invisibles sobre el fondo
|
|
1987
|
+
* blanco de `kf-drawer`. Acá hay un solo rail, un solo árbol de nav, que
|
|
1988
|
+
* cambia de posición según el viewport.
|
|
1989
|
+
*/
|
|
1990
|
+
declare class SidebarShell {
|
|
1991
|
+
/** Ítems del menú del rail. */
|
|
1992
|
+
readonly navItems: _angular_core.InputSignal<SidebarNavItemData[]>;
|
|
1993
|
+
/** Estado de colapso del rail en desktop, two-way. Sin efecto bajo los 900px (ver estilos). */
|
|
1994
|
+
readonly collapsed: _angular_core.ModelSignal<boolean>;
|
|
1995
|
+
/** Visibilidad del rail deslizado como panel en mobile, two-way. */
|
|
1996
|
+
readonly mobileOpen: _angular_core.ModelSignal<boolean>;
|
|
1997
|
+
/** Se emite al clickear un ítem — el consumidor decide cómo navegar (ej. `router.navigateByUrl`). */
|
|
1998
|
+
readonly navItemClick: _angular_core.OutputEmitterRef<SidebarNavItemData>;
|
|
1999
|
+
/** `true` bajo los 900px — sin esto, un rail dejado colapsado en desktop
|
|
2000
|
+
* seguía ocultando el label de cada ítem al abrir el panel en mobile. */
|
|
2001
|
+
private readonly isMobileViewport;
|
|
2002
|
+
/** Estado de colapso que efectivamente se le pasa a cada `kf-sidebar-nav-item`
|
|
2003
|
+
* y al propio botón de colapso. */
|
|
2004
|
+
protected readonly itemsCollapsed: _angular_core.Signal<boolean>;
|
|
2005
|
+
/** Cierra el panel mobile con Escape — mismo criterio que `Dropdown`/`Modal`/`Drawer`. */
|
|
2006
|
+
protected onEscape(): void;
|
|
2007
|
+
protected onNavItemClick(event: Event, item: SidebarNavItemData): void;
|
|
2008
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarShell, never>;
|
|
2009
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarShell, "kf-sidebar-shell", never, { "navItems": { "alias": "navItems"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "mobileOpen": { "alias": "mobileOpen"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; "mobileOpen": "mobileOpenChange"; "navItemClick": "navItemClick"; }, never, ["[kf-sidebar-brand]", "[kf-sidebar-brand-collapsed]", "[kf-sidebar-footer]", "[kf-sidebar-brand-mobile]"], true, never>;
|
|
1522
2010
|
}
|
|
1523
2011
|
|
|
1524
2012
|
/** Forma del placeholder. */
|
|
@@ -1649,44 +2137,6 @@ declare class Tabs {
|
|
|
1649
2137
|
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>;
|
|
1650
2138
|
}
|
|
1651
2139
|
|
|
1652
|
-
type TextAs = 'h1' | 'h2' | 'h3' | 'p' | 'span';
|
|
1653
|
-
type TextVariant = 'title-lg' | 'title-md' | 'title-sm' | 'body' | 'body-muted' | 'caption';
|
|
1654
|
-
type TextTone = 'neutral' | 'ok' | 'warn' | 'error' | 'info';
|
|
1655
|
-
/**
|
|
1656
|
-
* Tipografía unificada — separa la etiqueta semántica (`as`, qué es el
|
|
1657
|
-
* texto para el DOM/accesibilidad) del estilo visual (`variant`, cómo se
|
|
1658
|
-
* ve). Antes de este componente, cada pantalla que consume la librería
|
|
1659
|
-
* definía su propio `h1`/`p` con `font-size` suelto para el mismo rol
|
|
1660
|
-
* (título de página, subtítulo, texto secundario) — auditoría sobre
|
|
1661
|
-
* `web-portal-latam-frontend` encontró 9 tamaños distintos entre login y
|
|
1662
|
-
* home sin ningún paso de escala en común. `variant` resuelve eso contra
|
|
1663
|
-
* la escala de `tokens/base.css` (`--kf-font-size-*`).
|
|
1664
|
-
*
|
|
1665
|
-
* `tone` sigue la misma convención cerrada que `Alert`/`Badge`/`Chip`: sin
|
|
1666
|
-
* escape hatch de color libre. Si un caso necesita un color que `tone` no
|
|
1667
|
-
* cubre, es una discusión de design system, no una prop nueva acá.
|
|
1668
|
-
*
|
|
1669
|
-
* <kf-text as="h1" variant="title-lg">Bienvenido de nuevo</kf-text>
|
|
1670
|
-
* <kf-text as="p" variant="body-muted">Ingresá con tu cuenta corporativa.</kf-text>
|
|
1671
|
-
* <kf-text as="span" variant="caption" tone="error">Campo obligatorio</kf-text>
|
|
1672
|
-
*/
|
|
1673
|
-
declare class Text {
|
|
1674
|
-
/** Etiqueta semántica real que se renderiza — nunca es solo un `div`. */
|
|
1675
|
-
readonly as: _angular_core.InputSignal<TextAs>;
|
|
1676
|
-
readonly variant: _angular_core.InputSignal<TextVariant>;
|
|
1677
|
-
readonly tone: _angular_core.InputSignal<TextTone>;
|
|
1678
|
-
/**
|
|
1679
|
-
* Copia de `as` para uso dentro del template: `as` es palabra reservada
|
|
1680
|
-
* en las expresiones de Angular (`@if (x; as y)`), así que `@switch (as())`
|
|
1681
|
-
* no parsea — NG5002. La prop pública sigue llamándose `as` (es solo un
|
|
1682
|
-
* atributo HTML ahí, `<kf-text as="h1">`, no una expresión).
|
|
1683
|
-
*/
|
|
1684
|
-
protected readonly tag: _angular_core.Signal<TextAs>;
|
|
1685
|
-
protected hostClass(): string;
|
|
1686
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Text, never>;
|
|
1687
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<Text, "kf-text", never, { "as": { "alias": "as"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
2140
|
/**
|
|
1691
2141
|
* Visual tone of a toast. Maps to the state tokens in
|
|
1692
2142
|
* projects/ui/src/tokens/base.css. `loading` has no auto-dismiss and shows an
|
|
@@ -1784,6 +2234,34 @@ declare class ToastHost {
|
|
|
1784
2234
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ToastHost, "kf-toast-host", never, {}, {}, never, never, true, never>;
|
|
1785
2235
|
}
|
|
1786
2236
|
|
|
2237
|
+
type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
2238
|
+
/**
|
|
2239
|
+
* Tooltip de hover/focus — reemplaza el atributo `title` nativo del
|
|
2240
|
+
* navegador (lento en aparecer, sin estilo, inconsistente entre
|
|
2241
|
+
* navegadores/SO) por un panel propio, mismo mecanismo de
|
|
2242
|
+
* `@angular/cdk/overlay` que ya usa `Dropdown`.
|
|
2243
|
+
*
|
|
2244
|
+
* Pensado para el caso "ícono sin label visible necesita comunicar qué
|
|
2245
|
+
* es" (ej. `kf-sidebar-nav-item` colapsado). No es two-way: a diferencia
|
|
2246
|
+
* de `Dropdown`, esto se abre/cierra solo con hover/focus, nunca por click.
|
|
2247
|
+
*
|
|
2248
|
+
* <a [kfTooltip]="label()" kfTooltipPosition="right">…</a>
|
|
2249
|
+
*/
|
|
2250
|
+
declare class TooltipDirective {
|
|
2251
|
+
text: string;
|
|
2252
|
+
kfTooltipPosition: TooltipPosition;
|
|
2253
|
+
private readonly host;
|
|
2254
|
+
private readonly overlayService;
|
|
2255
|
+
private readonly viewContainerRef;
|
|
2256
|
+
private readonly injector;
|
|
2257
|
+
private overlayRef;
|
|
2258
|
+
protected show(): void;
|
|
2259
|
+
protected hide(): void;
|
|
2260
|
+
private positionsFor;
|
|
2261
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TooltipDirective, never>;
|
|
2262
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TooltipDirective, "[kfTooltip]", never, { "text": { "alias": "kfTooltip"; "required": false; }; "kfTooltipPosition": { "alias": "kfTooltipPosition"; "required": false; }; }, {}, never, never, true, never>;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
1787
2265
|
/**
|
|
1788
2266
|
* Estado puntual mostrado junto a la identidad del vehículo (ej. "En ruta",
|
|
1789
2267
|
* "Mantenimiento", "Fuera de servicio"). `tone` define el color semántico:
|
|
@@ -1842,5 +2320,5 @@ declare class ViewToggle {
|
|
|
1842
2320
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ViewToggle, "kf-view-toggle", never, { "view": { "alias": "view"; "required": true; "isSignal": true; }; }, { "viewChange": "viewChange"; }, never, never, true, never>;
|
|
1843
2321
|
}
|
|
1844
2322
|
|
|
1845
|
-
export { ActionTile, AdminBadge, Alert, Avatar, Badge, Breadcrumb, Button, Card, Carousel, CarouselSlide, Checkbox, Chip, CompanySelector, ContentSlot, ContentState, DataTable, Divider, Dropdown, DropdownItem, DropdownPanel, EmptyState, FeatureCard, Field, FieldLabel, FilterChips, FolderTabs, FolderTabsPanel, Icon, Input, Link, MetricCard, Modal, MultiSelect, PageHeader, Pagination, Panel, PortalHeader, ReserveBlock, SectionHeader, Segmented, Select, Skeleton, Spinner, StatTile, StatusPill, Tabs, Text, ToastHost, ToastService, VehicleHeader, ViewToggle };
|
|
1846
|
-
export type { AlertTone, BreadcrumbItem, CompanySelectorMeta, ContentStateKind, ContentStateLoad, DataTableCardRole, DataTableColumn, DataTableView, DividerOrientation, DropdownItemTone, FolderTabOption, IconName, IconSize, LinkVariant, MultiSelectOption, PaginationItem, PortalHeaderAdminAction, PortalHeaderNavItem, SegmentedOption, SkeletonVariant, SpinnerSize, TabOption, TextAs, TextTone, TextVariant, ToastOptions, ToastPromiseMessages, ToastState, ToastTone, VehicleHeaderStatus, ViewToggleOption };
|
|
2323
|
+
export { ActionTile, AdminBadge, Alert, AuthLayout, Avatar, Badge, Breadcrumb, Button, Card, Carousel, CarouselSlide, Checkbox, Chip, CompanySelector, ContentSlot, ContentState, DataTable, Divider, Drawer, DrawerLogout, DrawerSession, Dropdown, DropdownItem, DropdownPanel, EmptyState, FeatureCard, Field, FieldLabel, FilterChips, FolderTabs, FolderTabsPanel, Footer, Icon, Input, Link, MetricCard, Modal, MultiSelect, PageHeader, Pagination, Panel, PortalHeader, ReserveBlock, SectionHeader, Segmented, Select, SidebarNavItem, SidebarShell, Skeleton, Spinner, StatTile, StatusPill, Tabs, Text, ToastHost, ToastService, TooltipDirective, VehicleHeader, ViewToggle };
|
|
2324
|
+
export type { AlertTone, BreadcrumbItem, CompanySelectorMeta, ContentStateKind, ContentStateLoad, DataTableCardRole, DataTableColumn, DataTableView, DividerOrientation, DrawerSide, DropdownItemTone, DropdownPanelVariant, FolderTabOption, FooterLink, IconName, IconSize, LinkVariant, MultiSelectOption, PageHeaderTitleSize, PaginationItem, PortalHeaderAdminAction, PortalHeaderNavItem, SegmentedOption, SidebarNavItemData, SkeletonVariant, SpinnerSize, TabOption, TextAs, TextTone, TextVariant, ToastOptions, ToastPromiseMessages, ToastState, ToastTone, TooltipPosition, VehicleHeaderStatus, ViewToggleOption };
|