@kaufmann-lab/ui 0.1.17 → 0.1.18

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/README.md CHANGED
@@ -7,7 +7,7 @@ Ionic, que por debajo sigue siendo Angular.
7
7
  > **Nota sobre este README**: por ahora solo documenta `<kf-button>` en
8
8
  > detalle. La librería ya tiene muchos más componentes (`Input`, `Checkbox`,
9
9
  > `Select`, `Modal`, `Card`, `Tabs`, `Toast`, y otros) — para verlos, mirá el
10
- > código fuente en `projects/ui/src/lib/` en el
10
+ > código fuente en `projects/ui/core/src/lib/` en el
11
11
  > [repositorio](https://github.com/kaufmann-lab/kaufmann-ui-angular) hasta
12
12
  > que esta tabla se complete. Ver también el
13
13
  > [CHANGELOG](https://github.com/kaufmann-lab/kaufmann-ui-angular/blob/main/CHANGELOG.md)
@@ -0,0 +1,322 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Directive, input, booleanAttribute, contentChild, Component, output, computed } from '@angular/core';
3
+ import { Divider, Text, Icon, Avatar, Spinner } from '@kaufmann-lab/ui/core';
4
+
5
+ /**
6
+ * Marca el contenido que va en el slot de SSO de `kf-auth-layout` (típico:
7
+ * un `kf-sso-button`, o varios si el ecosistema suma más de un proveedor).
8
+ * `AuthLayout` la detecta vía `contentChild` para decidir si renderiza el
9
+ * separador "o" entre el bloque de SSO y el formulario tradicional
10
+ * proyectado en el slot por defecto — sin este marcador, `AuthLayout`
11
+ * tendría que adivinar si hubo proyección leyendo el DOM a mano.
12
+ *
13
+ * <kf-auth-layout brand="Mi Portal">
14
+ * <div kfAuthLayoutSso>
15
+ * <kf-sso-button provider="microsoft" (click)="loginWithMicrosoft()" />
16
+ * </div>
17
+ * <form ...>...</form>
18
+ * </kf-auth-layout>
19
+ */
20
+ class AuthLayoutSso {
21
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AuthLayoutSso, deps: [], target: i0.ɵɵFactoryTarget.Directive });
22
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: AuthLayoutSso, isStandalone: true, selector: "[kfAuthLayoutSso]", ngImport: i0 });
23
+ }
24
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AuthLayoutSso, decorators: [{
25
+ type: Directive,
26
+ args: [{
27
+ selector: '[kfAuthLayoutSso]',
28
+ }]
29
+ }] });
30
+
31
+ /**
32
+ * Layout a pantalla completa para pantallas de autenticación (login,
33
+ * recuperar contraseña, confirmación de envío) — panel de marca a la
34
+ * izquierda, contenido libre a la derecha en desktop; en mobile el panel de
35
+ * marca se oculta y un logo compacto queda visible arriba del formulario.
36
+ *
37
+ * Resuelve solo el "cascarón": cada portal arma su propio `<form>` con los
38
+ * componentes de la librería y lo proyecta en el slot por defecto.
39
+ *
40
+ * <kf-auth-layout
41
+ * brand="Mi Portal"
42
+ * brandLogoSrc="images/mi-portal-logo-white.png"
43
+ * brandLogoMobileSrc="images/mi-portal-logo-black.png"
44
+ * brandTagline="Frase corta de marca, propia de cada portal."
45
+ * >
46
+ * <form (ngSubmit)="onSubmit()">
47
+ * <kf-input label="Correo" type="email" />
48
+ * <kf-input label="Contraseña" type="password" toggleable />
49
+ * <kf-button type="submit">Ingresar</kf-button>
50
+ * </form>
51
+ * </kf-auth-layout>
52
+ *
53
+ * `backgroundVariant` controla la superficie del panel derecho:
54
+ * `'plain'` (fondo liso, comportamiento histórico), `'gradient'` (default —
55
+ * degradé sutil derivado de `--kf-color-primary`/`--kf-color-surface` vía
56
+ * `color-mix()`, ningún color hardcodeado) o `'pattern'` (el mismo degradé
57
+ * más una textura de puntos, también resuelta con tokens). Los tres se
58
+ * resuelven contra los tokens de tema ACTIVOS — cambiar de tema
59
+ * (`andes-maq`, `divemotor-star`, `kaufmann-ar`, futuros) no requiere tocar
60
+ * este componente ni pasarle un color a mano.
61
+ *
62
+ * `card`, en `false` por defecto (comportamiento histórico: el contenido
63
+ * proyectado flota sin superficie propia), envuelve el slot por defecto con
64
+ * la misma superficie de `kf-card` (fondo, borde, sombra, radio) para que
65
+ * el formulario deje de verse suelto sobre el fondo del panel.
66
+ *
67
+ * `title`/`subtitle` renderizan un encabezado de bienvenida DENTRO de la
68
+ * card, antes que cualquier otro contenido (jerarquía ya resuelta:
69
+ * `title-lg` + `body-muted`, ver `Text.ts`) — así ningún consumidor tiene
70
+ * que adivinar la variante de `kf-text` correcta ni terminar con un
71
+ * "Iniciar sesión" repetido y suelto dentro de su propio `<form>`. Sin
72
+ * `title`, no se renderiza ningún encabezado (comportamiento histórico).
73
+ *
74
+ * El slot `[kfAuthLayoutSso]` (ver `AuthLayoutSso`) es para el patrón
75
+ * "SSO primero, credenciales como alternativa secundaria" — típicamente un
76
+ * `kf-sso-button`. Cuando hay contenido ahí, `AuthLayout` resuelve el
77
+ * separador "o" automáticamente entre ese bloque y el contenido por
78
+ * defecto; sin ese slot, nada cambia frente al comportamiento actual.
79
+ *
80
+ * <kf-auth-layout
81
+ * brand="Mi Portal"
82
+ * backgroundVariant="pattern"
83
+ * card
84
+ * title="Iniciar sesión"
85
+ * subtitle="Usa tu cuenta corporativa o ingresa con contraseña"
86
+ * >
87
+ * <div kfAuthLayoutSso>
88
+ * <kf-sso-button provider="microsoft" (click)="loginWithMicrosoft()" />
89
+ * </div>
90
+ * <form (ngSubmit)="onSubmit()">
91
+ * <kf-input label="Correo" type="email" />
92
+ * <kf-input label="Contraseña" type="password" toggleable />
93
+ * <kf-button type="submit">Ingresar</kf-button>
94
+ * </form>
95
+ * </kf-auth-layout>
96
+ */
97
+ class AuthLayout {
98
+ /** Nombre de marca/portal — wordmark de respaldo si no hay logo, y `alt` de ambos logos. */
99
+ brand = input.required(/* @ts-ignore */
100
+ ...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
101
+ /** Logo en blanco para el panel oscuro de desktop. Sin esto, se muestra `brand()` como wordmark. */
102
+ brandLogoSrc = input(/* @ts-ignore */
103
+ ...(ngDevMode ? [undefined, { debugName: "brandLogoSrc" }] : /* istanbul ignore next */ []));
104
+ /** Frase corta bajo el logo. */
105
+ brandTagline = input(/* @ts-ignore */
106
+ ...(ngDevMode ? [undefined, { debugName: "brandTagline" }] : /* istanbul ignore next */ []));
107
+ /** Logo compacto para mobile, sobre fondo claro. Sin esto, reutiliza `brandLogoSrc`. */
108
+ brandLogoMobileSrc = input(/* @ts-ignore */
109
+ ...(ngDevMode ? [undefined, { debugName: "brandLogoMobileSrc" }] : /* istanbul ignore next */ []));
110
+ /** Superficie del panel derecho. Default `'gradient'`; `'plain'` preserva el fondo liso histórico. */
111
+ backgroundVariant = input('gradient', /* @ts-ignore */
112
+ ...(ngDevMode ? [{ debugName: "backgroundVariant" }] : /* istanbul ignore next */ []));
113
+ /** Envuelve el contenido proyectado con la superficie de `kf-card` (fondo, borde, sombra). Default `false` — preserva el comportamiento histórico. */
114
+ card = input(false, { ...(ngDevMode ? { debugName: "card" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
115
+ /** Título del encabezado dentro de la card (`title-lg`). Sin este input, no se renderiza ningún encabezado. */
116
+ title = input(/* @ts-ignore */
117
+ ...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ []));
118
+ /** Subtítulo del encabezado (`body-muted`), debajo de `title`. Sin efecto si `title` no está presente. */
119
+ subtitle = input(/* @ts-ignore */
120
+ ...(ngDevMode ? [undefined, { debugName: "subtitle" }] : /* istanbul ignore next */ []));
121
+ /** Presencia de contenido en el slot `[kfAuthLayoutSso]` — controla si se renderiza el separador "o". */
122
+ ssoContent = contentChild(AuthLayoutSso, /* @ts-ignore */
123
+ ...(ngDevMode ? [{ debugName: "ssoContent" }] : /* istanbul ignore next */ []));
124
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AuthLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: AuthLayout, isStandalone: true, selector: "kf-auth-layout", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: true, transformFunction: null }, brandLogoSrc: { classPropertyName: "brandLogoSrc", publicName: "brandLogoSrc", isSignal: true, isRequired: false, transformFunction: null }, brandTagline: { classPropertyName: "brandTagline", publicName: "brandTagline", isSignal: true, isRequired: false, transformFunction: null }, brandLogoMobileSrc: { classPropertyName: "brandLogoMobileSrc", publicName: "brandLogoMobileSrc", isSignal: true, isRequired: false, transformFunction: null }, backgroundVariant: { classPropertyName: "backgroundVariant", publicName: "backgroundVariant", isSignal: true, isRequired: false, transformFunction: null }, card: { classPropertyName: "card", publicName: "card", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-background": "backgroundVariant()" } }, queries: [{ propertyName: "ssoContent", first: true, predicate: AuthLayoutSso, descendants: true, isSignal: true }], ngImport: i0, template: "<aside class=\"kf-auth-layout__brand\">\n @if (brandLogoSrc()) {\n <img class=\"kf-auth-layout__logo\" [src]=\"brandLogoSrc()\" [alt]=\"brand()\" />\n } @else {\n <span class=\"kf-auth-layout__wordmark\">{{ brand() }}</span>\n }\n @if (brandTagline()) {\n <p class=\"kf-auth-layout__tagline\">{{ brandTagline() }}</p>\n }\n</aside>\n\n<main class=\"kf-auth-layout__content\">\n <div class=\"kf-auth-layout__panel\" [class.kf-auth-layout__panel--card]=\"card()\">\n <div class=\"kf-auth-layout__mobile-brand\">\n @if (brandLogoMobileSrc() || brandLogoSrc()) {\n <img\n class=\"kf-auth-layout__logo kf-auth-layout__logo--mobile\"\n [src]=\"brandLogoMobileSrc() || brandLogoSrc()\"\n [alt]=\"brand()\"\n />\n } @else {\n <span class=\"kf-auth-layout__wordmark kf-auth-layout__wordmark--mobile\">{{ brand() }}</span>\n }\n </div>\n\n @if (title(); as headerTitle) {\n <div class=\"kf-auth-layout__header\">\n <kf-text as=\"h1\" variant=\"title-lg\">{{ headerTitle }}</kf-text>\n @if (subtitle(); as headerSubtitle) {\n <kf-text as=\"p\" variant=\"body-muted\">{{ headerSubtitle }}</kf-text>\n }\n </div>\n }\n\n <div class=\"kf-auth-layout__sso\">\n <ng-content select=\"[kfAuthLayoutSso]\" />\n </div>\n\n @if (ssoContent()) {\n <div class=\"kf-auth-layout__divider\">\n <kf-divider />\n <kf-text as=\"span\" variant=\"caption\" class=\"kf-auth-layout__divider-label\">o</kf-text>\n <kf-divider />\n </div>\n }\n\n <div class=\"kf-auth-layout__body\">\n <ng-content />\n </div>\n </div>\n</main>\n", styles: ["@charset \"UTF-8\";:host{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);min-height:100dvh}.kf-auth-layout__brand{display:flex;flex-direction:column;justify-content:center;gap:var(--kf-space-md);padding:var(--kf-space-xl);background:linear-gradient(190deg,var(--kf-color-primary-active) 0%,var(--kf-color-tertiary-deep) 100%);color:var(--kf-color-white)}.kf-auth-layout__logo{height:1.75rem;width:fit-content}.kf-auth-layout__wordmark{font-family:var(--kf-font-title);font-weight:var(--kf-font-weight-title);font-size:var(--kf-font-size-title-lg);letter-spacing:-.01em}.kf-auth-layout__tagline{max-width:34ch;margin:0;font-family:var(--kf-font-body);font-size:var(--kf-font-size-body);color:#ffffffb8}.kf-auth-layout__content{display:flex;align-items:center;justify-content:center;padding:var(--kf-space-xl);background:var(--kf-color-surface)}:host([data-background=gradient]) .kf-auth-layout__content{background:linear-gradient(165deg,color-mix(in srgb,var(--kf-color-primary) 6%,var(--kf-color-surface)) 0%,var(--kf-color-surface) 55%,color-mix(in srgb,var(--kf-color-primary) 10%,var(--kf-color-surface)) 100%)}:host([data-background=pattern]) .kf-auth-layout__content{background-color:var(--kf-color-surface);background-image:radial-gradient(circle at 1px 1px,color-mix(in srgb,var(--kf-color-primary) 16%,transparent) 1px,transparent 0),linear-gradient(165deg,color-mix(in srgb,var(--kf-color-primary) 6%,var(--kf-color-surface)) 0%,var(--kf-color-surface) 55%,color-mix(in srgb,var(--kf-color-primary) 10%,var(--kf-color-surface)) 100%);background-size:18px 18px,100% 100%}.kf-auth-layout__panel{width:100%;max-width:360px;display:flex;flex-direction:column;gap:var(--kf-space-xl)}.kf-auth-layout__header{display:flex;flex-direction:column;gap:var(--kf-space-xs)}.kf-auth-layout__sso,.kf-auth-layout__body{display:flex;flex-direction:column;gap:var(--kf-space-sm)}.kf-auth-layout__panel--card{padding:var(--kf-space-xl);background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-md)}.kf-auth-layout__divider{display:flex;align-items:center;gap:var(--kf-space-sm)}.kf-auth-layout__divider kf-divider{flex:1 1 0}.kf-auth-layout__divider-label{flex:none}.kf-auth-layout__mobile-brand{display:none;text-align:center}.kf-auth-layout__logo--mobile{margin-inline:auto;height:1.5rem}.kf-auth-layout__wordmark--mobile{color:var(--kf-color-ink)}@media(max-width:900px){:host{grid-template-columns:1fr}.kf-auth-layout__brand{display:none}.kf-auth-layout__content{padding:var(--kf-space-lg) var(--kf-space-md)}.kf-auth-layout__mobile-brand{display:block;margin-bottom:var(--kf-space-md)}}@media(max-width:480px){.kf-auth-layout__panel{max-width:none}}\n"], dependencies: [{ kind: "component", type: Divider, selector: "kf-divider", inputs: ["orientation"] }, { kind: "component", type: Text, selector: "kf-text", inputs: ["as", "variant", "tone"] }] });
126
+ }
127
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AuthLayout, decorators: [{
128
+ type: Component,
129
+ args: [{ selector: 'kf-auth-layout', imports: [Divider, Text], host: {
130
+ '[attr.data-background]': 'backgroundVariant()',
131
+ }, template: "<aside class=\"kf-auth-layout__brand\">\n @if (brandLogoSrc()) {\n <img class=\"kf-auth-layout__logo\" [src]=\"brandLogoSrc()\" [alt]=\"brand()\" />\n } @else {\n <span class=\"kf-auth-layout__wordmark\">{{ brand() }}</span>\n }\n @if (brandTagline()) {\n <p class=\"kf-auth-layout__tagline\">{{ brandTagline() }}</p>\n }\n</aside>\n\n<main class=\"kf-auth-layout__content\">\n <div class=\"kf-auth-layout__panel\" [class.kf-auth-layout__panel--card]=\"card()\">\n <div class=\"kf-auth-layout__mobile-brand\">\n @if (brandLogoMobileSrc() || brandLogoSrc()) {\n <img\n class=\"kf-auth-layout__logo kf-auth-layout__logo--mobile\"\n [src]=\"brandLogoMobileSrc() || brandLogoSrc()\"\n [alt]=\"brand()\"\n />\n } @else {\n <span class=\"kf-auth-layout__wordmark kf-auth-layout__wordmark--mobile\">{{ brand() }}</span>\n }\n </div>\n\n @if (title(); as headerTitle) {\n <div class=\"kf-auth-layout__header\">\n <kf-text as=\"h1\" variant=\"title-lg\">{{ headerTitle }}</kf-text>\n @if (subtitle(); as headerSubtitle) {\n <kf-text as=\"p\" variant=\"body-muted\">{{ headerSubtitle }}</kf-text>\n }\n </div>\n }\n\n <div class=\"kf-auth-layout__sso\">\n <ng-content select=\"[kfAuthLayoutSso]\" />\n </div>\n\n @if (ssoContent()) {\n <div class=\"kf-auth-layout__divider\">\n <kf-divider />\n <kf-text as=\"span\" variant=\"caption\" class=\"kf-auth-layout__divider-label\">o</kf-text>\n <kf-divider />\n </div>\n }\n\n <div class=\"kf-auth-layout__body\">\n <ng-content />\n </div>\n </div>\n</main>\n", styles: ["@charset \"UTF-8\";:host{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);min-height:100dvh}.kf-auth-layout__brand{display:flex;flex-direction:column;justify-content:center;gap:var(--kf-space-md);padding:var(--kf-space-xl);background:linear-gradient(190deg,var(--kf-color-primary-active) 0%,var(--kf-color-tertiary-deep) 100%);color:var(--kf-color-white)}.kf-auth-layout__logo{height:1.75rem;width:fit-content}.kf-auth-layout__wordmark{font-family:var(--kf-font-title);font-weight:var(--kf-font-weight-title);font-size:var(--kf-font-size-title-lg);letter-spacing:-.01em}.kf-auth-layout__tagline{max-width:34ch;margin:0;font-family:var(--kf-font-body);font-size:var(--kf-font-size-body);color:#ffffffb8}.kf-auth-layout__content{display:flex;align-items:center;justify-content:center;padding:var(--kf-space-xl);background:var(--kf-color-surface)}:host([data-background=gradient]) .kf-auth-layout__content{background:linear-gradient(165deg,color-mix(in srgb,var(--kf-color-primary) 6%,var(--kf-color-surface)) 0%,var(--kf-color-surface) 55%,color-mix(in srgb,var(--kf-color-primary) 10%,var(--kf-color-surface)) 100%)}:host([data-background=pattern]) .kf-auth-layout__content{background-color:var(--kf-color-surface);background-image:radial-gradient(circle at 1px 1px,color-mix(in srgb,var(--kf-color-primary) 16%,transparent) 1px,transparent 0),linear-gradient(165deg,color-mix(in srgb,var(--kf-color-primary) 6%,var(--kf-color-surface)) 0%,var(--kf-color-surface) 55%,color-mix(in srgb,var(--kf-color-primary) 10%,var(--kf-color-surface)) 100%);background-size:18px 18px,100% 100%}.kf-auth-layout__panel{width:100%;max-width:360px;display:flex;flex-direction:column;gap:var(--kf-space-xl)}.kf-auth-layout__header{display:flex;flex-direction:column;gap:var(--kf-space-xs)}.kf-auth-layout__sso,.kf-auth-layout__body{display:flex;flex-direction:column;gap:var(--kf-space-sm)}.kf-auth-layout__panel--card{padding:var(--kf-space-xl);background:var(--kf-color-white);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-md)}.kf-auth-layout__divider{display:flex;align-items:center;gap:var(--kf-space-sm)}.kf-auth-layout__divider kf-divider{flex:1 1 0}.kf-auth-layout__divider-label{flex:none}.kf-auth-layout__mobile-brand{display:none;text-align:center}.kf-auth-layout__logo--mobile{margin-inline:auto;height:1.5rem}.kf-auth-layout__wordmark--mobile{color:var(--kf-color-ink)}@media(max-width:900px){:host{grid-template-columns:1fr}.kf-auth-layout__brand{display:none}.kf-auth-layout__content{padding:var(--kf-space-lg) var(--kf-space-md)}.kf-auth-layout__mobile-brand{display:block;margin-bottom:var(--kf-space-md)}}@media(max-width:480px){.kf-auth-layout__panel{max-width:none}}\n"] }]
132
+ }], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: true }] }], brandLogoSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLogoSrc", required: false }] }], brandTagline: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandTagline", required: false }] }], brandLogoMobileSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLogoMobileSrc", required: false }] }], backgroundVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundVariant", required: false }] }], card: [{ type: i0.Input, args: [{ isSignal: true, alias: "card", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], ssoContent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => AuthLayoutSso), { isSignal: true }] }] } });
133
+
134
+ /**
135
+ * Botón de cerrar sesión, pensado para proyectarse dentro de
136
+ * `[kf-drawer-footer]` de `kf-drawer`, o junto a `kf-drawer-session` dentro
137
+ * de `[kf-sidebar-footer]` de `kf-sidebar-shell` — separado de
138
+ * `kf-drawer-session` (que solo muestra identidad: brand, avatar, nombre,
139
+ * email), no anidado dentro de ella.
140
+ *
141
+ * Ícono `log-out` + label, color `--kf-color-error` con hover en
142
+ * `--kf-color-error-soft` y foco visible con `--kf-shadow-focus`. Separado
143
+ * de `kf-drawer-session` (solo identidad) por responsabilidad única.
144
+ *
145
+ * No sabe nada de autenticación real — solo emite `logoutClick` cuando el
146
+ * consumidor debe cerrar la sesión real.
147
+ *
148
+ * `collapsed` oculta el label y centra el ícono, exponiéndolo vía `title`
149
+ * — mismo criterio que `SidebarNavItem.collapsed` y
150
+ * `DrawerSession.collapsed`, para cuando este botón vive dentro de un
151
+ * `kf-sidebar-shell` colapsado.
152
+ *
153
+ * <kf-drawer-logout kf-portal-header-footer (logoutClick)="onLogout()" />
154
+ */
155
+ class DrawerLogout {
156
+ /** Label del botón, en español neutro por defecto. Input opcional por si
157
+ * algún consumidor futuro necesita otro texto. */
158
+ label = input('Cerrar sesión', /* @ts-ignore */
159
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
160
+ /** Oculta el label y centra el ícono — ver comentario de la clase. */
161
+ collapsed = input(false, { ...(ngDevMode ? { debugName: "collapsed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
162
+ logoutClick = output();
163
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DrawerLogout, deps: [], target: i0.ɵɵFactoryTarget.Component });
164
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: DrawerLogout, isStandalone: true, selector: "kf-drawer-logout", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { logoutClick: "logoutClick" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"kf-drawer-logout__button\"\n [class.kf-drawer-logout__button--collapsed]=\"collapsed()\"\n [attr.title]=\"collapsed() ? label() : null\"\n (click)=\"logoutClick.emit()\"\n>\n <kf-icon name=\"log-out\" size=\"sm\" />\n @if (!collapsed()) {\n {{ label() }}\n }\n</button>\n", styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-drawer-logout__button{display:flex;align-items:center;gap:var(--kf-space-xs);width:100%;border:none;background:transparent;padding:0;font:inherit;font-size:.875rem;font-weight:600;color:var(--kf-color-error);cursor:pointer}.kf-drawer-logout__button--collapsed{justify-content:center}.kf-drawer-logout__button:hover{color:var(--kf-color-error-strong);background:var(--kf-color-error-soft)}.kf-drawer-logout__button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size", "rotate", "filled"] }] });
165
+ }
166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DrawerLogout, decorators: [{
167
+ type: Component,
168
+ args: [{ selector: 'kf-drawer-logout', imports: [Icon], template: "<button\n type=\"button\"\n class=\"kf-drawer-logout__button\"\n [class.kf-drawer-logout__button--collapsed]=\"collapsed()\"\n [attr.title]=\"collapsed() ? label() : null\"\n (click)=\"logoutClick.emit()\"\n>\n <kf-icon name=\"log-out\" size=\"sm\" />\n @if (!collapsed()) {\n {{ label() }}\n }\n</button>\n", styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-drawer-logout__button{display:flex;align-items:center;gap:var(--kf-space-xs);width:100%;border:none;background:transparent;padding:0;font:inherit;font-size:.875rem;font-weight:600;color:var(--kf-color-error);cursor:pointer}.kf-drawer-logout__button--collapsed{justify-content:center}.kf-drawer-logout__button:hover{color:var(--kf-color-error-strong);background:var(--kf-color-error-soft)}.kf-drawer-logout__button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}\n"] }]
169
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], logoutClick: [{ type: i0.Output, args: ["logoutClick"] }] } });
170
+
171
+ /**
172
+ * Bloque de identidad para `[kf-drawer-header]` de `kf-drawer` o
173
+ * `[kf-sidebar-footer]` de `kf-sidebar-shell`: avatar + nombre + email,
174
+ * brand opcional arriba. Solo identidad — el logout vive aparte, en
175
+ * `kf-drawer-logout`.
176
+ *
177
+ * `collapsed` oculta brand/nombre/email y deja solo el avatar (para un
178
+ * `kf-sidebar-shell` colapsado). `interactive` convierte la tarjeta en un
179
+ * botón real que emite `cardClick`, para cuando la identidad es el
180
+ * disparador de un menú de acciones (ej. envuelta en `kf-dropdown`).
181
+ *
182
+ * <kf-dropdown [(open)]="menuOpen">
183
+ * <kf-drawer-session interactive name="Juan Pérez" email="juan@empresa.com" (cardClick)="menuOpen.set(!menuOpen())" />
184
+ * <kf-dropdown-panel variant="dark">
185
+ * <kf-dropdown-item icon="log-out" tone="error" (click)="onLogout()">Cerrar sesión</kf-dropdown-item>
186
+ * </kf-dropdown-panel>
187
+ * </kf-dropdown>
188
+ */
189
+ class DrawerSession {
190
+ name = input.required(/* @ts-ignore */
191
+ ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
192
+ email = input('', /* @ts-ignore */
193
+ ...(ngDevMode ? [{ debugName: "email" }] : /* istanbul ignore next */ []));
194
+ /**
195
+ * Etiqueta de rol o función del usuario dentro de la sesión (ej.
196
+ * "Coordinador", "Supervisor"). Se muestra como badge dentro de la
197
+ * identidad, debajo del email — distinto de `brand`, que es la marca o
198
+ * cliente mostrada como encabezado de todo el bloque, no un atributo de
199
+ * la persona.
200
+ */
201
+ role = input('', /* @ts-ignore */
202
+ ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
203
+ initials = input('', /* @ts-ignore */
204
+ ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
205
+ avatarUrl = input('', /* @ts-ignore */
206
+ ...(ngDevMode ? [{ debugName: "avatarUrl" }] : /* istanbul ignore next */ []));
207
+ /** Label superior opcional, ej. "Portal Kaufmann LATAM". */
208
+ brand = input('', /* @ts-ignore */
209
+ ...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
210
+ /** Oculta brand/nombre/email y centra el avatar — ver comentario de la clase. */
211
+ collapsed = input(false, { ...(ngDevMode ? { debugName: "collapsed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
212
+ /** Convierte la tarjeta en un botón real con ícono de kebab — ver comentario de la clase. */
213
+ interactive = input(false, { ...(ngDevMode ? { debugName: "interactive" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
214
+ /** Se emite al clickear la tarjeta, solo cuando `interactive` es `true`. */
215
+ cardClick = output();
216
+ /** Si no se pasa `initials`, se derivan de `name`: primera letra de cada
217
+ * una de las primeras 2 palabras, en mayúscula. */
218
+ displayInitials = computed(() => {
219
+ const explicit = this.initials();
220
+ if (explicit) {
221
+ return explicit;
222
+ }
223
+ return this.name()
224
+ .trim()
225
+ .split(/\s+/)
226
+ .slice(0, 2)
227
+ .map((word) => word.charAt(0).toUpperCase())
228
+ .join('');
229
+ }, /* @ts-ignore */
230
+ ...(ngDevMode ? [{ debugName: "displayInitials" }] : /* istanbul ignore next */ []));
231
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DrawerSession, deps: [], target: i0.ɵɵFactoryTarget.Component });
232
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: DrawerSession, isStandalone: true, selector: "kf-drawer-session", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, avatarUrl: { classPropertyName: "avatarUrl", publicName: "avatarUrl", isSignal: true, isRequired: false, transformFunction: null }, brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick" }, ngImport: i0, template: "@if (brand() && !collapsed()) {\n <span class=\"kf-drawer-session__brand\">{{ brand() }}</span>\n}\n\n@if (interactive()) {\n <button\n type=\"button\"\n class=\"kf-drawer-session__card kf-drawer-session__card--interactive\"\n [class.kf-drawer-session__card--collapsed]=\"collapsed()\"\n (click)=\"cardClick.emit()\"\n >\n <kf-avatar [initials]=\"displayInitials()\" [src]=\"avatarUrl()\" />\n @if (!collapsed()) {\n <div class=\"kf-drawer-session__identity\">\n <span class=\"kf-drawer-session__name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"kf-drawer-session__email\">{{ email() }}</span>\n }\n @if (role()) {\n <span class=\"kf-drawer-session__role\">{{ role() }}</span>\n }\n </div>\n <kf-icon name=\"more-vertical\" size=\"sm\" />\n }\n </button>\n} @else {\n <div class=\"kf-drawer-session__card\" [class.kf-drawer-session__card--collapsed]=\"collapsed()\">\n <kf-avatar [initials]=\"displayInitials()\" [src]=\"avatarUrl()\" />\n @if (!collapsed()) {\n <div class=\"kf-drawer-session__identity\">\n <span class=\"kf-drawer-session__name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"kf-drawer-session__email\">{{ email() }}</span>\n }\n @if (role()) {\n <span class=\"kf-drawer-session__role\">{{ role() }}</span>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-drawer-session__brand{display:block;margin-bottom:var(--kf-space-sm);font-family:var(--kf-font-mono);font-size:.6875rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#ffffffa6}.kf-drawer-session__card{box-sizing:border-box;display:flex;align-items:center;gap:var(--kf-space-sm);width:100%;padding:var(--kf-space-sm);border:1px solid rgba(255,255,255,.14);border-radius:var(--kf-radius-md);background:#ffffff0a}.kf-drawer-session__card--interactive{font:inherit;color:inherit;cursor:pointer;text-align:left;transition:background .14s}.kf-drawer-session__card--interactive:hover{background:#ffffff17}.kf-drawer-session__card--interactive:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-drawer-session__card--interactive kf-icon{flex:none;color:#ffffff73}.kf-drawer-session__card--collapsed{justify-content:center;width:40px;height:40px;padding:0;border-color:transparent;background:transparent}.kf-drawer-session__card--collapsed:hover{background:#ffffff17}.kf-drawer-session__identity{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}.kf-drawer-session__name{font-size:.9375rem;font-weight:600;color:var(--kf-color-white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-drawer-session__email{font-size:.8125rem;color:#ffffffa6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-drawer-session__role{display:inline-block;margin-top:2px;padding:2px var(--kf-space-xs);border:1px solid rgba(255,255,255,.16);border-radius:var(--kf-radius-pill);font-family:var(--kf-font-mono);font-size:.625rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:#ffffffd9;background:#ffffff14;width:fit-content}\n"], dependencies: [{ kind: "component", type: Avatar, selector: "kf-avatar", inputs: ["initials", "src", "round", "pill"] }, { kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size", "rotate", "filled"] }] });
233
+ }
234
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DrawerSession, decorators: [{
235
+ type: Component,
236
+ args: [{ selector: 'kf-drawer-session', imports: [Avatar, Icon], template: "@if (brand() && !collapsed()) {\n <span class=\"kf-drawer-session__brand\">{{ brand() }}</span>\n}\n\n@if (interactive()) {\n <button\n type=\"button\"\n class=\"kf-drawer-session__card kf-drawer-session__card--interactive\"\n [class.kf-drawer-session__card--collapsed]=\"collapsed()\"\n (click)=\"cardClick.emit()\"\n >\n <kf-avatar [initials]=\"displayInitials()\" [src]=\"avatarUrl()\" />\n @if (!collapsed()) {\n <div class=\"kf-drawer-session__identity\">\n <span class=\"kf-drawer-session__name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"kf-drawer-session__email\">{{ email() }}</span>\n }\n @if (role()) {\n <span class=\"kf-drawer-session__role\">{{ role() }}</span>\n }\n </div>\n <kf-icon name=\"more-vertical\" size=\"sm\" />\n }\n </button>\n} @else {\n <div class=\"kf-drawer-session__card\" [class.kf-drawer-session__card--collapsed]=\"collapsed()\">\n <kf-avatar [initials]=\"displayInitials()\" [src]=\"avatarUrl()\" />\n @if (!collapsed()) {\n <div class=\"kf-drawer-session__identity\">\n <span class=\"kf-drawer-session__name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"kf-drawer-session__email\">{{ email() }}</span>\n }\n @if (role()) {\n <span class=\"kf-drawer-session__role\">{{ role() }}</span>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-drawer-session__brand{display:block;margin-bottom:var(--kf-space-sm);font-family:var(--kf-font-mono);font-size:.6875rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#ffffffa6}.kf-drawer-session__card{box-sizing:border-box;display:flex;align-items:center;gap:var(--kf-space-sm);width:100%;padding:var(--kf-space-sm);border:1px solid rgba(255,255,255,.14);border-radius:var(--kf-radius-md);background:#ffffff0a}.kf-drawer-session__card--interactive{font:inherit;color:inherit;cursor:pointer;text-align:left;transition:background .14s}.kf-drawer-session__card--interactive:hover{background:#ffffff17}.kf-drawer-session__card--interactive:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-drawer-session__card--interactive kf-icon{flex:none;color:#ffffff73}.kf-drawer-session__card--collapsed{justify-content:center;width:40px;height:40px;padding:0;border-color:transparent;background:transparent}.kf-drawer-session__card--collapsed:hover{background:#ffffff17}.kf-drawer-session__identity{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}.kf-drawer-session__name{font-size:.9375rem;font-weight:600;color:var(--kf-color-white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-drawer-session__email{font-size:.8125rem;color:#ffffffa6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kf-drawer-session__role{display:inline-block;margin-top:2px;padding:2px var(--kf-space-xs);border:1px solid rgba(255,255,255,.16);border-radius:var(--kf-radius-pill);font-family:var(--kf-font-mono);font-size:.625rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:#ffffffd9;background:#ffffff14;width:fit-content}\n"] }]
237
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], email: [{ type: i0.Input, args: [{ isSignal: true, alias: "email", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], avatarUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarUrl", required: false }] }], brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], cardClick: [{ type: i0.Output, args: ["cardClick"] }] } });
238
+
239
+ const PROVIDER_CONFIG = {
240
+ microsoft: { label: 'Continuar con Microsoft' },
241
+ };
242
+ /**
243
+ * Botón de inicio de sesión vía SSO corporativo — pensado como pieza suelta,
244
+ * no acoplada a `kf-auth-layout`: cualquier consumidor puede usarlo solo,
245
+ * dentro o fuera del slot `[sso]` de `AuthLayout`.
246
+ *
247
+ * `provider` resuelve copy y glyph — hoy solo `'microsoft'` (el método
248
+ * principal de acceso del ecosistema, cuenta corporativa de Grupo Kaufmann),
249
+ * con la puerta abierta a sumar otros a futuro sin romper la API existente.
250
+ *
251
+ * El glyph es el ícono GENÉRICO de 4 cuadrados de colores que Microsoft
252
+ * publica en sus propias guías de marca para botones de terceros ("Sign in
253
+ * with Microsoft") — nunca el logotipo/wordmark oficial completo. No vive en
254
+ * el sprite de `kf-icon` (`icon-sprite.ts`) a propósito: ese catálogo es
255
+ * monocromático (`currentColor`, ver `Icon.ts`), pensado para trazos de un
256
+ * solo color — este glyph necesita sus 4 colores fijos tal como los define
257
+ * la guía de marca, así que un SVG inline propio es la opción correcta, no
258
+ * un glyph nuevo forzado al sprite compartido.
259
+ *
260
+ * El label por defecto viene de `provider` — pasar contenido propio via
261
+ * `<ng-content>` lo reemplaza (ej. un texto más corto en un lugar angosto).
262
+ *
263
+ * <kf-sso-button provider="microsoft" (ssoClick)="loginWithMicrosoft()" />
264
+ * <kf-sso-button provider="microsoft" [loading]="loggingIn()">
265
+ * Ingresar con cuenta corporativa
266
+ * </kf-sso-button>
267
+ */
268
+ class SsoButton {
269
+ provider = input('microsoft', /* @ts-ignore */
270
+ ...(ngDevMode ? [{ debugName: "provider" }] : /* istanbul ignore next */ []));
271
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
272
+ /** Reemplaza el glyph + label por `kf-spinner` y fuerza `disabled` — mismo
273
+ * patrón que `kf-button[loading]`. */
274
+ loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
275
+ /** Igual que `kf-button`: por defecto `submit` dentro de un `<form>`, pero
276
+ * este botón normalmente vive fuera de cualquier form (dispara un
277
+ * redirect a Microsoft Entra ID), así que casi siempre conviene `button`. */
278
+ type = input('button', /* @ts-ignore */
279
+ ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
280
+ config = computed(() => PROVIDER_CONFIG[this.provider()], /* @ts-ignore */
281
+ ...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
282
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SsoButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
283
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: SsoButton, isStandalone: true, selector: "kf-sso-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<button\n class=\"kf-sso-button\"\n [type]=\"type()\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"config().label\"\n>\n @if (loading()) {\n <kf-spinner size=\"sm\" />\n } @else {\n <!--\n \u00CDcono gen\u00E9rico \"Sign in with Microsoft\" de 4 cuadrados de colores\n (rojo, verde, azul, amarillo) \u2014 no el logotipo/wordmark oficial.\n Ver justificaci\u00F3n completa en el JSDoc de SsoButton.ts.\n -->\n <svg\n class=\"kf-sso-button__glyph\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"0\" y=\"0\" width=\"8.5\" height=\"8.5\" fill=\"#f25022\" />\n <rect x=\"9.5\" y=\"0\" width=\"8.5\" height=\"8.5\" fill=\"#7fba00\" />\n <rect x=\"0\" y=\"9.5\" width=\"8.5\" height=\"8.5\" fill=\"#00a4ef\" />\n <rect x=\"9.5\" y=\"9.5\" width=\"8.5\" height=\"8.5\" fill=\"#ffb900\" />\n </svg>\n }\n <span class=\"kf-sso-button__label\">\n <ng-content>{{ config().label }}</ng-content>\n </span>\n</button>\n", styles: [":host{display:block}.kf-sso-button{display:flex;align-items:center;justify-content:center;gap:var(--kf-space-sm);width:100%;font:inherit;font-weight:600;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border-strong);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);cursor:pointer;transition:background .14s,border-color .14s}.kf-sso-button:hover:not(:disabled){background:var(--kf-color-surface);border-color:var(--kf-color-text-muted)}.kf-sso-button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-sso-button:disabled{opacity:.5;cursor:not-allowed}.kf-sso-button__glyph{flex:none}.kf-sso-button__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "component", type: Spinner, selector: "kf-spinner", inputs: ["size", "label", "onDark"] }] });
284
+ }
285
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SsoButton, decorators: [{
286
+ type: Component,
287
+ args: [{ selector: 'kf-sso-button', imports: [Spinner], template: "<button\n class=\"kf-sso-button\"\n [type]=\"type()\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"config().label\"\n>\n @if (loading()) {\n <kf-spinner size=\"sm\" />\n } @else {\n <!--\n \u00CDcono gen\u00E9rico \"Sign in with Microsoft\" de 4 cuadrados de colores\n (rojo, verde, azul, amarillo) \u2014 no el logotipo/wordmark oficial.\n Ver justificaci\u00F3n completa en el JSDoc de SsoButton.ts.\n -->\n <svg\n class=\"kf-sso-button__glyph\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"0\" y=\"0\" width=\"8.5\" height=\"8.5\" fill=\"#f25022\" />\n <rect x=\"9.5\" y=\"0\" width=\"8.5\" height=\"8.5\" fill=\"#7fba00\" />\n <rect x=\"0\" y=\"9.5\" width=\"8.5\" height=\"8.5\" fill=\"#00a4ef\" />\n <rect x=\"9.5\" y=\"9.5\" width=\"8.5\" height=\"8.5\" fill=\"#ffb900\" />\n </svg>\n }\n <span class=\"kf-sso-button__label\">\n <ng-content>{{ config().label }}</ng-content>\n </span>\n</button>\n", styles: [":host{display:block}.kf-sso-button{display:flex;align-items:center;justify-content:center;gap:var(--kf-space-sm);width:100%;font:inherit;font-weight:600;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border-strong);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);cursor:pointer;transition:background .14s,border-color .14s}.kf-sso-button:hover:not(:disabled){background:var(--kf-color-surface);border-color:var(--kf-color-text-muted)}.kf-sso-button:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-sso-button:disabled{opacity:.5;cursor:not-allowed}.kf-sso-button__glyph{flex:none}.kf-sso-button__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
288
+ }], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }] } });
289
+
290
+ /*
291
+ * Public API Surface of ui/auth — entry point secundario, `@kaufmann-lab/ui/auth`.
292
+ *
293
+ * Piezas del flujo de login y de la identidad de sesión: el esqueleto de la
294
+ * pantalla de login (`AuthLayout` + su slot `AuthLayoutSso`), el botón de
295
+ * acceso por proveedor (`SsoButton`) y los bloques de sesión que se proyectan
296
+ * en un `kf-drawer` (`DrawerSession`, `DrawerLogout`). Ver `ENTRY-POINTS.md`
297
+ * en la raíz del repo para el criterio.
298
+ *
299
+ * `AdminBadge` NO vive acá aunque temáticamente encajaría: `PortalHeader`
300
+ * (`@kaufmann-lab/ui/core`) lo compone, y un `AdminBadge` en `/auth` (que
301
+ * importa `Icon`/`Text` de `/core`) cerraría el ciclo `/core` -> `/auth` ->
302
+ * `/core`, que ng-packagr rechaza en build.
303
+ *
304
+ * Consume sus piezas base (`Avatar`, `Divider`, `Icon`, `Spinner`, `Text`)
305
+ * desde `'@kaufmann-lab/ui/core'`, nunca desde la raíz `'@kaufmann-lab/ui'`
306
+ * (agregador que depende de todos los entry points — importarla desde acá
307
+ * cerraría un ciclo) ni por ruta relativa cruzando la frontera entre entry
308
+ * points (ng-packagr calcula un `rootDir` propio por entry point y rechaza
309
+ * archivos fuente fuera de él). La única ruta relativa cruzada es el `@use`
310
+ * de SCSS de `AuthLayout.scss` hacia el parcial de breakpoints de `/core`:
311
+ * se resuelve en compilación y no genera dependencia de runtime.
312
+ *
313
+ * La raíz `'@kaufmann-lab/ui'` los reexporta, así que
314
+ * `import { AuthLayout } from '@kaufmann-lab/ui'` sigue funcionando igual.
315
+ */
316
+
317
+ /**
318
+ * Generated bundle index. Do not edit.
319
+ */
320
+
321
+ export { AuthLayout, AuthLayoutSso, DrawerLogout, DrawerSession, SsoButton };
322
+ //# sourceMappingURL=kaufmann-lab-ui-auth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kaufmann-lab-ui-auth.mjs","sources":["../../../projects/ui/auth/src/lib/auth-layout/AuthLayoutSso.ts","../../../projects/ui/auth/src/lib/auth-layout/AuthLayout.ts","../../../projects/ui/auth/src/lib/auth-layout/AuthLayout.html","../../../projects/ui/auth/src/lib/drawer-logout/DrawerLogout.ts","../../../projects/ui/auth/src/lib/drawer-logout/DrawerLogout.html","../../../projects/ui/auth/src/lib/drawer-session/DrawerSession.ts","../../../projects/ui/auth/src/lib/drawer-session/DrawerSession.html","../../../projects/ui/auth/src/lib/sso-button/SsoButton.ts","../../../projects/ui/auth/src/lib/sso-button/SsoButton.html","../../../projects/ui/auth/src/public-api.ts","../../../projects/ui/auth/src/kaufmann-lab-ui-auth.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n/**\n * Marca el contenido que va en el slot de SSO de `kf-auth-layout` (típico:\n * un `kf-sso-button`, o varios si el ecosistema suma más de un proveedor).\n * `AuthLayout` la detecta vía `contentChild` para decidir si renderiza el\n * separador \"o\" entre el bloque de SSO y el formulario tradicional\n * proyectado en el slot por defecto — sin este marcador, `AuthLayout`\n * tendría que adivinar si hubo proyección leyendo el DOM a mano.\n *\n * <kf-auth-layout brand=\"Mi Portal\">\n * <div kfAuthLayoutSso>\n * <kf-sso-button provider=\"microsoft\" (click)=\"loginWithMicrosoft()\" />\n * </div>\n * <form ...>...</form>\n * </kf-auth-layout>\n */\n@Directive({\n selector: '[kfAuthLayoutSso]',\n})\nexport class AuthLayoutSso {}\n","import { booleanAttribute, Component, contentChild, input } from '@angular/core';\nimport { Divider, Text } from '@kaufmann-lab/ui/core';\nimport { AuthLayoutSso } from './AuthLayoutSso';\n\nexport type AuthLayoutBackground = 'plain' | 'gradient' | 'pattern';\n\n/**\n * Layout a pantalla completa para pantallas de autenticación (login,\n * recuperar contraseña, confirmación de envío) — panel de marca a la\n * izquierda, contenido libre a la derecha en desktop; en mobile el panel de\n * marca se oculta y un logo compacto queda visible arriba del formulario.\n *\n * Resuelve solo el \"cascarón\": cada portal arma su propio `<form>` con los\n * componentes de la librería y lo proyecta en el slot por defecto.\n *\n * <kf-auth-layout\n * brand=\"Mi Portal\"\n * brandLogoSrc=\"images/mi-portal-logo-white.png\"\n * brandLogoMobileSrc=\"images/mi-portal-logo-black.png\"\n * brandTagline=\"Frase corta de marca, propia de cada portal.\"\n * >\n * <form (ngSubmit)=\"onSubmit()\">\n * <kf-input label=\"Correo\" type=\"email\" />\n * <kf-input label=\"Contraseña\" type=\"password\" toggleable />\n * <kf-button type=\"submit\">Ingresar</kf-button>\n * </form>\n * </kf-auth-layout>\n *\n * `backgroundVariant` controla la superficie del panel derecho:\n * `'plain'` (fondo liso, comportamiento histórico), `'gradient'` (default —\n * degradé sutil derivado de `--kf-color-primary`/`--kf-color-surface` vía\n * `color-mix()`, ningún color hardcodeado) o `'pattern'` (el mismo degradé\n * más una textura de puntos, también resuelta con tokens). Los tres se\n * resuelven contra los tokens de tema ACTIVOS — cambiar de tema\n * (`andes-maq`, `divemotor-star`, `kaufmann-ar`, futuros) no requiere tocar\n * este componente ni pasarle un color a mano.\n *\n * `card`, en `false` por defecto (comportamiento histórico: el contenido\n * proyectado flota sin superficie propia), envuelve el slot por defecto con\n * la misma superficie de `kf-card` (fondo, borde, sombra, radio) para que\n * el formulario deje de verse suelto sobre el fondo del panel.\n *\n * `title`/`subtitle` renderizan un encabezado de bienvenida DENTRO de la\n * card, antes que cualquier otro contenido (jerarquía ya resuelta:\n * `title-lg` + `body-muted`, ver `Text.ts`) — así ningún consumidor tiene\n * que adivinar la variante de `kf-text` correcta ni terminar con un\n * \"Iniciar sesión\" repetido y suelto dentro de su propio `<form>`. Sin\n * `title`, no se renderiza ningún encabezado (comportamiento histórico).\n *\n * El slot `[kfAuthLayoutSso]` (ver `AuthLayoutSso`) es para el patrón\n * \"SSO primero, credenciales como alternativa secundaria\" — típicamente un\n * `kf-sso-button`. Cuando hay contenido ahí, `AuthLayout` resuelve el\n * separador \"o\" automáticamente entre ese bloque y el contenido por\n * defecto; sin ese slot, nada cambia frente al comportamiento actual.\n *\n * <kf-auth-layout\n * brand=\"Mi Portal\"\n * backgroundVariant=\"pattern\"\n * card\n * title=\"Iniciar sesión\"\n * subtitle=\"Usa tu cuenta corporativa o ingresa con contraseña\"\n * >\n * <div kfAuthLayoutSso>\n * <kf-sso-button provider=\"microsoft\" (click)=\"loginWithMicrosoft()\" />\n * </div>\n * <form (ngSubmit)=\"onSubmit()\">\n * <kf-input label=\"Correo\" type=\"email\" />\n * <kf-input label=\"Contraseña\" type=\"password\" toggleable />\n * <kf-button type=\"submit\">Ingresar</kf-button>\n * </form>\n * </kf-auth-layout>\n */\n@Component({\n selector: 'kf-auth-layout',\n imports: [Divider, Text],\n templateUrl: './AuthLayout.html',\n styleUrl: './AuthLayout.scss',\n host: {\n '[attr.data-background]': 'backgroundVariant()',\n },\n})\nexport class AuthLayout {\n /** Nombre de marca/portal — wordmark de respaldo si no hay logo, y `alt` de ambos logos. */\n readonly brand = input.required<string>();\n\n /** Logo en blanco para el panel oscuro de desktop. Sin esto, se muestra `brand()` como wordmark. */\n readonly brandLogoSrc = input<string>();\n\n /** Frase corta bajo el logo. */\n readonly brandTagline = input<string>();\n\n /** Logo compacto para mobile, sobre fondo claro. Sin esto, reutiliza `brandLogoSrc`. */\n readonly brandLogoMobileSrc = input<string>();\n\n /** Superficie del panel derecho. Default `'gradient'`; `'plain'` preserva el fondo liso histórico. */\n readonly backgroundVariant = input<AuthLayoutBackground>('gradient');\n\n /** Envuelve el contenido proyectado con la superficie de `kf-card` (fondo, borde, sombra). Default `false` — preserva el comportamiento histórico. */\n readonly card = input(false, { transform: booleanAttribute });\n\n /** Título del encabezado dentro de la card (`title-lg`). Sin este input, no se renderiza ningún encabezado. */\n readonly title = input<string>();\n\n /** Subtítulo del encabezado (`body-muted`), debajo de `title`. Sin efecto si `title` no está presente. */\n readonly subtitle = input<string>();\n\n /** Presencia de contenido en el slot `[kfAuthLayoutSso]` — controla si se renderiza el separador \"o\". */\n protected readonly ssoContent = contentChild(AuthLayoutSso);\n}\n","<aside class=\"kf-auth-layout__brand\">\n @if (brandLogoSrc()) {\n <img class=\"kf-auth-layout__logo\" [src]=\"brandLogoSrc()\" [alt]=\"brand()\" />\n } @else {\n <span class=\"kf-auth-layout__wordmark\">{{ brand() }}</span>\n }\n @if (brandTagline()) {\n <p class=\"kf-auth-layout__tagline\">{{ brandTagline() }}</p>\n }\n</aside>\n\n<main class=\"kf-auth-layout__content\">\n <div class=\"kf-auth-layout__panel\" [class.kf-auth-layout__panel--card]=\"card()\">\n <div class=\"kf-auth-layout__mobile-brand\">\n @if (brandLogoMobileSrc() || brandLogoSrc()) {\n <img\n class=\"kf-auth-layout__logo kf-auth-layout__logo--mobile\"\n [src]=\"brandLogoMobileSrc() || brandLogoSrc()\"\n [alt]=\"brand()\"\n />\n } @else {\n <span class=\"kf-auth-layout__wordmark kf-auth-layout__wordmark--mobile\">{{ brand() }}</span>\n }\n </div>\n\n @if (title(); as headerTitle) {\n <div class=\"kf-auth-layout__header\">\n <kf-text as=\"h1\" variant=\"title-lg\">{{ headerTitle }}</kf-text>\n @if (subtitle(); as headerSubtitle) {\n <kf-text as=\"p\" variant=\"body-muted\">{{ headerSubtitle }}</kf-text>\n }\n </div>\n }\n\n <div class=\"kf-auth-layout__sso\">\n <ng-content select=\"[kfAuthLayoutSso]\" />\n </div>\n\n @if (ssoContent()) {\n <div class=\"kf-auth-layout__divider\">\n <kf-divider />\n <kf-text as=\"span\" variant=\"caption\" class=\"kf-auth-layout__divider-label\">o</kf-text>\n <kf-divider />\n </div>\n }\n\n <div class=\"kf-auth-layout__body\">\n <ng-content />\n </div>\n </div>\n</main>\n","import { Component, booleanAttribute, input, output } from '@angular/core';\nimport { Icon } from '@kaufmann-lab/ui/core';\n\n/**\n * Botón de cerrar sesión, pensado para proyectarse dentro de\n * `[kf-drawer-footer]` de `kf-drawer`, o junto a `kf-drawer-session` dentro\n * de `[kf-sidebar-footer]` de `kf-sidebar-shell` — separado de\n * `kf-drawer-session` (que solo muestra identidad: brand, avatar, nombre,\n * email), no anidado dentro de ella.\n *\n * Ícono `log-out` + label, color `--kf-color-error` con hover en\n * `--kf-color-error-soft` y foco visible con `--kf-shadow-focus`. Separado\n * de `kf-drawer-session` (solo identidad) por responsabilidad única.\n *\n * No sabe nada de autenticación real — solo emite `logoutClick` cuando el\n * consumidor debe cerrar la sesión real.\n *\n * `collapsed` oculta el label y centra el ícono, exponiéndolo vía `title`\n * — mismo criterio que `SidebarNavItem.collapsed` y\n * `DrawerSession.collapsed`, para cuando este botón vive dentro de un\n * `kf-sidebar-shell` colapsado.\n *\n * <kf-drawer-logout kf-portal-header-footer (logoutClick)=\"onLogout()\" />\n */\n@Component({\n selector: 'kf-drawer-logout',\n imports: [Icon],\n templateUrl: './DrawerLogout.html',\n styleUrl: './DrawerLogout.css',\n})\nexport class DrawerLogout {\n /** Label del botón, en español neutro por defecto. Input opcional por si\n * algún consumidor futuro necesita otro texto. */\n readonly label = input('Cerrar sesión');\n\n /** Oculta el label y centra el ícono — ver comentario de la clase. */\n readonly collapsed = input(false, { transform: booleanAttribute });\n\n readonly logoutClick = output<void>();\n}\n","<button\n type=\"button\"\n class=\"kf-drawer-logout__button\"\n [class.kf-drawer-logout__button--collapsed]=\"collapsed()\"\n [attr.title]=\"collapsed() ? label() : null\"\n (click)=\"logoutClick.emit()\"\n>\n <kf-icon name=\"log-out\" size=\"sm\" />\n @if (!collapsed()) {\n {{ label() }}\n }\n</button>\n","import { Component, booleanAttribute, computed, input, output } from '@angular/core';\nimport { Avatar, Icon } from '@kaufmann-lab/ui/core';\n\n/**\n * Bloque de identidad para `[kf-drawer-header]` de `kf-drawer` o\n * `[kf-sidebar-footer]` de `kf-sidebar-shell`: avatar + nombre + email,\n * brand opcional arriba. Solo identidad — el logout vive aparte, en\n * `kf-drawer-logout`.\n *\n * `collapsed` oculta brand/nombre/email y deja solo el avatar (para un\n * `kf-sidebar-shell` colapsado). `interactive` convierte la tarjeta en un\n * botón real que emite `cardClick`, para cuando la identidad es el\n * disparador de un menú de acciones (ej. envuelta en `kf-dropdown`).\n *\n * <kf-dropdown [(open)]=\"menuOpen\">\n * <kf-drawer-session interactive name=\"Juan Pérez\" email=\"juan@empresa.com\" (cardClick)=\"menuOpen.set(!menuOpen())\" />\n * <kf-dropdown-panel variant=\"dark\">\n * <kf-dropdown-item icon=\"log-out\" tone=\"error\" (click)=\"onLogout()\">Cerrar sesión</kf-dropdown-item>\n * </kf-dropdown-panel>\n * </kf-dropdown>\n */\n@Component({\n selector: 'kf-drawer-session',\n imports: [Avatar, Icon],\n templateUrl: './DrawerSession.html',\n styleUrl: './DrawerSession.css',\n})\nexport class DrawerSession {\n readonly name = input.required<string>();\n readonly email = input<string>('');\n /**\n * Etiqueta de rol o función del usuario dentro de la sesión (ej.\n * \"Coordinador\", \"Supervisor\"). Se muestra como badge dentro de la\n * identidad, debajo del email — distinto de `brand`, que es la marca o\n * cliente mostrada como encabezado de todo el bloque, no un atributo de\n * la persona.\n */\n readonly role = input<string>('');\n readonly initials = input<string>('');\n readonly avatarUrl = input<string>('');\n /** Label superior opcional, ej. \"Portal Kaufmann LATAM\". */\n readonly brand = input<string>('');\n\n /** Oculta brand/nombre/email y centra el avatar — ver comentario de la clase. */\n readonly collapsed = input(false, { transform: booleanAttribute });\n\n /** Convierte la tarjeta en un botón real con ícono de kebab — ver comentario de la clase. */\n readonly interactive = input(false, { transform: booleanAttribute });\n\n /** Se emite al clickear la tarjeta, solo cuando `interactive` es `true`. */\n readonly cardClick = output<void>();\n\n /** Si no se pasa `initials`, se derivan de `name`: primera letra de cada\n * una de las primeras 2 palabras, en mayúscula. */\n protected readonly displayInitials = computed(() => {\n const explicit = this.initials();\n if (explicit) {\n return explicit;\n }\n return this.name()\n .trim()\n .split(/\\s+/)\n .slice(0, 2)\n .map((word) => word.charAt(0).toUpperCase())\n .join('');\n });\n}\n","@if (brand() && !collapsed()) {\n <span class=\"kf-drawer-session__brand\">{{ brand() }}</span>\n}\n\n@if (interactive()) {\n <button\n type=\"button\"\n class=\"kf-drawer-session__card kf-drawer-session__card--interactive\"\n [class.kf-drawer-session__card--collapsed]=\"collapsed()\"\n (click)=\"cardClick.emit()\"\n >\n <kf-avatar [initials]=\"displayInitials()\" [src]=\"avatarUrl()\" />\n @if (!collapsed()) {\n <div class=\"kf-drawer-session__identity\">\n <span class=\"kf-drawer-session__name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"kf-drawer-session__email\">{{ email() }}</span>\n }\n @if (role()) {\n <span class=\"kf-drawer-session__role\">{{ role() }}</span>\n }\n </div>\n <kf-icon name=\"more-vertical\" size=\"sm\" />\n }\n </button>\n} @else {\n <div class=\"kf-drawer-session__card\" [class.kf-drawer-session__card--collapsed]=\"collapsed()\">\n <kf-avatar [initials]=\"displayInitials()\" [src]=\"avatarUrl()\" />\n @if (!collapsed()) {\n <div class=\"kf-drawer-session__identity\">\n <span class=\"kf-drawer-session__name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"kf-drawer-session__email\">{{ email() }}</span>\n }\n @if (role()) {\n <span class=\"kf-drawer-session__role\">{{ role() }}</span>\n }\n </div>\n }\n </div>\n}\n","import { booleanAttribute, Component, computed, input } from '@angular/core';\nimport { Spinner } from '@kaufmann-lab/ui/core';\n\nexport type SsoProvider = 'microsoft';\n\n/** Copy y glyph por proveedor — agregar una entrada acá es todo lo que hace\n * falta para soportar un proveedor nuevo (ej. `google`), sin tocar el\n * template ni los estilos del componente. */\ninterface SsoProviderConfig {\n readonly label: string;\n}\n\nconst PROVIDER_CONFIG: Record<SsoProvider, SsoProviderConfig> = {\n microsoft: { label: 'Continuar con Microsoft' },\n};\n\n/**\n * Botón de inicio de sesión vía SSO corporativo — pensado como pieza suelta,\n * no acoplada a `kf-auth-layout`: cualquier consumidor puede usarlo solo,\n * dentro o fuera del slot `[sso]` de `AuthLayout`.\n *\n * `provider` resuelve copy y glyph — hoy solo `'microsoft'` (el método\n * principal de acceso del ecosistema, cuenta corporativa de Grupo Kaufmann),\n * con la puerta abierta a sumar otros a futuro sin romper la API existente.\n *\n * El glyph es el ícono GENÉRICO de 4 cuadrados de colores que Microsoft\n * publica en sus propias guías de marca para botones de terceros (\"Sign in\n * with Microsoft\") — nunca el logotipo/wordmark oficial completo. No vive en\n * el sprite de `kf-icon` (`icon-sprite.ts`) a propósito: ese catálogo es\n * monocromático (`currentColor`, ver `Icon.ts`), pensado para trazos de un\n * solo color — este glyph necesita sus 4 colores fijos tal como los define\n * la guía de marca, así que un SVG inline propio es la opción correcta, no\n * un glyph nuevo forzado al sprite compartido.\n *\n * El label por defecto viene de `provider` — pasar contenido propio via\n * `<ng-content>` lo reemplaza (ej. un texto más corto en un lugar angosto).\n *\n * <kf-sso-button provider=\"microsoft\" (ssoClick)=\"loginWithMicrosoft()\" />\n * <kf-sso-button provider=\"microsoft\" [loading]=\"loggingIn()\">\n * Ingresar con cuenta corporativa\n * </kf-sso-button>\n */\n@Component({\n selector: 'kf-sso-button',\n imports: [Spinner],\n templateUrl: './SsoButton.html',\n styleUrl: './SsoButton.css',\n})\nexport class SsoButton {\n readonly provider = input<SsoProvider>('microsoft');\n readonly disabled = input(false, { transform: booleanAttribute });\n /** Reemplaza el glyph + label por `kf-spinner` y fuerza `disabled` — mismo\n * patrón que `kf-button[loading]`. */\n readonly loading = input(false, { transform: booleanAttribute });\n /** Igual que `kf-button`: por defecto `submit` dentro de un `<form>`, pero\n * este botón normalmente vive fuera de cualquier form (dispara un\n * redirect a Microsoft Entra ID), así que casi siempre conviene `button`. */\n readonly type = input<'button' | 'submit'>('button');\n\n protected readonly config = computed(() => PROVIDER_CONFIG[this.provider()]);\n}\n","<button\n class=\"kf-sso-button\"\n [type]=\"type()\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"config().label\"\n>\n @if (loading()) {\n <kf-spinner size=\"sm\" />\n } @else {\n <!--\n Ícono genérico \"Sign in with Microsoft\" de 4 cuadrados de colores\n (rojo, verde, azul, amarillo) — no el logotipo/wordmark oficial.\n Ver justificación completa en el JSDoc de SsoButton.ts.\n -->\n <svg\n class=\"kf-sso-button__glyph\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"0\" y=\"0\" width=\"8.5\" height=\"8.5\" fill=\"#f25022\" />\n <rect x=\"9.5\" y=\"0\" width=\"8.5\" height=\"8.5\" fill=\"#7fba00\" />\n <rect x=\"0\" y=\"9.5\" width=\"8.5\" height=\"8.5\" fill=\"#00a4ef\" />\n <rect x=\"9.5\" y=\"9.5\" width=\"8.5\" height=\"8.5\" fill=\"#ffb900\" />\n </svg>\n }\n <span class=\"kf-sso-button__label\">\n <ng-content>{{ config().label }}</ng-content>\n </span>\n</button>\n","/*\n * Public API Surface of ui/auth — entry point secundario, `@kaufmann-lab/ui/auth`.\n *\n * Piezas del flujo de login y de la identidad de sesión: el esqueleto de la\n * pantalla de login (`AuthLayout` + su slot `AuthLayoutSso`), el botón de\n * acceso por proveedor (`SsoButton`) y los bloques de sesión que se proyectan\n * en un `kf-drawer` (`DrawerSession`, `DrawerLogout`). Ver `ENTRY-POINTS.md`\n * en la raíz del repo para el criterio.\n *\n * `AdminBadge` NO vive acá aunque temáticamente encajaría: `PortalHeader`\n * (`@kaufmann-lab/ui/core`) lo compone, y un `AdminBadge` en `/auth` (que\n * importa `Icon`/`Text` de `/core`) cerraría el ciclo `/core` -> `/auth` ->\n * `/core`, que ng-packagr rechaza en build.\n *\n * Consume sus piezas base (`Avatar`, `Divider`, `Icon`, `Spinner`, `Text`)\n * desde `'@kaufmann-lab/ui/core'`, nunca desde la raíz `'@kaufmann-lab/ui'`\n * (agregador que depende de todos los entry points — importarla desde acá\n * cerraría un ciclo) ni por ruta relativa cruzando la frontera entre entry\n * points (ng-packagr calcula un `rootDir` propio por entry point y rechaza\n * archivos fuente fuera de él). La única ruta relativa cruzada es el `@use`\n * de SCSS de `AuthLayout.scss` hacia el parcial de breakpoints de `/core`:\n * se resuelve en compilación y no genera dependencia de runtime.\n *\n * La raíz `'@kaufmann-lab/ui'` los reexporta, así que\n * `import { AuthLayout } from '@kaufmann-lab/ui'` sigue funcionando igual.\n */\n\nexport * from './lib/auth-layout/AuthLayout';\nexport * from './lib/auth-layout/AuthLayoutSso';\nexport * from './lib/drawer-logout/DrawerLogout';\nexport * from './lib/drawer-session/DrawerSession';\nexport * from './lib/sso-button/SsoButton';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}