@brickclay-org/ui 0.0.49 → 0.0.51

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.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, EventEmitter, HostListener, ViewChildren, Output, Input, Injectable, NgModule, forwardRef, ViewEncapsulation, Optional, Self, Directive, ViewChild, input, model, output, signal, computed, effect, inject, ElementRef, InjectionToken } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { CommonModule } from '@angular/common';
4
+ import { CommonModule, NgClass } from '@angular/common';
5
5
  import * as i1$1 from '@angular/forms';
6
6
  import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
7
7
  import moment from 'moment';
@@ -11,7 +11,7 @@ import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
11
11
  import * as i1$2 from '@angular/cdk/scrolling';
12
12
  import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
13
13
  import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
14
- import { DIALOG_DATA as DIALOG_DATA$1, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
14
+ import { DIALOG_DATA, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
15
15
  import { Overlay, OverlayModule } from '@angular/cdk/overlay';
16
16
  import { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';
17
17
 
@@ -4336,8 +4336,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4336
4336
  * as before.
4337
4337
  *
4338
4338
  * • `INTERNAL_DIALOG_CONFIG` — Internal-only token used to pass our
4339
- * full `DialogConfig` (including animation fields) to the custom
4340
- * `DialogContainerComponent`. Not part of the public API.
4339
+ * full `BkDialogConfig` (including animation fields) to the custom
4340
+ * `BkDialogContainerComponent`. Not part of the public API.
4341
4341
  */
4342
4342
  // ──── Public ─────────────────────────────────────────────────────────────
4343
4343
  /**
@@ -4349,10 +4349,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4349
4349
  *
4350
4350
  * Usage inside a dialog component:
4351
4351
  * ```ts
4352
- * constructor(@Inject(DIALOG_DATA) public data: MyDataType) {}
4352
+ * constructor(@Inject(BK_DIALOG_DATA) public data: MyDataType) {}
4353
4353
  * ```
4354
4354
  */
4355
- const DIALOG_DATA = DIALOG_DATA$1;
4355
+ const BK_DIALOG_DATA = DIALOG_DATA;
4356
4356
  /**
4357
4357
  * Optional token for providing global dialog defaults at the
4358
4358
  * application level.
@@ -4360,19 +4360,19 @@ const DIALOG_DATA = DIALOG_DATA$1;
4360
4360
  * Usage in `app.config.ts` or a module's `providers` array:
4361
4361
  * ```ts
4362
4362
  * providers: [
4363
- * { provide: DIALOG_GLOBAL_CONFIG, useValue: { animation: 'zoom', width: '600px' } }
4363
+ * { provide: BK_DIALOG_GLOBAL_CONFIG, useValue: { animation: 'zoom', width: '600px' } }
4364
4364
  * ]
4365
4365
  * ```
4366
4366
  */
4367
- const DIALOG_GLOBAL_CONFIG = new InjectionToken('DIALOG_GLOBAL_CONFIG');
4367
+ const BK_DIALOG_GLOBAL_CONFIG = new InjectionToken('BK_DIALOG_GLOBAL_CONFIG');
4368
4368
  // ──── Internal ───────────────────────────────────────────────────────────
4369
4369
  /**
4370
- * Internal token that carries our full `DialogConfig` (with animation
4371
- * settings, position offsets, etc.) into the `DialogContainerComponent`.
4370
+ * Internal token that carries our full `BkDialogConfig` (with animation
4371
+ * settings, position offsets, etc.) into the `BkDialogContainerComponent`.
4372
4372
  *
4373
4373
  * @internal — not exported from the barrel; do not depend on it.
4374
4374
  */
4375
- const INTERNAL_DIALOG_CONFIG = new InjectionToken('INTERNAL_DIALOG_CONFIG');
4375
+ const BK_INTERNAL_DIALOG_CONFIG = new InjectionToken('BK_INTERNAL_DIALOG_CONFIG');
4376
4376
 
4377
4377
  /**
4378
4378
  * Dialog Animations
@@ -4387,7 +4387,7 @@ const INTERNAL_DIALOG_CONFIG = new InjectionToken('INTERNAL_DIALOG_CONFIG');
4387
4387
  * 3. Future presets can be added without touching the component template.
4388
4388
  *
4389
4389
  * Each preset exports an `enter` and `leave` keyframe array plus a
4390
- * recommended timing object. The DialogContainerComponent plays these
4390
+ * recommended timing object. The BkDialogContainerComponent plays these
4391
4391
  * via `element.animate()`.
4392
4392
  */
4393
4393
  /**
@@ -4539,7 +4539,7 @@ function getDialogBackdropAnimation(enterDuration, leaveDuration) {
4539
4539
  }
4540
4540
 
4541
4541
  /**
4542
- * DialogContainerComponent
4542
+ * BkDialogContainerComponent
4543
4543
  *
4544
4544
  * Architecture Decision:
4545
4545
  * ─────────────────────
@@ -4559,19 +4559,19 @@ function getDialogBackdropAnimation(enterDuration, leaveDuration) {
4559
4559
  * • Position-offset application via CSS margin.
4560
4560
  *
4561
4561
  * This component is **never** used directly — it is created internally
4562
- * by `DialogService` via CDK's `Dialog.open()`.
4562
+ * by `BkDialogService` via CDK's `Dialog.open()`.
4563
4563
  */
4564
- class DialogContainerComponent extends CdkDialogContainer {
4564
+ class BkDialogContainerComponent extends CdkDialogContainer {
4565
4565
  /**
4566
4566
  * Our full config (including animation fields).
4567
- * Provided by DialogService via the INTERNAL_DIALOG_CONFIG token.
4567
+ * Provided by BkDialogService via the INTERNAL_DIALOG_CONFIG token.
4568
4568
  */
4569
- _dialogConfig = inject(INTERNAL_DIALOG_CONFIG);
4569
+ _dialogConfig = inject(BK_INTERNAL_DIALOG_CONFIG);
4570
4570
  // ──── Opened promise ─────────────────────────────────────────────────
4571
4571
  /**
4572
4572
  * Resolves when the enter animation finishes (or immediately for 'none').
4573
- * `DialogService` subscribes via `.then()` to emit `afterOpened` on the
4574
- * `DialogRef`.
4573
+ * `BkDialogService` subscribes via `.then()` to emit `afterOpened` on the
4574
+ * `BkDialogRef`.
4575
4575
  */
4576
4576
  _resolveOpened;
4577
4577
  opened = new Promise(resolve => {
@@ -4629,7 +4629,7 @@ class DialogContainerComponent extends CdkDialogContainer {
4629
4629
  }
4630
4630
  /**
4631
4631
  * Play the leave animation. Returns a Promise that resolves when done.
4632
- * Called by `DialogRef._runCloseSequence()` before CDK tears down the
4632
+ * Called by `BkDialogRef._runCloseSequence()` before CDK tears down the
4633
4633
  * overlay.
4634
4634
  */
4635
4635
  playLeaveAnimation() {
@@ -4681,10 +4681,10 @@ class DialogContainerComponent extends CdkDialogContainer {
4681
4681
  const pane = this._elementRef.nativeElement.closest('.cdk-overlay-pane');
4682
4682
  return pane?.parentElement?.querySelector('.cdk-overlay-backdrop') ?? null;
4683
4683
  }
4684
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogContainerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
4685
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: DialogContainerComponent, isStandalone: true, selector: "bk-dialog-container", host: { classAttribute: "bk-dialog-container" }, usesInheritance: true, ngImport: i0, template: "<!--\r\n Dialog Container Template (CDK-based)\r\n\r\n Architecture:\r\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n CDK Overlay manages the full overlay stack:\r\n\r\n \u250C\u2500 .cdk-overlay-container (fixed, z-index managed by CDK) \u2500\u2500\u2500\u2500\u2500\u2500\u2510\r\n \u2502 \u250C\u2500 .cdk-global-overlay-wrapper (flex-center) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\r\n \u2502 \u2502 .cdk-overlay-backdrop (click \u2192 close, CDK transition) \u2502 \u2502\r\n \u2502 \u2502 \u250C\u2500 .cdk-overlay-pane (width/height from config) \u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <bk-dialog-container> \u2190 this component (panel) \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <ng-template cdkPortalOutlet /> \u2190 user component \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <UserDialogComponent> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <h2 bk-dialog-title>Title</h2> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <div bk-dialog-content>Scrollable body</div> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <div bk-dialog-actions>Pinned buttons</div> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 </UserDialogComponent> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 </bk-dialog-container> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\r\n \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\r\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\r\n\r\n The host element IS the visible panel (background, radius, shadow).\r\n CDK Portal projects the caller's component as a direct child.\r\n\r\n Directives (BkDialogTitle, BkDialogContent, BkDialogActions, BkDialogClose)\r\n apply the corresponding CSS classes and add accessibility features.\r\n-->\r\n\r\n<ng-template cdkPortalOutlet />\r\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;max-height:inherit;background:var(--bk-dialog-panel-bg, #ffffff);border-radius:var(--bk-dialog-panel-radius, 8px);box-shadow:var( --bk-dialog-panel-shadow, 0 11px 15px -7px rgba(0, 0, 0, .2), 0 24px 38px 3px rgba(0, 0, 0, .14), 0 9px 46px 8px rgba(0, 0, 0, .12) );outline:0;box-sizing:border-box;overflow:hidden;will-change:transform,opacity}:host ::ng-deep>:first-child{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden}:host ::ng-deep .bk-dialog-content{flex:1 1 auto;overflow:auto;min-height:0;display:block;-webkit-overflow-scrolling:touch}:host ::ng-deep .bk-dialog-actions{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;min-height:52px}:host ::ng-deep .bk-dialog-title{flex:0 0 auto;margin:0}:host ::ng-deep .bk-dialog-actions-align-start{justify-content:flex-start}:host ::ng-deep .bk-dialog-actions-align-center{justify-content:center}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] });
4684
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContainerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
4685
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContainerComponent, isStandalone: true, selector: "bk-dialog-container", host: { classAttribute: "bk-dialog-container" }, usesInheritance: true, ngImport: i0, template: "<!--\r\n Dialog Container Template (CDK-based)\r\n\r\n Architecture:\r\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n CDK Overlay manages the full overlay stack:\r\n\r\n \u250C\u2500 .cdk-overlay-container (fixed, z-index managed by CDK) \u2500\u2500\u2500\u2500\u2500\u2500\u2510\r\n \u2502 \u250C\u2500 .cdk-global-overlay-wrapper (flex-center) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\r\n \u2502 \u2502 .cdk-overlay-backdrop (click \u2192 close, CDK transition) \u2502 \u2502\r\n \u2502 \u2502 \u250C\u2500 .cdk-overlay-pane (width/height from config) \u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <bk-dialog-container> \u2190 this component (panel) \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <ng-template cdkPortalOutlet /> \u2190 user component \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <UserDialogComponent> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <h2 bk-dialog-title>Title</h2> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <div bk-dialog-content>Scrollable body</div> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 <div bk-dialog-actions>Pinned buttons</div> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 </UserDialogComponent> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2502 </bk-dialog-container> \u2502 \u2502 \u2502\r\n \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\r\n \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\r\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\r\n\r\n The host element IS the visible panel (background, radius, shadow).\r\n CDK Portal projects the caller's component as a direct child.\r\n\r\n Directives (BkDialogTitle, BkDialogContent, BkDialogActions, BkDialogClose)\r\n apply the corresponding CSS classes and add accessibility features.\r\n-->\r\n\r\n<ng-template cdkPortalOutlet />\r\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;max-height:inherit;background:var(--bk-dialog-panel-bg, #ffffff);border-radius:var(--bk-dialog-panel-radius, 8px);box-shadow:var( --bk-dialog-panel-shadow, 0 11px 15px -7px rgba(0, 0, 0, .2), 0 24px 38px 3px rgba(0, 0, 0, .14), 0 9px 46px 8px rgba(0, 0, 0, .12) );outline:0;box-sizing:border-box;overflow:hidden;will-change:transform,opacity}:host ::ng-deep>:first-child{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden}:host ::ng-deep .bk-dialog-content{flex:1 1 auto;overflow:auto;min-height:0;display:block;-webkit-overflow-scrolling:touch}:host ::ng-deep .bk-dialog-actions{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;min-height:52px}:host ::ng-deep .bk-dialog-title{flex:0 0 auto;margin:0}:host ::ng-deep .bk-dialog-actions-align-start{justify-content:flex-start}:host ::ng-deep .bk-dialog-actions-align-center{justify-content:center}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] });
4686
4686
  }
4687
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogContainerComponent, decorators: [{
4687
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContainerComponent, decorators: [{
4688
4688
  type: Component,
4689
4689
  args: [{ selector: 'bk-dialog-container', standalone: true, imports: [CdkPortalOutlet], host: {
4690
4690
  'class': 'bk-dialog-container',
@@ -4692,7 +4692,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4692
4692
  }] });
4693
4693
 
4694
4694
  /**
4695
- * DialogRef — Handle returned to callers by `DialogService.open()`.
4695
+ * BkDialogRef — Handle returned to callers by `BkDialogService.open()`.
4696
4696
  *
4697
4697
  * Architecture Decision:
4698
4698
  * ─────────────────────
@@ -4707,13 +4707,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4707
4707
  * Ours keeps `<T, R>` (Component first, Result second) to match the
4708
4708
  * convention consumers already use.
4709
4709
  */
4710
- class DialogRef {
4710
+ class BkDialogRef {
4711
4711
  _cdkRef;
4712
4712
  /** Unique dialog identifier (managed by CDK). */
4713
4713
  id;
4714
4714
  /** Instance of the component rendered inside the dialog. */
4715
4715
  componentInstance;
4716
- // ──── Internal wiring (set by DialogService) ──────────────────────────
4716
+ // ──── Internal wiring (set by BkDialogService) ──────────────────────────
4717
4717
  /** @internal Container reference for leave animation. */
4718
4718
  _containerInstance;
4719
4719
  /** @internal Prevent double-close. */
@@ -4791,14 +4791,14 @@ class DialogRef {
4791
4791
  *
4792
4792
  * Architecture Decision:
4793
4793
  * ─────────────────────
4794
- * Our `DialogConfig` mirrors the fields from CDK's `DialogConfig` that we
4794
+ * Our `BkDialogConfig` mirrors the fields from CDK's `DialogConfig` that we
4795
4795
  * expose, plus adds custom animation properties powered by WAAPI.
4796
4796
  *
4797
- * When `DialogService.open()` is called these values are:
4797
+ * When `BkDialogService.open()` is called these values are:
4798
4798
  * 1. Merged with global defaults and per-call overrides.
4799
4799
  * 2. Mapped onto CDK's native `DialogConfig` for overlay, backdrop, scroll,
4800
4800
  * position, ARIA, and focus-trap management.
4801
- * 3. Passed to `DialogContainerComponent` via an internal token for
4801
+ * 3. Passed to `BkDialogContainerComponent` via an internal token for
4802
4802
  * animation playback and position offsets.
4803
4803
  *
4804
4804
  * CDK handles: unique IDs, z-index stacking, scroll blocking, focus trap,
@@ -4806,7 +4806,7 @@ class DialogRef {
4806
4806
  * We handle: WAAPI animations, panel appearance, convenience config sugar.
4807
4807
  */
4808
4808
  // ──── Defaults ───────────────────────────────────────────────────────────
4809
- const DEFAULT_DIALOG_CONFIG = {
4809
+ const BK_DEFAULT_DIALOG_CONFIG = {
4810
4810
  id: undefined,
4811
4811
  width: undefined,
4812
4812
  height: undefined,
@@ -4836,7 +4836,7 @@ const DEFAULT_DIALOG_CONFIG = {
4836
4836
  };
4837
4837
 
4838
4838
  /**
4839
- * DialogService — The core engine of the custom dialog system.
4839
+ * BkDialogService — The core engine of the custom dialog system.
4840
4840
  *
4841
4841
  * Architecture Decision:
4842
4842
  * ─────────────────────
@@ -4847,10 +4847,10 @@ const DEFAULT_DIALOG_CONFIG = {
4847
4847
  * z-index stacking, and unique ID management — battle-tested infra
4848
4848
  * shared with every Angular Material dialog in the ecosystem.
4849
4849
  *
4850
- * 2. We provide our own `DialogContainerComponent` (extending
4850
+ * 2. We provide our own `BkDialogContainerComponent` (extending
4851
4851
  * `CdkDialogContainer`) for WAAPI animations and panel styling.
4852
4852
  *
4853
- * 3. We wrap CDK's `DialogRef` in our own `DialogRef` to add the
4853
+ * 3. We wrap CDK's `DialogRef` in our own `BkDialogRef` to add the
4854
4854
  * leave-animation step before CDK tears down the overlay, and to
4855
4855
  * expose the same familiar API shape (`afterClosed()`, etc.).
4856
4856
  *
@@ -4873,13 +4873,13 @@ const DEFAULT_DIALOG_CONFIG = {
4873
4873
  * ─────────────
4874
4874
  * CDK manages the full lifecycle: on close it detaches the overlay,
4875
4875
  * destroys the container, and disposes the overlay ref.
4876
- * Our DialogRef subjects complete via CDK's `closed` observable,
4876
+ * Our BkDialogRef subjects complete via CDK's `closed` observable,
4877
4877
  * preventing lingering subscriptions.
4878
4878
  */
4879
- class DialogService {
4879
+ class BkDialogService {
4880
4880
  _cdkDialog = inject(Dialog);
4881
4881
  _overlay = inject(Overlay);
4882
- _globalConfig = inject(DIALOG_GLOBAL_CONFIG, { optional: true });
4882
+ _globalConfig = inject(BK_DIALOG_GLOBAL_CONFIG, { optional: true });
4883
4883
  /** Stack of currently open dialog refs (most recent = last). */
4884
4884
  _openDialogRefs = [];
4885
4885
  // ════════════════════════════════════════════════════════════════════
@@ -4891,7 +4891,7 @@ class DialogService {
4891
4891
  * @param component The component class to render inside the dialog.
4892
4892
  * @param config Optional per-dialog configuration (merged on top
4893
4893
  * of global and default settings).
4894
- * @returns A strongly-typed `DialogRef` to interact with.
4894
+ * @returns A strongly-typed `BkDialogRef` to interact with.
4895
4895
  *
4896
4896
  * @example
4897
4897
  * ```ts
@@ -4905,7 +4905,7 @@ class DialogService {
4905
4905
  open(component, config) {
4906
4906
  // ── 1. Merge configs: DEFAULT ← GLOBAL ← per-call ──────────────
4907
4907
  const mergedConfig = {
4908
- ...DEFAULT_DIALOG_CONFIG,
4908
+ ...BK_DEFAULT_DIALOG_CONFIG,
4909
4909
  ...(this._globalConfig ?? {}),
4910
4910
  ...(config ?? {}),
4911
4911
  };
@@ -4947,23 +4947,23 @@ class DialogService {
4947
4947
  positionStrategy: this._buildPositionStrategy(mergedConfig),
4948
4948
  // ── Custom container ──────────────────────────────────────────
4949
4949
  container: {
4950
- type: DialogContainerComponent,
4950
+ type: BkDialogContainerComponent,
4951
4951
  providers: () => [
4952
- { provide: INTERNAL_DIALOG_CONFIG, useValue: mergedConfig },
4952
+ { provide: BK_INTERNAL_DIALOG_CONFIG, useValue: mergedConfig },
4953
4953
  ],
4954
4954
  },
4955
4955
  // ── Provider callback ─────────────────────────────────────────
4956
4956
  // Runs after the container is created but before the user
4957
- // component. We create our `DialogRef` wrapper here and make
4957
+ // component. We create our `BkDialogRef` wrapper here and make
4958
4958
  // it available for injection in the user component.
4959
4959
  providers: (cdkRef, _cdkConfig, containerInstance) => {
4960
- ourRef = new DialogRef(cdkRef);
4960
+ ourRef = new BkDialogRef(cdkRef);
4961
4961
  ourRef._containerInstance = containerInstance;
4962
4962
  // Wire up afterOpened emission.
4963
4963
  containerInstance.opened
4964
4964
  .then(() => ourRef._emitOpened());
4965
4965
  return [
4966
- { provide: DialogRef, useValue: ourRef },
4966
+ { provide: BkDialogRef, useValue: ourRef },
4967
4967
  ];
4968
4968
  },
4969
4969
  };
@@ -4992,7 +4992,7 @@ class DialogService {
4992
4992
  }
4993
4993
  }
4994
4994
  /**
4995
- * Returns the `DialogRef` of the most recently opened dialog,
4995
+ * Returns the `BkDialogRef` of the most recently opened dialog,
4996
4996
  * or `undefined` if none are open.
4997
4997
  */
4998
4998
  getTopDialog() {
@@ -5013,7 +5013,7 @@ class DialogService {
5013
5013
  /**
5014
5014
  * Read-only snapshot of currently open dialog refs.
5015
5015
  * Used internally by content directives (`BkDialogTitle`, `BkDialogActions`,
5016
- * `BkDialogClose`) for the DOM-walk fallback when `DialogRef` is not
5016
+ * `BkDialogClose`) for the DOM-walk fallback when `BkDialogRef` is not
5017
5017
  * available via injection (e.g. inside `<ng-template>`).
5018
5018
  */
5019
5019
  get openDialogsRef() {
@@ -5135,10 +5135,10 @@ class DialogService {
5135
5135
  }
5136
5136
  return strategy;
5137
5137
  }
5138
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5139
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogService, providedIn: 'root' });
5138
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5139
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogService, providedIn: 'root' });
5140
5140
  }
5141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogService, decorators: [{
5141
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogService, decorators: [{
5142
5142
  type: Injectable,
5143
5143
  args: [{ providedIn: 'root' }]
5144
5144
  }] });
@@ -5172,7 +5172,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5172
5172
  let nextTitleId = 0;
5173
5173
  // ──── Helper ─────────────────────────────────────────────────────────────
5174
5174
  /**
5175
- * Finds the closest `DialogRef` by walking up the DOM from the given
5175
+ * Finds the closest `BkDialogRef` by walking up the DOM from the given
5176
5176
  * element to the nearest `bk-dialog-container` host, then matching its
5177
5177
  * `id` attribute against the currently open dialogs.
5178
5178
  *
@@ -5193,15 +5193,15 @@ function getClosestDialog(element, openDialogs) {
5193
5193
  }
5194
5194
  // ──── Base for Title / Actions ───────────────────────────────────────────
5195
5195
  /**
5196
- * Shared abstract base that resolves the owning `DialogRef` (via DI or
5196
+ * Shared abstract base that resolves the owning `BkDialogRef` (via DI or
5197
5197
  * DOM walk) and invokes `_onAdd()` / `_onRemove()` lifecycle hooks.
5198
5198
  *
5199
5199
  * Same pattern as Material's internal `MatDialogLayoutSection`.
5200
5200
  */
5201
5201
  class BkDialogLayoutSection {
5202
- _dialogRef = inject(DialogRef, { optional: true });
5202
+ _dialogRef = inject(BkDialogRef, { optional: true });
5203
5203
  _elementRef = inject((ElementRef));
5204
- _dialogService = inject(DialogService);
5204
+ _dialogService = inject(BkDialogService);
5205
5205
  ngOnInit() {
5206
5206
  if (!this._dialogRef) {
5207
5207
  this._dialogRef = getClosestDialog(this._elementRef, this._dialogService.openDialogsRef);
@@ -5375,9 +5375,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5375
5375
  * ```
5376
5376
  */
5377
5377
  class BkDialogClose {
5378
- _dialogRef = inject(DialogRef, { optional: true });
5378
+ _dialogRef = inject(BkDialogRef, { optional: true });
5379
5379
  _elementRef = inject((ElementRef));
5380
- _dialogService = inject(DialogService);
5380
+ _dialogService = inject(BkDialogService);
5381
5381
  /** Screen-reader label for the button. */
5382
5382
  ariaLabel;
5383
5383
  /** Prevents accidental form submits. Default: `'button'`. */
@@ -5440,7 +5440,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5440
5440
  *
5441
5441
  * • All components/directives are **standalone**.
5442
5442
  * • This module simply imports + re-exports them for convenience.
5443
- * • `DialogService` is `providedIn: 'root'`, so it does NOT need to
5443
+ * • `BkDialogService` is `providedIn: 'root'`, so it does NOT need to
5444
5444
  * be listed in `providers` here — it is tree-shakeable and available
5445
5445
  * app-wide automatically.
5446
5446
  *
@@ -5473,7 +5473,7 @@ class BkDialogModule {
5473
5473
  OverlayModule,
5474
5474
  PortalModule,
5475
5475
  // ── Our standalone pieces ───────────────────────────────────────
5476
- DialogContainerComponent,
5476
+ BkDialogContainerComponent,
5477
5477
  BkDialogTitle,
5478
5478
  BkDialogContent,
5479
5479
  BkDialogActions,
@@ -5500,7 +5500,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5500
5500
  OverlayModule,
5501
5501
  PortalModule,
5502
5502
  // ── Our standalone pieces ───────────────────────────────────────
5503
- DialogContainerComponent,
5503
+ BkDialogContainerComponent,
5504
5504
  BkDialogTitle,
5505
5505
  BkDialogContent,
5506
5506
  BkDialogActions,
@@ -5543,6 +5543,231 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5543
5543
  type: Input
5544
5544
  }] } });
5545
5545
 
5546
+ class AvatarProfile {
5547
+ // ---------- Display inputs ----------
5548
+ src = null;
5549
+ alt = 'Avatar';
5550
+ name = '';
5551
+ size = 'md';
5552
+ fallback = 'auto';
5553
+ // ---------- Functional inputs ----------
5554
+ /** Whether upload / remove actions are enabled */
5555
+ editable = true;
5556
+ /** Accepted file MIME types for the file picker */
5557
+ accept = 'image/jpeg, image/png';
5558
+ /** Max file size in KB (0 = no limit) */
5559
+ maxFileSizeKB = 0;
5560
+ /** Label shown on the upload button */
5561
+ uploadLabel = 'Upload';
5562
+ /** Hint text shown below the upload button */
5563
+ hint = '500x500 JPEG, PNG Image';
5564
+ /** External loading state (e.g. while uploading) */
5565
+ loading = false;
5566
+ /** Whether the remove badge is shown when an image is present */
5567
+ removable = false;
5568
+ // ---------- Form / CVA inputs ----------
5569
+ /** Label displayed above the avatar */
5570
+ label = '';
5571
+ /** Whether the field is required (shows asterisk) */
5572
+ required = false;
5573
+ /** External error state flag */
5574
+ hasError = false;
5575
+ /** Error message to display when hasError is true */
5576
+ errorMessage = '';
5577
+ /** Disabled state (also set via CVA setDisabledState) */
5578
+ disabled = false;
5579
+ // ---------- Outputs ----------
5580
+ /** Emits the selected File after validation passes */
5581
+ fileSelected = new EventEmitter();
5582
+ /** Emits when the user clicks the remove badge */
5583
+ removed = new EventEmitter();
5584
+ /** Emits a human-readable error string on validation failure */
5585
+ fileError = new EventEmitter();
5586
+ initials = '';
5587
+ imageLoadFailed = false;
5588
+ /** Local blob URL for instant preview before server upload completes */
5589
+ previewUrl = null;
5590
+ // ---------- CVA Callbacks ----------
5591
+ onChange = (_value) => { };
5592
+ onTouched = () => { };
5593
+ writeValue(value) {
5594
+ this.src = value || null;
5595
+ // When a new value arrives from the form (e.g. server URL after upload),
5596
+ // discard any stale local blob preview so displaySrc uses the real URL
5597
+ this.revokePreview();
5598
+ this.imageLoadFailed = false;
5599
+ }
5600
+ registerOnChange(fn) {
5601
+ this.onChange = fn;
5602
+ }
5603
+ registerOnTouched(fn) {
5604
+ this.onTouched = fn;
5605
+ }
5606
+ setDisabledState(isDisabled) {
5607
+ this.disabled = isDisabled;
5608
+ this.editable = !isDisabled;
5609
+ }
5610
+ // ---------- Lifecycle ----------
5611
+ ngOnChanges(changes) {
5612
+ if (this.name) {
5613
+ this.initials = this.getInitials(this.name);
5614
+ }
5615
+ this.imageLoadFailed = false;
5616
+ // When the parent updates [src] via @Input (non-CVA usage), discard the local preview
5617
+ if (changes['src'] && this.previewUrl) {
5618
+ this.revokePreview();
5619
+ }
5620
+ }
5621
+ ngOnDestroy() {
5622
+ this.revokePreview();
5623
+ }
5624
+ onImageError() {
5625
+ this.imageLoadFailed = true;
5626
+ }
5627
+ // ---------- Derived UI ----------
5628
+ /** The URL the template should display — local preview takes priority over the server src */
5629
+ get displaySrc() {
5630
+ return this.previewUrl ?? this.src;
5631
+ }
5632
+ get showInitials() {
5633
+ if (!this.name)
5634
+ return false;
5635
+ if (this.fallback === 'icon')
5636
+ return false;
5637
+ if (this.fallback === 'camera')
5638
+ return false;
5639
+ if (this.fallback === 'initials')
5640
+ return true;
5641
+ return true; // auto
5642
+ }
5643
+ get containerClasses() {
5644
+ return ['avatar-profile', this.size].join(' ');
5645
+ }
5646
+ get sizeClasses() {
5647
+ return [this.size];
5648
+ }
5649
+ get showRemoveButton() {
5650
+ return this.removable && this.editable && !!(this.displaySrc) && !this.imageLoadFailed;
5651
+ }
5652
+ // ---------- File handling ----------
5653
+ onFileSelected(event) {
5654
+ const input = event.target;
5655
+ if (!input.files?.length)
5656
+ return;
5657
+ const file = input.files[0];
5658
+ // Validate file type
5659
+ if (this.accept && !this.isFileTypeValid(file)) {
5660
+ this.fileError.emit(`Invalid file type. Accepted: ${this.accept}`);
5661
+ input.value = '';
5662
+ return;
5663
+ }
5664
+ // Validate file size
5665
+ if (this.maxFileSizeKB > 0 && file.size > this.maxFileSizeKB * 1024) {
5666
+ this.fileError.emit(`File size exceeds ${this.maxFileSizeKB}KB limit.`);
5667
+ input.value = '';
5668
+ return;
5669
+ }
5670
+ // Instant local preview — no server round-trip needed to show the image
5671
+ this.revokePreview();
5672
+ this.previewUrl = URL.createObjectURL(file);
5673
+ this.imageLoadFailed = false;
5674
+ // Push the preview URL as the form value so validation (e.g. required) passes
5675
+ this.onChange(this.previewUrl);
5676
+ this.onTouched();
5677
+ this.fileSelected.emit(event);
5678
+ input.value = ''; // reset so re-selecting the same file still triggers change
5679
+ }
5680
+ onRemove() {
5681
+ this.revokePreview();
5682
+ this.src = null;
5683
+ this.onChange(null);
5684
+ this.onTouched();
5685
+ this.removed.emit();
5686
+ }
5687
+ // ---------- Utils ----------
5688
+ /** Revoke the previous object URL to free memory */
5689
+ revokePreview() {
5690
+ if (this.previewUrl) {
5691
+ URL.revokeObjectURL(this.previewUrl);
5692
+ this.previewUrl = null;
5693
+ }
5694
+ }
5695
+ isFileTypeValid(file) {
5696
+ const accepted = this.accept.split(',').map(t => t.trim());
5697
+ return accepted.some(type => {
5698
+ if (type.endsWith('/*')) {
5699
+ return file.type.startsWith(type.replace('/*', '/'));
5700
+ }
5701
+ return file.type === type;
5702
+ });
5703
+ }
5704
+ getInitials(name) {
5705
+ const parts = name.trim().split(/\s+/);
5706
+ if (parts.length === 1) {
5707
+ return parts[0].slice(0, 2).toUpperCase();
5708
+ }
5709
+ return (parts[0][0] + parts.at(-1)[0]).toUpperCase();
5710
+ }
5711
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AvatarProfile, deps: [], target: i0.ɵɵFactoryTarget.Component });
5712
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AvatarProfile, isStandalone: true, selector: "bk-avatar-profile", inputs: { src: "src", alt: "alt", name: "name", size: "size", fallback: "fallback", editable: "editable", accept: "accept", maxFileSizeKB: "maxFileSizeKB", uploadLabel: "uploadLabel", hint: "hint", loading: "loading", removable: "removable", label: "label", required: "required", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled" }, outputs: { fileSelected: "fileSelected", removed: "removed", fileError: "fileError" }, providers: [
5713
+ {
5714
+ provide: NG_VALUE_ACCESSOR,
5715
+ useExisting: forwardRef(() => AvatarProfile),
5716
+ multi: true
5717
+ }
5718
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"avatar-profile-container\" [ngClass]=\"sizeClasses\">\r\n @if (label) {\r\n <label class=\"avatar-profile-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"avatar-profile-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"flex gap-4 justify-end\">\r\n <div\r\n [ngClass]=\"containerClasses\"\r\n [bkTooltip]=\"name\"\r\n [bkTooltipPosition]=\"'top'\"\r\n >\r\n\r\n <!-- Loading overlay -->\r\n @if (loading) {\r\n <div class=\"absolute inset-0 flex items-center justify-center z-10 rounded-full bg-white/60\">\r\n <div class=\"w-5 h-5 border-2 border-[#141414] border-t-transparent rounded-full animate-spin\"></div>\r\n </div>\r\n }\r\n\r\n @if (displaySrc && !imageLoadFailed) {\r\n <img\r\n [src]=\"displaySrc\"\r\n [alt]=\"alt\"\r\n class=\"avatar-img\"\r\n (error)=\"onImageError()\"\r\n />\r\n }\r\n\r\n @else if (fallback === 'camera') {\r\n <svg class=\"placeholder-icon\" width=\"23\" height=\"24\" viewBox=\"0 0 23 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18.3843 4.66667C17.6726 4.66667 17.0193 4.25833 16.6926 3.62833L15.8526 1.93667C15.316 0.875 13.916 0 12.726 0H10.0543C8.85264 0 7.45264 0.875 6.91598 1.93667L6.07598 3.62833C5.74931 4.25833 5.09598 4.66667 4.38431 4.66667C1.85264 4.66667 -0.154023 6.80167 0.00931005 9.32167L0.615977 18.9583C0.755977 21.3617 2.05098 23.3333 5.27098 23.3333H17.4976C20.7176 23.3333 22.001 21.3617 22.1526 18.9583L22.7593 9.32167C22.9226 6.80167 20.916 4.66667 18.3843 4.66667ZM9.63431 6.125H13.1343C13.6126 6.125 14.0093 6.52167 14.0093 7C14.0093 7.47833 13.6126 7.875 13.1343 7.875H9.63431C9.15598 7.875 8.75931 7.47833 8.75931 7C8.75931 6.52167 9.15598 6.125 9.63431 6.125ZM11.3843 18.8067C9.21431 18.8067 7.44098 17.045 7.44098 14.8633C7.44098 12.6817 9.20264 10.92 11.3843 10.92C13.566 10.92 15.3276 12.6817 15.3276 14.8633C15.3276 17.045 13.5543 18.8067 11.3843 18.8067Z\" fill=\"#6B7080\"/>\r\n </svg>\r\n }\r\n\r\n @else if (showInitials) {\r\n <span class=\"avatar-text\">\r\n {{ initials }}\r\n </span>\r\n }\r\n\r\n @else {\r\n <svg class=\"placeholder-icon\" viewBox=\"0 0 32 32\" fill=\"none\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" > <g clip-path=\"url(#clip0)\"> <path d=\"M16 16c3.682 0 6.667-2.985 6.667-6.667S19.682 2.667 16 2.667 9.333 5.651 9.333 9.333 12.318 16 16 16Z\" stroke=\"#363C51\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" /> <path d=\"M27.453 29.333C27.453 24.173 22.32 20 16 20S4.547 24.173 4.547 29.333\" stroke=\"#363C51\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" /> </g> <defs> <clipPath id=\"clip0\"> <rect width=\"32\" height=\"32\" fill=\"white\" /> </clipPath> </defs> </svg>\r\n }\r\n\r\n <!-- Remove badge -->\r\n @if (showRemoveButton) {\r\n <button\r\n type=\"button\"\r\n class=\"remove-badge\"\r\n (click)=\"onRemove()\"\r\n aria-label=\"Remove avatar\"\r\n >\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M1 1L9 9M9 1L1 9\" stroke=\"#6B7080\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\r\n </svg>\r\n </button>\r\n }\r\n\r\n </div>\r\n <div class=\"flex flex-col gap-2 justify-end items-start\">\r\n @if (editable) {\r\n <label class=\"upload-button cursor-pointer\">\r\n {{ uploadLabel }}\r\n <input\r\n type=\"file\"\r\n class=\"hidden\"\r\n [accept]=\"accept\"\r\n [disabled]=\"disabled\"\r\n (change)=\"onFileSelected($event)\"\r\n />\r\n </label>\r\n }\r\n @if (!hasError && hint) {\r\n <p class=\"profile-size\">{{ hint }}</p>\r\n }\r\n @if (hasError && errorMessage) {\r\n <p class=\"avatar-profile-error\">{{ errorMessage }}</p>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".avatar-profile-container{@apply flex flex-col gap-1.5;}.avatar-profile-label{@apply text-sm font-medium text-[#141414];}.avatar-profile-label-required{@apply text-[#E7000B] ml-0.5;}.avatar-profile-error{@apply text-xs text-[#E7000B] font-normal;}.avatar-profile{@apply relative inline-flex items-center justify-center rounded-full flex-shrink-0 select-none shadow-lg transition-all duration-200 border-[3px] border-white bg-[#F9FAFA];}.avatar-profile .avatar-img{@apply w-full h-full object-cover rounded-full;}.upload-button{@apply font-medium text-[#6B7080] border border-[#E3E3E7] rounded shadow-sm;}.sm .upload-button{@apply text-[12px] leading-[18px] px-2 py-3;}.md .upload-button{@apply text-[14px] leading-[20px] px-[10px] py-2.5;}.lg .upload-button{@apply text-[16px] leading-[24px] px-[18px] py-2.5;}.xl .upload-button{@apply text-[16px] leading-[24px] px-5 py-3;}.profile-size{@apply font-medium text-[#6B7080];}.sm .profile-size{@apply text-[10px] leading-[14px];}.md .profile-size{@apply text-[12px] leading-[18px];}.lg .profile-size{@apply text-[14px] leading-[20px];}.xl .profile-size{@apply text-[16px] leading-[24px];}.avatar-profile.sm .avatar-text{@apply font-medium text-[30px] leading-[38px];}.avatar-profile.md .avatar-text{@apply font-medium text-[36px] leading-[44px];}.avatar-profile.lg .avatar-text{@apply font-medium text-[45px] leading-[55px];}.avatar-profile.xl .avatar-text{@apply font-medium text-[60px] leading-[72px];}.avatar-profile{@apply font-medium text-[#6B7080];}.avatar-profile.sm{@apply size-[72px] text-sm;}.avatar-profile.md{@apply size-[96px] text-base;}.avatar-profile.lg{@apply size-[120px] text-[18px] leading-[26px];}.avatar-profile.xl{@apply size-[160px] text-xl;}.avatar-profile.sm .placeholder-icon{@apply size-[28px];}.avatar-profile.md .placeholder-icon{@apply size-[42px];}.avatar-profile.lg .placeholder-icon{@apply size-[52px];}.avatar-profile.xl .placeholder-icon{@apply size-[65px];}.remove-badge{@apply absolute top-0 right-0 w-5 h-5 bg-white rounded-full shadow-md flex items-center justify-center cursor-pointer hover:bg-gray-50 transition z-20 border-0 p-0;}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition"] }] });
5719
+ }
5720
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AvatarProfile, decorators: [{
5721
+ type: Component,
5722
+ args: [{ selector: 'bk-avatar-profile', imports: [NgClass, CommonModule, BKTooltipDirective], providers: [
5723
+ {
5724
+ provide: NG_VALUE_ACCESSOR,
5725
+ useExisting: forwardRef(() => AvatarProfile),
5726
+ multi: true
5727
+ }
5728
+ ], template: "<div class=\"avatar-profile-container\" [ngClass]=\"sizeClasses\">\r\n @if (label) {\r\n <label class=\"avatar-profile-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"avatar-profile-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"flex gap-4 justify-end\">\r\n <div\r\n [ngClass]=\"containerClasses\"\r\n [bkTooltip]=\"name\"\r\n [bkTooltipPosition]=\"'top'\"\r\n >\r\n\r\n <!-- Loading overlay -->\r\n @if (loading) {\r\n <div class=\"absolute inset-0 flex items-center justify-center z-10 rounded-full bg-white/60\">\r\n <div class=\"w-5 h-5 border-2 border-[#141414] border-t-transparent rounded-full animate-spin\"></div>\r\n </div>\r\n }\r\n\r\n @if (displaySrc && !imageLoadFailed) {\r\n <img\r\n [src]=\"displaySrc\"\r\n [alt]=\"alt\"\r\n class=\"avatar-img\"\r\n (error)=\"onImageError()\"\r\n />\r\n }\r\n\r\n @else if (fallback === 'camera') {\r\n <svg class=\"placeholder-icon\" width=\"23\" height=\"24\" viewBox=\"0 0 23 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18.3843 4.66667C17.6726 4.66667 17.0193 4.25833 16.6926 3.62833L15.8526 1.93667C15.316 0.875 13.916 0 12.726 0H10.0543C8.85264 0 7.45264 0.875 6.91598 1.93667L6.07598 3.62833C5.74931 4.25833 5.09598 4.66667 4.38431 4.66667C1.85264 4.66667 -0.154023 6.80167 0.00931005 9.32167L0.615977 18.9583C0.755977 21.3617 2.05098 23.3333 5.27098 23.3333H17.4976C20.7176 23.3333 22.001 21.3617 22.1526 18.9583L22.7593 9.32167C22.9226 6.80167 20.916 4.66667 18.3843 4.66667ZM9.63431 6.125H13.1343C13.6126 6.125 14.0093 6.52167 14.0093 7C14.0093 7.47833 13.6126 7.875 13.1343 7.875H9.63431C9.15598 7.875 8.75931 7.47833 8.75931 7C8.75931 6.52167 9.15598 6.125 9.63431 6.125ZM11.3843 18.8067C9.21431 18.8067 7.44098 17.045 7.44098 14.8633C7.44098 12.6817 9.20264 10.92 11.3843 10.92C13.566 10.92 15.3276 12.6817 15.3276 14.8633C15.3276 17.045 13.5543 18.8067 11.3843 18.8067Z\" fill=\"#6B7080\"/>\r\n </svg>\r\n }\r\n\r\n @else if (showInitials) {\r\n <span class=\"avatar-text\">\r\n {{ initials }}\r\n </span>\r\n }\r\n\r\n @else {\r\n <svg class=\"placeholder-icon\" viewBox=\"0 0 32 32\" fill=\"none\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" > <g clip-path=\"url(#clip0)\"> <path d=\"M16 16c3.682 0 6.667-2.985 6.667-6.667S19.682 2.667 16 2.667 9.333 5.651 9.333 9.333 12.318 16 16 16Z\" stroke=\"#363C51\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" /> <path d=\"M27.453 29.333C27.453 24.173 22.32 20 16 20S4.547 24.173 4.547 29.333\" stroke=\"#363C51\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" /> </g> <defs> <clipPath id=\"clip0\"> <rect width=\"32\" height=\"32\" fill=\"white\" /> </clipPath> </defs> </svg>\r\n }\r\n\r\n <!-- Remove badge -->\r\n @if (showRemoveButton) {\r\n <button\r\n type=\"button\"\r\n class=\"remove-badge\"\r\n (click)=\"onRemove()\"\r\n aria-label=\"Remove avatar\"\r\n >\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M1 1L9 9M9 1L1 9\" stroke=\"#6B7080\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\r\n </svg>\r\n </button>\r\n }\r\n\r\n </div>\r\n <div class=\"flex flex-col gap-2 justify-end items-start\">\r\n @if (editable) {\r\n <label class=\"upload-button cursor-pointer\">\r\n {{ uploadLabel }}\r\n <input\r\n type=\"file\"\r\n class=\"hidden\"\r\n [accept]=\"accept\"\r\n [disabled]=\"disabled\"\r\n (change)=\"onFileSelected($event)\"\r\n />\r\n </label>\r\n }\r\n @if (!hasError && hint) {\r\n <p class=\"profile-size\">{{ hint }}</p>\r\n }\r\n @if (hasError && errorMessage) {\r\n <p class=\"avatar-profile-error\">{{ errorMessage }}</p>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".avatar-profile-container{@apply flex flex-col gap-1.5;}.avatar-profile-label{@apply text-sm font-medium text-[#141414];}.avatar-profile-label-required{@apply text-[#E7000B] ml-0.5;}.avatar-profile-error{@apply text-xs text-[#E7000B] font-normal;}.avatar-profile{@apply relative inline-flex items-center justify-center rounded-full flex-shrink-0 select-none shadow-lg transition-all duration-200 border-[3px] border-white bg-[#F9FAFA];}.avatar-profile .avatar-img{@apply w-full h-full object-cover rounded-full;}.upload-button{@apply font-medium text-[#6B7080] border border-[#E3E3E7] rounded shadow-sm;}.sm .upload-button{@apply text-[12px] leading-[18px] px-2 py-3;}.md .upload-button{@apply text-[14px] leading-[20px] px-[10px] py-2.5;}.lg .upload-button{@apply text-[16px] leading-[24px] px-[18px] py-2.5;}.xl .upload-button{@apply text-[16px] leading-[24px] px-5 py-3;}.profile-size{@apply font-medium text-[#6B7080];}.sm .profile-size{@apply text-[10px] leading-[14px];}.md .profile-size{@apply text-[12px] leading-[18px];}.lg .profile-size{@apply text-[14px] leading-[20px];}.xl .profile-size{@apply text-[16px] leading-[24px];}.avatar-profile.sm .avatar-text{@apply font-medium text-[30px] leading-[38px];}.avatar-profile.md .avatar-text{@apply font-medium text-[36px] leading-[44px];}.avatar-profile.lg .avatar-text{@apply font-medium text-[45px] leading-[55px];}.avatar-profile.xl .avatar-text{@apply font-medium text-[60px] leading-[72px];}.avatar-profile{@apply font-medium text-[#6B7080];}.avatar-profile.sm{@apply size-[72px] text-sm;}.avatar-profile.md{@apply size-[96px] text-base;}.avatar-profile.lg{@apply size-[120px] text-[18px] leading-[26px];}.avatar-profile.xl{@apply size-[160px] text-xl;}.avatar-profile.sm .placeholder-icon{@apply size-[28px];}.avatar-profile.md .placeholder-icon{@apply size-[42px];}.avatar-profile.lg .placeholder-icon{@apply size-[52px];}.avatar-profile.xl .placeholder-icon{@apply size-[65px];}.remove-badge{@apply absolute top-0 right-0 w-5 h-5 bg-white rounded-full shadow-md flex items-center justify-center cursor-pointer hover:bg-gray-50 transition z-20 border-0 p-0;}\n"] }]
5729
+ }], propDecorators: { src: [{
5730
+ type: Input
5731
+ }], alt: [{
5732
+ type: Input
5733
+ }], name: [{
5734
+ type: Input
5735
+ }], size: [{
5736
+ type: Input
5737
+ }], fallback: [{
5738
+ type: Input
5739
+ }], editable: [{
5740
+ type: Input
5741
+ }], accept: [{
5742
+ type: Input
5743
+ }], maxFileSizeKB: [{
5744
+ type: Input
5745
+ }], uploadLabel: [{
5746
+ type: Input
5747
+ }], hint: [{
5748
+ type: Input
5749
+ }], loading: [{
5750
+ type: Input
5751
+ }], removable: [{
5752
+ type: Input
5753
+ }], label: [{
5754
+ type: Input
5755
+ }], required: [{
5756
+ type: Input
5757
+ }], hasError: [{
5758
+ type: Input
5759
+ }], errorMessage: [{
5760
+ type: Input
5761
+ }], disabled: [{
5762
+ type: Input
5763
+ }], fileSelected: [{
5764
+ type: Output
5765
+ }], removed: [{
5766
+ type: Output
5767
+ }], fileError: [{
5768
+ type: Output
5769
+ }] } });
5770
+
5546
5771
  /*
5547
5772
  * Public API Surface of brickclay-lib
5548
5773
  */
@@ -5552,5 +5777,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5552
5777
  * Generated bundle index. Do not edit.
5553
5778
  */
5554
5779
 
5555
- export { BKTooltipDirective, BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogTitle, BkGrid, BkIconButton, BkInput, BkInputChips, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule, DEFAULT_DIALOG_CONFIG, DIALOG_DATA, DIALOG_GLOBAL_CONFIG, DialogRef, DialogService, getDialogBackdropAnimation, getDialogPanelAnimation };
5780
+ export { AvatarProfile, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkGrid, BkIconButton, BkInput, BkInputChips, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule, getDialogBackdropAnimation, getDialogPanelAnimation };
5556
5781
  //# sourceMappingURL=brickclay-org-ui.mjs.map