@kaufmann-lab/ui 0.1.3 → 0.1.9
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 +824 -311
- package/fesm2022/kaufmann-lab-ui.mjs.map +1 -1
- package/package.json +2 -1
- package/src/tokens/base.css +20 -0
- package/types/kaufmann-lab-ui.d.ts +336 -75
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, inject, computed, effect, Component, booleanAttribute, model, output, numberAttribute, contentChildren, signal, DestroyRef, viewChild, forwardRef,
|
|
2
|
+
import { input, inject, computed, effect, Component, booleanAttribute, model, output, numberAttribute, contentChildren, signal, DestroyRef, viewChild, forwardRef, ViewContainerRef, HostListener, TemplateRef, contentChild, ElementRef, Directive, ChangeDetectionStrategy, afterRenderEffect, afterNextRender, Injectable } from '@angular/core';
|
|
3
3
|
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
|
|
4
4
|
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
5
|
+
import { Overlay } from '@angular/cdk/overlay';
|
|
6
|
+
import { TemplatePortal } from '@angular/cdk/portal';
|
|
5
7
|
|
|
6
8
|
/** Símbolo de trazo "activity" (grilla 24×24) — ver `icons/index.ts` para el registro completo. */
|
|
7
9
|
const activity = {
|
|
@@ -849,6 +851,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
849
851
|
}, styles: [":host{display:inline-flex;align-items:center;gap:var(--kf-space-xs);padding:var(--kf-space-xs) var(--kf-space-sm);border-radius:var(--kf-radius-pill);background:var(--kf-color-warning-soft);border:1px solid var(--kf-color-warning);color:var(--kf-color-warning-strong);font-size:.75rem;font-weight:700;letter-spacing:.02em;text-transform:uppercase;line-height:1}:host(.kf-admin-badge--inline){background:transparent;border-color:#e2b93b80;color:var(--kf-color-warning)}\n"] }]
|
|
850
852
|
}], propDecorators: { inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }] } });
|
|
851
853
|
|
|
854
|
+
/**
|
|
855
|
+
* Indicador de carga indeterminado: inline, dentro de un botón, o como único
|
|
856
|
+
* contenido de una sección mientras llega la data.
|
|
857
|
+
*
|
|
858
|
+
* Cuando se conoce la forma del contenido que viene, preferir `kf-skeleton`
|
|
859
|
+
* (dibuja la silueta). El spinner es para "algo está pasando" sin forma
|
|
860
|
+
* conocida — guardar, enviar, reintentar.
|
|
861
|
+
*
|
|
862
|
+
* Lleva `role="status"`, así que el lector de pantalla anuncia el `label`
|
|
863
|
+
* cuando aparece. Sin `label` cae en un texto accesible por defecto.
|
|
864
|
+
*
|
|
865
|
+
* <kf-spinner />
|
|
866
|
+
* <kf-spinner size="sm" label="Cargando…" />
|
|
867
|
+
* <kf-spinner onDark />
|
|
868
|
+
*/
|
|
869
|
+
class Spinner {
|
|
870
|
+
size = input('md', /* @ts-ignore */
|
|
871
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
872
|
+
/** Texto al lado del anillo. Vacío deja solo el anillo (y el texto para lectores). */
|
|
873
|
+
label = input('', /* @ts-ignore */
|
|
874
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
875
|
+
/** Invierte los colores para fondos oscuros. */
|
|
876
|
+
onDark = input(false, { ...(ngDevMode ? { debugName: "onDark" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
877
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Spinner, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
878
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Spinner, isStandalone: true, selector: "kf-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, onDark: { classPropertyName: "onDark", publicName: "onDark", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
879
|
+
<span class="kf-spinner" [class.kf-spinner--on-dark]="onDark()" role="status">
|
|
880
|
+
<span class="kf-spinner__ring" [class]="'kf-spinner__ring--' + size()"></span>
|
|
881
|
+
@if (label()) {
|
|
882
|
+
<span class="kf-spinner__label">{{ label() }}</span>
|
|
883
|
+
} @else {
|
|
884
|
+
<span class="kf-spinner__sr">Cargando</span>
|
|
885
|
+
}
|
|
886
|
+
</span>
|
|
887
|
+
`, isInline: true, styles: [":host{display:inline-block}.kf-spinner{display:inline-flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}.kf-spinner__ring{display:inline-block;flex:none;border-radius:var(--kf-radius-pill);border:2px solid var(--kf-color-border);border-top-color:var(--kf-color-primary);animation:kf-spinner-turn .7s linear infinite}.kf-spinner__ring--sm{width:16px;height:16px}.kf-spinner__ring--md{width:24px;height:24px;border-width:3px}.kf-spinner__ring--lg{width:32px;height:32px;border-width:3px}.kf-spinner__label{font-size:.875rem;color:var(--kf-color-text-muted)}.kf-spinner--on-dark .kf-spinner__ring{border-color:#ffffff47;border-top-color:var(--kf-color-white)}.kf-spinner--on-dark .kf-spinner__label{color:var(--kf-color-white)}@keyframes kf-spinner-turn{to{transform:rotate(360deg)}}.kf-spinner__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media(prefers-reduced-motion:reduce){.kf-spinner__ring{animation-duration:2s}}\n"] });
|
|
888
|
+
}
|
|
889
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Spinner, decorators: [{
|
|
890
|
+
type: Component,
|
|
891
|
+
args: [{ selector: 'kf-spinner', template: `
|
|
892
|
+
<span class="kf-spinner" [class.kf-spinner--on-dark]="onDark()" role="status">
|
|
893
|
+
<span class="kf-spinner__ring" [class]="'kf-spinner__ring--' + size()"></span>
|
|
894
|
+
@if (label()) {
|
|
895
|
+
<span class="kf-spinner__label">{{ label() }}</span>
|
|
896
|
+
} @else {
|
|
897
|
+
<span class="kf-spinner__sr">Cargando</span>
|
|
898
|
+
}
|
|
899
|
+
</span>
|
|
900
|
+
`, styles: [":host{display:inline-block}.kf-spinner{display:inline-flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}.kf-spinner__ring{display:inline-block;flex:none;border-radius:var(--kf-radius-pill);border:2px solid var(--kf-color-border);border-top-color:var(--kf-color-primary);animation:kf-spinner-turn .7s linear infinite}.kf-spinner__ring--sm{width:16px;height:16px}.kf-spinner__ring--md{width:24px;height:24px;border-width:3px}.kf-spinner__ring--lg{width:32px;height:32px;border-width:3px}.kf-spinner__label{font-size:.875rem;color:var(--kf-color-text-muted)}.kf-spinner--on-dark .kf-spinner__ring{border-color:#ffffff47;border-top-color:var(--kf-color-white)}.kf-spinner--on-dark .kf-spinner__label{color:var(--kf-color-white)}@keyframes kf-spinner-turn{to{transform:rotate(360deg)}}.kf-spinner__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media(prefers-reduced-motion:reduce){.kf-spinner__ring{animation-duration:2s}}\n"] }]
|
|
901
|
+
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onDark: [{ type: i0.Input, args: [{ isSignal: true, alias: "onDark", required: false }] }] } });
|
|
902
|
+
|
|
852
903
|
/**
|
|
853
904
|
* Wraps a native `<button>`, so keyboard handling, focus and form submission
|
|
854
905
|
* keep working. The cost of the wrapper is forwarding `disabled` and `type` by
|
|
@@ -864,10 +915,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
864
915
|
*
|
|
865
916
|
* `(click)` is not forwarded — it bubbles from the inner button to the host.
|
|
866
917
|
*
|
|
918
|
+
* `loading` replaces the projected content with `kf-spinner` and forces
|
|
919
|
+
* `disabled` — for the common "Ingresando…"/"Enviando…" submit pattern,
|
|
920
|
+
* which before this prop existed as plain text swaps with no visual
|
|
921
|
+
* indicator (see `web-portal-latam-frontend`'s login submit buttons).
|
|
922
|
+
*
|
|
867
923
|
* <kf-button (click)="save()">Save</kf-button>
|
|
868
924
|
* <kf-button variant="ghost" disabled>Cancel</kf-button>
|
|
869
925
|
* <kf-button variant="danger" (click)="remove()">Delete</kf-button>
|
|
870
926
|
* <kf-button size="sm" icon="calendar" block>Reservar hora</kf-button>
|
|
927
|
+
* <kf-button type="submit" [loading]="submitting()">Ingresar</kf-button>
|
|
871
928
|
*/
|
|
872
929
|
class Button {
|
|
873
930
|
variant = input('primary', /* @ts-ignore */
|
|
@@ -883,11 +940,19 @@ class Button {
|
|
|
883
940
|
...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
884
941
|
/** Stretches the button to the full width of its container. */
|
|
885
942
|
block = input(false, { ...(ngDevMode ? { debugName: "block" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
943
|
+
/** Replaces the projected content with `kf-spinner` and forces `disabled`. */
|
|
944
|
+
loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
945
|
+
/** `ghost`/`outline` have no solid background — the default spinner ring already reads fine there. */
|
|
946
|
+
hasSolidFill = computed(() => {
|
|
947
|
+
const variant = this.variant();
|
|
948
|
+
return variant !== 'ghost' && variant !== 'outline';
|
|
949
|
+
}, /* @ts-ignore */
|
|
950
|
+
...(ngDevMode ? [{ debugName: "hasSolidFill" }] : /* istanbul ignore next */ []));
|
|
886
951
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Button, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
887
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Button, isStandalone: true, selector: "kf-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.block": "block() ? '' : null" } }, ngImport: i0, template: `
|
|
952
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Button, isStandalone: true, selector: "kf-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.block": "block() ? '' : null" } }, ngImport: i0, template: `
|
|
888
953
|
<button
|
|
889
954
|
[type]="type()"
|
|
890
|
-
[disabled]="disabled()"
|
|
955
|
+
[disabled]="disabled() || loading()"
|
|
891
956
|
[class.kf-button--secondary]="variant() === 'secondary'"
|
|
892
957
|
[class.kf-button--ghost]="variant() === 'ghost'"
|
|
893
958
|
[class.kf-button--outline]="variant() === 'outline'"
|
|
@@ -895,19 +960,27 @@ class Button {
|
|
|
895
960
|
[class.kf-button--sm]="size() === 'sm'"
|
|
896
961
|
[class.kf-button--lg]="size() === 'lg'"
|
|
897
962
|
>
|
|
898
|
-
@if (
|
|
899
|
-
<kf-
|
|
963
|
+
@if (loading()) {
|
|
964
|
+
<kf-spinner size="sm" [onDark]="hasSolidFill()" />
|
|
965
|
+
} @else {
|
|
966
|
+
@if (icon(); as iconName) {
|
|
967
|
+
<kf-icon
|
|
968
|
+
class="kf-button__icon"
|
|
969
|
+
[name]="iconName"
|
|
970
|
+
[size]="size() === 'lg' ? 'md' : 'sm'"
|
|
971
|
+
/>
|
|
972
|
+
}
|
|
973
|
+
<ng-content />
|
|
900
974
|
}
|
|
901
|
-
<ng-content />
|
|
902
975
|
</button>
|
|
903
|
-
`, isInline: true, styles: [":host{display:inline-block}:host([block]){display:block}button{display:inline-flex;align-items:center;justify-content:center;gap:var(--kf-space-xs);width:100%;font:inherit;font-weight:600;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-primary);border-radius:var(--kf-radius-sm);background:var(--kf-color-primary);color:var(--kf-color-white);cursor:pointer;transition:background .14s,border-color .14s,color .14s}button:hover:not(:disabled){background:var(--kf-color-primary-hover);border-color:var(--kf-color-primary-hover)}button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}button:disabled{opacity:.5;cursor:not-allowed}button.kf-button--secondary{border-color:var(--kf-color-secondary);background:var(--kf-color-secondary)}button.kf-button--secondary:hover:not(:disabled){background:var(--kf-color-secondary-hover);border-color:var(--kf-color-secondary-hover)}button.kf-button--ghost{background:transparent;border-color:transparent;color:var(--kf-color-primary)}button.kf-button--ghost:hover:not(:disabled){background:var(--kf-color-primary-soft)}button.kf-button--outline{background:transparent;border-color:var(--kf-color-border-strong);color:var(--kf-color-text)}button.kf-button--outline:hover:not(:disabled){background:var(--kf-color-surface);border-color:var(--kf-color-text-muted)}button.kf-button--danger{border-color:var(--kf-color-error);background:var(--kf-color-error)}button.kf-button--danger:hover:not(:disabled){background:var(--kf-color-error-hover);border-color:var(--kf-color-error-hover)}button.kf-button--sm{padding:6px var(--kf-space-sm);font-size:.85rem}button.kf-button--lg{padding:var(--kf-space-sm) var(--kf-space-lg);font-size:1.05rem}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
976
|
+
`, isInline: true, styles: [":host{display:inline-block}:host([block]){display:block}button{display:inline-flex;align-items:center;justify-content:center;gap:var(--kf-space-xs);width:100%;font:inherit;font-weight:600;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-primary);border-radius:var(--kf-radius-sm);background:var(--kf-color-primary);color:var(--kf-color-white);cursor:pointer;transition:background .14s,border-color .14s,color .14s}button:hover:not(:disabled){background:var(--kf-color-primary-hover);border-color:var(--kf-color-primary-hover)}button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}button:disabled{opacity:.5;cursor:not-allowed}button.kf-button--secondary{border-color:var(--kf-color-secondary);background:var(--kf-color-secondary)}button.kf-button--secondary:hover:not(:disabled){background:var(--kf-color-secondary-hover);border-color:var(--kf-color-secondary-hover)}button.kf-button--ghost{background:transparent;border-color:transparent;color:var(--kf-color-primary)}button.kf-button--ghost:hover:not(:disabled){background:var(--kf-color-primary-soft)}button.kf-button--outline{background:transparent;border-color:var(--kf-color-border-strong);color:var(--kf-color-text)}button.kf-button--outline:hover:not(:disabled){background:var(--kf-color-surface);border-color:var(--kf-color-text-muted)}button.kf-button--danger{border-color:var(--kf-color-error);background:var(--kf-color-error)}button.kf-button--danger:hover:not(:disabled){background:var(--kf-color-error-hover);border-color:var(--kf-color-error-hover)}button.kf-button--sm{padding:6px var(--kf-space-sm);font-size:.85rem}button.kf-button--lg{padding:var(--kf-space-sm) var(--kf-space-lg);font-size:1.05rem}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }, { kind: "component", type: Spinner, selector: "kf-spinner", inputs: ["size", "label", "onDark"] }] });
|
|
904
977
|
}
|
|
905
978
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Button, decorators: [{
|
|
906
979
|
type: Component,
|
|
907
|
-
args: [{ selector: 'kf-button', imports: [Icon], template: `
|
|
980
|
+
args: [{ selector: 'kf-button', imports: [Icon, Spinner], template: `
|
|
908
981
|
<button
|
|
909
982
|
[type]="type()"
|
|
910
|
-
[disabled]="disabled()"
|
|
983
|
+
[disabled]="disabled() || loading()"
|
|
911
984
|
[class.kf-button--secondary]="variant() === 'secondary'"
|
|
912
985
|
[class.kf-button--ghost]="variant() === 'ghost'"
|
|
913
986
|
[class.kf-button--outline]="variant() === 'outline'"
|
|
@@ -915,15 +988,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
915
988
|
[class.kf-button--sm]="size() === 'sm'"
|
|
916
989
|
[class.kf-button--lg]="size() === 'lg'"
|
|
917
990
|
>
|
|
918
|
-
@if (
|
|
919
|
-
<kf-
|
|
991
|
+
@if (loading()) {
|
|
992
|
+
<kf-spinner size="sm" [onDark]="hasSolidFill()" />
|
|
993
|
+
} @else {
|
|
994
|
+
@if (icon(); as iconName) {
|
|
995
|
+
<kf-icon
|
|
996
|
+
class="kf-button__icon"
|
|
997
|
+
[name]="iconName"
|
|
998
|
+
[size]="size() === 'lg' ? 'md' : 'sm'"
|
|
999
|
+
/>
|
|
1000
|
+
}
|
|
1001
|
+
<ng-content />
|
|
920
1002
|
}
|
|
921
|
-
<ng-content />
|
|
922
1003
|
</button>
|
|
923
1004
|
`, host: {
|
|
924
1005
|
'[attr.block]': "block() ? '' : null",
|
|
925
1006
|
}, styles: [":host{display:inline-block}:host([block]){display:block}button{display:inline-flex;align-items:center;justify-content:center;gap:var(--kf-space-xs);width:100%;font:inherit;font-weight:600;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-primary);border-radius:var(--kf-radius-sm);background:var(--kf-color-primary);color:var(--kf-color-white);cursor:pointer;transition:background .14s,border-color .14s,color .14s}button:hover:not(:disabled){background:var(--kf-color-primary-hover);border-color:var(--kf-color-primary-hover)}button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}button:disabled{opacity:.5;cursor:not-allowed}button.kf-button--secondary{border-color:var(--kf-color-secondary);background:var(--kf-color-secondary)}button.kf-button--secondary:hover:not(:disabled){background:var(--kf-color-secondary-hover);border-color:var(--kf-color-secondary-hover)}button.kf-button--ghost{background:transparent;border-color:transparent;color:var(--kf-color-primary)}button.kf-button--ghost:hover:not(:disabled){background:var(--kf-color-primary-soft)}button.kf-button--outline{background:transparent;border-color:var(--kf-color-border-strong);color:var(--kf-color-text)}button.kf-button--outline:hover:not(:disabled){background:var(--kf-color-surface);border-color:var(--kf-color-text-muted)}button.kf-button--danger{border-color:var(--kf-color-error);background:var(--kf-color-error)}button.kf-button--danger:hover:not(:disabled){background:var(--kf-color-error-hover);border-color:var(--kf-color-error-hover)}button.kf-button--sm{padding:6px var(--kf-space-sm);font-size:.85rem}button.kf-button--lg{padding:var(--kf-space-sm) var(--kf-space-lg);font-size:1.05rem}\n"] }]
|
|
926
|
-
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], block: [{ type: i0.Input, args: [{ isSignal: true, alias: "block", required: false }] }] } });
|
|
1007
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], block: [{ type: i0.Input, args: [{ isSignal: true, alias: "block", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }] } });
|
|
927
1008
|
|
|
928
1009
|
/**
|
|
929
1010
|
* Banner contextual que vive dentro del flujo: validaciones, avisos de
|
|
@@ -1463,7 +1544,7 @@ class Carousel {
|
|
|
1463
1544
|
aria-label="Slide anterior"
|
|
1464
1545
|
(click)="previous()"
|
|
1465
1546
|
>
|
|
1466
|
-
|
|
1547
|
+
<kf-icon name="chevron-left" size="sm" />
|
|
1467
1548
|
</button>
|
|
1468
1549
|
<button
|
|
1469
1550
|
type="button"
|
|
@@ -1471,16 +1552,16 @@ class Carousel {
|
|
|
1471
1552
|
aria-label="Slide siguiente"
|
|
1472
1553
|
(click)="next()"
|
|
1473
1554
|
>
|
|
1474
|
-
|
|
1555
|
+
<kf-icon name="chevron-right" size="sm" />
|
|
1475
1556
|
</button>
|
|
1476
1557
|
</div>
|
|
1477
1558
|
}
|
|
1478
1559
|
</div>
|
|
1479
|
-
`, isInline: true, styles: [":host{display:block;height:100%;font-family:var(--kf-font-body)}.kf-carousel{position:relative;height:100%}.kf-carousel__viewport{height:100%;overflow:hidden;border-radius:var(--kf-radius-md)}.kf-carousel__track{display:flex;height:100%;transition:transform .32s ease}.kf-carousel__controls{position:absolute;z-index:2;right:var(--kf-space-sm);bottom:var(--kf-space-sm);display:flex;align-items:center;gap:var(--kf-space-sm)}.kf-carousel__arrow{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border:1px solid rgb(255 255 255 / 22%);border-radius:var(--kf-radius-pill);background:#ffffff1f;color:#fff;
|
|
1560
|
+
`, isInline: true, styles: [":host{display:block;height:100%;font-family:var(--kf-font-body)}.kf-carousel{position:relative;height:100%}.kf-carousel__viewport{height:100%;overflow:hidden;border-radius:var(--kf-radius-md)}.kf-carousel__track{display:flex;height:100%;transition:transform .32s ease}.kf-carousel__controls{position:absolute;z-index:2;right:var(--kf-space-sm);bottom:var(--kf-space-sm);display:flex;align-items:center;gap:var(--kf-space-sm)}.kf-carousel__arrow{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border:1px solid rgb(255 255 255 / 22%);border-radius:var(--kf-radius-pill);background:#ffffff1f;color:#fff;cursor:pointer;transition:background .14s}.kf-carousel__arrow:hover{background:#ffffff3d}.kf-carousel__arrow:focus-visible{outline:none;box-shadow:0 0 0 2px #fff9}.kf-carousel__dots{display:flex;gap:var(--kf-space-xs)}.kf-carousel__dot{width:7px;height:7px;padding:0;border:none;border-radius:var(--kf-radius-pill);background:#ffffff59;cursor:pointer;transition:background .14s,width .14s}.kf-carousel__dot:focus-visible{outline:none;box-shadow:0 0 0 2px #fff9}.kf-carousel__dot--active{width:1.125rem;border-radius:var(--kf-radius-xs);background:#fff}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
1480
1561
|
}
|
|
1481
1562
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Carousel, decorators: [{
|
|
1482
1563
|
type: Component,
|
|
1483
|
-
args: [{ selector: 'kf-carousel', template: `
|
|
1564
|
+
args: [{ selector: 'kf-carousel', imports: [Icon], template: `
|
|
1484
1565
|
<div
|
|
1485
1566
|
class="kf-carousel"
|
|
1486
1567
|
(mouseenter)="pauseAutoplay()"
|
|
@@ -1518,7 +1599,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
1518
1599
|
aria-label="Slide anterior"
|
|
1519
1600
|
(click)="previous()"
|
|
1520
1601
|
>
|
|
1521
|
-
|
|
1602
|
+
<kf-icon name="chevron-left" size="sm" />
|
|
1522
1603
|
</button>
|
|
1523
1604
|
<button
|
|
1524
1605
|
type="button"
|
|
@@ -1526,12 +1607,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
1526
1607
|
aria-label="Slide siguiente"
|
|
1527
1608
|
(click)="next()"
|
|
1528
1609
|
>
|
|
1529
|
-
|
|
1610
|
+
<kf-icon name="chevron-right" size="sm" />
|
|
1530
1611
|
</button>
|
|
1531
1612
|
</div>
|
|
1532
1613
|
}
|
|
1533
1614
|
</div>
|
|
1534
|
-
`, styles: [":host{display:block;height:100%;font-family:var(--kf-font-body)}.kf-carousel{position:relative;height:100%}.kf-carousel__viewport{height:100%;overflow:hidden;border-radius:var(--kf-radius-md)}.kf-carousel__track{display:flex;height:100%;transition:transform .32s ease}.kf-carousel__controls{position:absolute;z-index:2;right:var(--kf-space-sm);bottom:var(--kf-space-sm);display:flex;align-items:center;gap:var(--kf-space-sm)}.kf-carousel__arrow{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border:1px solid rgb(255 255 255 / 22%);border-radius:var(--kf-radius-pill);background:#ffffff1f;color:#fff;
|
|
1615
|
+
`, styles: [":host{display:block;height:100%;font-family:var(--kf-font-body)}.kf-carousel{position:relative;height:100%}.kf-carousel__viewport{height:100%;overflow:hidden;border-radius:var(--kf-radius-md)}.kf-carousel__track{display:flex;height:100%;transition:transform .32s ease}.kf-carousel__controls{position:absolute;z-index:2;right:var(--kf-space-sm);bottom:var(--kf-space-sm);display:flex;align-items:center;gap:var(--kf-space-sm)}.kf-carousel__arrow{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border:1px solid rgb(255 255 255 / 22%);border-radius:var(--kf-radius-pill);background:#ffffff1f;color:#fff;cursor:pointer;transition:background .14s}.kf-carousel__arrow:hover{background:#ffffff3d}.kf-carousel__arrow:focus-visible{outline:none;box-shadow:0 0 0 2px #fff9}.kf-carousel__dots{display:flex;gap:var(--kf-space-xs)}.kf-carousel__dot{width:7px;height:7px;padding:0;border:none;border-radius:var(--kf-radius-pill);background:#ffffff59;cursor:pointer;transition:background .14s,width .14s}.kf-carousel__dot:focus-visible{outline:none;box-shadow:0 0 0 2px #fff9}.kf-carousel__dot--active{width:1.125rem;border-radius:var(--kf-radius-xs);background:#fff}\n"] }]
|
|
1535
1616
|
}], propDecorators: { autoplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplay", required: false }] }], interval: [{ type: i0.Input, args: [{ isSignal: true, alias: "interval", required: false }] }], indexChange: [{ type: i0.Output, args: ["indexChange"] }], slides: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => CarouselSlide), { isSignal: true }] }] } });
|
|
1536
1617
|
|
|
1537
1618
|
/**
|
|
@@ -1700,10 +1781,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
1700
1781
|
}], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
|
|
1701
1782
|
|
|
1702
1783
|
/**
|
|
1703
|
-
*
|
|
1704
|
-
*
|
|
1705
|
-
*
|
|
1706
|
-
*
|
|
1784
|
+
* Separador visual simple entre bloques de contenido. `orientation`
|
|
1785
|
+
* controla si es una línea horizontal (para separar secciones apiladas) o
|
|
1786
|
+
* vertical (para separar elementos en una fila, ej. acciones en una toolbar,
|
|
1787
|
+
* o las columnas de metadata en `kf-company-selector`).
|
|
1788
|
+
*
|
|
1789
|
+
* En `vertical`, el divisor necesita una altura del contexto donde vive —
|
|
1790
|
+
* `:host { align-self: stretch }` lo hace ocupar la altura del contenedor
|
|
1791
|
+
* flex/grid padre sin que el consumidor tenga que fijarla a mano. `flex:
|
|
1792
|
+
* none` evita que el propio divisor se achique a 0 dentro de ese contenedor
|
|
1793
|
+
* flex cuando hay contenido hermano compitiendo por espacio.
|
|
1707
1794
|
*
|
|
1708
1795
|
* <kf-divider />
|
|
1709
1796
|
* <kf-divider orientation="vertical" />
|
|
@@ -1712,15 +1799,15 @@ class Divider {
|
|
|
1712
1799
|
orientation = input('horizontal', /* @ts-ignore */
|
|
1713
1800
|
...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
1714
1801
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Divider, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1715
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: Divider, isStandalone: true, selector: "kf-divider", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "separator" }, properties: { "attr.
|
|
1802
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: Divider, isStandalone: true, selector: "kf-divider", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "separator" }, properties: { "attr.orientation": "orientation()", "attr.aria-orientation": "orientation()" } }, ngImport: i0, template: '', isInline: true, styles: [":host{display:block;flex:none;border:none;background:var(--kf-color-border)}:host,:host([orientation=\"horizontal\"]){width:100%;height:1px}:host([orientation=\"vertical\"]){align-self:stretch;width:1px;height:auto}\n"] });
|
|
1716
1803
|
}
|
|
1717
1804
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Divider, decorators: [{
|
|
1718
1805
|
type: Component,
|
|
1719
1806
|
args: [{ selector: 'kf-divider', template: '', host: {
|
|
1720
1807
|
role: 'separator',
|
|
1808
|
+
'[attr.orientation]': 'orientation()',
|
|
1721
1809
|
'[attr.aria-orientation]': 'orientation()',
|
|
1722
|
-
|
|
1723
|
-
}, styles: [":host{display:block;flex:none;background:var(--kf-color-border)}:host(.kf-divider--vertical){width:1px;align-self:stretch}:host(:not(.kf-divider--vertical)){width:100%;height:1px}\n"] }]
|
|
1810
|
+
}, styles: [":host{display:block;flex:none;border:none;background:var(--kf-color-border)}:host,:host([orientation=\"horizontal\"]){width:100%;height:1px}:host([orientation=\"vertical\"]){align-self:stretch;width:1px;height:auto}\n"] }]
|
|
1724
1811
|
}], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }] } });
|
|
1725
1812
|
|
|
1726
1813
|
/**
|
|
@@ -1771,23 +1858,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
1771
1858
|
`, styles: [":host{display:contents}.kf-field-label{font-family:var(--kf-font-title);font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--kf-color-text-muted)}.kf-field-label__required{color:var(--kf-color-error);margin-inline-start:2px}\n"] }]
|
|
1772
1859
|
}], propDecorators: { for: [{ type: i0.Input, args: [{ isSignal: true, alias: "for", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }] } });
|
|
1773
1860
|
|
|
1774
|
-
let nextId$
|
|
1861
|
+
let nextId$1 = 0;
|
|
1775
1862
|
/**
|
|
1776
1863
|
* Dropdown de selección simple con panel propio — NUNCA usa el `<select>`
|
|
1777
1864
|
* nativo del navegador. Un `<select>` real siempre delega el popup de
|
|
1778
1865
|
* opciones al sistema operativo, y ningún CSS puede controlar cómo se ve
|
|
1779
|
-
* ese popup
|
|
1780
|
-
*
|
|
1781
|
-
*
|
|
1866
|
+
* ese popup.
|
|
1867
|
+
*
|
|
1868
|
+
* Hasta la `0.1.5` existía además `kf-select-menu`, un segundo componente
|
|
1869
|
+
* prácticamente idéntico (mismo trigger, mismo panel, mismo CSS) que solo
|
|
1870
|
+
* se diferenciaba en aceptar `options` únicamente como `{ value, label }[]`
|
|
1871
|
+
* (sin el atajo `string[]` que `Select` ya tenía). Se fusionaron en este
|
|
1872
|
+
* componente en la `0.2.0` — mantener dos componentes con la misma
|
|
1873
|
+
* interacción y el mismo aspecto visual, cuya única diferencia real era la
|
|
1874
|
+
* forma de un input, no se sostenía como dos piezas separadas del catálogo.
|
|
1782
1875
|
*
|
|
1783
|
-
*
|
|
1784
|
-
*
|
|
1785
|
-
* solo de estilo (label uppercase, fondo gris que pasa a blanco al foco,
|
|
1786
|
-
* a tono con `Input`) y que acepta `options` como `string[]` además de
|
|
1787
|
-
* `{ value, label }[]`.
|
|
1876
|
+
* El panel flotante se conecta al trigger vía `@angular/cdk/overlay` — el
|
|
1877
|
+
* mismo mecanismo que `Dropdown` (ver `../dropdown/Dropdown.ts`).
|
|
1788
1878
|
*
|
|
1789
1879
|
* <kf-select label="Sede" [options]="['Lima', 'Arequipa', 'Trujillo']" placeholder="Selecciona…" />
|
|
1790
1880
|
* <kf-select [options]="[{ value: 'pe', label: 'Perú' }]" (valueChange)="onCountry($event)" />
|
|
1881
|
+
*
|
|
1882
|
+
* Pendiente: el prop `icon` de otros componentes del design system requiere
|
|
1883
|
+
* un componente Icon / sprite SVG que esta librería todavía no tiene — este
|
|
1884
|
+
* componente no usa iconos, así que no aplica acá.
|
|
1791
1885
|
*/
|
|
1792
1886
|
class Select {
|
|
1793
1887
|
label = input(/* @ts-ignore */
|
|
@@ -1800,7 +1894,7 @@ class Select {
|
|
|
1800
1894
|
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
1801
1895
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1802
1896
|
valueChange = output();
|
|
1803
|
-
instanceId = `kf-select-${nextId$
|
|
1897
|
+
instanceId = `kf-select-${nextId$1++}`;
|
|
1804
1898
|
triggerId = `${this.instanceId}-trigger`;
|
|
1805
1899
|
listboxId = `${this.instanceId}-listbox`;
|
|
1806
1900
|
isOpen = signal(false, /* @ts-ignore */
|
|
@@ -1810,7 +1904,34 @@ class Select {
|
|
|
1810
1904
|
...(ngDevMode ? [{ debugName: "normalizedOptions" }] : /* istanbul ignore next */ []));
|
|
1811
1905
|
selectedOption = computed(() => this.normalizedOptions().find((option) => option.value === this.value()), /* @ts-ignore */
|
|
1812
1906
|
...(ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []));
|
|
1813
|
-
|
|
1907
|
+
triggerRef = viewChild.required('trigger', /* @ts-ignore */
|
|
1908
|
+
...(ngDevMode ? [{ debugName: "triggerRef" }] : /* istanbul ignore next */ []));
|
|
1909
|
+
panelTemplate = viewChild.required('panelTemplate', /* @ts-ignore */
|
|
1910
|
+
...(ngDevMode ? [{ debugName: "panelTemplate" }] : /* istanbul ignore next */ []));
|
|
1911
|
+
overlayService = inject(Overlay);
|
|
1912
|
+
viewContainerRef = inject(ViewContainerRef);
|
|
1913
|
+
destroyRef = inject(DestroyRef);
|
|
1914
|
+
overlayRef = null;
|
|
1915
|
+
constructor() {
|
|
1916
|
+
effect(() => {
|
|
1917
|
+
if (this.isOpen()) {
|
|
1918
|
+
this.attach();
|
|
1919
|
+
}
|
|
1920
|
+
else {
|
|
1921
|
+
this.detach();
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
this.destroyRef.onDestroy(() => this.overlayRef?.dispose());
|
|
1925
|
+
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Respaldo de `overlayRef.keydownEvents()`: ese observable del CDK solo ve
|
|
1928
|
+
* teclas presionadas con el foco DENTRO del pane del overlay. Si el foco
|
|
1929
|
+
* sigue en el trigger (o en cualquier otro lado de la página) mientras el
|
|
1930
|
+
* panel está abierto, `keydownEvents()` nunca dispara.
|
|
1931
|
+
*/
|
|
1932
|
+
onDocumentEscape() {
|
|
1933
|
+
this.isOpen.set(false);
|
|
1934
|
+
}
|
|
1814
1935
|
toggle() {
|
|
1815
1936
|
if (this.disabled()) {
|
|
1816
1937
|
return;
|
|
@@ -1823,16 +1944,53 @@ class Select {
|
|
|
1823
1944
|
this.valueChange.emit(option.value);
|
|
1824
1945
|
}
|
|
1825
1946
|
}
|
|
1826
|
-
|
|
1827
|
-
if (this.
|
|
1828
|
-
|
|
1947
|
+
attach() {
|
|
1948
|
+
if (this.overlayRef?.hasAttached()) {
|
|
1949
|
+
return;
|
|
1829
1950
|
}
|
|
1951
|
+
const overlayRef = this.getOrCreateOverlayRef();
|
|
1952
|
+
// Se remide el ancho del trigger en cada apertura, no solo la primera —
|
|
1953
|
+
// ver la misma nota en SelectMenu: cachear el ancho en la creación del
|
|
1954
|
+
// overlay lo deja desincronizado si el trigger cambia de tamaño entre
|
|
1955
|
+
// una apertura y la siguiente.
|
|
1956
|
+
overlayRef.updateSize({ width: this.triggerRef().nativeElement.getBoundingClientRect().width });
|
|
1957
|
+
const portal = new TemplatePortal(this.panelTemplate(), this.viewContainerRef);
|
|
1958
|
+
overlayRef.attach(portal);
|
|
1959
|
+
overlayRef.outsidePointerEvents().subscribe(() => this.isOpen.set(false));
|
|
1960
|
+
overlayRef.keydownEvents().subscribe((event) => {
|
|
1961
|
+
if (event.key === 'Escape') {
|
|
1962
|
+
this.isOpen.set(false);
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1830
1965
|
}
|
|
1831
|
-
|
|
1832
|
-
this.
|
|
1966
|
+
detach() {
|
|
1967
|
+
this.overlayRef?.detach();
|
|
1968
|
+
}
|
|
1969
|
+
getOrCreateOverlayRef() {
|
|
1970
|
+
if (this.overlayRef) {
|
|
1971
|
+
return this.overlayRef;
|
|
1972
|
+
}
|
|
1973
|
+
const positionStrategy = this.overlayService
|
|
1974
|
+
.position()
|
|
1975
|
+
.flexibleConnectedTo(this.triggerRef())
|
|
1976
|
+
.withPositions([
|
|
1977
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
1978
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
1979
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
1980
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
1981
|
+
])
|
|
1982
|
+
.withViewportMargin(8)
|
|
1983
|
+
.withPush(true);
|
|
1984
|
+
this.overlayRef = this.overlayService.create({
|
|
1985
|
+
positionStrategy,
|
|
1986
|
+
scrollStrategy: this.overlayService.scrollStrategies.reposition(),
|
|
1987
|
+
width: this.triggerRef().nativeElement.getBoundingClientRect().width,
|
|
1988
|
+
maxWidth: '90vw',
|
|
1989
|
+
});
|
|
1990
|
+
return this.overlayRef;
|
|
1833
1991
|
}
|
|
1834
1992
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Select, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1835
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Select, isStandalone: true, selector: "kf-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:
|
|
1993
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Select, isStandalone: true, selector: "kf-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:keydown.escape": "onDocumentEscape()" } }, viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "panelTemplate", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1836
1994
|
@if (label()) {
|
|
1837
1995
|
<kf-field-label [for]="triggerId">{{ label() }}</kf-field-label>
|
|
1838
1996
|
}
|
|
@@ -1857,7 +2015,7 @@ class Select {
|
|
|
1857
2015
|
aria-hidden="true"
|
|
1858
2016
|
></span>
|
|
1859
2017
|
</button>
|
|
1860
|
-
|
|
2018
|
+
<ng-template #panelTemplate>
|
|
1861
2019
|
<ul
|
|
1862
2020
|
class="kf-select__panel"
|
|
1863
2021
|
[id]="listboxId"
|
|
@@ -1881,8 +2039,8 @@ class Select {
|
|
|
1881
2039
|
<li class="kf-select__empty">Sin opciones disponibles</li>
|
|
1882
2040
|
}
|
|
1883
2041
|
</ul>
|
|
1884
|
-
|
|
1885
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column;gap:var(--kf-space-xs);
|
|
2042
|
+
</ng-template>
|
|
2043
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;gap:var(--kf-space-xs);width:240px;font-family:var(--kf-font-body)}.kf-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-sm);width:100%;font:inherit;color:var(--kf-color-text);padding:var(--kf-space-sm) var(--kf-space-md);background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);cursor:pointer;transition:border-color .14s,box-shadow .14s}.kf-select__trigger:hover:not(:disabled){border-color:var(--kf-color-border-strong)}.kf-select__trigger:focus-visible{outline:none;border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-select__trigger--disabled{opacity:.5;cursor:not-allowed}.kf-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kf-select__value--placeholder{color:var(--kf-color-text-muted)}.kf-select__caret{flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--kf-color-text-muted);border-bottom:2px solid var(--kf-color-text-muted);transform:rotate(45deg);transition:transform .14s;margin-top:-4px}.kf-select__caret--open{transform:rotate(-135deg);margin-top:4px}.kf-select__panel{box-sizing:border-box;width:100%;margin:0;padding:var(--kf-space-xs) 0;list-style:none;max-height:240px;overflow-y:auto;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-md)}.kf-select__option{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-select__option:hover{background:var(--kf-color-primary-soft)}.kf-select__option--selected{background:var(--kf-color-primary-soft);color:var(--kf-color-primary);font-weight:600}.kf-select__empty{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text-muted)}\n"], dependencies: [{ kind: "component", type: FieldLabel, selector: "kf-field-label", inputs: ["for", "required"] }] });
|
|
1886
2044
|
}
|
|
1887
2045
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Select, decorators: [{
|
|
1888
2046
|
type: Component,
|
|
@@ -1911,7 +2069,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
1911
2069
|
aria-hidden="true"
|
|
1912
2070
|
></span>
|
|
1913
2071
|
</button>
|
|
1914
|
-
|
|
2072
|
+
<ng-template #panelTemplate>
|
|
1915
2073
|
<ul
|
|
1916
2074
|
class="kf-select__panel"
|
|
1917
2075
|
[id]="listboxId"
|
|
@@ -1935,12 +2093,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
1935
2093
|
<li class="kf-select__empty">Sin opciones disponibles</li>
|
|
1936
2094
|
}
|
|
1937
2095
|
</ul>
|
|
1938
|
-
|
|
1939
|
-
`, styles: [":host{display:flex;flex-direction:column;gap:var(--kf-space-xs);
|
|
1940
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }],
|
|
1941
|
-
type: HostListener,
|
|
1942
|
-
args: ['document:click', ['$event']]
|
|
1943
|
-
}], onEscape: [{
|
|
2096
|
+
</ng-template>
|
|
2097
|
+
`, styles: [":host{display:flex;flex-direction:column;gap:var(--kf-space-xs);width:240px;font-family:var(--kf-font-body)}.kf-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-sm);width:100%;font:inherit;color:var(--kf-color-text);padding:var(--kf-space-sm) var(--kf-space-md);background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);cursor:pointer;transition:border-color .14s,box-shadow .14s}.kf-select__trigger:hover:not(:disabled){border-color:var(--kf-color-border-strong)}.kf-select__trigger:focus-visible{outline:none;border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-select__trigger--disabled{opacity:.5;cursor:not-allowed}.kf-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kf-select__value--placeholder{color:var(--kf-color-text-muted)}.kf-select__caret{flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--kf-color-text-muted);border-bottom:2px solid var(--kf-color-text-muted);transform:rotate(45deg);transition:transform .14s;margin-top:-4px}.kf-select__caret--open{transform:rotate(-135deg);margin-top:4px}.kf-select__panel{box-sizing:border-box;width:100%;margin:0;padding:var(--kf-space-xs) 0;list-style:none;max-height:240px;overflow-y:auto;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-md)}.kf-select__option{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-select__option:hover{background:var(--kf-color-primary-soft)}.kf-select__option--selected{background:var(--kf-color-primary-soft);color:var(--kf-color-primary);font-weight:600}.kf-select__empty{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text-muted)}\n"] }]
|
|
2098
|
+
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], triggerRef: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], panelTemplate: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], onDocumentEscape: [{
|
|
1944
2099
|
type: HostListener,
|
|
1945
2100
|
args: ['document:keydown.escape']
|
|
1946
2101
|
}] } });
|
|
@@ -2179,55 +2334,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
2179
2334
|
`, styles: [":host{display:block}.kf-skeleton{display:block;background:linear-gradient(90deg,var(--kf-color-border) 25%,var(--kf-color-surface) 37%,var(--kf-color-border) 63%);background-size:400% 100%;animation:kf-skeleton-shimmer 1.4s ease infinite}.kf-skeleton--text{height:14px;border-radius:var(--kf-radius-xs)}.kf-skeleton--rect{height:80px;border-radius:var(--kf-radius-sm)}.kf-skeleton--circle{aspect-ratio:1 / 1;border-radius:var(--kf-radius-pill)}@keyframes kf-skeleton-shimmer{0%{background-position:100% 0}to{background-position:0 0}}@media(prefers-reduced-motion:reduce){.kf-skeleton{animation:none;background:var(--kf-color-border)}}\n"] }]
|
|
2180
2335
|
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }] } });
|
|
2181
2336
|
|
|
2182
|
-
/**
|
|
2183
|
-
* Indicador de carga indeterminado: inline, dentro de un botón, o como único
|
|
2184
|
-
* contenido de una sección mientras llega la data.
|
|
2185
|
-
*
|
|
2186
|
-
* Cuando se conoce la forma del contenido que viene, preferir `kf-skeleton`
|
|
2187
|
-
* (dibuja la silueta). El spinner es para "algo está pasando" sin forma
|
|
2188
|
-
* conocida — guardar, enviar, reintentar.
|
|
2189
|
-
*
|
|
2190
|
-
* Lleva `role="status"`, así que el lector de pantalla anuncia el `label`
|
|
2191
|
-
* cuando aparece. Sin `label` cae en un texto accesible por defecto.
|
|
2192
|
-
*
|
|
2193
|
-
* <kf-spinner />
|
|
2194
|
-
* <kf-spinner size="sm" label="Cargando…" />
|
|
2195
|
-
* <kf-spinner onDark />
|
|
2196
|
-
*/
|
|
2197
|
-
class Spinner {
|
|
2198
|
-
size = input('md', /* @ts-ignore */
|
|
2199
|
-
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2200
|
-
/** Texto al lado del anillo. Vacío deja solo el anillo (y el texto para lectores). */
|
|
2201
|
-
label = input('', /* @ts-ignore */
|
|
2202
|
-
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
2203
|
-
/** Invierte los colores para fondos oscuros. */
|
|
2204
|
-
onDark = input(false, { ...(ngDevMode ? { debugName: "onDark" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2205
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Spinner, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2206
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Spinner, isStandalone: true, selector: "kf-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, onDark: { classPropertyName: "onDark", publicName: "onDark", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2207
|
-
<span class="kf-spinner" [class.kf-spinner--on-dark]="onDark()" role="status">
|
|
2208
|
-
<span class="kf-spinner__ring" [class]="'kf-spinner__ring--' + size()"></span>
|
|
2209
|
-
@if (label()) {
|
|
2210
|
-
<span class="kf-spinner__label">{{ label() }}</span>
|
|
2211
|
-
} @else {
|
|
2212
|
-
<span class="kf-spinner__sr">Cargando</span>
|
|
2213
|
-
}
|
|
2214
|
-
</span>
|
|
2215
|
-
`, isInline: true, styles: [":host{display:inline-block}.kf-spinner{display:inline-flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}.kf-spinner__ring{display:inline-block;flex:none;border-radius:var(--kf-radius-pill);border:2px solid var(--kf-color-border);border-top-color:var(--kf-color-primary);animation:kf-spinner-turn .7s linear infinite}.kf-spinner__ring--sm{width:16px;height:16px}.kf-spinner__ring--md{width:24px;height:24px;border-width:3px}.kf-spinner__ring--lg{width:32px;height:32px;border-width:3px}.kf-spinner__label{font-size:.875rem;color:var(--kf-color-text-muted)}.kf-spinner--on-dark .kf-spinner__ring{border-color:#ffffff47;border-top-color:var(--kf-color-white)}.kf-spinner--on-dark .kf-spinner__label{color:var(--kf-color-white)}@keyframes kf-spinner-turn{to{transform:rotate(360deg)}}.kf-spinner__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media(prefers-reduced-motion:reduce){.kf-spinner__ring{animation-duration:2s}}\n"] });
|
|
2216
|
-
}
|
|
2217
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Spinner, decorators: [{
|
|
2218
|
-
type: Component,
|
|
2219
|
-
args: [{ selector: 'kf-spinner', template: `
|
|
2220
|
-
<span class="kf-spinner" [class.kf-spinner--on-dark]="onDark()" role="status">
|
|
2221
|
-
<span class="kf-spinner__ring" [class]="'kf-spinner__ring--' + size()"></span>
|
|
2222
|
-
@if (label()) {
|
|
2223
|
-
<span class="kf-spinner__label">{{ label() }}</span>
|
|
2224
|
-
} @else {
|
|
2225
|
-
<span class="kf-spinner__sr">Cargando</span>
|
|
2226
|
-
}
|
|
2227
|
-
</span>
|
|
2228
|
-
`, styles: [":host{display:inline-block}.kf-spinner{display:inline-flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}.kf-spinner__ring{display:inline-block;flex:none;border-radius:var(--kf-radius-pill);border:2px solid var(--kf-color-border);border-top-color:var(--kf-color-primary);animation:kf-spinner-turn .7s linear infinite}.kf-spinner__ring--sm{width:16px;height:16px}.kf-spinner__ring--md{width:24px;height:24px;border-width:3px}.kf-spinner__ring--lg{width:32px;height:32px;border-width:3px}.kf-spinner__label{font-size:.875rem;color:var(--kf-color-text-muted)}.kf-spinner--on-dark .kf-spinner__ring{border-color:#ffffff47;border-top-color:var(--kf-color-white)}.kf-spinner--on-dark .kf-spinner__label{color:var(--kf-color-white)}@keyframes kf-spinner-turn{to{transform:rotate(360deg)}}.kf-spinner__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media(prefers-reduced-motion:reduce){.kf-spinner__ring{animation-duration:2s}}\n"] }]
|
|
2229
|
-
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onDark: [{ type: i0.Input, args: [{ isSignal: true, alias: "onDark", required: false }] }] } });
|
|
2230
|
-
|
|
2231
2337
|
/**
|
|
2232
2338
|
* Wrapper de los cuatro estados que toda sección tiene: cargando, con datos,
|
|
2233
2339
|
* vacía y con error. Un componente en vez de tres `@if` sueltos, porque es
|
|
@@ -2788,6 +2894,229 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
2788
2894
|
`, styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-data-table{background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-sm);overflow:hidden}.kf-data-table--flush{border:none;box-shadow:none;border-radius:0}.kf-data-table__toolbar{display:flex;justify-content:flex-end;padding:var(--kf-space-sm) var(--kf-space-md);border-bottom:1px solid var(--kf-color-border)}.kf-data-table__view-toggle{display:inline-flex;gap:2px;padding:2px;background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm)}.kf-data-table__view-option{font:inherit;font-size:.875em;padding:var(--kf-space-xs) var(--kf-space-sm);border:none;background:transparent;color:var(--kf-color-text-muted);border-radius:var(--kf-radius-xs);cursor:pointer;transition:background .14s,color .14s}.kf-data-table__view-option:hover:not(.kf-data-table__view-option--active){color:var(--kf-color-text)}.kf-data-table__view-option--active{background:var(--kf-color-white);color:var(--kf-color-ink);box-shadow:var(--kf-shadow-xs)}.kf-data-table__view-option:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-data-table__scroll{overflow-x:auto}.kf-data-table__table{width:100%;border-collapse:collapse;text-align:left}.kf-data-table__table th,.kf-data-table__table td{padding:var(--kf-space-sm) var(--kf-space-md);border-bottom:1px solid var(--kf-color-border);white-space:nowrap}.kf-data-table__table th{font-family:var(--kf-font-title);font-size:.8125em;text-transform:uppercase;letter-spacing:.02em;color:var(--kf-color-text-muted);background:var(--kf-color-surface)}.kf-data-table__table td{color:var(--kf-color-text)}.kf-data-table__table tbody tr:last-child td{border-bottom:none}.kf-data-table__row{cursor:pointer;transition:background .14s}.kf-data-table__row:hover{background:var(--kf-color-primary-soft)}.kf-data-table__cell--right{text-align:right}.kf-data-table__empty{padding:var(--kf-space-md)}.kf-data-table__footer{padding:var(--kf-space-sm) var(--kf-space-md);border-top:1px solid var(--kf-color-border)}.kf-data-table__footer:empty{display:none}.kf-data-table__cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--kf-space-md);padding:var(--kf-space-md)}.kf-data-table__card{display:flex;flex-direction:column;border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);overflow:hidden;transition:border-color .14s,box-shadow .14s}.kf-data-table__card--interactive{cursor:pointer}.kf-data-table__card:hover{border-color:var(--kf-color-border-strong);box-shadow:var(--kf-shadow-xs)}.kf-data-table__card--interactive:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-data-table__card-header{display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-md)}.kf-data-table__card-media{flex:none}.kf-data-table__card-media img,.kf-data-table__thumb{display:block;width:48px;height:48px;border-radius:var(--kf-radius-xs);object-fit:cover;background:var(--kf-color-surface)}.kf-data-table__card-heading{display:flex;flex-direction:column;gap:var(--kf-space-xs);min-width:0}.kf-data-table__card-title{font-family:var(--kf-font-title);font-weight:600;color:var(--kf-color-ink);overflow-wrap:anywhere}.kf-data-table__card-statuses,.kf-data-table__card-actions{display:flex;flex-wrap:wrap;gap:var(--kf-space-xs)}.kf-data-table__card-fields{display:flex;flex-direction:column;gap:var(--kf-space-xs);padding:var(--kf-space-md)}.kf-data-table__card-header+.kf-data-table__card-fields{padding-top:0}.kf-data-table__card-field{display:flex;justify-content:space-between;gap:var(--kf-space-sm)}.kf-data-table__card-actions{justify-content:flex-end;margin-top:auto;padding:var(--kf-space-sm) var(--kf-space-md);border-top:1px solid var(--kf-color-border);background:var(--kf-color-surface)}.kf-data-table__thumb{width:32px;height:32px}.kf-data-table__card-label{font-family:var(--kf-font-title);font-size:.8125em;text-transform:uppercase;letter-spacing:.02em;color:var(--kf-color-text-muted)}.kf-data-table__card-value{color:var(--kf-color-text);text-align:right}\n"] }]
|
|
2789
2895
|
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }], cardable: [{ type: i0.Input, args: [{ isSignal: true, alias: "cardable", required: false }] }], defaultView: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultView", required: false }] }], render: [{ type: i0.Input, args: [{ isSignal: true, alias: "render", required: false }] }], cellTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellTemplates", required: false }] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }] } });
|
|
2790
2896
|
|
|
2897
|
+
/**
|
|
2898
|
+
* Ítem de acción dentro de un `kf-dropdown-panel`. Es un `<button>` nativo
|
|
2899
|
+
* por dentro (no un `<a>`): las acciones de un menú de este tipo disparan
|
|
2900
|
+
* comportamiento en la pantalla actual (cerrar sesión, ejecutar un
|
|
2901
|
+
* comando), no navegan a otra URL.
|
|
2902
|
+
*
|
|
2903
|
+
* <kf-dropdown-item (click)="onLogout()" tone="error">Cerrar sesión</kf-dropdown-item>
|
|
2904
|
+
*/
|
|
2905
|
+
class DropdownItem {
|
|
2906
|
+
tone = input('neutral', /* @ts-ignore */
|
|
2907
|
+
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
2908
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DropdownItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2909
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: DropdownItem, isStandalone: true, selector: "kf-dropdown-item", inputs: { tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2910
|
+
<button
|
|
2911
|
+
type="button"
|
|
2912
|
+
class="kf-dropdown-item"
|
|
2913
|
+
[class.kf-dropdown-item--error]="tone() === 'error'"
|
|
2914
|
+
role="menuitem"
|
|
2915
|
+
>
|
|
2916
|
+
<ng-content />
|
|
2917
|
+
</button>
|
|
2918
|
+
`, isInline: true, styles: [":host{display:block}.kf-dropdown-item{display:block;width:100%;padding:var(--kf-space-sm) var(--kf-space-md);border:none;background:transparent;font:inherit;text-align:left;color:var(--kf-color-text);cursor:pointer}.kf-dropdown-item:hover{background:var(--kf-color-surface)}.kf-dropdown-item:focus-visible{outline:none;box-shadow:inset var(--kf-shadow-focus)}.kf-dropdown-item--error{color:var(--kf-color-error-strong)}.kf-dropdown-item--error:hover{background:var(--kf-color-error-soft)}\n"] });
|
|
2919
|
+
}
|
|
2920
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DropdownItem, decorators: [{
|
|
2921
|
+
type: Component,
|
|
2922
|
+
args: [{ selector: 'kf-dropdown-item', template: `
|
|
2923
|
+
<button
|
|
2924
|
+
type="button"
|
|
2925
|
+
class="kf-dropdown-item"
|
|
2926
|
+
[class.kf-dropdown-item--error]="tone() === 'error'"
|
|
2927
|
+
role="menuitem"
|
|
2928
|
+
>
|
|
2929
|
+
<ng-content />
|
|
2930
|
+
</button>
|
|
2931
|
+
`, styles: [":host{display:block}.kf-dropdown-item{display:block;width:100%;padding:var(--kf-space-sm) var(--kf-space-md);border:none;background:transparent;font:inherit;text-align:left;color:var(--kf-color-text);cursor:pointer}.kf-dropdown-item:hover{background:var(--kf-color-surface)}.kf-dropdown-item:focus-visible{outline:none;box-shadow:inset var(--kf-shadow-focus)}.kf-dropdown-item--error{color:var(--kf-color-error-strong)}.kf-dropdown-item--error:hover{background:var(--kf-color-error-soft)}\n"] }]
|
|
2932
|
+
}], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
|
|
2933
|
+
/**
|
|
2934
|
+
* Contenido del panel flotante de un `kf-dropdown`. Es solo una plantilla
|
|
2935
|
+
* (`<ng-template>` por dentro, capturada vía `TemplateRef`) — `Dropdown` la
|
|
2936
|
+
* conecta al overlay real cuando `open` pasa a `true`, no la renderiza en su
|
|
2937
|
+
* propio lugar del DOM. Esto es lo que permite que el panel aparezca pegado
|
|
2938
|
+
* al host de `Dropdown` sin importar dónde esté ese host en la página.
|
|
2939
|
+
*
|
|
2940
|
+
* <kf-dropdown [(open)]="menuOpen">
|
|
2941
|
+
* <kf-dropdown-panel>
|
|
2942
|
+
* <kf-dropdown-item (click)="onLogout()">Cerrar sesión</kf-dropdown-item>
|
|
2943
|
+
* </kf-dropdown-panel>
|
|
2944
|
+
* </kf-dropdown>
|
|
2945
|
+
*/
|
|
2946
|
+
class DropdownPanel {
|
|
2947
|
+
templateRef = viewChild.required(TemplateRef, /* @ts-ignore */
|
|
2948
|
+
...(ngDevMode ? [{ debugName: "templateRef" }] : /* istanbul ignore next */ []));
|
|
2949
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DropdownPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2950
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: DropdownPanel, isStandalone: true, selector: "kf-dropdown-panel", viewQueries: [{ propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2951
|
+
<ng-template>
|
|
2952
|
+
<div class="kf-dropdown-panel">
|
|
2953
|
+
<div class="kf-dropdown-panel__inner" role="menu">
|
|
2954
|
+
<ng-content />
|
|
2955
|
+
</div>
|
|
2956
|
+
</div>
|
|
2957
|
+
</ng-template>
|
|
2958
|
+
`, isInline: true, styles: [".kf-dropdown-panel{min-width:220px;max-width:100%;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-lg);font-family:var(--kf-font-body);animation:kf-dropdown-panel-enter .14s ease-out}.kf-dropdown-panel__inner{padding:var(--kf-space-xs) 0;overflow:hidden;border-radius:inherit}@media(prefers-reduced-motion:reduce){.kf-dropdown-panel{animation:none}}@keyframes kf-dropdown-panel-enter{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}\n"] });
|
|
2959
|
+
}
|
|
2960
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DropdownPanel, decorators: [{
|
|
2961
|
+
type: Component,
|
|
2962
|
+
args: [{ selector: 'kf-dropdown-panel', template: `
|
|
2963
|
+
<ng-template>
|
|
2964
|
+
<div class="kf-dropdown-panel">
|
|
2965
|
+
<div class="kf-dropdown-panel__inner" role="menu">
|
|
2966
|
+
<ng-content />
|
|
2967
|
+
</div>
|
|
2968
|
+
</div>
|
|
2969
|
+
</ng-template>
|
|
2970
|
+
`, styles: [".kf-dropdown-panel{min-width:220px;max-width:100%;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-lg);font-family:var(--kf-font-body);animation:kf-dropdown-panel-enter .14s ease-out}.kf-dropdown-panel__inner{padding:var(--kf-space-xs) 0;overflow:hidden;border-radius:inherit}@media(prefers-reduced-motion:reduce){.kf-dropdown-panel{animation:none}}@keyframes kf-dropdown-panel-enter{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}\n"] }]
|
|
2971
|
+
}], propDecorators: { templateRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
|
|
2972
|
+
/**
|
|
2973
|
+
* Menú de acciones flotante, conectado a un elemento disparador vía
|
|
2974
|
+
* `@angular/cdk/overlay` — la misma pieza que usa Angular Material para
|
|
2975
|
+
* `mat-menu`/`mat-select`. Resuelve el patrón que antes se reimplementaba a
|
|
2976
|
+
* mano en cada consumidor (ver el session-menu de `web-portal-latam-frontend`,
|
|
2977
|
+
* ~80 líneas de HTML/TS/SCSS para toggle + click-afuera + Escape + animación
|
|
2978
|
+
* de entrada, acopladas a una clase interna no pública de `PortalHeader`).
|
|
2979
|
+
*
|
|
2980
|
+
* Se apoya en el CDK en vez de un `position: absolute` casero (como sí hace
|
|
2981
|
+
* `SelectMenu`, que puede permitírselo porque su trigger vive siempre dentro
|
|
2982
|
+
* del propio componente) porque acá el disparador real puede vivir en OTRO
|
|
2983
|
+
* componente por completo — ej. el avatar dentro de `kf-portal-header` — y
|
|
2984
|
+
* el panel tiene que aparecer pegado a ESE elemento sin importar dónde el
|
|
2985
|
+
* consumidor ubique al `Dropdown` en su HTML. El Overlay CDK calcula esa
|
|
2986
|
+
* posición (con fallback si no entra en pantalla) en vez de que cada
|
|
2987
|
+
* consumidor lo recalcule a mano.
|
|
2988
|
+
*
|
|
2989
|
+
* `open` es two-way, igual que `Alert`/`Modal`: el consumidor decide qué
|
|
2990
|
+
* dispara la apertura (puede ser un `(click)` en un botón propio, o un
|
|
2991
|
+
* evento de otro componente como `PortalHeader.sessionClick`) — `Dropdown`
|
|
2992
|
+
* en sí no renderiza ningún trigger, su propio host es el punto de anclaje
|
|
2993
|
+
* visual del panel.
|
|
2994
|
+
*
|
|
2995
|
+
* <kf-dropdown [(open)]="menuOpen">
|
|
2996
|
+
* <kf-dropdown-panel>
|
|
2997
|
+
* <div class="mi-header">Sesión iniciada como {{ email() }}</div>
|
|
2998
|
+
* <kf-dropdown-item (click)="onLogout()" tone="error">Cerrar sesión</kf-dropdown-item>
|
|
2999
|
+
* </kf-dropdown-panel>
|
|
3000
|
+
* </kf-dropdown>
|
|
3001
|
+
*/
|
|
3002
|
+
class Dropdown {
|
|
3003
|
+
/** Visibilidad del panel, two-way: `[(open)]="menuOpen"`. */
|
|
3004
|
+
open = model(false, /* @ts-ignore */
|
|
3005
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
3006
|
+
/**
|
|
3007
|
+
* Elemento al que se conecta el overlay, si es distinto del propio host
|
|
3008
|
+
* de `Dropdown`. Sin esto, `Dropdown` asume que ÉL MISMO es visualmente
|
|
3009
|
+
* el disparador (caso normal: el consumidor arma su propio botón como
|
|
3010
|
+
* contenido, y `Dropdown` envuelve ese contenido). Cuando el disparador
|
|
3011
|
+
* real vive dentro de OTRO componente que no se puede envolver sin
|
|
3012
|
+
* ensanchar el área de click a algo más grande que el botón (ej. el
|
|
3013
|
+
* avatar de sesión dentro de `PortalHeader`, que convive con logo y
|
|
3014
|
+
* navegación en el mismo host), `anchor` permite apuntar el overlay a la
|
|
3015
|
+
* referencia real de ese componente en vez de al host vacío de
|
|
3016
|
+
* `Dropdown`.
|
|
3017
|
+
*
|
|
3018
|
+
* <kf-dropdown [(open)]="menuOpen" [anchor]="headerRef()">
|
|
3019
|
+
*/
|
|
3020
|
+
anchor = input(/* @ts-ignore */
|
|
3021
|
+
...(ngDevMode ? [undefined, { debugName: "anchor" }] : /* istanbul ignore next */ []));
|
|
3022
|
+
panel = contentChild(DropdownPanel, /* @ts-ignore */
|
|
3023
|
+
...(ngDevMode ? [{ debugName: "panel" }] : /* istanbul ignore next */ []));
|
|
3024
|
+
overlayService = inject(Overlay);
|
|
3025
|
+
host = inject((ElementRef));
|
|
3026
|
+
viewContainerRef = inject(ViewContainerRef);
|
|
3027
|
+
destroyRef = inject(DestroyRef);
|
|
3028
|
+
overlayRef = null;
|
|
3029
|
+
constructor() {
|
|
3030
|
+
effect(() => {
|
|
3031
|
+
if (this.open()) {
|
|
3032
|
+
this.attach();
|
|
3033
|
+
}
|
|
3034
|
+
else {
|
|
3035
|
+
this.detach();
|
|
3036
|
+
}
|
|
3037
|
+
});
|
|
3038
|
+
this.destroyRef.onDestroy(() => this.overlayRef?.dispose());
|
|
3039
|
+
}
|
|
3040
|
+
/**
|
|
3041
|
+
* Respaldo de `overlayRef.keydownEvents()`: ese observable del CDK solo
|
|
3042
|
+
* ve teclas presionadas con el foco DENTRO del pane del overlay. Si el
|
|
3043
|
+
* usuario abre el menú y presiona Escape con el foco en otro lado de la
|
|
3044
|
+
* página (caso común — el foco puede seguir en el botón disparador, que
|
|
3045
|
+
* vive fuera del overlay), `keydownEvents()` nunca dispara. Este listener
|
|
3046
|
+
* a nivel de documento cubre ese caso; el de `keydownEvents()` sigue
|
|
3047
|
+
* activo para cuando el foco sí está dentro del panel.
|
|
3048
|
+
*/
|
|
3049
|
+
onDocumentEscape() {
|
|
3050
|
+
this.open.set(false);
|
|
3051
|
+
}
|
|
3052
|
+
attach() {
|
|
3053
|
+
const panel = this.panel();
|
|
3054
|
+
if (!panel || this.overlayRef?.hasAttached()) {
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
3057
|
+
const overlayRef = this.getOrCreateOverlayRef();
|
|
3058
|
+
const portal = new TemplatePortal(panel.templateRef(), this.viewContainerRef);
|
|
3059
|
+
overlayRef.attach(portal);
|
|
3060
|
+
overlayRef.outsidePointerEvents().subscribe(() => this.open.set(false));
|
|
3061
|
+
overlayRef.keydownEvents().subscribe((event) => {
|
|
3062
|
+
if (event.key === 'Escape') {
|
|
3063
|
+
this.open.set(false);
|
|
3064
|
+
}
|
|
3065
|
+
});
|
|
3066
|
+
}
|
|
3067
|
+
detach() {
|
|
3068
|
+
this.overlayRef?.detach();
|
|
3069
|
+
}
|
|
3070
|
+
getOrCreateOverlayRef() {
|
|
3071
|
+
if (this.overlayRef) {
|
|
3072
|
+
return this.overlayRef;
|
|
3073
|
+
}
|
|
3074
|
+
const positionStrategy = this.overlayService
|
|
3075
|
+
.position()
|
|
3076
|
+
.flexibleConnectedTo(this.anchor() ?? this.host)
|
|
3077
|
+
// 4 posiciones, no 2: además de abajo/arriba (alineado al borde
|
|
3078
|
+
// derecho del anchor, el caso común), agrega el mismo par alineado al
|
|
3079
|
+
// borde IZQUIERDO. Con solo el par "end" — como estaba antes — un
|
|
3080
|
+
// trigger cerca del borde derecho de la pantalla no tenía ningún
|
|
3081
|
+
// fallback horizontal: el panel se salía del viewport en vez de
|
|
3082
|
+
// reacomodarse hacia la izquierda. El CDK prueba cada posición en
|
|
3083
|
+
// orden y usa la primera que entra completa en el viewport.
|
|
3084
|
+
.withPositions([
|
|
3085
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
3086
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
3087
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
3088
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
3089
|
+
])
|
|
3090
|
+
// Margen de seguridad contra los bordes del viewport — sin esto, el
|
|
3091
|
+
// CDK puede considerar una posición "válida" aunque quede pegada al
|
|
3092
|
+
// borde con 0px de aire.
|
|
3093
|
+
.withViewportMargin(8)
|
|
3094
|
+
// Si ninguna de las 4 posiciones entra completa (viewport muy
|
|
3095
|
+
// angosto), la última se ajusta con push en vez de desbordarse fuera
|
|
3096
|
+
// de pantalla sin control.
|
|
3097
|
+
.withPush(true);
|
|
3098
|
+
this.overlayRef = this.overlayService.create({
|
|
3099
|
+
positionStrategy,
|
|
3100
|
+
scrollStrategy: this.overlayService.scrollStrategies.reposition(),
|
|
3101
|
+
// Sin esto, el panel puede quedar más angosto que su propio
|
|
3102
|
+
// `min-width` en pantallas chicas si el CDK decide recortar — fija un
|
|
3103
|
+
// techo razonable en vez de dejarlo crecer sin límite ni encogerse
|
|
3104
|
+
// por debajo de lo legible.
|
|
3105
|
+
maxWidth: '90vw',
|
|
3106
|
+
});
|
|
3107
|
+
return this.overlayRef;
|
|
3108
|
+
}
|
|
3109
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Dropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3110
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: Dropdown, isStandalone: true, selector: "kf-dropdown", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { listeners: { "document:keydown.escape": "onDocumentEscape()" } }, queries: [{ propertyName: "panel", first: true, predicate: DropdownPanel, descendants: true, isSignal: true }], ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{display:inline-block}\n"] });
|
|
3111
|
+
}
|
|
3112
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Dropdown, decorators: [{
|
|
3113
|
+
type: Component,
|
|
3114
|
+
args: [{ selector: 'kf-dropdown', template: `<ng-content />`, styles: [":host{display:inline-block}\n"] }]
|
|
3115
|
+
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: false }] }], panel: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownPanel), { isSignal: true }] }], onDocumentEscape: [{
|
|
3116
|
+
type: HostListener,
|
|
3117
|
+
args: ['document:keydown.escape']
|
|
3118
|
+
}] } });
|
|
3119
|
+
|
|
2791
3120
|
/**
|
|
2792
3121
|
* Bloque promocional sobre fondo oscuro de marca (página 37) — campañas,
|
|
2793
3122
|
* accesos directos o el portal de autoatención. Usa `--kf-color-tertiary-deep`
|
|
@@ -3016,6 +3345,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3016
3345
|
`, styles: [":host{display:block}.kf-filter-chips{display:flex;flex-wrap:wrap;gap:var(--kf-space-xs)}.kf-filter-chips__chip{font:inherit;padding:var(--kf-space-xs) var(--kf-space-md);border-radius:var(--kf-radius-pill);border:1px solid var(--kf-color-border);background:var(--kf-color-surface);color:var(--kf-color-text);cursor:pointer;transition:background .14s,border-color .14s,color .14s}.kf-filter-chips__chip:hover:not(.kf-filter-chips__chip--active){border-color:var(--kf-color-border-strong)}.kf-filter-chips__chip:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-filter-chips__chip--active{background:var(--kf-color-ink);border-color:var(--kf-color-ink);color:var(--kf-color-white)}\n"] }]
|
|
3017
3346
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
3018
3347
|
|
|
3348
|
+
/**
|
|
3349
|
+
* Marca el contenido que `kf-folder-tabs` debe proyectar dentro de su
|
|
3350
|
+
* panel. Sin lógica propia — existe solo como token de tipo para que
|
|
3351
|
+
* `contentChild(FolderTabsPanel)` pueda detectar si el consumidor proyectó
|
|
3352
|
+
* algo (mismo mecanismo que `kf-dropdown` usa con `contentChild(DropdownPanel)`;
|
|
3353
|
+
* acá no hace falta un componente completo, alcanza con una directiva de
|
|
3354
|
+
* atributo porque el panel no necesita comportamiento propio, solo marcar
|
|
3355
|
+
* su presencia).
|
|
3356
|
+
*
|
|
3357
|
+
* <div kf-folder-tabs-panel>...</div>
|
|
3358
|
+
*/
|
|
3359
|
+
class FolderTabsPanel {
|
|
3360
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabsPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3361
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: FolderTabsPanel, isStandalone: true, selector: "[kf-folder-tabs-panel]", ngImport: i0 });
|
|
3362
|
+
}
|
|
3363
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabsPanel, decorators: [{
|
|
3364
|
+
type: Directive,
|
|
3365
|
+
args: [{ selector: '[kf-folder-tabs-panel]' }]
|
|
3366
|
+
}] });
|
|
3019
3367
|
/**
|
|
3020
3368
|
* Tabs con forma de "carpeta": el borde superior queda redondeado y el borde
|
|
3021
3369
|
* inferior de la pestaña activa se funde visualmente con el panel de
|
|
@@ -3026,9 +3374,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3026
3374
|
* `--active` se mueve de un botón a otro, y eso vuelve a disparar el keyframe
|
|
3027
3375
|
* sin tocar JS.
|
|
3028
3376
|
*
|
|
3029
|
-
* El
|
|
3030
|
-
*
|
|
3377
|
+
* El panel de contenido es un `<ng-content>` OPCIONAL — si el consumidor no
|
|
3378
|
+
* proyecta nada, `kf-folder-tabs` renderiza solo la fila de pestañas (mismo
|
|
3379
|
+
* comportamiento que antes de que existiera este slot, detectado con
|
|
3380
|
+
* `contentChild()` sin `.required`, igual patrón que usa `kf-dropdown` para
|
|
3381
|
+
* saber si hay un `kf-dropdown-panel` proyectado). Si SÍ proyecta contenido,
|
|
3382
|
+
* se envuelve en un panel con la esquina superior-izquierda recta (nace ahí
|
|
3383
|
+
* la primera pestaña, siempre pegada al borde izquierdo de la fila — un
|
|
3384
|
+
* radio ahí competiría visualmente con el propio borde redondeado de esa
|
|
3385
|
+
* pestaña) y las otras tres redondeadas. El `border-bottom` de 2px de la
|
|
3386
|
+
* pestaña activa (ver `.kf-folder-tabs__tab--active` más abajo) es la señal
|
|
3387
|
+
* visual de conexión con el panel para CUALQUIER pestaña activa, sin
|
|
3388
|
+
* necesitar mover ni medir nada.
|
|
3389
|
+
*
|
|
3390
|
+
* El borde izquierdo de toda la fila (y por lo tanto de la esquina recta
|
|
3391
|
+
* del panel) depende de que ninguna pestaña se corra al cambiar de estado
|
|
3392
|
+
* — ver `transform-origin: bottom left` en `.kf-folder-tabs__tab`: con el
|
|
3393
|
+
* origen centrado (como estaba antes), el `scale()` de la pestaña inactiva
|
|
3394
|
+
* encogía el borde izquierdo unos px, y ese corrimiento sub-pixel es lo que
|
|
3395
|
+
* hacía que este mismo diseño (esquina fija) se viera "roto" cuando la
|
|
3396
|
+
* pestaña activa no era la primera. Con el origen anclado a la izquierda,
|
|
3397
|
+
* el corrimiento desaparece y la esquina fija vuelve a ser una solución
|
|
3398
|
+
* válida y simple — sin necesitar medir la pestaña activa por JS.
|
|
3399
|
+
*
|
|
3400
|
+
* Antes de este slot, el patrón era que el consumidor pusiera su propia
|
|
3401
|
+
* card como HERMANO de `kf-folder-tabs` y anulara a mano el radio superior
|
|
3402
|
+
* completo (`border-top-left-radius: 0`, `border-top-right-radius: 0` — ver
|
|
3403
|
+
* el caso original de `web-portal-latam-frontend`). Encapsular esto acá
|
|
3404
|
+
* evita que cada consumidor repita esas reglas a mano.
|
|
3031
3405
|
*
|
|
3406
|
+
* <kf-folder-tabs [options]="tabs" [value]="active" (valueChange)="active = $event">
|
|
3407
|
+
* <div kf-folder-tabs-panel>contenido de la pestaña activa</div>
|
|
3408
|
+
* </kf-folder-tabs>
|
|
3409
|
+
*
|
|
3410
|
+
* <!-- o, sin contenido, como antes: -->
|
|
3032
3411
|
* <kf-folder-tabs [options]="tabs" [value]="active" (valueChange)="active = $event" />
|
|
3033
3412
|
*/
|
|
3034
3413
|
class FolderTabs {
|
|
@@ -3037,6 +3416,18 @@ class FolderTabs {
|
|
|
3037
3416
|
value = input.required(/* @ts-ignore */
|
|
3038
3417
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
3039
3418
|
valueChange = output();
|
|
3419
|
+
/**
|
|
3420
|
+
* Detecta si el consumidor proyectó contenido marcado con
|
|
3421
|
+
* `kf-folder-tabs-panel` — sin `.required`, así que es `undefined`
|
|
3422
|
+
* cuando no hay nada proyectado (mismo patrón que usa `kf-dropdown` con
|
|
3423
|
+
* `contentChild(DropdownPanel)` para saber si hay un panel que
|
|
3424
|
+
* attachear). `hasPanel()` decide si el wrapper del panel participa del
|
|
3425
|
+
* layout (`display: contents` si no).
|
|
3426
|
+
*/
|
|
3427
|
+
projectedPanel = contentChild(FolderTabsPanel, /* @ts-ignore */
|
|
3428
|
+
...(ngDevMode ? [{ debugName: "projectedPanel" }] : /* istanbul ignore next */ []));
|
|
3429
|
+
hasPanel = computed(() => this.projectedPanel() !== undefined, /* @ts-ignore */
|
|
3430
|
+
...(ngDevMode ? [{ debugName: "hasPanel" }] : /* istanbul ignore next */ []));
|
|
3040
3431
|
select(value) {
|
|
3041
3432
|
if (value === this.value()) {
|
|
3042
3433
|
return;
|
|
@@ -3073,7 +3464,7 @@ class FolderTabs {
|
|
|
3073
3464
|
nextButton?.focus();
|
|
3074
3465
|
}
|
|
3075
3466
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3076
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: FolderTabs, isStandalone: true, selector: "kf-folder-tabs", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
|
|
3467
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: FolderTabs, isStandalone: true, selector: "kf-folder-tabs", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChange: "valueChange" }, queries: [{ propertyName: "projectedPanel", first: true, predicate: FolderTabsPanel, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
3077
3468
|
<div class="kf-folder-tabs" role="tablist">
|
|
3078
3469
|
@for (option of options(); track option.value) {
|
|
3079
3470
|
<button
|
|
@@ -3095,7 +3486,11 @@ class FolderTabs {
|
|
|
3095
3486
|
</button>
|
|
3096
3487
|
}
|
|
3097
3488
|
</div>
|
|
3098
|
-
|
|
3489
|
+
|
|
3490
|
+
<div class="kf-folder-tabs__panel" [class.kf-folder-tabs__panel--empty]="!hasPanel()">
|
|
3491
|
+
<ng-content select="[kf-folder-tabs-panel]" />
|
|
3492
|
+
</div>
|
|
3493
|
+
`, isInline: true, styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-folder-tabs{display:flex;align-items:flex-end;gap:var(--kf-space-xs);perspective:900px}.kf-folder-tabs__tab{position:relative;display:inline-flex;align-items:center;gap:var(--kf-space-xs);font:inherit;font-size:.9rem;color:var(--kf-color-text-muted);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-bottom-color:var(--kf-color-border-strong);border-radius:var(--kf-radius-sm) var(--kf-radius-sm) 0 0;padding:var(--kf-space-sm) var(--kf-space-md);cursor:pointer;transform-origin:bottom left;transform:translateY(5px) scale(.985);transition:background .14s,color .14s,border-color .14s,transform .22s cubic-bezier(.32,.72,0,1)}.kf-folder-tabs__tab:hover:not(.kf-folder-tabs__tab--active){color:var(--kf-color-text);background:var(--kf-color-white);transform:translateY(2px) scale(.99)}.kf-folder-tabs__tab:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus);z-index:1}.kf-folder-tabs__tab--active{z-index:1;color:var(--kf-color-primary);font-weight:700;background:var(--kf-color-white);border-color:var(--kf-color-border);border-bottom:2px solid var(--kf-color-primary);box-shadow:0 -6px 14px -10px #10182866;transform:translateY(1px);animation:kf-folder-tabs-pull .34s cubic-bezier(.22,1.2,.36,1) both}@keyframes kf-folder-tabs-pull{0%{transform:translateY(7px) rotateX(-10deg) scale(.97)}60%{transform:translateY(1px) rotateX(2deg) scale(1.01)}to{transform:translateY(1px) rotateX(0) scale(1)}}@media(prefers-reduced-motion:reduce){.kf-folder-tabs__tab,.kf-folder-tabs__tab--active{animation:none;transition:background .14s,color .14s,border-color .14s}}.kf-folder-tabs__panel--empty{display:contents}.kf-folder-tabs__panel:not(.kf-folder-tabs__panel--empty){background:var(--kf-color-white);border-right:1px solid var(--kf-color-border);border-bottom:1px solid var(--kf-color-border);border-left:1px solid var(--kf-color-border);border-top:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);border-top-left-radius:0;overflow:hidden}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
3099
3494
|
}
|
|
3100
3495
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabs, decorators: [{
|
|
3101
3496
|
type: Component,
|
|
@@ -3121,8 +3516,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3121
3516
|
</button>
|
|
3122
3517
|
}
|
|
3123
3518
|
</div>
|
|
3124
|
-
|
|
3125
|
-
|
|
3519
|
+
|
|
3520
|
+
<div class="kf-folder-tabs__panel" [class.kf-folder-tabs__panel--empty]="!hasPanel()">
|
|
3521
|
+
<ng-content select="[kf-folder-tabs-panel]" />
|
|
3522
|
+
</div>
|
|
3523
|
+
`, styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-folder-tabs{display:flex;align-items:flex-end;gap:var(--kf-space-xs);perspective:900px}.kf-folder-tabs__tab{position:relative;display:inline-flex;align-items:center;gap:var(--kf-space-xs);font:inherit;font-size:.9rem;color:var(--kf-color-text-muted);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-bottom-color:var(--kf-color-border-strong);border-radius:var(--kf-radius-sm) var(--kf-radius-sm) 0 0;padding:var(--kf-space-sm) var(--kf-space-md);cursor:pointer;transform-origin:bottom left;transform:translateY(5px) scale(.985);transition:background .14s,color .14s,border-color .14s,transform .22s cubic-bezier(.32,.72,0,1)}.kf-folder-tabs__tab:hover:not(.kf-folder-tabs__tab--active){color:var(--kf-color-text);background:var(--kf-color-white);transform:translateY(2px) scale(.99)}.kf-folder-tabs__tab:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus);z-index:1}.kf-folder-tabs__tab--active{z-index:1;color:var(--kf-color-primary);font-weight:700;background:var(--kf-color-white);border-color:var(--kf-color-border);border-bottom:2px solid var(--kf-color-primary);box-shadow:0 -6px 14px -10px #10182866;transform:translateY(1px);animation:kf-folder-tabs-pull .34s cubic-bezier(.22,1.2,.36,1) both}@keyframes kf-folder-tabs-pull{0%{transform:translateY(7px) rotateX(-10deg) scale(.97)}60%{transform:translateY(1px) rotateX(2deg) scale(1.01)}to{transform:translateY(1px) rotateX(0) scale(1)}}@media(prefers-reduced-motion:reduce){.kf-folder-tabs__tab,.kf-folder-tabs__tab--active{animation:none;transition:background .14s,color .14s,border-color .14s}}.kf-folder-tabs__panel--empty{display:contents}.kf-folder-tabs__panel:not(.kf-folder-tabs__panel--empty){background:var(--kf-color-white);border-right:1px solid var(--kf-color-border);border-bottom:1px solid var(--kf-color-border);border-left:1px solid var(--kf-color-border);border-top:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);border-top-left-radius:0;overflow:hidden}\n"] }]
|
|
3524
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], projectedPanel: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FolderTabsPanel), { isSignal: true }] }] } });
|
|
3126
3525
|
|
|
3127
3526
|
/**
|
|
3128
3527
|
* Input de formulario apilado: label arriba (en mayúsculas vía CSS), campo con
|
|
@@ -3369,6 +3768,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3369
3768
|
`, styles: [":host{display:flex;flex-direction:column;gap:var(--kf-space-xs);font-family:var(--kf-font-body)}.kf-input__field{display:flex;align-items:center;gap:var(--kf-space-sm);padding:0 var(--kf-space-sm);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);transition:background .14s,border-color .14s,box-shadow .14s}.kf-input__field--focused{background:var(--kf-color-white);border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-input__field--invalid{border-color:var(--kf-color-error)}.kf-input__field--invalid.kf-input__field--focused{box-shadow:0 0 0 3px #eb575738}.kf-input__field--disabled{opacity:.5}.kf-input__icon{color:var(--kf-color-text-muted)}.kf-input__field--invalid .kf-input__icon{color:var(--kf-color-error)}.kf-input__control{flex:1;min-width:0;border:none;outline:none;background:transparent;font:inherit;color:var(--kf-color-text);padding:var(--kf-space-sm) 0}.kf-input__control::placeholder{color:var(--kf-color-text-muted)}.kf-input__control:disabled{cursor:not-allowed}.kf-input__suffix{flex:none;color:var(--kf-color-text-muted);font-size:.875rem}.kf-input__toggle{flex:none;display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;padding:var(--kf-space-xs);margin:0 calc(var(--kf-space-xs) * -1);color:var(--kf-color-text-muted);cursor:pointer;border-radius:var(--kf-radius-xs);transition:color .14s}.kf-input__toggle:hover{color:var(--kf-color-text)}.kf-input__toggle:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-input__hint{font-size:.75rem;color:var(--kf-color-text-muted)}.kf-input__error{display:flex;align-items:center;gap:var(--kf-space-xs);font-size:.75rem;font-weight:600;color:var(--kf-color-error-strong)}\n"] }]
|
|
3370
3769
|
}], propDecorators: { nativeInput: [{ type: i0.ViewChild, args: ['nativeInput', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }] } });
|
|
3371
3770
|
|
|
3771
|
+
/**
|
|
3772
|
+
* Acción de bajo énfasis con apariencia de texto — "¿Olvidaste tu
|
|
3773
|
+
* contraseña?", "Volver a iniciar sesión". Antes de este componente,
|
|
3774
|
+
* `web-portal-latam-frontend` reimplementaba esto dos veces (`.login__forgot`
|
|
3775
|
+
* como `<a href="#">` con `preventDefault()`, `.login__back` como
|
|
3776
|
+
* `<button>`), cada una con su propio `:focus-visible` copiado literal.
|
|
3777
|
+
*
|
|
3778
|
+
* Es siempre un `<button type="button">` por dentro, nunca un `<a>`: ninguno
|
|
3779
|
+
* de los dos casos reales navega a otra URL, ambos disparan una acción en la
|
|
3780
|
+
* misma pantalla (cambiar de vista, someter un flujo). Si en el futuro un
|
|
3781
|
+
* consumidor necesita navegación real con href, esa es una discusión de API
|
|
3782
|
+
* distinta (`kf-link` con `[routerLink]`/`href`), no se fuerza acá sin caso
|
|
3783
|
+
* de uso confirmado.
|
|
3784
|
+
*
|
|
3785
|
+
* `variant="default"` (color primario, subrayado en hover) es para la
|
|
3786
|
+
* acción de mayor jerarquía relativa de la pantalla (ej. "¿Olvidaste tu
|
|
3787
|
+
* contraseña?"); `variant="muted"` (gris que pasa a primario en hover) es
|
|
3788
|
+
* para acciones de retroceso/salida (ej. "← Volver a iniciar sesión").
|
|
3789
|
+
*
|
|
3790
|
+
* <kf-link (click)="onForgotPassword()">¿Olvidaste tu contraseña?</kf-link>
|
|
3791
|
+
* <kf-link variant="muted" (click)="onBack()">← Volver a iniciar sesión</kf-link>
|
|
3792
|
+
*/
|
|
3793
|
+
class Link {
|
|
3794
|
+
variant = input('default', /* @ts-ignore */
|
|
3795
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
3796
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3797
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Link, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3798
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: Link, isStandalone: true, selector: "kf-link", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
3799
|
+
<button
|
|
3800
|
+
type="button"
|
|
3801
|
+
class="kf-link"
|
|
3802
|
+
[class.kf-link--muted]="variant() === 'muted'"
|
|
3803
|
+
[disabled]="disabled()"
|
|
3804
|
+
>
|
|
3805
|
+
<ng-content />
|
|
3806
|
+
</button>
|
|
3807
|
+
`, isInline: true, styles: [":host{display:inline-block}.kf-link{padding:0;border:none;background:transparent;font:inherit;font-weight:500;color:var(--kf-color-primary);text-decoration:none;cursor:pointer}.kf-link:hover:not(:disabled){text-decoration:underline}.kf-link:focus-visible{outline:2px solid var(--kf-color-primary);outline-offset:2px;border-radius:var(--kf-radius-xs)}.kf-link:disabled{opacity:.5;cursor:not-allowed}.kf-link--muted{color:var(--kf-color-text-muted)}.kf-link--muted:hover:not(:disabled){color:var(--kf-color-primary);text-decoration:none}\n"] });
|
|
3808
|
+
}
|
|
3809
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Link, decorators: [{
|
|
3810
|
+
type: Component,
|
|
3811
|
+
args: [{ selector: 'kf-link', template: `
|
|
3812
|
+
<button
|
|
3813
|
+
type="button"
|
|
3814
|
+
class="kf-link"
|
|
3815
|
+
[class.kf-link--muted]="variant() === 'muted'"
|
|
3816
|
+
[disabled]="disabled()"
|
|
3817
|
+
>
|
|
3818
|
+
<ng-content />
|
|
3819
|
+
</button>
|
|
3820
|
+
`, styles: [":host{display:inline-block}.kf-link{padding:0;border:none;background:transparent;font:inherit;font-weight:500;color:var(--kf-color-primary);text-decoration:none;cursor:pointer}.kf-link:hover:not(:disabled){text-decoration:underline}.kf-link:focus-visible{outline:2px solid var(--kf-color-primary);outline-offset:2px;border-radius:var(--kf-radius-xs)}.kf-link:disabled{opacity:.5;cursor:not-allowed}.kf-link--muted{color:var(--kf-color-text-muted)}.kf-link--muted:hover:not(:disabled){color:var(--kf-color-primary);text-decoration:none}\n"] }]
|
|
3821
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
3822
|
+
|
|
3372
3823
|
/**
|
|
3373
3824
|
* Card de estadística/KPI: label, valor grande, ícono opcional en la esquina
|
|
3374
3825
|
* superior derecha, badge de esquina opcional (pegado al valor) y una nota
|
|
@@ -3620,7 +4071,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3620
4071
|
args: ['click', ['$event']]
|
|
3621
4072
|
}] } });
|
|
3622
4073
|
|
|
3623
|
-
let nextId
|
|
4074
|
+
let nextId = 0;
|
|
3624
4075
|
/**
|
|
3625
4076
|
* Dropdown de selección múltiple con checkboxes internos, siguiendo el mismo
|
|
3626
4077
|
* patrón de panel flotante que `SelectMenu` (panel con `position: absolute`
|
|
@@ -3657,7 +4108,7 @@ class MultiSelect {
|
|
|
3657
4108
|
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
3658
4109
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3659
4110
|
valuesChange = output();
|
|
3660
|
-
instanceId = `kf-multi-select-${nextId
|
|
4111
|
+
instanceId = `kf-multi-select-${nextId++}`;
|
|
3661
4112
|
triggerId = `${this.instanceId}-trigger`;
|
|
3662
4113
|
listboxId = `${this.instanceId}-listbox`;
|
|
3663
4114
|
isOpen = signal(false, /* @ts-ignore */
|
|
@@ -3793,7 +4244,7 @@ class MultiSelect {
|
|
|
3793
4244
|
}
|
|
3794
4245
|
</ul>
|
|
3795
4246
|
}
|
|
3796
|
-
`, isInline: true, styles: [":host{display:inline-flex;flex-direction:column;gap:var(--kf-space-xs);position:relative;font:inherit;
|
|
4247
|
+
`, isInline: true, styles: [":host{display:inline-flex;flex-direction:column;gap:var(--kf-space-xs);position:relative;font:inherit;width:240px}.kf-multi-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-sm);width:100%;font:inherit;font-family:var(--kf-font-body);padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);cursor:pointer;transition:border-color .14s,box-shadow .14s}.kf-multi-select__trigger:hover:not(:disabled){border-color:var(--kf-color-border-strong)}.kf-multi-select__trigger:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-multi-select__trigger:disabled{opacity:.5;cursor:not-allowed}.kf-multi-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;text-align:left}.kf-multi-select__value--placeholder{color:var(--kf-color-text-muted)}.kf-multi-select__count{flex:none;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 5px;border-radius:var(--kf-radius-pill);background:var(--kf-color-primary);color:var(--kf-color-white);font-size:.72rem;font-weight:700}.kf-multi-select__caret{flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--kf-color-text-muted);border-bottom:2px solid var(--kf-color-text-muted);transform:rotate(45deg);transition:transform .14s;margin-top:-4px}.kf-multi-select__caret--open{transform:rotate(-135deg);margin-top:4px}.kf-multi-select__panel{position:absolute;top:100%;left:0;right:0;z-index:10;margin:var(--kf-space-xs) 0 0;padding:var(--kf-space-xs) 0;list-style:none;max-height:240px;overflow-y:auto;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-md)}.kf-multi-select__option{display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-multi-select__option:hover{background:var(--kf-color-primary-soft)}.kf-multi-select__option--selected{color:var(--kf-color-primary);font-weight:600}.kf-multi-select__checkbox{display:inline-flex;flex-shrink:0;width:var(--kf-space-md);height:var(--kf-space-md);border:1px solid var(--kf-color-border-strong);border-radius:var(--kf-radius-xs);background:var(--kf-color-white);transition:background .14s,border-color .14s;position:relative}.kf-multi-select__checkbox--checked{background:var(--kf-color-primary);border-color:var(--kf-color-primary)}.kf-multi-select__checkbox--checked:after{content:\"\";position:absolute;left:4px;top:1px;width:4px;height:8px;border:solid var(--kf-color-white);border-width:0 2px 2px 0;transform:rotate(45deg)}.kf-multi-select__checkbox--indeterminate{background:var(--kf-color-primary);border-color:var(--kf-color-primary)}.kf-multi-select__checkbox--indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--kf-color-white);border:none;transform:none}.kf-multi-select__option-label{overflow:hidden;text-overflow:ellipsis}.kf-multi-select__empty{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text-muted)}\n"], dependencies: [{ kind: "component", type: FieldLabel, selector: "kf-field-label", inputs: ["for", "required"] }] });
|
|
3797
4248
|
}
|
|
3798
4249
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: MultiSelect, decorators: [{
|
|
3799
4250
|
type: Component,
|
|
@@ -3875,7 +4326,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3875
4326
|
}
|
|
3876
4327
|
</ul>
|
|
3877
4328
|
}
|
|
3878
|
-
`, styles: [":host{display:inline-flex;flex-direction:column;gap:var(--kf-space-xs);position:relative;font:inherit;
|
|
4329
|
+
`, styles: [":host{display:inline-flex;flex-direction:column;gap:var(--kf-space-xs);position:relative;font:inherit;width:240px}.kf-multi-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-sm);width:100%;font:inherit;font-family:var(--kf-font-body);padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);cursor:pointer;transition:border-color .14s,box-shadow .14s}.kf-multi-select__trigger:hover:not(:disabled){border-color:var(--kf-color-border-strong)}.kf-multi-select__trigger:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-multi-select__trigger:disabled{opacity:.5;cursor:not-allowed}.kf-multi-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;text-align:left}.kf-multi-select__value--placeholder{color:var(--kf-color-text-muted)}.kf-multi-select__count{flex:none;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 5px;border-radius:var(--kf-radius-pill);background:var(--kf-color-primary);color:var(--kf-color-white);font-size:.72rem;font-weight:700}.kf-multi-select__caret{flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--kf-color-text-muted);border-bottom:2px solid var(--kf-color-text-muted);transform:rotate(45deg);transition:transform .14s;margin-top:-4px}.kf-multi-select__caret--open{transform:rotate(-135deg);margin-top:4px}.kf-multi-select__panel{position:absolute;top:100%;left:0;right:0;z-index:10;margin:var(--kf-space-xs) 0 0;padding:var(--kf-space-xs) 0;list-style:none;max-height:240px;overflow-y:auto;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-md)}.kf-multi-select__option{display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-multi-select__option:hover{background:var(--kf-color-primary-soft)}.kf-multi-select__option--selected{color:var(--kf-color-primary);font-weight:600}.kf-multi-select__checkbox{display:inline-flex;flex-shrink:0;width:var(--kf-space-md);height:var(--kf-space-md);border:1px solid var(--kf-color-border-strong);border-radius:var(--kf-radius-xs);background:var(--kf-color-white);transition:background .14s,border-color .14s;position:relative}.kf-multi-select__checkbox--checked{background:var(--kf-color-primary);border-color:var(--kf-color-primary)}.kf-multi-select__checkbox--checked:after{content:\"\";position:absolute;left:4px;top:1px;width:4px;height:8px;border:solid var(--kf-color-white);border-width:0 2px 2px 0;transform:rotate(45deg)}.kf-multi-select__checkbox--indeterminate{background:var(--kf-color-primary);border-color:var(--kf-color-primary)}.kf-multi-select__checkbox--indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--kf-color-white);border:none;transform:none}.kf-multi-select__option-label{overflow:hidden;text-overflow:ellipsis}.kf-multi-select__empty{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text-muted)}\n"] }]
|
|
3879
4330
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], values: [{ type: i0.Input, args: [{ isSignal: true, alias: "values", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valuesChange: [{ type: i0.Output, args: ["valuesChange"] }], onDocumentClick: [{
|
|
3880
4331
|
type: HostListener,
|
|
3881
4332
|
args: ['document:click', ['$event']]
|
|
@@ -4171,12 +4622,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4171
4622
|
* Es distinto de `kf-page-header`/`kf-page-head` (título de una vista
|
|
4172
4623
|
* interna) — este es el chrome global del portal, se monta una sola vez.
|
|
4173
4624
|
*
|
|
4625
|
+
* `:host` es `position: sticky; top: 0` — el header queda pegado arriba al
|
|
4626
|
+
* hacer scroll. No es `fixed`: como no se superpone al contenido en el
|
|
4627
|
+
* primer render, no hace falta que el consumidor compense con
|
|
4628
|
+
* `padding-top`.
|
|
4629
|
+
*
|
|
4630
|
+
* Bajo los 768px, el `<nav>` deja de mostrarse en línea junto al logo y
|
|
4631
|
+
* colapsa detrás de un botón de menú (ícono `menu`/`x`) que despliega un
|
|
4632
|
+
* drawer lateral (desde el borde derecho, `position: fixed` + overlay de
|
|
4633
|
+
* fondo) con los mismos `navItems` en columna. Ese drawer expone un slot
|
|
4634
|
+
* (`<ng-content select="[kf-portal-header-extra]">`) al final, pensado
|
|
4635
|
+
* para que el consumidor proyecte contenido propio que en escritorio vive
|
|
4636
|
+
* en otro lugar (ej. el menú de sesión) — `PortalHeader` no sabe qué es
|
|
4637
|
+
* ese contenido ni cómo se abre, solo le da un lugar dentro del drawer ya
|
|
4638
|
+
* desplegado. El overlay cierra el drawer al tocarlo, y `Escape` también.
|
|
4639
|
+
*
|
|
4174
4640
|
* <kf-portal-header
|
|
4175
4641
|
* [isAdmin]="true"
|
|
4176
4642
|
* [adminActions]="[{ label: 'Consultar deuda clientes', href: '/deuda' }, { label: 'Cambiar DNI', href: '/dni' }]"
|
|
4177
4643
|
* [navItems]="[{ label: 'Home', href: '/', active: true }, { label: 'Vehículos', href: '/vehiculos' }]"
|
|
4178
4644
|
* userInitials="TS"
|
|
4179
|
-
*
|
|
4645
|
+
* >
|
|
4646
|
+
* <div kf-portal-header-extra>contenido propio, solo visible en el panel mobile</div>
|
|
4647
|
+
* </kf-portal-header>
|
|
4180
4648
|
*/
|
|
4181
4649
|
class PortalHeader {
|
|
4182
4650
|
brand = input('DIVEMOTOR', /* @ts-ignore */
|
|
@@ -4189,8 +4657,26 @@ class PortalHeader {
|
|
|
4189
4657
|
userInitials = input.required(/* @ts-ignore */
|
|
4190
4658
|
...(ngDevMode ? [{ debugName: "userInitials" }] : /* istanbul ignore next */ []));
|
|
4191
4659
|
sessionClick = output();
|
|
4660
|
+
/** Visibilidad del drawer de navegación mobile (bajo los 768px). */
|
|
4661
|
+
mobileMenuOpen = signal(false, /* @ts-ignore */
|
|
4662
|
+
...(ngDevMode ? [{ debugName: "mobileMenuOpen" }] : /* istanbul ignore next */ []));
|
|
4663
|
+
/** Cierra el drawer con Escape — mismo patrón que cualquier drawer/modal. */
|
|
4664
|
+
onEscape() {
|
|
4665
|
+
this.mobileMenuOpen.set(false);
|
|
4666
|
+
}
|
|
4667
|
+
/**
|
|
4668
|
+
* `ElementRef` real del botón de sesión (el avatar en la esquina
|
|
4669
|
+
* derecha), no de todo el header. Pensado para anclar un `kf-dropdown`
|
|
4670
|
+
* externo — sin esto, el único `ElementRef` disponible desde afuera es el
|
|
4671
|
+
* del host de `PortalHeader`, que ocupa el ancho completo de la pantalla
|
|
4672
|
+
* (logo + nav + sesión), y el overlay del CDK termina "pegado" a la
|
|
4673
|
+
* esquina del header entero en vez de al botón que el usuario clickeó.
|
|
4674
|
+
*
|
|
4675
|
+
* <kf-dropdown [(open)]="menuOpen" [anchor]="header().sessionButtonRef()">
|
|
4676
|
+
*/
|
|
4677
|
+
sessionButtonRef = viewChild.required('sessionButton', { ...(ngDevMode ? { debugName: "sessionButtonRef" } : /* istanbul ignore next */ {}), read: ElementRef });
|
|
4192
4678
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PortalHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4193
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: PortalHeader, isStandalone: true, selector: "kf-portal-header", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: true, isRequired: false, transformFunction: null }, adminActions: { classPropertyName: "adminActions", publicName: "adminActions", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, userInitials: { classPropertyName: "userInitials", publicName: "userInitials", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { sessionClick: "sessionClick" }, ngImport: i0, template: `
|
|
4679
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: PortalHeader, isStandalone: true, selector: "kf-portal-header", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: true, isRequired: false, transformFunction: null }, adminActions: { classPropertyName: "adminActions", publicName: "adminActions", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, userInitials: { classPropertyName: "userInitials", publicName: "userInitials", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { sessionClick: "sessionClick" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "sessionButtonRef", first: true, predicate: ["sessionButton"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: `
|
|
4194
4680
|
@if (isAdmin()) {
|
|
4195
4681
|
<div class="kf-portal-header__admin-bar">
|
|
4196
4682
|
<kf-admin-badge inline />
|
|
@@ -4203,6 +4689,7 @@ class PortalHeader {
|
|
|
4203
4689
|
}
|
|
4204
4690
|
<div class="kf-portal-header__brand-bar">
|
|
4205
4691
|
<span class="kf-portal-header__logo">{{ brand() }}</span>
|
|
4692
|
+
|
|
4206
4693
|
<nav class="kf-portal-header__nav">
|
|
4207
4694
|
@for (item of navItems(); track item.label) {
|
|
4208
4695
|
<a
|
|
@@ -4214,15 +4701,54 @@ class PortalHeader {
|
|
|
4214
4701
|
</a>
|
|
4215
4702
|
}
|
|
4216
4703
|
</nav>
|
|
4217
|
-
|
|
4704
|
+
|
|
4705
|
+
<button
|
|
4706
|
+
#sessionButton
|
|
4707
|
+
type="button"
|
|
4708
|
+
class="kf-portal-header__session"
|
|
4709
|
+
(click)="sessionClick.emit()"
|
|
4710
|
+
>
|
|
4218
4711
|
<kf-avatar [initials]="userInitials()" pill />
|
|
4219
4712
|
</button>
|
|
4713
|
+
|
|
4714
|
+
<button
|
|
4715
|
+
type="button"
|
|
4716
|
+
class="kf-portal-header__menu-toggle"
|
|
4717
|
+
[attr.aria-expanded]="mobileMenuOpen()"
|
|
4718
|
+
aria-label="Abrir menú de navegación"
|
|
4719
|
+
(click)="mobileMenuOpen.set(!mobileMenuOpen())"
|
|
4720
|
+
>
|
|
4721
|
+
<kf-icon [name]="mobileMenuOpen() ? 'x' : 'menu'" size="md" />
|
|
4722
|
+
</button>
|
|
4220
4723
|
</div>
|
|
4221
|
-
|
|
4724
|
+
|
|
4725
|
+
@if (mobileMenuOpen()) {
|
|
4726
|
+
<div class="kf-portal-header__overlay" (click)="mobileMenuOpen.set(false)"></div>
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4729
|
+
<nav
|
|
4730
|
+
class="kf-portal-header__drawer"
|
|
4731
|
+
[class.kf-portal-header__drawer--open]="mobileMenuOpen()"
|
|
4732
|
+
role="menu"
|
|
4733
|
+
[attr.aria-hidden]="!mobileMenuOpen()"
|
|
4734
|
+
>
|
|
4735
|
+
@for (item of navItems(); track item.label) {
|
|
4736
|
+
<a
|
|
4737
|
+
class="kf-portal-header__mobile-nav-item"
|
|
4738
|
+
[class.kf-portal-header__mobile-nav-item--active]="item.active"
|
|
4739
|
+
[href]="item.href"
|
|
4740
|
+
(click)="mobileMenuOpen.set(false)"
|
|
4741
|
+
>
|
|
4742
|
+
{{ item.label }}
|
|
4743
|
+
</a>
|
|
4744
|
+
}
|
|
4745
|
+
<ng-content select="[kf-portal-header-extra]" />
|
|
4746
|
+
</nav>
|
|
4747
|
+
`, isInline: true, styles: [":host{display:block;position:sticky;top:0;z-index:30;font-family:var(--kf-font-body)}.kf-portal-header__admin-bar{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-md);padding:var(--kf-space-xs) var(--kf-space-lg);background:var(--kf-color-tertiary-deep)}.kf-portal-header__admin-actions{display:flex;gap:var(--kf-space-md)}.kf-portal-header__admin-action{font-size:.8125rem;font-weight:600;color:#ffffffd9;text-decoration:none}.kf-portal-header__admin-action:hover{color:var(--kf-color-white)}.kf-portal-header__brand-bar{display:flex;align-items:center;gap:var(--kf-space-lg);padding:var(--kf-space-sm) var(--kf-space-lg);background:var(--kf-color-tertiary-deep);border-top:1px solid rgba(255,255,255,.1)}.kf-portal-header__logo{font-family:var(--kf-font-title);font-size:1.25rem;font-weight:700;letter-spacing:.02em;color:var(--kf-color-white);text-transform:uppercase;flex:1 1 auto;min-width:0}.kf-portal-header__nav{display:flex;align-items:center;gap:var(--kf-space-xs);flex:1 1 auto}.kf-portal-header__nav-item{padding:var(--kf-space-xs) var(--kf-space-md);border-radius:var(--kf-radius-sm);color:#ffffffbf;font-size:.875rem;font-weight:600;text-decoration:none;white-space:nowrap;transition:background .14s,color .14s}.kf-portal-header__nav-item:hover:not(.kf-portal-header__nav-item--active){color:var(--kf-color-white)}.kf-portal-header__nav-item--active{background:var(--kf-color-white);color:var(--kf-color-ink)}.kf-portal-header__session{flex:none;border:none;background:transparent;padding:0;cursor:pointer}.kf-portal-header__menu-toggle{display:none;flex:none;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:var(--kf-radius-sm);background:transparent;color:var(--kf-color-white);cursor:pointer}.kf-portal-header__menu-toggle:hover{background:#ffffff1a}.kf-portal-header__overlay{position:fixed;inset:0;background:#10182866;z-index:39}.kf-portal-header__drawer{position:fixed;top:0;right:0;bottom:0;z-index:40;display:none;flex-direction:column;width:min(80vw,320px);padding:var(--kf-space-lg);background:var(--kf-color-tertiary-deep);box-shadow:-8px 0 24px -8px #1018284d;transform:translate(100%);visibility:hidden;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear .24s}.kf-portal-header__drawer--open{transform:translate(0);visibility:visible;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear 0s}.kf-portal-header__mobile-nav-item{padding:var(--kf-space-sm) var(--kf-space-xs);color:#ffffffd9;font-size:.9375rem;font-weight:600;text-decoration:none;border-radius:var(--kf-radius-sm)}.kf-portal-header__mobile-nav-item:hover{background:#ffffff14}.kf-portal-header__mobile-nav-item--active{color:var(--kf-color-white);background:#ffffff24}@media(max-width:768px){.kf-portal-header__nav,.kf-portal-header__session{display:none}.kf-portal-header__menu-toggle{display:inline-flex}.kf-portal-header__drawer{display:flex}}\n"], dependencies: [{ kind: "component", type: AdminBadge, selector: "kf-admin-badge", inputs: ["inline"] }, { kind: "component", type: Avatar, selector: "kf-avatar", inputs: ["initials", "src", "round", "pill"] }, { kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
4222
4748
|
}
|
|
4223
4749
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PortalHeader, decorators: [{
|
|
4224
4750
|
type: Component,
|
|
4225
|
-
args: [{ selector: 'kf-portal-header', imports: [AdminBadge, Avatar], template: `
|
|
4751
|
+
args: [{ selector: 'kf-portal-header', imports: [AdminBadge, Avatar, Icon], template: `
|
|
4226
4752
|
@if (isAdmin()) {
|
|
4227
4753
|
<div class="kf-portal-header__admin-bar">
|
|
4228
4754
|
<kf-admin-badge inline />
|
|
@@ -4235,6 +4761,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4235
4761
|
}
|
|
4236
4762
|
<div class="kf-portal-header__brand-bar">
|
|
4237
4763
|
<span class="kf-portal-header__logo">{{ brand() }}</span>
|
|
4764
|
+
|
|
4238
4765
|
<nav class="kf-portal-header__nav">
|
|
4239
4766
|
@for (item of navItems(); track item.label) {
|
|
4240
4767
|
<a
|
|
@@ -4246,12 +4773,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4246
4773
|
</a>
|
|
4247
4774
|
}
|
|
4248
4775
|
</nav>
|
|
4249
|
-
|
|
4776
|
+
|
|
4777
|
+
<button
|
|
4778
|
+
#sessionButton
|
|
4779
|
+
type="button"
|
|
4780
|
+
class="kf-portal-header__session"
|
|
4781
|
+
(click)="sessionClick.emit()"
|
|
4782
|
+
>
|
|
4250
4783
|
<kf-avatar [initials]="userInitials()" pill />
|
|
4251
4784
|
</button>
|
|
4785
|
+
|
|
4786
|
+
<button
|
|
4787
|
+
type="button"
|
|
4788
|
+
class="kf-portal-header__menu-toggle"
|
|
4789
|
+
[attr.aria-expanded]="mobileMenuOpen()"
|
|
4790
|
+
aria-label="Abrir menú de navegación"
|
|
4791
|
+
(click)="mobileMenuOpen.set(!mobileMenuOpen())"
|
|
4792
|
+
>
|
|
4793
|
+
<kf-icon [name]="mobileMenuOpen() ? 'x' : 'menu'" size="md" />
|
|
4794
|
+
</button>
|
|
4252
4795
|
</div>
|
|
4253
|
-
|
|
4254
|
-
|
|
4796
|
+
|
|
4797
|
+
@if (mobileMenuOpen()) {
|
|
4798
|
+
<div class="kf-portal-header__overlay" (click)="mobileMenuOpen.set(false)"></div>
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
<nav
|
|
4802
|
+
class="kf-portal-header__drawer"
|
|
4803
|
+
[class.kf-portal-header__drawer--open]="mobileMenuOpen()"
|
|
4804
|
+
role="menu"
|
|
4805
|
+
[attr.aria-hidden]="!mobileMenuOpen()"
|
|
4806
|
+
>
|
|
4807
|
+
@for (item of navItems(); track item.label) {
|
|
4808
|
+
<a
|
|
4809
|
+
class="kf-portal-header__mobile-nav-item"
|
|
4810
|
+
[class.kf-portal-header__mobile-nav-item--active]="item.active"
|
|
4811
|
+
[href]="item.href"
|
|
4812
|
+
(click)="mobileMenuOpen.set(false)"
|
|
4813
|
+
>
|
|
4814
|
+
{{ item.label }}
|
|
4815
|
+
</a>
|
|
4816
|
+
}
|
|
4817
|
+
<ng-content select="[kf-portal-header-extra]" />
|
|
4818
|
+
</nav>
|
|
4819
|
+
`, styles: [":host{display:block;position:sticky;top:0;z-index:30;font-family:var(--kf-font-body)}.kf-portal-header__admin-bar{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-md);padding:var(--kf-space-xs) var(--kf-space-lg);background:var(--kf-color-tertiary-deep)}.kf-portal-header__admin-actions{display:flex;gap:var(--kf-space-md)}.kf-portal-header__admin-action{font-size:.8125rem;font-weight:600;color:#ffffffd9;text-decoration:none}.kf-portal-header__admin-action:hover{color:var(--kf-color-white)}.kf-portal-header__brand-bar{display:flex;align-items:center;gap:var(--kf-space-lg);padding:var(--kf-space-sm) var(--kf-space-lg);background:var(--kf-color-tertiary-deep);border-top:1px solid rgba(255,255,255,.1)}.kf-portal-header__logo{font-family:var(--kf-font-title);font-size:1.25rem;font-weight:700;letter-spacing:.02em;color:var(--kf-color-white);text-transform:uppercase;flex:1 1 auto;min-width:0}.kf-portal-header__nav{display:flex;align-items:center;gap:var(--kf-space-xs);flex:1 1 auto}.kf-portal-header__nav-item{padding:var(--kf-space-xs) var(--kf-space-md);border-radius:var(--kf-radius-sm);color:#ffffffbf;font-size:.875rem;font-weight:600;text-decoration:none;white-space:nowrap;transition:background .14s,color .14s}.kf-portal-header__nav-item:hover:not(.kf-portal-header__nav-item--active){color:var(--kf-color-white)}.kf-portal-header__nav-item--active{background:var(--kf-color-white);color:var(--kf-color-ink)}.kf-portal-header__session{flex:none;border:none;background:transparent;padding:0;cursor:pointer}.kf-portal-header__menu-toggle{display:none;flex:none;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:var(--kf-radius-sm);background:transparent;color:var(--kf-color-white);cursor:pointer}.kf-portal-header__menu-toggle:hover{background:#ffffff1a}.kf-portal-header__overlay{position:fixed;inset:0;background:#10182866;z-index:39}.kf-portal-header__drawer{position:fixed;top:0;right:0;bottom:0;z-index:40;display:none;flex-direction:column;width:min(80vw,320px);padding:var(--kf-space-lg);background:var(--kf-color-tertiary-deep);box-shadow:-8px 0 24px -8px #1018284d;transform:translate(100%);visibility:hidden;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear .24s}.kf-portal-header__drawer--open{transform:translate(0);visibility:visible;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear 0s}.kf-portal-header__mobile-nav-item{padding:var(--kf-space-sm) var(--kf-space-xs);color:#ffffffd9;font-size:.9375rem;font-weight:600;text-decoration:none;border-radius:var(--kf-radius-sm)}.kf-portal-header__mobile-nav-item:hover{background:#ffffff14}.kf-portal-header__mobile-nav-item--active{color:var(--kf-color-white);background:#ffffff24}@media(max-width:768px){.kf-portal-header__nav,.kf-portal-header__session{display:none}.kf-portal-header__menu-toggle{display:inline-flex}.kf-portal-header__drawer{display:flex}}\n"] }]
|
|
4820
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: false }] }], isAdmin: [{ type: i0.Input, args: [{ isSignal: true, alias: "isAdmin", required: false }] }], adminActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminActions", required: false }] }], navItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navItems", required: false }] }], userInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "userInitials", required: true }] }], sessionClick: [{ type: i0.Output, args: ["sessionClick"] }], onEscape: [{
|
|
4821
|
+
type: HostListener,
|
|
4822
|
+
args: ['document:keydown.escape']
|
|
4823
|
+
}], sessionButtonRef: [{ type: i0.ViewChild, args: ['sessionButton', { ...{ read: ElementRef }, isSignal: true }] }] } });
|
|
4255
4824
|
|
|
4256
4825
|
/**
|
|
4257
4826
|
* Estado vacío de reservas en taller con llamada a agendar (página 36):
|
|
@@ -4347,10 +4916,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4347
4916
|
* `<ng-content select="[actions]">` para no acoplar el componente a un set
|
|
4348
4917
|
* fijo de botones.
|
|
4349
4918
|
*
|
|
4350
|
-
* `size
|
|
4351
|
-
*
|
|
4352
|
-
*
|
|
4353
|
-
*
|
|
4919
|
+
* `size` sigue la misma escala `'sm'|'md'|'lg'` que `Button`/`Icon`/`Spinner`
|
|
4920
|
+
* (`md` es el default): `sm` reduce tipografía y espaciado para usarse
|
|
4921
|
+
* dentro de cards ya compactas, `lg` los agranda para encabezar un bloque
|
|
4922
|
+
* más prominente. Antes de la `0.2.0`, `size` solo aceptaba `'sm'` —
|
|
4923
|
+
* placeholder incompleto de esta misma escala; los valores de `lg` son una
|
|
4924
|
+
* extrapolación proporcional de la escala existente (sin un caso de uso
|
|
4925
|
+
* real todavía que los valide, a diferencia de `sm`, que sí viene de un
|
|
4926
|
+
* patrón real de uso dentro de cards). `solid` rellena el chip de ícono con
|
|
4927
|
+
* el color primario sólido en vez del tratamiento "soft" (fondo tenue) —
|
|
4928
|
+
* pensado para superficies que ya tienen un tinte de color propio, donde el
|
|
4929
|
+
* chip "soft" perdería contraste.
|
|
4354
4930
|
*
|
|
4355
4931
|
* <kf-section-header icon="settings" title="Preferencias"
|
|
4356
4932
|
* subtitle="Configuración general de la cuenta">
|
|
@@ -4358,6 +4934,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4358
4934
|
* </kf-section-header>
|
|
4359
4935
|
*
|
|
4360
4936
|
* <kf-section-header title="Detalle" size="sm" [solid]="true" />
|
|
4937
|
+
* <kf-section-header title="Resumen de flota" size="lg" />
|
|
4361
4938
|
*/
|
|
4362
4939
|
class SectionHeader {
|
|
4363
4940
|
icon = input(/* @ts-ignore */
|
|
@@ -4366,14 +4943,24 @@ class SectionHeader {
|
|
|
4366
4943
|
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
4367
4944
|
subtitle = input(/* @ts-ignore */
|
|
4368
4945
|
...(ngDevMode ? [undefined, { debugName: "subtitle" }] : /* istanbul ignore next */ []));
|
|
4369
|
-
size = input(/* @ts-ignore */
|
|
4370
|
-
...(ngDevMode ? [
|
|
4946
|
+
size = input('md', /* @ts-ignore */
|
|
4947
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
4371
4948
|
solid = input(false, { ...(ngDevMode ? { debugName: "solid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4949
|
+
iconSize = computed(() => {
|
|
4950
|
+
if (this.size() === 'sm') {
|
|
4951
|
+
return 'sm';
|
|
4952
|
+
}
|
|
4953
|
+
if (this.size() === 'lg') {
|
|
4954
|
+
return 'lg';
|
|
4955
|
+
}
|
|
4956
|
+
return 'md';
|
|
4957
|
+
}, /* @ts-ignore */
|
|
4958
|
+
...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
|
|
4372
4959
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SectionHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4373
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: SectionHeader, isStandalone: true, selector: "kf-section-header", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, solid: { classPropertyName: "solid", publicName: "solid", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.kf-section-header--sm": "size() === 'sm'" } }, ngImport: i0, template: `
|
|
4960
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: SectionHeader, isStandalone: true, selector: "kf-section-header", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, solid: { classPropertyName: "solid", publicName: "solid", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.kf-section-header--sm": "size() === 'sm'", "class.kf-section-header--lg": "size() === 'lg'" } }, ngImport: i0, template: `
|
|
4374
4961
|
@if (icon(); as iconName) {
|
|
4375
4962
|
<span class="kf-section-header__icon" [class.kf-section-header__icon--solid]="solid()">
|
|
4376
|
-
<kf-icon [name]="iconName" [size]="
|
|
4963
|
+
<kf-icon [name]="iconName" [size]="iconSize()" />
|
|
4377
4964
|
</span>
|
|
4378
4965
|
}
|
|
4379
4966
|
|
|
@@ -4387,14 +4974,14 @@ class SectionHeader {
|
|
|
4387
4974
|
<span class="kf-section-header__actions">
|
|
4388
4975
|
<ng-content select="[actions]" />
|
|
4389
4976
|
</span>
|
|
4390
|
-
`, isInline: true, styles: [":host{display:flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}:host(.kf-section-header--sm){gap:var(--kf-space-xs)}.kf-section-header__icon{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:2.5rem;block-size:2.5rem;border-radius:var(--kf-radius-sm);background:var(--kf-color-primary-soft);color:var(--kf-color-primary)}:host(.kf-section-header--sm) .kf-section-header__icon{inline-size:1.75rem;block-size:1.75rem;border-radius:var(--kf-radius-xs)}.kf-section-header__icon--solid{background:var(--kf-color-primary);color:var(--kf-color-white)}.kf-section-header__text{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}.kf-section-header__title{font-family:var(--kf-font-title);font-size:1rem;font-weight:700;color:var(--kf-color-ink);line-height:1.3}:host(.kf-section-header--sm) .kf-section-header__title{font-size:.875rem}.kf-section-header__subtitle{font-size:.8125rem;color:var(--kf-color-text-muted);line-height:1.3}:host(.kf-section-header--sm) .kf-section-header__subtitle{font-size:.75rem}.kf-section-header__actions{flex:none;display:flex;align-items:center;gap:var(--kf-space-sm)}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
4977
|
+
`, isInline: true, styles: [":host{display:flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}:host(.kf-section-header--sm){gap:var(--kf-space-xs)}:host(.kf-section-header--lg){gap:var(--kf-space-md)}.kf-section-header__icon{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:2.5rem;block-size:2.5rem;border-radius:var(--kf-radius-sm);background:var(--kf-color-primary-soft);color:var(--kf-color-primary)}:host(.kf-section-header--sm) .kf-section-header__icon{inline-size:1.75rem;block-size:1.75rem;border-radius:var(--kf-radius-xs)}:host(.kf-section-header--lg) .kf-section-header__icon{inline-size:3.25rem;block-size:3.25rem;border-radius:var(--kf-radius-md)}.kf-section-header__icon--solid{background:var(--kf-color-primary);color:var(--kf-color-white)}.kf-section-header__text{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}.kf-section-header__title{font-family:var(--kf-font-title);font-size:1rem;font-weight:700;color:var(--kf-color-ink);line-height:1.3}:host(.kf-section-header--sm) .kf-section-header__title{font-size:.875rem}:host(.kf-section-header--lg) .kf-section-header__title{font-size:1.25rem}.kf-section-header__subtitle{font-size:.8125rem;color:var(--kf-color-text-muted);line-height:1.3}:host(.kf-section-header--sm) .kf-section-header__subtitle{font-size:.75rem}:host(.kf-section-header--lg) .kf-section-header__subtitle{font-size:.9375rem}.kf-section-header__actions{flex:none;display:flex;align-items:center;gap:var(--kf-space-sm)}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
4391
4978
|
}
|
|
4392
4979
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SectionHeader, decorators: [{
|
|
4393
4980
|
type: Component,
|
|
4394
4981
|
args: [{ selector: 'kf-section-header', imports: [Icon], template: `
|
|
4395
4982
|
@if (icon(); as iconName) {
|
|
4396
4983
|
<span class="kf-section-header__icon" [class.kf-section-header__icon--solid]="solid()">
|
|
4397
|
-
<kf-icon [name]="iconName" [size]="
|
|
4984
|
+
<kf-icon [name]="iconName" [size]="iconSize()" />
|
|
4398
4985
|
</span>
|
|
4399
4986
|
}
|
|
4400
4987
|
|
|
@@ -4410,7 +4997,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4410
4997
|
</span>
|
|
4411
4998
|
`, host: {
|
|
4412
4999
|
'[class.kf-section-header--sm]': "size() === 'sm'",
|
|
4413
|
-
|
|
5000
|
+
'[class.kf-section-header--lg]': "size() === 'lg'",
|
|
5001
|
+
}, styles: [":host{display:flex;align-items:center;gap:var(--kf-space-sm);font-family:var(--kf-font-body)}:host(.kf-section-header--sm){gap:var(--kf-space-xs)}:host(.kf-section-header--lg){gap:var(--kf-space-md)}.kf-section-header__icon{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:2.5rem;block-size:2.5rem;border-radius:var(--kf-radius-sm);background:var(--kf-color-primary-soft);color:var(--kf-color-primary)}:host(.kf-section-header--sm) .kf-section-header__icon{inline-size:1.75rem;block-size:1.75rem;border-radius:var(--kf-radius-xs)}:host(.kf-section-header--lg) .kf-section-header__icon{inline-size:3.25rem;block-size:3.25rem;border-radius:var(--kf-radius-md)}.kf-section-header__icon--solid{background:var(--kf-color-primary);color:var(--kf-color-white)}.kf-section-header__text{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}.kf-section-header__title{font-family:var(--kf-font-title);font-size:1rem;font-weight:700;color:var(--kf-color-ink);line-height:1.3}:host(.kf-section-header--sm) .kf-section-header__title{font-size:.875rem}:host(.kf-section-header--lg) .kf-section-header__title{font-size:1.25rem}.kf-section-header__subtitle{font-size:.8125rem;color:var(--kf-color-text-muted);line-height:1.3}:host(.kf-section-header--sm) .kf-section-header__subtitle{font-size:.75rem}:host(.kf-section-header--lg) .kf-section-header__subtitle{font-size:.9375rem}.kf-section-header__actions{flex:none;display:flex;align-items:center;gap:var(--kf-space-sm)}\n"] }]
|
|
4414
5002
|
}], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], solid: [{ type: i0.Input, args: [{ isSignal: true, alias: "solid", required: false }] }] } });
|
|
4415
5003
|
|
|
4416
5004
|
/**
|
|
@@ -4484,184 +5072,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4484
5072
|
`, styles: [":host{display:inline-block}.kf-segmented__track{position:relative;display:grid;grid-template-columns:repeat(var(--kf-segmented-count),1fr);gap:2px;padding:2px;background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md)}.kf-segmented__thumb{position:absolute;top:2px;left:2px;width:calc((100% - 4px) / var(--kf-segmented-count));height:calc(100% - 4px);background:var(--kf-color-white);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-xs);transform:translate(calc(var(--kf-segmented-index, 0) * 100%));transition:transform .2s ease}.kf-segmented__option{position:relative;z-index:1;font:inherit;padding:var(--kf-space-xs) var(--kf-space-md);border:none;background:transparent;color:var(--kf-color-text-muted);border-radius:var(--kf-radius-sm);cursor:pointer;transition:color .14s}.kf-segmented__option:hover:not(.kf-segmented__option--active){color:var(--kf-color-text)}.kf-segmented__option--active{color:var(--kf-color-ink)}.kf-segmented__option:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}\n"] }]
|
|
4485
5073
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
4486
5074
|
|
|
4487
|
-
let nextId = 0;
|
|
4488
|
-
/**
|
|
4489
|
-
* Dropdown de selección simple pero con panel propio (no usa `<select>` nativo),
|
|
4490
|
-
* para cuando se necesita más control visual que un `<select>` estándar permite.
|
|
4491
|
-
*
|
|
4492
|
-
* El panel flotante se implementa con `position: absolute` sobre el host
|
|
4493
|
-
* (sin Angular CDK Overlay, que no es dependencia del proyecto). Se abre y
|
|
4494
|
-
* cierra por click en el disparador, y se cierra al hacer click afuera o al
|
|
4495
|
-
* presionar Escape.
|
|
4496
|
-
*
|
|
4497
|
-
* <kf-select-menu
|
|
4498
|
-
* label="País"
|
|
4499
|
-
* [options]="countries"
|
|
4500
|
-
* [value]="selectedCountry()"
|
|
4501
|
-
* (valueChange)="selectedCountry.set($event)"
|
|
4502
|
-
* />
|
|
4503
|
-
*
|
|
4504
|
-
* Pendiente: el prop `icon` de otros componentes del design system requiere
|
|
4505
|
-
* un componente Icon / sprite SVG que esta librería todavía no tiene — este
|
|
4506
|
-
* componente no usa iconos, así que no aplica acá.
|
|
4507
|
-
*/
|
|
4508
|
-
class SelectMenu {
|
|
4509
|
-
label = input(/* @ts-ignore */
|
|
4510
|
-
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
|
|
4511
|
-
options = input([], /* @ts-ignore */
|
|
4512
|
-
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
4513
|
-
value = input(/* @ts-ignore */
|
|
4514
|
-
...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
|
|
4515
|
-
placeholder = input('Seleccionar', /* @ts-ignore */
|
|
4516
|
-
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
4517
|
-
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4518
|
-
valueChange = output();
|
|
4519
|
-
instanceId = `kf-select-menu-${nextId++}`;
|
|
4520
|
-
triggerId = `${this.instanceId}-trigger`;
|
|
4521
|
-
listboxId = `${this.instanceId}-listbox`;
|
|
4522
|
-
isOpen = signal(false, /* @ts-ignore */
|
|
4523
|
-
...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
4524
|
-
selectedOption = computed(() => this.options().find((option) => option.value === this.value()), /* @ts-ignore */
|
|
4525
|
-
...(ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []));
|
|
4526
|
-
host = inject((ElementRef));
|
|
4527
|
-
toggle() {
|
|
4528
|
-
if (this.disabled()) {
|
|
4529
|
-
return;
|
|
4530
|
-
}
|
|
4531
|
-
this.isOpen.update((open) => !open);
|
|
4532
|
-
}
|
|
4533
|
-
select(option) {
|
|
4534
|
-
this.isOpen.set(false);
|
|
4535
|
-
if (option.value !== this.value()) {
|
|
4536
|
-
this.valueChange.emit(option.value);
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
4539
|
-
onDocumentClick(event) {
|
|
4540
|
-
if (this.isOpen() && !this.host.nativeElement.contains(event.target)) {
|
|
4541
|
-
this.isOpen.set(false);
|
|
4542
|
-
}
|
|
4543
|
-
}
|
|
4544
|
-
onEscape() {
|
|
4545
|
-
this.isOpen.set(false);
|
|
4546
|
-
}
|
|
4547
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SelectMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4548
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: SelectMenu, isStandalone: true, selector: "kf-select-menu", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: `
|
|
4549
|
-
@if (label()) {
|
|
4550
|
-
<kf-field-label [for]="triggerId">{{ label() }}</kf-field-label>
|
|
4551
|
-
}
|
|
4552
|
-
<button
|
|
4553
|
-
#trigger
|
|
4554
|
-
type="button"
|
|
4555
|
-
[id]="triggerId"
|
|
4556
|
-
class="kf-select-menu__trigger"
|
|
4557
|
-
[disabled]="disabled()"
|
|
4558
|
-
[attr.aria-haspopup]="'listbox'"
|
|
4559
|
-
[attr.aria-expanded]="isOpen()"
|
|
4560
|
-
[attr.aria-controls]="isOpen() ? listboxId : null"
|
|
4561
|
-
(click)="toggle()"
|
|
4562
|
-
>
|
|
4563
|
-
<span
|
|
4564
|
-
class="kf-select-menu__value"
|
|
4565
|
-
[class.kf-select-menu__value--placeholder]="!selectedOption()"
|
|
4566
|
-
>
|
|
4567
|
-
{{ selectedOption()?.label ?? placeholder() }}
|
|
4568
|
-
</span>
|
|
4569
|
-
<span
|
|
4570
|
-
class="kf-select-menu__caret"
|
|
4571
|
-
[class.kf-select-menu__caret--open]="isOpen()"
|
|
4572
|
-
aria-hidden="true"
|
|
4573
|
-
></span>
|
|
4574
|
-
</button>
|
|
4575
|
-
@if (isOpen()) {
|
|
4576
|
-
<ul
|
|
4577
|
-
class="kf-select-menu__panel"
|
|
4578
|
-
[id]="listboxId"
|
|
4579
|
-
role="listbox"
|
|
4580
|
-
[attr.aria-labelledby]="triggerId"
|
|
4581
|
-
>
|
|
4582
|
-
@for (option of options(); track option.value) {
|
|
4583
|
-
<li
|
|
4584
|
-
class="kf-select-menu__option"
|
|
4585
|
-
[class.kf-select-menu__option--selected]="option.value === value()"
|
|
4586
|
-
role="option"
|
|
4587
|
-
tabindex="0"
|
|
4588
|
-
[attr.aria-selected]="option.value === value()"
|
|
4589
|
-
(click)="select(option)"
|
|
4590
|
-
(keydown.enter)="select(option)"
|
|
4591
|
-
(keydown.space)="$event.preventDefault(); select(option)"
|
|
4592
|
-
>
|
|
4593
|
-
{{ option.label }}
|
|
4594
|
-
</li>
|
|
4595
|
-
} @empty {
|
|
4596
|
-
<li class="kf-select-menu__empty">Sin opciones disponibles</li>
|
|
4597
|
-
}
|
|
4598
|
-
</ul>
|
|
4599
|
-
}
|
|
4600
|
-
`, isInline: true, styles: [":host{display:inline-flex;flex-direction:column;gap:var(--kf-space-xs);position:relative;font:inherit;min-width:200px}.kf-select-menu__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-sm);width:100%;font:inherit;font-family:var(--kf-font-body);padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);cursor:pointer;transition:border-color .14s,box-shadow .14s}.kf-select-menu__trigger:hover:not(:disabled){border-color:var(--kf-color-border-strong)}.kf-select-menu__trigger:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-select-menu__trigger:disabled{opacity:.5;cursor:not-allowed}.kf-select-menu__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kf-select-menu__value--placeholder{color:var(--kf-color-text-muted)}.kf-select-menu__caret{flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--kf-color-text-muted);border-bottom:2px solid var(--kf-color-text-muted);transform:rotate(45deg);transition:transform .14s;margin-top:-4px}.kf-select-menu__caret--open{transform:rotate(-135deg);margin-top:4px}.kf-select-menu__panel{position:absolute;top:100%;left:0;right:0;z-index:10;margin:var(--kf-space-xs) 0 0;padding:var(--kf-space-xs) 0;list-style:none;max-height:240px;overflow-y:auto;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-md)}.kf-select-menu__option{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-select-menu__option:hover{background:var(--kf-color-primary-soft)}.kf-select-menu__option--selected{background:var(--kf-color-primary-soft);color:var(--kf-color-primary);font-weight:600}.kf-select-menu__empty{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text-muted)}\n"], dependencies: [{ kind: "component", type: FieldLabel, selector: "kf-field-label", inputs: ["for", "required"] }] });
|
|
4601
|
-
}
|
|
4602
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SelectMenu, decorators: [{
|
|
4603
|
-
type: Component,
|
|
4604
|
-
args: [{ selector: 'kf-select-menu', imports: [FieldLabel], template: `
|
|
4605
|
-
@if (label()) {
|
|
4606
|
-
<kf-field-label [for]="triggerId">{{ label() }}</kf-field-label>
|
|
4607
|
-
}
|
|
4608
|
-
<button
|
|
4609
|
-
#trigger
|
|
4610
|
-
type="button"
|
|
4611
|
-
[id]="triggerId"
|
|
4612
|
-
class="kf-select-menu__trigger"
|
|
4613
|
-
[disabled]="disabled()"
|
|
4614
|
-
[attr.aria-haspopup]="'listbox'"
|
|
4615
|
-
[attr.aria-expanded]="isOpen()"
|
|
4616
|
-
[attr.aria-controls]="isOpen() ? listboxId : null"
|
|
4617
|
-
(click)="toggle()"
|
|
4618
|
-
>
|
|
4619
|
-
<span
|
|
4620
|
-
class="kf-select-menu__value"
|
|
4621
|
-
[class.kf-select-menu__value--placeholder]="!selectedOption()"
|
|
4622
|
-
>
|
|
4623
|
-
{{ selectedOption()?.label ?? placeholder() }}
|
|
4624
|
-
</span>
|
|
4625
|
-
<span
|
|
4626
|
-
class="kf-select-menu__caret"
|
|
4627
|
-
[class.kf-select-menu__caret--open]="isOpen()"
|
|
4628
|
-
aria-hidden="true"
|
|
4629
|
-
></span>
|
|
4630
|
-
</button>
|
|
4631
|
-
@if (isOpen()) {
|
|
4632
|
-
<ul
|
|
4633
|
-
class="kf-select-menu__panel"
|
|
4634
|
-
[id]="listboxId"
|
|
4635
|
-
role="listbox"
|
|
4636
|
-
[attr.aria-labelledby]="triggerId"
|
|
4637
|
-
>
|
|
4638
|
-
@for (option of options(); track option.value) {
|
|
4639
|
-
<li
|
|
4640
|
-
class="kf-select-menu__option"
|
|
4641
|
-
[class.kf-select-menu__option--selected]="option.value === value()"
|
|
4642
|
-
role="option"
|
|
4643
|
-
tabindex="0"
|
|
4644
|
-
[attr.aria-selected]="option.value === value()"
|
|
4645
|
-
(click)="select(option)"
|
|
4646
|
-
(keydown.enter)="select(option)"
|
|
4647
|
-
(keydown.space)="$event.preventDefault(); select(option)"
|
|
4648
|
-
>
|
|
4649
|
-
{{ option.label }}
|
|
4650
|
-
</li>
|
|
4651
|
-
} @empty {
|
|
4652
|
-
<li class="kf-select-menu__empty">Sin opciones disponibles</li>
|
|
4653
|
-
}
|
|
4654
|
-
</ul>
|
|
4655
|
-
}
|
|
4656
|
-
`, styles: [":host{display:inline-flex;flex-direction:column;gap:var(--kf-space-xs);position:relative;font:inherit;min-width:200px}.kf-select-menu__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-sm);width:100%;font:inherit;font-family:var(--kf-font-body);padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);cursor:pointer;transition:border-color .14s,box-shadow .14s}.kf-select-menu__trigger:hover:not(:disabled){border-color:var(--kf-color-border-strong)}.kf-select-menu__trigger:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-select-menu__trigger:disabled{opacity:.5;cursor:not-allowed}.kf-select-menu__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kf-select-menu__value--placeholder{color:var(--kf-color-text-muted)}.kf-select-menu__caret{flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--kf-color-text-muted);border-bottom:2px solid var(--kf-color-text-muted);transform:rotate(45deg);transition:transform .14s;margin-top:-4px}.kf-select-menu__caret--open{transform:rotate(-135deg);margin-top:4px}.kf-select-menu__panel{position:absolute;top:100%;left:0;right:0;z-index:10;margin:var(--kf-space-xs) 0 0;padding:var(--kf-space-xs) 0;list-style:none;max-height:240px;overflow-y:auto;background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:var(--kf-shadow-md)}.kf-select-menu__option{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-select-menu__option:hover{background:var(--kf-color-primary-soft)}.kf-select-menu__option--selected{background:var(--kf-color-primary-soft);color:var(--kf-color-primary);font-weight:600}.kf-select-menu__empty{padding:var(--kf-space-sm) var(--kf-space-md);color:var(--kf-color-text-muted)}\n"] }]
|
|
4657
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], onDocumentClick: [{
|
|
4658
|
-
type: HostListener,
|
|
4659
|
-
args: ['document:click', ['$event']]
|
|
4660
|
-
}], onEscape: [{
|
|
4661
|
-
type: HostListener,
|
|
4662
|
-
args: ['document:keydown.escape']
|
|
4663
|
-
}] } });
|
|
4664
|
-
|
|
4665
5075
|
/**
|
|
4666
5076
|
* Indicador numérico compacto (página 34): label + valor grande, con un
|
|
4667
5077
|
* ícono a la derecha del label — más chico y sin badge de esquina que
|
|
@@ -4930,6 +5340,109 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4930
5340
|
`, styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-tabs{position:relative;display:flex;align-items:stretch;gap:var(--kf-space-md);border-bottom:1px solid var(--kf-color-border)}.kf-tabs__tab{display:inline-flex;align-items:center;gap:var(--kf-space-xs);font:inherit;font-size:.9rem;color:var(--kf-color-text-muted);background:transparent;border:none;padding:var(--kf-space-sm) 0;cursor:pointer;transition:color .14s}.kf-tabs__tab:hover:not(.kf-tabs__tab--active){color:var(--kf-color-text)}.kf-tabs__tab:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus);border-radius:var(--kf-radius-xs)}.kf-tabs__tab--active{color:var(--kf-color-primary);font-size:1rem;font-weight:700}.kf-tabs__indicator{position:absolute;bottom:-1px;left:0;height:2px;background:var(--kf-color-primary);border-radius:2px 2px 0 0;pointer-events:none;transition:transform .28s cubic-bezier(.32,.72,0,1),width .28s cubic-bezier(.32,.72,0,1),opacity .14s}@media(prefers-reduced-motion:reduce){.kf-tabs__indicator{transition:opacity .14s}}\n"] }]
|
|
4931
5341
|
}], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], track: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }] } });
|
|
4932
5342
|
|
|
5343
|
+
/**
|
|
5344
|
+
* Tipografía unificada — separa la etiqueta semántica (`as`, qué es el
|
|
5345
|
+
* texto para el DOM/accesibilidad) del estilo visual (`variant`, cómo se
|
|
5346
|
+
* ve). Antes de este componente, cada pantalla que consume la librería
|
|
5347
|
+
* definía su propio `h1`/`p` con `font-size` suelto para el mismo rol
|
|
5348
|
+
* (título de página, subtítulo, texto secundario) — auditoría sobre
|
|
5349
|
+
* `web-portal-latam-frontend` encontró 9 tamaños distintos entre login y
|
|
5350
|
+
* home sin ningún paso de escala en común. `variant` resuelve eso contra
|
|
5351
|
+
* la escala de `tokens/base.css` (`--kf-font-size-*`).
|
|
5352
|
+
*
|
|
5353
|
+
* `tone` sigue la misma convención cerrada que `Alert`/`Badge`/`Chip`: sin
|
|
5354
|
+
* escape hatch de color libre. Si un caso necesita un color que `tone` no
|
|
5355
|
+
* cubre, es una discusión de design system, no una prop nueva acá.
|
|
5356
|
+
*
|
|
5357
|
+
* <kf-text as="h1" variant="title-lg">Bienvenido de nuevo</kf-text>
|
|
5358
|
+
* <kf-text as="p" variant="body-muted">Ingresá con tu cuenta corporativa.</kf-text>
|
|
5359
|
+
* <kf-text as="span" variant="caption" tone="error">Campo obligatorio</kf-text>
|
|
5360
|
+
*/
|
|
5361
|
+
class Text {
|
|
5362
|
+
/** Etiqueta semántica real que se renderiza — nunca es solo un `div`. */
|
|
5363
|
+
as = input('p', /* @ts-ignore */
|
|
5364
|
+
...(ngDevMode ? [{ debugName: "as" }] : /* istanbul ignore next */ []));
|
|
5365
|
+
variant = input('body', /* @ts-ignore */
|
|
5366
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
5367
|
+
tone = input('neutral', /* @ts-ignore */
|
|
5368
|
+
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
5369
|
+
/**
|
|
5370
|
+
* Copia de `as` para uso dentro del template: `as` es palabra reservada
|
|
5371
|
+
* en las expresiones de Angular (`@if (x; as y)`), así que `@switch (as())`
|
|
5372
|
+
* no parsea — NG5002. La prop pública sigue llamándose `as` (es solo un
|
|
5373
|
+
* atributo HTML ahí, `<kf-text as="h1">`, no una expresión).
|
|
5374
|
+
*/
|
|
5375
|
+
tag = computed(() => this.as(), /* @ts-ignore */
|
|
5376
|
+
...(ngDevMode ? [{ debugName: "tag" }] : /* istanbul ignore next */ []));
|
|
5377
|
+
hostClass() {
|
|
5378
|
+
const classes = [`kf-text--${this.variant()}`];
|
|
5379
|
+
if (this.tone() !== 'neutral') {
|
|
5380
|
+
classes.push(`kf-text--${this.tone()}`);
|
|
5381
|
+
}
|
|
5382
|
+
return classes.join(' ');
|
|
5383
|
+
}
|
|
5384
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Text, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5385
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: Text, isStandalone: true, selector: "kf-text", inputs: { as: { classPropertyName: "as", publicName: "as", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
5386
|
+
<!--
|
|
5387
|
+
Una sola proyección compartida (ng-template + ngTemplateOutlet) en vez
|
|
5388
|
+
de un <ng-content> por cada rama del @switch: Angular solo conecta la
|
|
5389
|
+
proyección real del consumidor a la PRIMERA instancia de <ng-content>
|
|
5390
|
+
que encuentra en el árbol de compilación — con un <ng-content> por
|
|
5391
|
+
rama, todas menos una quedan vacías en runtime (bug detectado por
|
|
5392
|
+
Text.spec.ts, no algo documentado a simple vista en los docs de Angular).
|
|
5393
|
+
-->
|
|
5394
|
+
<ng-template #projected><ng-content /></ng-template>
|
|
5395
|
+
@switch (tag()) {
|
|
5396
|
+
@case ('h1') {
|
|
5397
|
+
<h1 [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></h1>
|
|
5398
|
+
}
|
|
5399
|
+
@case ('h2') {
|
|
5400
|
+
<h2 [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></h2>
|
|
5401
|
+
}
|
|
5402
|
+
@case ('h3') {
|
|
5403
|
+
<h3 [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></h3>
|
|
5404
|
+
}
|
|
5405
|
+
@case ('span') {
|
|
5406
|
+
<span [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></span>
|
|
5407
|
+
}
|
|
5408
|
+
@default {
|
|
5409
|
+
<p [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></p>
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
`, isInline: true, styles: [":host{display:contents}h1,h2,h3,p,span{margin:0;font-family:var(--kf-font-body);color:var(--kf-color-text)}.kf-text--title-lg{font-family:var(--kf-font-title);font-size:var(--kf-font-size-title-lg);font-weight:var(--kf-font-weight-title);color:var(--kf-color-ink)}.kf-text--title-md{font-family:var(--kf-font-title);font-size:var(--kf-font-size-title-md);font-weight:var(--kf-font-weight-title);color:var(--kf-color-ink)}.kf-text--title-sm{font-family:var(--kf-font-title);font-size:var(--kf-font-size-title-sm);font-weight:var(--kf-font-weight-title);color:var(--kf-color-ink)}.kf-text--body{font-size:var(--kf-font-size-body);font-weight:var(--kf-font-weight-body)}.kf-text--body-muted{font-size:var(--kf-font-size-body);font-weight:var(--kf-font-weight-body);color:var(--kf-color-text-muted)}.kf-text--caption{font-size:var(--kf-font-size-caption);font-weight:var(--kf-font-weight-body);color:var(--kf-color-text-muted)}.kf-text--ok{color:var(--kf-color-success-strong)}.kf-text--warn{color:var(--kf-color-warning-strong)}.kf-text--error{color:var(--kf-color-error-strong)}.kf-text--info{color:var(--kf-color-info-strong)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
5413
|
+
}
|
|
5414
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Text, decorators: [{
|
|
5415
|
+
type: Component,
|
|
5416
|
+
args: [{ selector: 'kf-text', imports: [NgTemplateOutlet], template: `
|
|
5417
|
+
<!--
|
|
5418
|
+
Una sola proyección compartida (ng-template + ngTemplateOutlet) en vez
|
|
5419
|
+
de un <ng-content> por cada rama del @switch: Angular solo conecta la
|
|
5420
|
+
proyección real del consumidor a la PRIMERA instancia de <ng-content>
|
|
5421
|
+
que encuentra en el árbol de compilación — con un <ng-content> por
|
|
5422
|
+
rama, todas menos una quedan vacías en runtime (bug detectado por
|
|
5423
|
+
Text.spec.ts, no algo documentado a simple vista en los docs de Angular).
|
|
5424
|
+
-->
|
|
5425
|
+
<ng-template #projected><ng-content /></ng-template>
|
|
5426
|
+
@switch (tag()) {
|
|
5427
|
+
@case ('h1') {
|
|
5428
|
+
<h1 [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></h1>
|
|
5429
|
+
}
|
|
5430
|
+
@case ('h2') {
|
|
5431
|
+
<h2 [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></h2>
|
|
5432
|
+
}
|
|
5433
|
+
@case ('h3') {
|
|
5434
|
+
<h3 [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></h3>
|
|
5435
|
+
}
|
|
5436
|
+
@case ('span') {
|
|
5437
|
+
<span [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></span>
|
|
5438
|
+
}
|
|
5439
|
+
@default {
|
|
5440
|
+
<p [class]="hostClass()"><ng-container [ngTemplateOutlet]="projected" /></p>
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
`, styles: [":host{display:contents}h1,h2,h3,p,span{margin:0;font-family:var(--kf-font-body);color:var(--kf-color-text)}.kf-text--title-lg{font-family:var(--kf-font-title);font-size:var(--kf-font-size-title-lg);font-weight:var(--kf-font-weight-title);color:var(--kf-color-ink)}.kf-text--title-md{font-family:var(--kf-font-title);font-size:var(--kf-font-size-title-md);font-weight:var(--kf-font-weight-title);color:var(--kf-color-ink)}.kf-text--title-sm{font-family:var(--kf-font-title);font-size:var(--kf-font-size-title-sm);font-weight:var(--kf-font-weight-title);color:var(--kf-color-ink)}.kf-text--body{font-size:var(--kf-font-size-body);font-weight:var(--kf-font-weight-body)}.kf-text--body-muted{font-size:var(--kf-font-size-body);font-weight:var(--kf-font-weight-body);color:var(--kf-color-text-muted)}.kf-text--caption{font-size:var(--kf-font-size-caption);font-weight:var(--kf-font-weight-body);color:var(--kf-color-text-muted)}.kf-text--ok{color:var(--kf-color-success-strong)}.kf-text--warn{color:var(--kf-color-warning-strong)}.kf-text--error{color:var(--kf-color-error-strong)}.kf-text--info{color:var(--kf-color-info-strong)}\n"] }]
|
|
5444
|
+
}], propDecorators: { as: [{ type: i0.Input, args: [{ isSignal: true, alias: "as", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
|
|
5445
|
+
|
|
4933
5446
|
/** Fixed icon per tone (page 20 of the design system) — not configurable per call. */
|
|
4934
5447
|
const TOAST_ICON = {
|
|
4935
5448
|
success: 'check-circle',
|
|
@@ -5279,5 +5792,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
5279
5792
|
* Generated bundle index. Do not edit.
|
|
5280
5793
|
*/
|
|
5281
5794
|
|
|
5282
|
-
export { ActionTile, AdminBadge, Alert, Avatar, Badge, Breadcrumb, Button, Card, Carousel, CarouselSlide, Checkbox, Chip, CompanySelector, ContentSlot, ContentState, DataTable, Divider, EmptyState, FeatureCard, Field, FieldLabel, FilterChips, FolderTabs, Icon, Input, MetricCard, Modal, MultiSelect, PageHeader, Pagination, Panel, PortalHeader, ReserveBlock, SectionHeader, Segmented, Select,
|
|
5795
|
+
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 };
|
|
5283
5796
|
//# sourceMappingURL=kaufmann-lab-ui.mjs.map
|