@brickclay-org/ui 0.0.41 → 0.0.43

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,15 +1,19 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, HostListener, ViewChildren, Output, Input, Injectable, NgModule, forwardRef, ViewEncapsulation, Optional, Self, ViewChild, input, model, output, signal, computed, effect, inject, ElementRef } from '@angular/core';
2
+ import { Component, EventEmitter, HostListener, ViewChildren, Output, Input, Injectable, NgModule, forwardRef, ViewEncapsulation, Optional, Self, ViewChild, input, model, output, signal, computed, effect, inject, ElementRef, InjectionToken, Directive } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule } 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';
8
- import { Subject } from 'rxjs';
8
+ import { Subject, filter } from 'rxjs';
9
9
  import * as i2 from '@angular/cdk/drag-drop';
10
10
  import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
11
- import { ScrollingModule } from '@angular/cdk/scrolling';
11
+ import * as i1$2 from '@angular/cdk/scrolling';
12
+ import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
12
13
  import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
14
+ import { DIALOG_DATA as DIALOG_DATA$1, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
15
+ import { Overlay, OverlayModule } from '@angular/cdk/overlay';
16
+ import { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';
13
17
 
14
18
  // Icon paths that will be resolved relative to the library's assets folder
15
19
  // When published to npm, users will need to configure their angular.json to include these assets
@@ -3031,15 +3035,18 @@ class BkSelect {
3031
3035
  notFoundText = input('No items found', ...(ngDevMode ? [{ debugName: "notFoundText" }] : []));
3032
3036
  loadingText = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingText" }] : []));
3033
3037
  clearAllText = input('Clear all', ...(ngDevMode ? [{ debugName: "clearAllText" }] : []));
3038
+ groupBy = input('', ...(ngDevMode ? [{ debugName: "groupBy" }] : [])); // NEW
3039
+ colorKey = input('', ...(ngDevMode ? [{ debugName: "colorKey" }] : [])); // e.g. "color"
3034
3040
  // iconSrc = input<string>('Clear all');
3035
3041
  iconAlt = 'icon';
3036
- label = 'Label';
3042
+ label = '';
3037
3043
  required = false;
3038
3044
  iconSrc; // optional icon
3039
3045
  // Config
3040
3046
  multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
3041
3047
  maxLabels = input(2, ...(ngDevMode ? [{ debugName: "maxLabels" }] : []));
3042
3048
  searchable = input(true, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
3049
+ allSelect = input(false, ...(ngDevMode ? [{ debugName: "allSelect" }] : []));
3043
3050
  clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
3044
3051
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
3045
3052
  disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
@@ -3136,7 +3143,16 @@ class BkSelect {
3136
3143
  // this.markedIndex.set(0);
3137
3144
  this.open.emit();
3138
3145
  this.focus.emit();
3139
- setTimeout(() => this.searchInput?.nativeElement.focus());
3146
+ // this.markedIndex.set(0);
3147
+ // setTimeout(() => this.searchInput?.nativeElement.focus());
3148
+ setTimeout(() => {
3149
+ if (this.searchable()) {
3150
+ this.searchInput?.nativeElement.focus();
3151
+ }
3152
+ else {
3153
+ this.controlWrapper?.nativeElement.focus();
3154
+ }
3155
+ });
3140
3156
  }
3141
3157
  closeDropdown() {
3142
3158
  if (!this.isOpen())
@@ -3241,7 +3257,7 @@ class BkSelect {
3241
3257
  handleClear(event) {
3242
3258
  event.stopPropagation();
3243
3259
  this.updateModel([]);
3244
- this.clear.emit();
3260
+ this.clear.emit(null);
3245
3261
  }
3246
3262
  updateModel(items) {
3247
3263
  this.selectedOptions.set(items);
@@ -3249,14 +3265,14 @@ class BkSelect {
3249
3265
  const values = items.map(i => this.resolveValue(i));
3250
3266
  this._value = values;
3251
3267
  this.onChange(values);
3252
- this.change.emit(values);
3268
+ this.change.emit(items);
3253
3269
  }
3254
3270
  else {
3255
3271
  const item = items[0] || null;
3256
3272
  const value = item ? this.resolveValue(item) : null;
3257
3273
  this._value = value;
3258
3274
  this.onChange(value);
3259
- this.change.emit(value);
3275
+ this.change.emit(item);
3260
3276
  }
3261
3277
  }
3262
3278
  onSearchInput(event) {
@@ -3354,14 +3370,38 @@ class BkSelect {
3354
3370
  this.controlWrapper.nativeElement.focus();
3355
3371
  this.openDropdown();
3356
3372
  }
3373
+ groupedItems = computed(() => {
3374
+ const groupKey = this.groupBy();
3375
+ const list = this.filteredItems();
3376
+ if (!groupKey) {
3377
+ return [{ group: null, items: list }];
3378
+ }
3379
+ const map = new Map();
3380
+ list.forEach(item => {
3381
+ const key = item[groupKey] ?? 'Others';
3382
+ if (!map.has(key))
3383
+ map.set(key, []);
3384
+ map.get(key).push(item);
3385
+ });
3386
+ return Array.from(map.entries()).map(([group, items]) => ({
3387
+ group,
3388
+ items
3389
+ }));
3390
+ }, ...(ngDevMode ? [{ debugName: "groupedItems" }] : []));
3391
+ resolveColor(item) {
3392
+ if (!item)
3393
+ return null;
3394
+ const key = this.colorKey();
3395
+ return key && typeof item === 'object' ? item[key] : null;
3396
+ }
3357
3397
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
3358
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkSelect, isStandalone: true, selector: "bk-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, notFoundText: { classPropertyName: "notFoundText", publicName: "notFoundText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, clearAllText: { classPropertyName: "clearAllText", publicName: "clearAllText", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxLabels: { classPropertyName: "maxLabels", publicName: "maxLabels", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", 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 }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", open: "open", close: "close", focus: "focus", blur: "blur", search: "search", clear: "clear", change: "change", scrollToEnd: "scrollToEnd" }, host: { listeners: { "window:scroll": "onWindowEvents()", "window:resize": "onWindowEvents()", "document:click": "onClickOutside($event)" } }, providers: [
3398
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkSelect, isStandalone: true, selector: "bk-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, notFoundText: { classPropertyName: "notFoundText", publicName: "notFoundText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, clearAllText: { classPropertyName: "clearAllText", publicName: "clearAllText", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxLabels: { classPropertyName: "maxLabels", publicName: "maxLabels", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allSelect: { classPropertyName: "allSelect", publicName: "allSelect", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", 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 }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", open: "open", close: "close", focus: "focus", blur: "blur", search: "search", clear: "clear", change: "change", scrollToEnd: "scrollToEnd" }, host: { listeners: { "window:scroll": "onWindowEvents()", "window:resize": "onWindowEvents()", "document:click": "onClickOutside($event)" } }, providers: [
3359
3399
  {
3360
3400
  provide: NG_VALUE_ACCESSOR,
3361
3401
  useExisting: forwardRef(() => BkSelect),
3362
3402
  multi: true
3363
3403
  }
3364
- ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "optionsListContainer", first: true, predicate: ["optionsListContainer"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }], ngImport: i0, template: "<div class=\"ng-select-container\">\r\n\r\n <label\r\n class=\"input-label\"\r\n (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div\r\n #controlWrapper\r\n class=\"ng-select-control\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"disabled()\"\r\n (mousedown)=\"toggleDropdown($event)\"\r\n >\r\n <!-- Icon (Always visible if set) -->\r\n @if(iconSrc){\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"shrink-0\" />\r\n }\r\n <div class=\"ng-value-container\">\r\n @if (selectedOptions().length === 0)\r\n {\r\n <div class=\"ng-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if\r\n (multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-chips\">\r\n @for (opt of selectedOptions().slice(0, maxLabels()); track $index) {\r\n <div class=\"ng-value-chip\">\r\n <span class=\"ng-value-label\">{{ resolveLabel(opt) }}</span>\r\n <span class=\"ng-value-icon\" (mousedown)=\"removeOption(opt, $event)\">\u00D7</span>\r\n </div>\r\n }\r\n @if (selectedOptions().length > maxLabels()) {\r\n <div class=\"ng-value-chip remaining-count\"><span class=\"ng-value-label\">+{{ selectedOptions().length - maxLabels() }} more</span></div>\r\n }\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-label-single\">{{ resolveLabel(selectedOptions()[0]) }}</div>\r\n }\r\n </div>\r\n <div class=\"ng-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && !disabled()) {\r\n <span class=\"ng-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>\r\n </span>\r\n }\r\n <span class=\"ng-arrow-wrapper\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"custom-ng-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n (scroll)=\"onScroll($event)\"\r\n\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n >\r\n\r\n\r\n @if (searchable()) {\r\n <div class=\"ng-dropdown-search\">\r\n <div class=\"ng-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line></svg>\r\n <input #searchInput type=\"text\" class=\"ng-search-input\" [value]=\"searchTerm()\" [placeholder]=\"'Search...'\" (input)=\"onSearchInput($event)\" (keydown)=\"onKeyDown($event)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n </div>\r\n }\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div class=\"ng-option select-all-option\" (mousedown)=\"toggleSelectAll($event)\">\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isAllSelected()\" [class.border-blue-600]=\"isAllSelected()\">\r\n @if(isAllSelected()){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n <span class=\"font-semibold\">Select All</span>\r\n </div>\r\n }\r\n <div #optionsListContainer class=\"ng-options-list\">\r\n @if (loading()) { <div class=\"ng-option-disabled\">{{ loadingText() }}</div> }\r\n @else {\r\n @for (item of filteredItems(); track $index) {\r\n <div #optionsRef class=\"ng-option\" [class.selected]=\"isItemSelected(item)\" [class.marked]=\"$index === markedIndex()\" (click)=\"handleSelection(item, $event)\" (click)=\"markedIndex.set($index)\">\r\n @if (multiple()) {\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isItemSelected(item)\" [class.border-blue-600]=\"isItemSelected(item)\">\r\n @if(isItemSelected(item)){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n }\r\n <span class=\"flex-1\">{{ resolveLabel(item) }}</span>\r\n @if (!multiple() && isItemSelected(item)) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"20 6 9 17 4 12\"/></svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) { <div class=\"ng-option-disabled\">{{ notFoundText() }}</div> }\r\n }\r\n </div>\r\n\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ng-select-container{@apply relative w-full box-border;}.ng-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded transition-all duration-200 px-3 py-[9.2px] cursor-pointer;}.ng-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.ng-select-control.disabled{@apply bg-[#F4F4F6] cursor-not-allowed opacity-60;}.ng-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.ng-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.ng-value-label-single{@apply font-normal text-sm text-[#141414] truncate w-full;}.ng-value-chips{@apply flex flex-wrap gap-1 w-full;}.ng-value-chip{@apply flex items-center bg-gray-100 border border-gray-200 rounded px-2 py-0.5 max-w-full;}.ng-value-chip .ng-value-label{@apply text-[#15191E] truncate max-w-[150px];}.ng-value-chip .ng-value-icon{@apply ml-1 text-gray-500 hover:text-red-500 cursor-pointer text-base font-bold leading-none px-1;}.ng-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.ng-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.ng-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.ng-arrow-wrapper.open{@apply rotate-180;}.custom-ng-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default;}.ng-dropdown-search{@apply px-2 pt-2;}.ng-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.ng-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.ng-options-list{@apply max-h-60 overflow-auto relative p-2.5 mb-3.5 flex flex-col gap-0.5;}.ng-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414];}.ng-option:hover,.ng-option.marked,.ng-option.selected{@apply bg-[#F8F8F8] rounded-md;}.ng-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default;}.ng-value-chip.remaining-count{@apply bg-gray-200 text-gray-600 font-semibold cursor-default;}.select-all-option{@apply sticky top-0 z-20 flex items-center px-3 py-2 cursor-pointer border-b border-[#E3E6EE] bg-gray-50 text-[#15191E];}.select-all-option:hover{@apply bg-gray-100;}.custom-ng-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}::-webkit-scrollbar-thumb:hover{background:#909090}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
3404
+ ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "optionsListContainer", first: true, predicate: ["optionsListContainer"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }], ngImport: i0, template: "<div class=\"ng-select-container\">\r\n\r\n @if(label){\r\n <label\r\n class=\"input-label\"\r\n (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div\r\n #controlWrapper\r\n class=\"ng-select-control\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"disabled()\"\r\n (mousedown)=\"toggleDropdown($event)\"\r\n >\r\n <!-- Icon (Always visible if set) -->\r\n @if (iconSrc) {\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"shrink-0\"/>\r\n }\r\n <div class=\"ng-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"ng-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-chips\">\r\n @for (opt of selectedOptions().slice(0, maxLabels()); track $index) {\r\n <div class=\"multi-badge-item\">\r\n <span class=\"multi-badge-item-text\" [style.color]=\"resolveColor(opt)\">{{ resolveLabel(opt) }}</span>\r\n\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\">\r\n <path d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\" stroke=\"#BBBDC5\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n }\r\n @if (selectedOptions().length > maxLabels()) {\r\n <div class=\"multi-badge-item\"><span\r\n class=\"multi-badge-item-text\">+{{ selectedOptions().length - maxLabels() }}</span></div>\r\n }\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-label-single\" [style.color]=\"resolveColor(selectedOptions()[0])\">\r\n {{ resolveLabel(selectedOptions()[0]) }}</div>\r\n }\r\n </div>\r\n <div class=\"ng-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && !disabled()) {\r\n <span class=\"ng-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\"\r\n y1=\"6\" x2=\"6\"\r\n y2=\"18\"></line><line\r\n x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>\r\n </span>\r\n }\r\n <span class=\"ng-arrow-wrapper\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path\r\n d=\"m6 9 6 6 6-6\"/></svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"custom-ng-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n (scroll)=\"onScroll($event)\"\r\n\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n [class.grouped]=\"groupBy()\"\r\n >\r\n\r\n\r\n @if (searchable()) {\r\n <div class=\"ng-dropdown-search\">\r\n <div class=\"ng-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\">\r\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\r\n </svg>\r\n <input #searchInput type=\"text\" class=\"ng-search-input\" [value]=\"searchTerm()\" [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\" (keydown)=\"onKeyDown($event)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n </div>\r\n }\r\n <div #optionsListContainer class=\"ng-options-list\">\r\n @if (loading()) {\r\n <div class=\"ng-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()){\r\n\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div class=\"ng-option\" (mousedown)=\"toggleSelectAll($event)\" [class.selected]=\"isAllSelected()\">\r\n <div class=\"flex-1 flex justify-between\">\r\n <span>Select All</span>\r\n @if (isAllSelected()) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.5\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n\r\n @if (group.group) {\r\n <div class=\"ng-option-group\">\r\n {{ group.group }}\r\n </div>\r\n }\r\n\r\n @for (item of group.items; track $index) {\r\n <div #optionsRef class=\"ng-option\" [class.selected]=\"isItemSelected(item)\" [class.marked]=\"$index === markedIndex()\" (click)=\"handleSelection(item, $event)\">\r\n <div class=\"flex-1 flex justify-between\">\r\n <span [style.color]=\"resolveColor(item)\">{{ resolveLabel(item) }}</span>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\"\r\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n }\r\n\r\n @if (filteredItems().length === 0) {\r\n <div class=\"ng-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ng-select-container{@apply relative w-full box-border;}.ng-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded transition-all duration-200 px-3 py-2.5 cursor-pointer;}.ng-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.ng-select-control.disabled{@apply bg-[#F4F4F6] cursor-not-allowed opacity-60;}.ng-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.ng-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.ng-value-label-single{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full;}.multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];}.multi-badge-item-text{@apply text-[10px] leading-[14px] font-normal text-[#6B7080];}.multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.ng-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.ng-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.ng-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.ng-arrow-wrapper.open{@apply rotate-180;}.custom-ng-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.ng-dropdown-search{@apply px-2 pt-2;}.ng-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.ng-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.ng-options-list{@apply max-h-60 overflow-auto relative flex flex-col gap-0.5;}.ng-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414];}.ng-option:hover,.ng-option.marked,.ng-option.selected{@apply bg-[#F8F8F8] rounded-md;}.grouped .ng-option{@apply ps-5;}.ng-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default;}.select-all-option{@apply sticky top-0 z-20 flex items-center px-3 py-2 cursor-pointer border-b border-[#E3E6EE] bg-gray-50 text-[#15191E];}.select-all-option:hover{@apply bg-gray-100;}.custom-ng-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.ng-options-list ::-webkit-scrollbar{width:10px}.ng-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.ng-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.ng-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.ng-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.ng-option-group:not(:first-child){@apply mt-4;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
3365
3405
  }
3366
3406
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
3367
3407
  type: Component,
@@ -3371,8 +3411,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3371
3411
  useExisting: forwardRef(() => BkSelect),
3372
3412
  multi: true
3373
3413
  }
3374
- ], template: "<div class=\"ng-select-container\">\r\n\r\n <label\r\n class=\"input-label\"\r\n (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div\r\n #controlWrapper\r\n class=\"ng-select-control\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"disabled()\"\r\n (mousedown)=\"toggleDropdown($event)\"\r\n >\r\n <!-- Icon (Always visible if set) -->\r\n @if(iconSrc){\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"shrink-0\" />\r\n }\r\n <div class=\"ng-value-container\">\r\n @if (selectedOptions().length === 0)\r\n {\r\n <div class=\"ng-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if\r\n (multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-chips\">\r\n @for (opt of selectedOptions().slice(0, maxLabels()); track $index) {\r\n <div class=\"ng-value-chip\">\r\n <span class=\"ng-value-label\">{{ resolveLabel(opt) }}</span>\r\n <span class=\"ng-value-icon\" (mousedown)=\"removeOption(opt, $event)\">\u00D7</span>\r\n </div>\r\n }\r\n @if (selectedOptions().length > maxLabels()) {\r\n <div class=\"ng-value-chip remaining-count\"><span class=\"ng-value-label\">+{{ selectedOptions().length - maxLabels() }} more</span></div>\r\n }\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-label-single\">{{ resolveLabel(selectedOptions()[0]) }}</div>\r\n }\r\n </div>\r\n <div class=\"ng-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && !disabled()) {\r\n <span class=\"ng-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>\r\n </span>\r\n }\r\n <span class=\"ng-arrow-wrapper\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"custom-ng-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n (scroll)=\"onScroll($event)\"\r\n\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n >\r\n\r\n\r\n @if (searchable()) {\r\n <div class=\"ng-dropdown-search\">\r\n <div class=\"ng-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line></svg>\r\n <input #searchInput type=\"text\" class=\"ng-search-input\" [value]=\"searchTerm()\" [placeholder]=\"'Search...'\" (input)=\"onSearchInput($event)\" (keydown)=\"onKeyDown($event)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n </div>\r\n }\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div class=\"ng-option select-all-option\" (mousedown)=\"toggleSelectAll($event)\">\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isAllSelected()\" [class.border-blue-600]=\"isAllSelected()\">\r\n @if(isAllSelected()){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n <span class=\"font-semibold\">Select All</span>\r\n </div>\r\n }\r\n <div #optionsListContainer class=\"ng-options-list\">\r\n @if (loading()) { <div class=\"ng-option-disabled\">{{ loadingText() }}</div> }\r\n @else {\r\n @for (item of filteredItems(); track $index) {\r\n <div #optionsRef class=\"ng-option\" [class.selected]=\"isItemSelected(item)\" [class.marked]=\"$index === markedIndex()\" (click)=\"handleSelection(item, $event)\" (click)=\"markedIndex.set($index)\">\r\n @if (multiple()) {\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isItemSelected(item)\" [class.border-blue-600]=\"isItemSelected(item)\">\r\n @if(isItemSelected(item)){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n }\r\n <span class=\"flex-1\">{{ resolveLabel(item) }}</span>\r\n @if (!multiple() && isItemSelected(item)) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"20 6 9 17 4 12\"/></svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) { <div class=\"ng-option-disabled\">{{ notFoundText() }}</div> }\r\n }\r\n </div>\r\n\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ng-select-container{@apply relative w-full box-border;}.ng-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded transition-all duration-200 px-3 py-[9.2px] cursor-pointer;}.ng-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.ng-select-control.disabled{@apply bg-[#F4F4F6] cursor-not-allowed opacity-60;}.ng-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.ng-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.ng-value-label-single{@apply font-normal text-sm text-[#141414] truncate w-full;}.ng-value-chips{@apply flex flex-wrap gap-1 w-full;}.ng-value-chip{@apply flex items-center bg-gray-100 border border-gray-200 rounded px-2 py-0.5 max-w-full;}.ng-value-chip .ng-value-label{@apply text-[#15191E] truncate max-w-[150px];}.ng-value-chip .ng-value-icon{@apply ml-1 text-gray-500 hover:text-red-500 cursor-pointer text-base font-bold leading-none px-1;}.ng-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.ng-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.ng-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.ng-arrow-wrapper.open{@apply rotate-180;}.custom-ng-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default;}.ng-dropdown-search{@apply px-2 pt-2;}.ng-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.ng-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.ng-options-list{@apply max-h-60 overflow-auto relative p-2.5 mb-3.5 flex flex-col gap-0.5;}.ng-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414];}.ng-option:hover,.ng-option.marked,.ng-option.selected{@apply bg-[#F8F8F8] rounded-md;}.ng-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default;}.ng-value-chip.remaining-count{@apply bg-gray-200 text-gray-600 font-semibold cursor-default;}.select-all-option{@apply sticky top-0 z-20 flex items-center px-3 py-2 cursor-pointer border-b border-[#E3E6EE] bg-gray-50 text-[#15191E];}.select-all-option:hover{@apply bg-gray-100;}.custom-ng-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}::-webkit-scrollbar-thumb:hover{background:#909090}\n"] }]
3375
- }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], notFoundText: [{ type: i0.Input, args: [{ isSignal: true, alias: "notFoundText", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], clearAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllText", required: false }] }], iconAlt: [{
3414
+ ], template: "<div class=\"ng-select-container\">\r\n\r\n @if(label){\r\n <label\r\n class=\"input-label\"\r\n (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div\r\n #controlWrapper\r\n class=\"ng-select-control\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"disabled()\"\r\n (mousedown)=\"toggleDropdown($event)\"\r\n >\r\n <!-- Icon (Always visible if set) -->\r\n @if (iconSrc) {\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"shrink-0\"/>\r\n }\r\n <div class=\"ng-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"ng-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-chips\">\r\n @for (opt of selectedOptions().slice(0, maxLabels()); track $index) {\r\n <div class=\"multi-badge-item\">\r\n <span class=\"multi-badge-item-text\" [style.color]=\"resolveColor(opt)\">{{ resolveLabel(opt) }}</span>\r\n\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\">\r\n <path d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\" stroke=\"#BBBDC5\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n }\r\n @if (selectedOptions().length > maxLabels()) {\r\n <div class=\"multi-badge-item\"><span\r\n class=\"multi-badge-item-text\">+{{ selectedOptions().length - maxLabels() }}</span></div>\r\n }\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-label-single\" [style.color]=\"resolveColor(selectedOptions()[0])\">\r\n {{ resolveLabel(selectedOptions()[0]) }}</div>\r\n }\r\n </div>\r\n <div class=\"ng-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && !disabled()) {\r\n <span class=\"ng-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\"\r\n y1=\"6\" x2=\"6\"\r\n y2=\"18\"></line><line\r\n x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>\r\n </span>\r\n }\r\n <span class=\"ng-arrow-wrapper\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path\r\n d=\"m6 9 6 6 6-6\"/></svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"custom-ng-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n (scroll)=\"onScroll($event)\"\r\n\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n [class.grouped]=\"groupBy()\"\r\n >\r\n\r\n\r\n @if (searchable()) {\r\n <div class=\"ng-dropdown-search\">\r\n <div class=\"ng-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\">\r\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\r\n </svg>\r\n <input #searchInput type=\"text\" class=\"ng-search-input\" [value]=\"searchTerm()\" [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\" (keydown)=\"onKeyDown($event)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n </div>\r\n }\r\n <div #optionsListContainer class=\"ng-options-list\">\r\n @if (loading()) {\r\n <div class=\"ng-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()){\r\n\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div class=\"ng-option\" (mousedown)=\"toggleSelectAll($event)\" [class.selected]=\"isAllSelected()\">\r\n <div class=\"flex-1 flex justify-between\">\r\n <span>Select All</span>\r\n @if (isAllSelected()) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.5\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n\r\n @if (group.group) {\r\n <div class=\"ng-option-group\">\r\n {{ group.group }}\r\n </div>\r\n }\r\n\r\n @for (item of group.items; track $index) {\r\n <div #optionsRef class=\"ng-option\" [class.selected]=\"isItemSelected(item)\" [class.marked]=\"$index === markedIndex()\" (click)=\"handleSelection(item, $event)\">\r\n <div class=\"flex-1 flex justify-between\">\r\n <span [style.color]=\"resolveColor(item)\">{{ resolveLabel(item) }}</span>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\"\r\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n }\r\n\r\n @if (filteredItems().length === 0) {\r\n <div class=\"ng-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ng-select-container{@apply relative w-full box-border;}.ng-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded transition-all duration-200 px-3 py-2.5 cursor-pointer;}.ng-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.ng-select-control.disabled{@apply bg-[#F4F4F6] cursor-not-allowed opacity-60;}.ng-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.ng-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.ng-value-label-single{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full;}.multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];}.multi-badge-item-text{@apply text-[10px] leading-[14px] font-normal text-[#6B7080];}.multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.ng-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.ng-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.ng-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.ng-arrow-wrapper.open{@apply rotate-180;}.custom-ng-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.ng-dropdown-search{@apply px-2 pt-2;}.ng-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.ng-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.ng-options-list{@apply max-h-60 overflow-auto relative flex flex-col gap-0.5;}.ng-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414];}.ng-option:hover,.ng-option.marked,.ng-option.selected{@apply bg-[#F8F8F8] rounded-md;}.grouped .ng-option{@apply ps-5;}.ng-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default;}.select-all-option{@apply sticky top-0 z-20 flex items-center px-3 py-2 cursor-pointer border-b border-[#E3E6EE] bg-gray-50 text-[#15191E];}.select-all-option:hover{@apply bg-gray-100;}.custom-ng-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.ng-options-list ::-webkit-scrollbar{width:10px}.ng-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.ng-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.ng-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.ng-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.ng-option-group:not(:first-child){@apply mt-4;}\n"] }]
3415
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], notFoundText: [{ type: i0.Input, args: [{ isSignal: true, alias: "notFoundText", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], clearAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllText", required: false }] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], colorKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorKey", required: false }] }], iconAlt: [{
3376
3416
  type: Input
3377
3417
  }], label: [{
3378
3418
  type: Input
@@ -3380,7 +3420,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3380
3420
  type: Input
3381
3421
  }], iconSrc: [{
3382
3422
  type: Input
3383
- }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLabels", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], closeOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnSelect", required: false }] }], dropdownPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownPosition", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], open: [{ type: i0.Output, args: ["open"] }], close: [{ type: i0.Output, args: ["close"] }], focus: [{ type: i0.Output, args: ["focus"] }], blur: [{ type: i0.Output, args: ["blur"] }], search: [{ type: i0.Output, args: ["search"] }], clear: [{ type: i0.Output, args: ["clear"] }], change: [{ type: i0.Output, args: ["change"] }], scrollToEnd: [{ type: i0.Output, args: ["scrollToEnd"] }], searchInput: [{
3423
+ }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLabels", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], allSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "allSelect", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], closeOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnSelect", required: false }] }], dropdownPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownPosition", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], open: [{ type: i0.Output, args: ["open"] }], close: [{ type: i0.Output, args: ["close"] }], focus: [{ type: i0.Output, args: ["focus"] }], blur: [{ type: i0.Output, args: ["blur"] }], search: [{ type: i0.Output, args: ["search"] }], clear: [{ type: i0.Output, args: ["clear"] }], change: [{ type: i0.Output, args: ["change"] }], scrollToEnd: [{ type: i0.Output, args: ["scrollToEnd"] }], searchInput: [{
3384
3424
  type: ViewChild,
3385
3425
  args: ['searchInput']
3386
3426
  }], optionsListContainer: [{
@@ -3749,7 +3789,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3749
3789
  args: ['document:click', ['$event']]
3750
3790
  }] } });
3751
3791
 
3752
- class BkChips {
3792
+ class BkInputChips {
3753
3793
  badgeInput;
3754
3794
  fieldWrapper;
3755
3795
  // --- Configuration Inputs ---
@@ -3928,21 +3968,21 @@ class BkChips {
3928
3968
  this.onChange([...this.badges]);
3929
3969
  this.blur.emit(event);
3930
3970
  }
3931
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
3932
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkChips, isStandalone: true, selector: "bk-chips", inputs: { id: "id", name: "name", label: "label", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", readOnly: "readOnly", hasError: "hasError", errorMessage: "errorMessage" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur" }, providers: [
3971
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInputChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
3972
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkInputChips, isStandalone: true, selector: "bk-input-chips", inputs: { id: "id", name: "name", label: "label", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", readOnly: "readOnly", hasError: "hasError", errorMessage: "errorMessage" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur" }, providers: [
3933
3973
  {
3934
3974
  provide: NG_VALUE_ACCESSOR,
3935
- useExisting: forwardRef(() => BkChips),
3975
+ useExisting: forwardRef(() => BkInputChips),
3936
3976
  multi: true
3937
3977
  }
3938
3978
  ], viewQueries: [{ propertyName: "badgeInput", first: true, predicate: ["badgeInput"], descendants: true }, { propertyName: "fieldWrapper", first: true, predicate: ["fieldWrapper"], descendants: true }], ngImport: i0, template: "<div class=\"input-badge-container\">\r\n @if (label) {\r\n <label\r\n [for]=\"id\"\r\n class=\"input-badge-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-badge-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"input-badge-wrapper\">\r\n <div\r\n #fieldWrapper\r\n class=\"input-badge-field-wrapper\"\r\n [ngClass]=\"{\r\n 'input-badge-field-wrapper--default': inputState === 'default',\r\n 'input-badge-field-wrapper--focused': inputState === 'focused',\r\n 'input-badge-field-wrapper--filled': inputState === 'filled',\r\n 'input-badge-field-wrapper--error': inputState === 'error',\r\n 'input-badge-field-wrapper--disabled': inputState === 'disabled',\r\n 'input-badge-field-wrapper--scrollable': needsScroll\r\n }\"\r\n (click)=\"focusInput()\"\r\n >\r\n <!-- Badges -->\r\n @for (badge of badges; track badge; let i = $index) {\r\n <div class=\"input-badge-item\">\r\n <span class=\"input-badge-item-text\">{{ badge }}</span>\r\n @if (!disabled) {\r\n <button type=\"button\" (click)=\"removeBadge(i); $event.stopPropagation()\"class=\"input-badge-item-close\" >\r\n <img src=\"../../../../assets/images/icons/global/badge-close.svg\" alt=\"Remove\" class=\"input-badge-item-close-icon\"/>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Input Field -->\r\n <input\r\n #badgeInput\r\n type=\"text\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [value]=\"inputValue\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n [placeholder]=\"badges.length === 0 ? placeholder : ''\"\r\n [disabled]=\"disabled\"\r\n [readOnly]=\"readOnly\"\r\n class=\"input-badge-input\"\r\n [ngClass]=\"{\r\n 'input-badge-input--default': inputState === 'default',\r\n 'input-badge-input--focused': inputState === 'focused',\r\n 'input-badge-input--filled': inputState === 'filled',\r\n 'input-badge-input--error': inputState === 'error',\r\n 'input-badge-input--disabled': inputState === 'disabled'\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"input-badge-footer\">\r\n <div class=\"input-badge-footer-content\">\r\n @if (hasError) {\r\n <span class=\"input-badge-error\"> {{ errorMessage }}</span>\r\n } @else if (hint) {\r\n <span class=\"input-badge-hint\"> {{ hint }}</span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".input-badge-container{@apply flex flex-col gap-1.5 w-full;}.input-badge-label{@apply text-sm font-medium text-[#141414] block;}.input-badge-label-required{@apply text-[#E7000B] ml-0.5;}.input-badge-wrapper{@apply relative;}.input-badge-field-wrapper{@apply w-full px-3 py-2 text-sm border rounded-[4px] outline-none transition-colors duration-200 bg-white flex flex-wrap gap-2 items-start;height:40px;box-sizing:border-box;overflow-y:hidden;overflow-x:hidden}.input-badge-field-wrapper--scrollable{overflow-y:auto}.input-badge-field-wrapper--default{@apply border-[#E3E3E7] text-[#141414];}.input-badge-field-wrapper--default:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--focused{@apply border-[#6B7080] text-[#141414];}.input-badge-field-wrapper--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-badge-field-wrapper--filled:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--error{@apply border-[#FA727A] text-[#141414];}.input-badge-field-wrapper--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed;}.input-badge-item{@apply inline-flex items-center gap-1 px-2 py-[2.5px] bg-white border border-[#E3E3E7] rounded-[4px];}.input-badge-item-text{@apply text-sm leading-[18px] font-normal text-[#6B7080];}.input-badge-item-close{@apply cursor-pointer outline-none w-3 h-3;}.input-badge-input{@apply flex-1 min-w-[120px] outline-none bg-transparent text-[#141414] placeholder:text-[#6B7080] h-auto;flex-basis:120px}.input-badge-input--default,.input-badge-input--focused,.input-badge-input--filled,.input-badge-input--error{@apply text-[#141414];}.input-badge-input--disabled{@apply text-[#A1A3AE] cursor-not-allowed;}.input-badge-footer{@apply flex justify-between items-start font-normal text-sm;}.input-badge-footer-content{@apply flex-1;}.input-badge-hint{@apply text-xs text-[#868997] font-normal;}.input-badge-error{@apply text-xs text-[#F34050] font-normal;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }] });
3939
3979
  }
3940
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkChips, decorators: [{
3980
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInputChips, decorators: [{
3941
3981
  type: Component,
3942
- args: [{ selector: 'bk-chips', standalone: true, imports: [CommonModule, FormsModule], providers: [
3982
+ args: [{ selector: 'bk-input-chips', standalone: true, imports: [CommonModule, FormsModule], providers: [
3943
3983
  {
3944
3984
  provide: NG_VALUE_ACCESSOR,
3945
- useExisting: forwardRef(() => BkChips),
3985
+ useExisting: forwardRef(() => BkInputChips),
3946
3986
  multi: true
3947
3987
  }
3948
3988
  ], template: "<div class=\"input-badge-container\">\r\n @if (label) {\r\n <label\r\n [for]=\"id\"\r\n class=\"input-badge-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-badge-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"input-badge-wrapper\">\r\n <div\r\n #fieldWrapper\r\n class=\"input-badge-field-wrapper\"\r\n [ngClass]=\"{\r\n 'input-badge-field-wrapper--default': inputState === 'default',\r\n 'input-badge-field-wrapper--focused': inputState === 'focused',\r\n 'input-badge-field-wrapper--filled': inputState === 'filled',\r\n 'input-badge-field-wrapper--error': inputState === 'error',\r\n 'input-badge-field-wrapper--disabled': inputState === 'disabled',\r\n 'input-badge-field-wrapper--scrollable': needsScroll\r\n }\"\r\n (click)=\"focusInput()\"\r\n >\r\n <!-- Badges -->\r\n @for (badge of badges; track badge; let i = $index) {\r\n <div class=\"input-badge-item\">\r\n <span class=\"input-badge-item-text\">{{ badge }}</span>\r\n @if (!disabled) {\r\n <button type=\"button\" (click)=\"removeBadge(i); $event.stopPropagation()\"class=\"input-badge-item-close\" >\r\n <img src=\"../../../../assets/images/icons/global/badge-close.svg\" alt=\"Remove\" class=\"input-badge-item-close-icon\"/>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Input Field -->\r\n <input\r\n #badgeInput\r\n type=\"text\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [value]=\"inputValue\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n [placeholder]=\"badges.length === 0 ? placeholder : ''\"\r\n [disabled]=\"disabled\"\r\n [readOnly]=\"readOnly\"\r\n class=\"input-badge-input\"\r\n [ngClass]=\"{\r\n 'input-badge-input--default': inputState === 'default',\r\n 'input-badge-input--focused': inputState === 'focused',\r\n 'input-badge-input--filled': inputState === 'filled',\r\n 'input-badge-input--error': inputState === 'error',\r\n 'input-badge-input--disabled': inputState === 'disabled'\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"input-badge-footer\">\r\n <div class=\"input-badge-footer-content\">\r\n @if (hasError) {\r\n <span class=\"input-badge-error\"> {{ errorMessage }}</span>\r\n } @else if (hint) {\r\n <span class=\"input-badge-hint\"> {{ hint }}</span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".input-badge-container{@apply flex flex-col gap-1.5 w-full;}.input-badge-label{@apply text-sm font-medium text-[#141414] block;}.input-badge-label-required{@apply text-[#E7000B] ml-0.5;}.input-badge-wrapper{@apply relative;}.input-badge-field-wrapper{@apply w-full px-3 py-2 text-sm border rounded-[4px] outline-none transition-colors duration-200 bg-white flex flex-wrap gap-2 items-start;height:40px;box-sizing:border-box;overflow-y:hidden;overflow-x:hidden}.input-badge-field-wrapper--scrollable{overflow-y:auto}.input-badge-field-wrapper--default{@apply border-[#E3E3E7] text-[#141414];}.input-badge-field-wrapper--default:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--focused{@apply border-[#6B7080] text-[#141414];}.input-badge-field-wrapper--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-badge-field-wrapper--filled:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--error{@apply border-[#FA727A] text-[#141414];}.input-badge-field-wrapper--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed;}.input-badge-item{@apply inline-flex items-center gap-1 px-2 py-[2.5px] bg-white border border-[#E3E3E7] rounded-[4px];}.input-badge-item-text{@apply text-sm leading-[18px] font-normal text-[#6B7080];}.input-badge-item-close{@apply cursor-pointer outline-none w-3 h-3;}.input-badge-input{@apply flex-1 min-w-[120px] outline-none bg-transparent text-[#141414] placeholder:text-[#6B7080] h-auto;flex-basis:120px}.input-badge-input--default,.input-badge-input--focused,.input-badge-input--filled,.input-badge-input--error{@apply text-[#141414];}.input-badge-input--disabled{@apply text-[#A1A3AE] cursor-not-allowed;}.input-badge-footer{@apply flex justify-between items-start font-normal text-sm;}.input-badge-footer-content{@apply flex-1;}.input-badge-hint{@apply text-xs text-[#868997] font-normal;}.input-badge-error{@apply text-xs text-[#F34050] font-normal;}\n"] }]
@@ -4022,6 +4062,1202 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4022
4062
  type: Output
4023
4063
  }] } });
4024
4064
 
4065
+ /**
4066
+ * Dialog Injection Tokens
4067
+ *
4068
+ * Architecture Decision:
4069
+ * ─────────────────────
4070
+ * • `DIALOG_DATA` — Re-exported from `@angular/cdk/dialog` so that
4071
+ * consumers import from our barrel and the token identity matches
4072
+ * exactly what CDK's `Dialog` service provides in the injector.
4073
+ * This means `@Inject(DIALOG_DATA)` works without any extra wiring.
4074
+ *
4075
+ * • `DIALOG_GLOBAL_CONFIG` — Optional app-level defaults, same pattern
4076
+ * as before.
4077
+ *
4078
+ * • `INTERNAL_DIALOG_CONFIG` — Internal-only token used to pass our
4079
+ * full `DialogConfig` (including animation fields) to the custom
4080
+ * `DialogContainerComponent`. Not part of the public API.
4081
+ */
4082
+ // ──── Public ─────────────────────────────────────────────────────────────
4083
+ /**
4084
+ * Injection token used to pass arbitrary data into a dialog component.
4085
+ *
4086
+ * This is CDK's own `DIALOG_DATA` token — re-exported so that imports
4087
+ * from our barrel (`shared/components/dialog`) resolve to the exact same
4088
+ * token that CDK's `Dialog` service provides.
4089
+ *
4090
+ * Usage inside a dialog component:
4091
+ * ```ts
4092
+ * constructor(@Inject(DIALOG_DATA) public data: MyDataType) {}
4093
+ * ```
4094
+ */
4095
+ const DIALOG_DATA = DIALOG_DATA$1;
4096
+ /**
4097
+ * Optional token for providing global dialog defaults at the
4098
+ * application level.
4099
+ *
4100
+ * Usage in `app.config.ts` or a module's `providers` array:
4101
+ * ```ts
4102
+ * providers: [
4103
+ * { provide: DIALOG_GLOBAL_CONFIG, useValue: { animation: 'zoom', width: '600px' } }
4104
+ * ]
4105
+ * ```
4106
+ */
4107
+ const DIALOG_GLOBAL_CONFIG = new InjectionToken('DIALOG_GLOBAL_CONFIG');
4108
+ // ──── Internal ───────────────────────────────────────────────────────────
4109
+ /**
4110
+ * Internal token that carries our full `DialogConfig` (with animation
4111
+ * settings, position offsets, etc.) into the `DialogContainerComponent`.
4112
+ *
4113
+ * @internal — not exported from the barrel; do not depend on it.
4114
+ */
4115
+ const INTERNAL_DIALOG_CONFIG = new InjectionToken('INTERNAL_DIALOG_CONFIG');
4116
+
4117
+ /**
4118
+ * Dialog Animations
4119
+ *
4120
+ * Architecture Decision:
4121
+ * ─────────────────────
4122
+ * Animations are implemented via the Web Animations API (WAAPI) instead of
4123
+ * Angular's @angular/animations so that:
4124
+ * 1. The dialog container stays truly standalone — no BrowserAnimationsModule
4125
+ * dependency is required.
4126
+ * 2. We have full programmatic control over timing, easing, and cleanup.
4127
+ * 3. Future presets can be added without touching the component template.
4128
+ *
4129
+ * Each preset exports an `enter` and `leave` keyframe array plus a
4130
+ * recommended timing object. The DialogContainerComponent plays these
4131
+ * via `element.animate()`.
4132
+ */
4133
+ /**
4134
+ * Build enter/leave WAAPI keyframes for the dialog **panel** element.
4135
+ */
4136
+ function getDialogPanelAnimation(preset, enterDuration, leaveDuration) {
4137
+ const easeEnter = 'cubic-bezier(0.0, 0.0, 0.2, 1)'; // decelerate
4138
+ const easeLeave = 'cubic-bezier(0.4, 0.0, 1, 1)'; // accelerate
4139
+ switch (preset) {
4140
+ // ─── Fade ────────────────────────────────────────────────────
4141
+ case 'fade':
4142
+ return {
4143
+ enter: {
4144
+ keyframes: [
4145
+ { opacity: 0, transform: 'scale(0.95)' },
4146
+ { opacity: 1, transform: 'scale(1)' },
4147
+ ],
4148
+ options: { duration: enterDuration, easing: easeEnter, fill: 'forwards' },
4149
+ },
4150
+ leave: {
4151
+ keyframes: [
4152
+ { opacity: 1, transform: 'scale(1)' },
4153
+ { opacity: 0, transform: 'scale(0.95)' },
4154
+ ],
4155
+ options: { duration: leaveDuration, easing: easeLeave, fill: 'forwards' },
4156
+ },
4157
+ };
4158
+ // ─── Zoom ────────────────────────────────────────────────────
4159
+ case 'zoom':
4160
+ return {
4161
+ enter: {
4162
+ keyframes: [
4163
+ { opacity: 0, transform: 'scale(0.5)' },
4164
+ { opacity: 1, transform: 'scale(1)' },
4165
+ ],
4166
+ options: { duration: enterDuration, easing: easeEnter, fill: 'forwards' },
4167
+ },
4168
+ leave: {
4169
+ keyframes: [
4170
+ { opacity: 1, transform: 'scale(1)' },
4171
+ { opacity: 0, transform: 'scale(0.5)' },
4172
+ ],
4173
+ options: { duration: leaveDuration, easing: easeLeave, fill: 'forwards' },
4174
+ },
4175
+ };
4176
+ // ─── Slide Top ───────────────────────────────────────────────
4177
+ case 'slide-top':
4178
+ return {
4179
+ enter: {
4180
+ keyframes: [
4181
+ { opacity: 0, transform: 'translateY(-40px)' },
4182
+ { opacity: 1, transform: 'translateY(0)' },
4183
+ ],
4184
+ options: { duration: enterDuration, easing: easeEnter, fill: 'forwards' },
4185
+ },
4186
+ leave: {
4187
+ keyframes: [
4188
+ { opacity: 1, transform: 'translateY(0)' },
4189
+ { opacity: 0, transform: 'translateY(-40px)' },
4190
+ ],
4191
+ options: { duration: leaveDuration, easing: easeLeave, fill: 'forwards' },
4192
+ },
4193
+ };
4194
+ // ─── Slide Bottom ────────────────────────────────────────────
4195
+ case 'slide-bottom':
4196
+ return {
4197
+ enter: {
4198
+ keyframes: [
4199
+ { opacity: 0, transform: 'translateY(40px)' },
4200
+ { opacity: 1, transform: 'translateY(0)' },
4201
+ ],
4202
+ options: { duration: enterDuration, easing: easeEnter, fill: 'forwards' },
4203
+ },
4204
+ leave: {
4205
+ keyframes: [
4206
+ { opacity: 1, transform: 'translateY(0)' },
4207
+ { opacity: 0, transform: 'translateY(40px)' },
4208
+ ],
4209
+ options: { duration: leaveDuration, easing: easeLeave, fill: 'forwards' },
4210
+ },
4211
+ };
4212
+ // ─── Slide Left ──────────────────────────────────────────────
4213
+ case 'slide-left':
4214
+ return {
4215
+ enter: {
4216
+ keyframes: [
4217
+ { opacity: 0, transform: 'translateX(-40px)' },
4218
+ { opacity: 1, transform: 'translateX(0)' },
4219
+ ],
4220
+ options: { duration: enterDuration, easing: easeEnter, fill: 'forwards' },
4221
+ },
4222
+ leave: {
4223
+ keyframes: [
4224
+ { opacity: 1, transform: 'translateX(0)' },
4225
+ { opacity: 0, transform: 'translateX(-40px)' },
4226
+ ],
4227
+ options: { duration: leaveDuration, easing: easeLeave, fill: 'forwards' },
4228
+ },
4229
+ };
4230
+ // ─── Slide Right ─────────────────────────────────────────────
4231
+ case 'slide-right':
4232
+ return {
4233
+ enter: {
4234
+ keyframes: [
4235
+ { opacity: 0, transform: 'translateX(40px)' },
4236
+ { opacity: 1, transform: 'translateX(0)' },
4237
+ ],
4238
+ options: { duration: enterDuration, easing: easeEnter, fill: 'forwards' },
4239
+ },
4240
+ leave: {
4241
+ keyframes: [
4242
+ { opacity: 1, transform: 'translateX(0)' },
4243
+ { opacity: 0, transform: 'translateX(40px)' },
4244
+ ],
4245
+ options: { duration: leaveDuration, easing: easeLeave, fill: 'forwards' },
4246
+ },
4247
+ };
4248
+ // ─── None ────────────────────────────────────────────────────
4249
+ case 'none':
4250
+ default:
4251
+ return {
4252
+ enter: {
4253
+ keyframes: [{ opacity: 1 }],
4254
+ options: { duration: 0, fill: 'forwards' },
4255
+ },
4256
+ leave: {
4257
+ keyframes: [{ opacity: 0 }],
4258
+ options: { duration: 0, fill: 'forwards' },
4259
+ },
4260
+ };
4261
+ }
4262
+ }
4263
+ /**
4264
+ * Build enter/leave WAAPI keyframes for the **backdrop** element.
4265
+ * The backdrop always uses a simple opacity fade regardless of the
4266
+ * panel animation preset.
4267
+ */
4268
+ function getDialogBackdropAnimation(enterDuration, leaveDuration) {
4269
+ return {
4270
+ enter: {
4271
+ keyframes: [{ opacity: 0 }, { opacity: 1 }],
4272
+ options: { duration: enterDuration, easing: 'ease-out', fill: 'forwards' },
4273
+ },
4274
+ leave: {
4275
+ keyframes: [{ opacity: 1 }, { opacity: 0 }],
4276
+ options: { duration: leaveDuration, easing: 'ease-in', fill: 'forwards' },
4277
+ },
4278
+ };
4279
+ }
4280
+
4281
+ /**
4282
+ * DialogContainerComponent
4283
+ *
4284
+ * Architecture Decision:
4285
+ * ─────────────────────
4286
+ * Extends CDK's `CdkDialogContainer` — the headless base class that
4287
+ * provides:
4288
+ * • Focus-trap management (tab key stays inside the dialog).
4289
+ * • Auto-focus / restore-focus behaviour.
4290
+ * • Portal outlet (`<ng-template cdkPortalOutlet />`) for dynamic
4291
+ * component projection.
4292
+ * • ARIA attribute management on the host element.
4293
+ *
4294
+ * We add:
4295
+ * • WAAPI enter / leave animations on the panel (host element) and
4296
+ * the CDK backdrop sibling.
4297
+ * • Flex-column styles on the dynamically created component host so
4298
+ * `.bk-dialog-content` scrolls and `.bk-dialog-actions` stays pinned.
4299
+ * • Position-offset application via CSS margin.
4300
+ *
4301
+ * This component is **never** used directly — it is created internally
4302
+ * by `DialogService` via CDK's `Dialog.open()`.
4303
+ */
4304
+ class DialogContainerComponent extends CdkDialogContainer {
4305
+ /**
4306
+ * Our full config (including animation fields).
4307
+ * Provided by DialogService via the INTERNAL_DIALOG_CONFIG token.
4308
+ */
4309
+ _dialogConfig = inject(INTERNAL_DIALOG_CONFIG);
4310
+ // ──── Opened promise ─────────────────────────────────────────────────
4311
+ /**
4312
+ * Resolves when the enter animation finishes (or immediately for 'none').
4313
+ * `DialogService` subscribes via `.then()` to emit `afterOpened` on the
4314
+ * `DialogRef`.
4315
+ */
4316
+ _resolveOpened;
4317
+ opened = new Promise(resolve => {
4318
+ this._resolveOpened = resolve;
4319
+ });
4320
+ // ──── Lifecycle ──────────────────────────────────────────────────────
4321
+ ngOnInit() {
4322
+ this._playEnterAnimation();
4323
+ this._applyPositionOffsets();
4324
+ }
4325
+ // ──── Portal override ────────────────────────────────────────────────
4326
+ /**
4327
+ * Override the CDK base to apply flex-column layout on the dynamically
4328
+ * created component's host element.
4329
+ *
4330
+ * Angular's emulated view encapsulation prevents scoped CSS from reaching
4331
+ * dynamically-projected elements, so we set styles programmatically.
4332
+ */
4333
+ attachComponentPortal(portal) {
4334
+ const ref = super.attachComponentPortal(portal);
4335
+ const el = ref.location.nativeElement;
4336
+ el.style.display = 'flex';
4337
+ el.style.flexDirection = 'column';
4338
+ el.style.flex = '1 1 auto';
4339
+ el.style.minHeight = '0';
4340
+ el.style.overflow = 'hidden';
4341
+ return ref;
4342
+ }
4343
+ // ──── WAAPI Animations ───────────────────────────────────────────────
4344
+ /**
4345
+ * Play the enter animation on the panel (host element) and backdrop.
4346
+ * Resolves the `opened` promise when the panel animation finishes.
4347
+ */
4348
+ _playEnterAnimation() {
4349
+ const preset = this._dialogConfig.animation ?? 'fade';
4350
+ if (preset === 'none') {
4351
+ this._resolveOpened();
4352
+ return;
4353
+ }
4354
+ const enterDur = this._dialogConfig.animationDurationEnter ?? 200;
4355
+ const leaveDur = this._dialogConfig.animationDurationLeave ?? 150;
4356
+ // ── Panel animation ──
4357
+ const panelAnim = getDialogPanelAnimation(preset, enterDur, leaveDur);
4358
+ const anim = this._elementRef.nativeElement.animate(panelAnim.enter.keyframes, panelAnim.enter.options);
4359
+ // ── Backdrop animation ──
4360
+ const backdropEl = this._getBackdropElement();
4361
+ if (backdropEl) {
4362
+ // Override CDK's CSS transition so our WAAPI timing wins.
4363
+ backdropEl.style.transition = 'none';
4364
+ backdropEl.style.backgroundColor = 'var(--dialog-backdrop-bg, rgba(0, 0, 0, 0.5))';
4365
+ const bdAnim = getDialogBackdropAnimation(enterDur, leaveDur);
4366
+ backdropEl.animate(bdAnim.enter.keyframes, bdAnim.enter.options);
4367
+ }
4368
+ anim.onfinish = () => this._resolveOpened();
4369
+ }
4370
+ /**
4371
+ * Play the leave animation. Returns a Promise that resolves when done.
4372
+ * Called by `DialogRef._runCloseSequence()` before CDK tears down the
4373
+ * overlay.
4374
+ */
4375
+ playLeaveAnimation() {
4376
+ const preset = this._dialogConfig.animation ?? 'fade';
4377
+ if (preset === 'none')
4378
+ return Promise.resolve();
4379
+ const enterDur = this._dialogConfig.animationDurationEnter ?? 200;
4380
+ const leaveDur = this._dialogConfig.animationDurationLeave ?? 150;
4381
+ return new Promise(resolve => {
4382
+ // ── Panel ──
4383
+ const panelAnim = getDialogPanelAnimation(preset, enterDur, leaveDur);
4384
+ const anim = this._elementRef.nativeElement.animate(panelAnim.leave.keyframes, panelAnim.leave.options);
4385
+ // ── Backdrop ──
4386
+ const backdropEl = this._getBackdropElement();
4387
+ if (backdropEl) {
4388
+ const bdAnim = getDialogBackdropAnimation(enterDur, leaveDur);
4389
+ backdropEl.animate(bdAnim.leave.keyframes, bdAnim.leave.options);
4390
+ }
4391
+ anim.onfinish = () => resolve();
4392
+ // Safety net — resolve even if onfinish never fires (SSR, etc.).
4393
+ setTimeout(() => resolve(), leaveDur + 50);
4394
+ });
4395
+ }
4396
+ // ──── Position Offsets ───────────────────────────────────────────────
4397
+ /**
4398
+ * Apply explicit position offsets via CSS margin.
4399
+ * These are additive to CDK's `GlobalPositionStrategy` alignment.
4400
+ */
4401
+ _applyPositionOffsets() {
4402
+ const pos = this._dialogConfig.position;
4403
+ if (!pos)
4404
+ return;
4405
+ const el = this._elementRef.nativeElement;
4406
+ if (pos.top)
4407
+ el.style.marginTop = pos.top;
4408
+ if (pos.bottom)
4409
+ el.style.marginBottom = pos.bottom;
4410
+ if (pos.left)
4411
+ el.style.marginLeft = pos.left;
4412
+ if (pos.right)
4413
+ el.style.marginRight = pos.right;
4414
+ }
4415
+ // ──── Helpers ────────────────────────────────────────────────────────
4416
+ /**
4417
+ * CDK places the backdrop as a sibling of `.cdk-overlay-pane`.
4418
+ * Walk up from our host → pane → wrapper, then query for the backdrop.
4419
+ */
4420
+ _getBackdropElement() {
4421
+ const pane = this._elementRef.nativeElement.closest('.cdk-overlay-pane');
4422
+ return pane?.parentElement?.querySelector('.cdk-overlay-backdrop') ?? null;
4423
+ }
4424
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogContainerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
4425
+ 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"] }] });
4426
+ }
4427
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogContainerComponent, decorators: [{
4428
+ type: Component,
4429
+ args: [{ selector: 'bk-dialog-container', standalone: true, imports: [CdkPortalOutlet], host: {
4430
+ 'class': 'bk-dialog-container',
4431
+ }, 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"] }]
4432
+ }] });
4433
+
4434
+ /**
4435
+ * DialogRef — Handle returned to callers by `DialogService.open()`.
4436
+ *
4437
+ * Architecture Decision:
4438
+ * ─────────────────────
4439
+ * Wraps CDK's `DialogRef` to add:
4440
+ * • WAAPI leave-animation before CDK tears down the overlay.
4441
+ * • Per-instance `afterOpened()` observable (CDK only has a service-level
4442
+ * `afterOpened` Subject).
4443
+ * • The same familiar API shape used by callers (`close`, `afterClosed`,
4444
+ * `backdropClick`, `keydownEvents`, `componentInstance`).
4445
+ *
4446
+ * CDK's `DialogRef<R, C>` has Result first, Component second.
4447
+ * Ours keeps `<T, R>` (Component first, Result second) to match the
4448
+ * convention consumers already use.
4449
+ */
4450
+ class DialogRef {
4451
+ _cdkRef;
4452
+ /** Unique dialog identifier (managed by CDK). */
4453
+ id;
4454
+ /** Instance of the component rendered inside the dialog. */
4455
+ componentInstance;
4456
+ // ──── Internal wiring (set by DialogService) ──────────────────────────
4457
+ /** @internal Container reference for leave animation. */
4458
+ _containerInstance;
4459
+ /** @internal Prevent double-close. */
4460
+ _closing = false;
4461
+ /** @internal Per-instance afterOpened Subject. */
4462
+ _afterOpened$ = new Subject();
4463
+ constructor(
4464
+ /**
4465
+ * @internal Wrapped CDK ref.
4466
+ * Typed as `CdkDialogRef<any>` to avoid deep generic-variance issues
4467
+ * that arise from CDK's `config.providers` callback signature.
4468
+ * The public API (`afterClosed`, etc.) re-types the observables.
4469
+ */
4470
+ _cdkRef) {
4471
+ this._cdkRef = _cdkRef;
4472
+ this.id = _cdkRef.id;
4473
+ }
4474
+ // ──── Public API ──────────────────────────────────────────────────────
4475
+ /**
4476
+ * Close the dialog, optionally returning a result.
4477
+ * Plays the WAAPI leave animation, then delegates to CDK for cleanup.
4478
+ */
4479
+ close(result) {
4480
+ if (this._closing)
4481
+ return;
4482
+ this._closing = true;
4483
+ this._runCloseSequence(result);
4484
+ }
4485
+ /**
4486
+ * Observable that emits (and completes) once after the dialog has been
4487
+ * removed from the DOM and all cleanup is done.
4488
+ */
4489
+ afterClosed() {
4490
+ return this._cdkRef.closed;
4491
+ }
4492
+ /**
4493
+ * Observable that emits (and completes) when the enter animation
4494
+ * finishes and the dialog is fully visible.
4495
+ */
4496
+ afterOpened() {
4497
+ return this._afterOpened$.asObservable();
4498
+ }
4499
+ /**
4500
+ * Observable of backdrop / outside-pointer click events.
4501
+ */
4502
+ backdropClick() {
4503
+ return this._cdkRef.outsidePointerEvents;
4504
+ }
4505
+ /**
4506
+ * Observable of keyboard events dispatched while this dialog is open.
4507
+ */
4508
+ keydownEvents() {
4509
+ return this._cdkRef.keydownEvents;
4510
+ }
4511
+ // ──── Internal helpers ────────────────────────────────────────────────
4512
+ /** @internal Called by the container once the enter animation finishes. */
4513
+ _emitOpened() {
4514
+ this._afterOpened$.next();
4515
+ this._afterOpened$.complete();
4516
+ }
4517
+ /** Play leave animation, then close via CDK. */
4518
+ async _runCloseSequence(result) {
4519
+ try {
4520
+ await this._containerInstance.playLeaveAnimation();
4521
+ }
4522
+ catch {
4523
+ // Animation may fail in SSR / test — proceed anyway.
4524
+ }
4525
+ this._cdkRef.close(result);
4526
+ }
4527
+ }
4528
+
4529
+ /**
4530
+ * Dialog Configuration
4531
+ *
4532
+ * Architecture Decision:
4533
+ * ─────────────────────
4534
+ * Our `DialogConfig` mirrors the fields from CDK's `DialogConfig` that we
4535
+ * expose, plus adds custom animation properties powered by WAAPI.
4536
+ *
4537
+ * When `DialogService.open()` is called these values are:
4538
+ * 1. Merged with global defaults and per-call overrides.
4539
+ * 2. Mapped onto CDK's native `DialogConfig` for overlay, backdrop, scroll,
4540
+ * position, ARIA, and focus-trap management.
4541
+ * 3. Passed to `DialogContainerComponent` via an internal token for
4542
+ * animation playback and position offsets.
4543
+ *
4544
+ * CDK handles: unique IDs, z-index stacking, scroll blocking, focus trap,
4545
+ * backdrop rendering, overlay positioning, keyboard events.
4546
+ * We handle: WAAPI animations, panel appearance, convenience config sugar.
4547
+ */
4548
+ // ──── Defaults ───────────────────────────────────────────────────────────
4549
+ const DEFAULT_DIALOG_CONFIG = {
4550
+ id: undefined,
4551
+ width: undefined,
4552
+ height: undefined,
4553
+ minWidth: undefined,
4554
+ minHeight: undefined,
4555
+ maxWidth: '90vw',
4556
+ maxHeight: '90vh',
4557
+ disableClose: false,
4558
+ closeOnBackdrop: true,
4559
+ closeOnEsc: true,
4560
+ hasBackdrop: true,
4561
+ lockScroll: true,
4562
+ panelClass: '',
4563
+ backdropClass: '',
4564
+ data: undefined,
4565
+ animation: 'fade',
4566
+ animationDurationEnter: 200,
4567
+ animationDurationLeave: 150,
4568
+ position: undefined,
4569
+ role: 'dialog',
4570
+ ariaLabel: undefined,
4571
+ ariaLabelledBy: undefined,
4572
+ ariaDescribedBy: undefined,
4573
+ autoFocus: true,
4574
+ restoreFocus: true,
4575
+ scrollStrategy: undefined,
4576
+ };
4577
+
4578
+ /**
4579
+ * DialogService — The core engine of the custom dialog system.
4580
+ *
4581
+ * Architecture Decision:
4582
+ * ─────────────────────
4583
+ * Built on top of Angular CDK's `Dialog` service (the same foundation
4584
+ * that `MatDialog` uses internally):
4585
+ *
4586
+ * 1. CDK creates the overlay, backdrop, scroll-blocking, focus-trap,
4587
+ * z-index stacking, and unique ID management — battle-tested infra
4588
+ * shared with every Angular Material dialog in the ecosystem.
4589
+ *
4590
+ * 2. We provide our own `DialogContainerComponent` (extending
4591
+ * `CdkDialogContainer`) for WAAPI animations and panel styling.
4592
+ *
4593
+ * 3. We wrap CDK's `DialogRef` in our own `DialogRef` to add the
4594
+ * leave-animation step before CDK tears down the overlay, and to
4595
+ * expose the same familiar API shape (`afterClosed()`, etc.).
4596
+ *
4597
+ * 4. Configuration is merged DEFAULT → GLOBAL → per-call, then mapped
4598
+ * to CDK's native config with our extras carried via an internal
4599
+ * injection token.
4600
+ *
4601
+ * What CDK handles for us (no custom code needed):
4602
+ * ─────────────────────────────────────────────────
4603
+ * ✓ Unique dialog IDs (throws on collision)
4604
+ * ✓ Z-index stacking via `.cdk-overlay-container`
4605
+ * ✓ Focus trap (tab key stays inside dialog)
4606
+ * ✓ Auto-focus / restore-focus
4607
+ * ✓ Scroll blocking (BlockScrollStrategy)
4608
+ * ✓ Backdrop rendering and click detection
4609
+ * ✓ Keyboard event forwarding
4610
+ * ✓ Overlay DOM lifecycle (create → attach → detach → dispose)
4611
+ *
4612
+ * Memory safety:
4613
+ * ─────────────
4614
+ * CDK manages the full lifecycle: on close it detaches the overlay,
4615
+ * destroys the container, and disposes the overlay ref.
4616
+ * Our DialogRef subjects complete via CDK's `closed` observable,
4617
+ * preventing lingering subscriptions.
4618
+ */
4619
+ class DialogService {
4620
+ _cdkDialog = inject(Dialog);
4621
+ _overlay = inject(Overlay);
4622
+ _globalConfig = inject(DIALOG_GLOBAL_CONFIG, { optional: true });
4623
+ /** Stack of currently open dialog refs (most recent = last). */
4624
+ _openDialogRefs = [];
4625
+ // ════════════════════════════════════════════════════════════════════
4626
+ // Public API
4627
+ // ════════════════════════════════════════════════════════════════════
4628
+ /**
4629
+ * Open a dialog containing the given component.
4630
+ *
4631
+ * @param component The component class to render inside the dialog.
4632
+ * @param config Optional per-dialog configuration (merged on top
4633
+ * of global and default settings).
4634
+ * @returns A strongly-typed `DialogRef` to interact with.
4635
+ *
4636
+ * @example
4637
+ * ```ts
4638
+ * const ref = this.dialog.open(UserFormComponent, {
4639
+ * width: '500px',
4640
+ * data: { userId: 10 },
4641
+ * });
4642
+ * ref.afterClosed().subscribe(result => console.log(result));
4643
+ * ```
4644
+ */
4645
+ open(component, config) {
4646
+ // ── 1. Merge configs: DEFAULT ← GLOBAL ← per-call ──────────────
4647
+ const mergedConfig = {
4648
+ ...DEFAULT_DIALOG_CONFIG,
4649
+ ...(this._globalConfig ?? {}),
4650
+ ...(config ?? {}),
4651
+ };
4652
+ // ── 2. Prepare the return ref (set inside providers callback) ───
4653
+ let ourRef;
4654
+ // ── 3. Build CDK-native config ──────────────────────────────────
4655
+ const cdkConfig = {
4656
+ // Identity
4657
+ id: mergedConfig.id,
4658
+ // Sizing (applied on .cdk-overlay-pane)
4659
+ width: mergedConfig.width,
4660
+ height: mergedConfig.height,
4661
+ minWidth: mergedConfig.minWidth,
4662
+ minHeight: mergedConfig.minHeight,
4663
+ maxWidth: mergedConfig.maxWidth ?? '90vw',
4664
+ maxHeight: mergedConfig.maxHeight ?? '90vh',
4665
+ // Backdrop
4666
+ hasBackdrop: mergedConfig.hasBackdrop !== false,
4667
+ backdropClass: mergedConfig.backdropClass || 'cdk-overlay-dark-backdrop',
4668
+ // Panel class (always include our base class)
4669
+ panelClass: this._buildPanelClasses(mergedConfig),
4670
+ // Data (CDK provides this as DIALOG_DATA automatically)
4671
+ data: mergedConfig.data,
4672
+ // We manage close ourselves for fine-grained closeOnBackdrop / closeOnEsc.
4673
+ disableClose: true,
4674
+ // Accessibility
4675
+ autoFocus: mergedConfig.autoFocus ?? true,
4676
+ restoreFocus: mergedConfig.restoreFocus ?? true,
4677
+ role: mergedConfig.role ?? 'dialog',
4678
+ ariaLabel: mergedConfig.ariaLabel ?? null,
4679
+ ariaLabelledBy: mergedConfig.ariaLabelledBy ?? null,
4680
+ ariaDescribedBy: mergedConfig.ariaDescribedBy ?? null,
4681
+ // Scroll strategy
4682
+ scrollStrategy: mergedConfig.scrollStrategy ??
4683
+ (mergedConfig.lockScroll !== false
4684
+ ? this._overlay.scrollStrategies.block()
4685
+ : this._overlay.scrollStrategies.noop()),
4686
+ // Position strategy (centered by default, shifted by offsets)
4687
+ positionStrategy: this._buildPositionStrategy(mergedConfig),
4688
+ // ── Custom container ──────────────────────────────────────────
4689
+ container: {
4690
+ type: DialogContainerComponent,
4691
+ providers: () => [
4692
+ { provide: INTERNAL_DIALOG_CONFIG, useValue: mergedConfig },
4693
+ ],
4694
+ },
4695
+ // ── Provider callback ─────────────────────────────────────────
4696
+ // Runs after the container is created but before the user
4697
+ // component. We create our `DialogRef` wrapper here and make
4698
+ // it available for injection in the user component.
4699
+ providers: (cdkRef, _cdkConfig, containerInstance) => {
4700
+ ourRef = new DialogRef(cdkRef);
4701
+ ourRef._containerInstance = containerInstance;
4702
+ // Wire up afterOpened emission.
4703
+ containerInstance.opened
4704
+ .then(() => ourRef._emitOpened());
4705
+ return [
4706
+ { provide: DialogRef, useValue: ourRef },
4707
+ ];
4708
+ },
4709
+ };
4710
+ // ── 4. Open via CDK ─────────────────────────────────────────────
4711
+ const cdkRef = this._cdkDialog.open(component, cdkConfig);
4712
+ // ── 5. Link componentInstance ───────────────────────────────────
4713
+ ourRef.componentInstance = cdkRef.componentInstance;
4714
+ // ── 6. Set up close-on-backdrop / close-on-ESC ──────────────────
4715
+ this._setupCloseListeners(ourRef, mergedConfig);
4716
+ // ── 7. Track in stack ───────────────────────────────────────────
4717
+ this._openDialogRefs.push(ourRef);
4718
+ // ── 8. Cleanup on close ─────────────────────────────────────────
4719
+ ourRef.afterClosed().subscribe(() => {
4720
+ const idx = this._openDialogRefs.indexOf(ourRef);
4721
+ if (idx !== -1)
4722
+ this._openDialogRefs.splice(idx, 1);
4723
+ });
4724
+ return ourRef;
4725
+ }
4726
+ /**
4727
+ * Close all currently open dialogs (most recent first).
4728
+ */
4729
+ closeAll() {
4730
+ for (let i = this._openDialogRefs.length - 1; i >= 0; i--) {
4731
+ this._openDialogRefs[i].close();
4732
+ }
4733
+ }
4734
+ /**
4735
+ * Returns the `DialogRef` of the most recently opened dialog,
4736
+ * or `undefined` if none are open.
4737
+ */
4738
+ getTopDialog() {
4739
+ return this._openDialogRefs[this._openDialogRefs.length - 1];
4740
+ }
4741
+ /**
4742
+ * Get a dialog by its CDK-managed unique ID.
4743
+ */
4744
+ getDialogById(id) {
4745
+ return this._openDialogRefs.find(r => r.id === id);
4746
+ }
4747
+ /**
4748
+ * Number of currently open dialogs.
4749
+ */
4750
+ get openDialogCount() {
4751
+ return this._openDialogRefs.length;
4752
+ }
4753
+ /**
4754
+ * Read-only snapshot of currently open dialog refs.
4755
+ * Used internally by content directives (`BkDialogTitle`, `BkDialogActions`,
4756
+ * `BkDialogClose`) for the DOM-walk fallback when `DialogRef` is not
4757
+ * available via injection (e.g. inside `<ng-template>`).
4758
+ */
4759
+ get openDialogsRef() {
4760
+ return this._openDialogRefs;
4761
+ }
4762
+ // ════════════════════════════════════════════════════════════════════
4763
+ // Convenience Helpers
4764
+ // ════════════════════════════════════════════════════════════════════
4765
+ /**
4766
+ * Open a simple confirmation dialog.
4767
+ * Resolves `true` if the user confirms, `false` otherwise.
4768
+ *
4769
+ * @example
4770
+ * ```ts
4771
+ * const ref = this.dialog.confirm({
4772
+ * message: 'Delete this item?',
4773
+ * component: ConfirmDialogComponent,
4774
+ * });
4775
+ * ref.afterClosed().subscribe(yes => { if (yes) ... });
4776
+ * ```
4777
+ */
4778
+ confirm(options) {
4779
+ return this.open(options.component, {
4780
+ width: options.width ?? '400px',
4781
+ disableClose: true,
4782
+ closeOnBackdrop: false,
4783
+ animation: 'fade',
4784
+ data: {
4785
+ title: options.title ?? 'Confirm',
4786
+ message: options.message,
4787
+ btnOkText: options.btnOkText ?? 'Yes',
4788
+ btnCancelText: options.btnCancelText ?? 'No',
4789
+ },
4790
+ });
4791
+ }
4792
+ /**
4793
+ * Open a simple alert dialog.
4794
+ */
4795
+ alert(options) {
4796
+ return this.open(options.component, {
4797
+ width: options.width ?? '400px',
4798
+ disableClose: true,
4799
+ closeOnBackdrop: false,
4800
+ animation: 'fade',
4801
+ data: {
4802
+ title: options.title ?? 'Alert',
4803
+ message: options.message,
4804
+ btnOkText: options.btnOkText ?? 'OK',
4805
+ },
4806
+ });
4807
+ }
4808
+ // ════════════════════════════════════════════════════════════════════
4809
+ // Private
4810
+ // ════════════════════════════════════════════════════════════════════
4811
+ /**
4812
+ * Subscribe to backdrop-click and ESC events on the CDK ref,
4813
+ * closing the dialog based on our config flags.
4814
+ *
4815
+ * We always set CDK `disableClose: true` so that CDK never auto-closes;
4816
+ * this gives us fine-grained control over `closeOnBackdrop` and
4817
+ * `closeOnEsc` independently.
4818
+ */
4819
+ _setupCloseListeners(ref, config) {
4820
+ if (config.disableClose)
4821
+ return;
4822
+ // Backdrop click
4823
+ if (config.closeOnBackdrop !== false) {
4824
+ ref.backdropClick().subscribe(() => ref.close());
4825
+ }
4826
+ // ESC key
4827
+ if (config.closeOnEsc !== false) {
4828
+ ref.keydownEvents()
4829
+ .pipe(filter((e) => e.key === 'Escape' || e.key === 'Esc'))
4830
+ .subscribe((e) => {
4831
+ e.preventDefault();
4832
+ ref.close();
4833
+ });
4834
+ }
4835
+ }
4836
+ /**
4837
+ * Build the CSS classes for the CDK overlay pane.
4838
+ * Always includes our base class; adds user-provided classes on top.
4839
+ */
4840
+ _buildPanelClasses(config) {
4841
+ const classes = ['bk-dialog-pane'];
4842
+ if (config.panelClass) {
4843
+ if (Array.isArray(config.panelClass)) {
4844
+ classes.push(...config.panelClass);
4845
+ }
4846
+ else {
4847
+ classes.push(config.panelClass);
4848
+ }
4849
+ }
4850
+ return classes;
4851
+ }
4852
+ /**
4853
+ * Build CDK's `GlobalPositionStrategy` from our position config.
4854
+ * Falls back to centred (both axes) when no position is specified.
4855
+ */
4856
+ _buildPositionStrategy(config) {
4857
+ const strategy = this._overlay.position().global();
4858
+ if (config.position?.top) {
4859
+ strategy.top(config.position.top);
4860
+ }
4861
+ else if (config.position?.bottom) {
4862
+ strategy.bottom(config.position.bottom);
4863
+ }
4864
+ else {
4865
+ strategy.centerVertically();
4866
+ }
4867
+ if (config.position?.left) {
4868
+ strategy.left(config.position.left);
4869
+ }
4870
+ else if (config.position?.right) {
4871
+ strategy.right(config.position.right);
4872
+ }
4873
+ else {
4874
+ strategy.centerHorizontally();
4875
+ }
4876
+ return strategy;
4877
+ }
4878
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4879
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogService, providedIn: 'root' });
4880
+ }
4881
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DialogService, decorators: [{
4882
+ type: Injectable,
4883
+ args: [{ providedIn: 'root' }]
4884
+ }] });
4885
+
4886
+ /**
4887
+ * Dialog Content Directives
4888
+ *
4889
+ * Architecture Decision:
4890
+ * ─────────────────────
4891
+ * These directives mirror Angular Material's dialog content directives:
4892
+ *
4893
+ * MatDialogTitle → BkDialogTitle
4894
+ * MatDialogContent → BkDialogContent
4895
+ * MatDialogActions → BkDialogActions
4896
+ * MatDialogClose → BkDialogClose
4897
+ *
4898
+ * Each directive:
4899
+ * 1. Applies the corresponding CSS host class (e.g. `bk-dialog-content`)
4900
+ * that is styled in `dialog-container.css` via `::ng-deep`.
4901
+ * 2. Provides extra accessibility or behavioural features on top of the
4902
+ * plain CSS class.
4903
+ *
4904
+ * Consumers can still use the raw CSS classes directly (without importing
4905
+ * these directives) for backward compatibility, but the directives are
4906
+ * preferred because they add CdkScrollable, ARIA integration, and one-click
4907
+ * close behaviour.
4908
+ *
4909
+ * @see https://github.com/angular/components/blob/main/src/material/dialog/dialog-content-directives.ts
4910
+ */
4911
+ // ──── ID Generation ──────────────────────────────────────────────────────
4912
+ let nextTitleId = 0;
4913
+ // ──── Helper ─────────────────────────────────────────────────────────────
4914
+ /**
4915
+ * Finds the closest `DialogRef` by walking up the DOM from the given
4916
+ * element to the nearest `bk-dialog-container` host, then matching its
4917
+ * `id` attribute against the currently open dialogs.
4918
+ *
4919
+ * This fallback is necessary when a directive lives inside an
4920
+ * `<ng-template>` (TemplateRef), where the dialog's custom injector is
4921
+ * not available.
4922
+ *
4923
+ * @see Material's `getClosestDialog` in `dialog-content-directives.ts`
4924
+ */
4925
+ function getClosestDialog(element, openDialogs) {
4926
+ let parent = element.nativeElement.parentElement;
4927
+ while (parent && !parent.classList.contains('bk-dialog-container')) {
4928
+ parent = parent.parentElement;
4929
+ }
4930
+ return parent
4931
+ ? openDialogs.find(ref => ref.id === parent.id) ?? null
4932
+ : null;
4933
+ }
4934
+ // ──── Base for Title / Actions ───────────────────────────────────────────
4935
+ /**
4936
+ * Shared abstract base that resolves the owning `DialogRef` (via DI or
4937
+ * DOM walk) and invokes `_onAdd()` / `_onRemove()` lifecycle hooks.
4938
+ *
4939
+ * Same pattern as Material's internal `MatDialogLayoutSection`.
4940
+ */
4941
+ class BkDialogLayoutSection {
4942
+ _dialogRef = inject(DialogRef, { optional: true });
4943
+ _elementRef = inject((ElementRef));
4944
+ _dialogService = inject(DialogService);
4945
+ ngOnInit() {
4946
+ if (!this._dialogRef) {
4947
+ this._dialogRef = getClosestDialog(this._elementRef, this._dialogService.openDialogsRef);
4948
+ }
4949
+ if (this._dialogRef) {
4950
+ Promise.resolve().then(() => this._onAdd());
4951
+ }
4952
+ }
4953
+ ngOnDestroy() {
4954
+ if (this._dialogRef) {
4955
+ Promise.resolve().then(() => this._onRemove());
4956
+ }
4957
+ }
4958
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogLayoutSection, deps: [], target: i0.ɵɵFactoryTarget.Directive });
4959
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogLayoutSection, isStandalone: true, ngImport: i0 });
4960
+ }
4961
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogLayoutSection, decorators: [{
4962
+ type: Directive,
4963
+ args: [{ standalone: true }]
4964
+ }] });
4965
+ // ════════════════════════════════════════════════════════════════════════
4966
+ // BkDialogTitle
4967
+ // ════════════════════════════════════════════════════════════════════════
4968
+ /**
4969
+ * Marks an element as the dialog title.
4970
+ *
4971
+ * • Generates a unique `id` and binds it to the host element.
4972
+ * • Registers the `id` with the CDK container's `aria-labelledby` queue
4973
+ * so screen readers announce the dialog title automatically.
4974
+ *
4975
+ * Usage:
4976
+ * ```html
4977
+ * <h2 bk-dialog-title>Edit User</h2>
4978
+ * ```
4979
+ */
4980
+ class BkDialogTitle extends BkDialogLayoutSection {
4981
+ /** Unique element `id`. Auto-generated but can be overridden. */
4982
+ id = `bk-dialog-title-${nextTitleId++}`;
4983
+ _onAdd() {
4984
+ // Register with the CdkDialogContainer's aria-labelledby queue.
4985
+ // _containerInstance extends CdkDialogContainer which has _addAriaLabelledBy.
4986
+ this._dialogRef?._containerInstance?._addAriaLabelledBy?.(this.id);
4987
+ }
4988
+ _onRemove() {
4989
+ this._dialogRef?._containerInstance?._removeAriaLabelledBy?.(this.id);
4990
+ }
4991
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogTitle, deps: null, target: i0.ɵɵFactoryTarget.Directive });
4992
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogTitle, isStandalone: true, selector: "[bk-dialog-title], [bkDialogTitle]", inputs: { id: "id" }, host: { properties: { "id": "id" }, classAttribute: "bk-dialog-title" }, exportAs: ["bkDialogTitle"], usesInheritance: true, ngImport: i0 });
4993
+ }
4994
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogTitle, decorators: [{
4995
+ type: Directive,
4996
+ args: [{
4997
+ selector: '[bk-dialog-title], [bkDialogTitle]',
4998
+ standalone: true,
4999
+ exportAs: 'bkDialogTitle',
5000
+ host: {
5001
+ 'class': 'bk-dialog-title',
5002
+ '[id]': 'id',
5003
+ },
5004
+ }]
5005
+ }], propDecorators: { id: [{
5006
+ type: Input
5007
+ }] } });
5008
+ // ════════════════════════════════════════════════════════════════════════
5009
+ // BkDialogContent
5010
+ // ════════════════════════════════════════════════════════════════════════
5011
+ /**
5012
+ * Scrollable content area of a dialog.
5013
+ *
5014
+ * • Applies the `bk-dialog-content` CSS class → `flex: 1 1 auto; overflow: auto`.
5015
+ * • Composes CDK's `CdkScrollable` for scroll-position monitoring and
5016
+ * integration with CDK's scroll dispatcher.
5017
+ *
5018
+ * Usage (attribute):
5019
+ * ```html
5020
+ * <div bk-dialog-content>
5021
+ * <!-- body content — this area scrolls -->
5022
+ * </div>
5023
+ * ```
5024
+ *
5025
+ * Usage (element):
5026
+ * ```html
5027
+ * <bk-dialog-content>...</bk-dialog-content>
5028
+ * ```
5029
+ */
5030
+ class BkDialogContent {
5031
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5032
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive: i1$2.CdkScrollable }], ngImport: i0 });
5033
+ }
5034
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, decorators: [{
5035
+ type: Directive,
5036
+ args: [{
5037
+ selector: '[bk-dialog-content], bk-dialog-content, [bkDialogContent]',
5038
+ standalone: true,
5039
+ exportAs: 'bkDialogContent',
5040
+ host: {
5041
+ 'class': 'bk-dialog-content',
5042
+ },
5043
+ hostDirectives: [CdkScrollable],
5044
+ }]
5045
+ }] });
5046
+ // ════════════════════════════════════════════════════════════════════════
5047
+ // BkDialogActions
5048
+ // ════════════════════════════════════════════════════════════════════════
5049
+ /**
5050
+ * Container for action buttons at the bottom of a dialog.
5051
+ * Stays pinned when the content area scrolls.
5052
+ *
5053
+ * • Applies `bk-dialog-actions` class → `flex: 0 0 auto` (never shrinks).
5054
+ * • Optional `align` input controls horizontal alignment.
5055
+ *
5056
+ * Usage:
5057
+ * ```html
5058
+ * <div bk-dialog-actions>
5059
+ * <button (click)="cancel()">Cancel</button>
5060
+ * <button (click)="save()">Save</button>
5061
+ * </div>
5062
+ *
5063
+ * <!-- With alignment -->
5064
+ * <div bk-dialog-actions align="center">...</div>
5065
+ * ```
5066
+ */
5067
+ class BkDialogActions extends BkDialogLayoutSection {
5068
+ /** Horizontal alignment of action buttons. */
5069
+ align;
5070
+ _onAdd() {
5071
+ // Future: notify container for action section count (like Material).
5072
+ }
5073
+ _onRemove() {
5074
+ // No-op.
5075
+ }
5076
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogActions, deps: null, target: i0.ɵɵFactoryTarget.Directive });
5077
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogActions, isStandalone: true, selector: "[bk-dialog-actions], bk-dialog-actions, [bkDialogActions]", inputs: { align: "align" }, host: { properties: { "class.bk-dialog-actions-align-start": "align === \"start\"", "class.bk-dialog-actions-align-center": "align === \"center\"", "class.bk-dialog-actions-align-end": "align === \"end\"" }, classAttribute: "bk-dialog-actions" }, exportAs: ["bkDialogActions"], usesInheritance: true, ngImport: i0 });
5078
+ }
5079
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogActions, decorators: [{
5080
+ type: Directive,
5081
+ args: [{
5082
+ selector: '[bk-dialog-actions], bk-dialog-actions, [bkDialogActions]',
5083
+ standalone: true,
5084
+ exportAs: 'bkDialogActions',
5085
+ host: {
5086
+ 'class': 'bk-dialog-actions',
5087
+ '[class.bk-dialog-actions-align-start]': 'align === "start"',
5088
+ '[class.bk-dialog-actions-align-center]': 'align === "center"',
5089
+ '[class.bk-dialog-actions-align-end]': 'align === "end"',
5090
+ },
5091
+ }]
5092
+ }], propDecorators: { align: [{
5093
+ type: Input
5094
+ }] } });
5095
+ // ════════════════════════════════════════════════════════════════════════
5096
+ // BkDialogClose
5097
+ // ════════════════════════════════════════════════════════════════════════
5098
+ /**
5099
+ * Closes the dialog when the host element is clicked.
5100
+ * Optionally returns a result value to the opener.
5101
+ *
5102
+ * • Sets `type="button"` by default to prevent accidental form submissions.
5103
+ * • Supports an optional `aria-label` for screen readers.
5104
+ *
5105
+ * Usage:
5106
+ * ```html
5107
+ * <!-- Close with no result -->
5108
+ * <button bk-dialog-close>Cancel</button>
5109
+ *
5110
+ * <!-- Close with a result value -->
5111
+ * <button [bk-dialog-close]="'confirmed'">OK</button>
5112
+ *
5113
+ * <!-- Alternative camelCase binding -->
5114
+ * <button [bkDialogClose]="myResult">Done</button>
5115
+ * ```
5116
+ */
5117
+ class BkDialogClose {
5118
+ _dialogRef = inject(DialogRef, { optional: true });
5119
+ _elementRef = inject((ElementRef));
5120
+ _dialogService = inject(DialogService);
5121
+ /** Screen-reader label for the button. */
5122
+ ariaLabel;
5123
+ /** Prevents accidental form submits. Default: `'button'`. */
5124
+ type = 'button';
5125
+ /** Dialog result — set via `[bk-dialog-close]="value"`. */
5126
+ dialogResult;
5127
+ /** Alternative camelCase binding: `[bkDialogClose]="value"`. */
5128
+ _bkDialogClose;
5129
+ ngOnInit() {
5130
+ if (!this._dialogRef) {
5131
+ this._dialogRef = getClosestDialog(this._elementRef, this._dialogService.openDialogsRef);
5132
+ }
5133
+ }
5134
+ ngOnChanges(changes) {
5135
+ const proxiedChange = changes['_bkDialogClose'] || changes['dialogResult'];
5136
+ if (proxiedChange) {
5137
+ this.dialogResult = proxiedChange.currentValue;
5138
+ }
5139
+ }
5140
+ _onButtonClick(_event) {
5141
+ this._dialogRef?.close(this.dialogResult);
5142
+ }
5143
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogClose, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5144
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogClose, isStandalone: true, selector: "[bk-dialog-close], [bkDialogClose]", inputs: { ariaLabel: ["aria-label", "ariaLabel"], type: "type", dialogResult: ["bk-dialog-close", "dialogResult"], _bkDialogClose: ["bkDialogClose", "_bkDialogClose"] }, host: { listeners: { "click": "_onButtonClick($event)" }, properties: { "attr.aria-label": "ariaLabel || null", "attr.type": "type" } }, exportAs: ["bkDialogClose"], usesOnChanges: true, ngImport: i0 });
5145
+ }
5146
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogClose, decorators: [{
5147
+ type: Directive,
5148
+ args: [{
5149
+ selector: '[bk-dialog-close], [bkDialogClose]',
5150
+ standalone: true,
5151
+ exportAs: 'bkDialogClose',
5152
+ host: {
5153
+ '(click)': '_onButtonClick($event)',
5154
+ '[attr.aria-label]': 'ariaLabel || null',
5155
+ '[attr.type]': 'type',
5156
+ },
5157
+ }]
5158
+ }], propDecorators: { ariaLabel: [{
5159
+ type: Input,
5160
+ args: ['aria-label']
5161
+ }], type: [{
5162
+ type: Input
5163
+ }], dialogResult: [{
5164
+ type: Input,
5165
+ args: ['bk-dialog-close']
5166
+ }], _bkDialogClose: [{
5167
+ type: Input,
5168
+ args: ['bkDialogClose']
5169
+ }] } });
5170
+
5171
+ /**
5172
+ * BkDialogModule
5173
+ *
5174
+ * Optional NgModule wrapper for projects that prefer module-based usage.
5175
+ *
5176
+ * Architecture Decision:
5177
+ * ─────────────────────
5178
+ * Follows the exact same pattern as Angular Material's `MatDialogModule`
5179
+ * and `@brickclay-org/ui`'s `CalendarModule`:
5180
+ *
5181
+ * • All components/directives are **standalone**.
5182
+ * • This module simply imports + re-exports them for convenience.
5183
+ * • `DialogService` is `providedIn: 'root'`, so it does NOT need to
5184
+ * be listed in `providers` here — it is tree-shakeable and available
5185
+ * app-wide automatically.
5186
+ *
5187
+ * Two usage styles:
5188
+ *
5189
+ * ───────── Module-based (NgModule) ─────────
5190
+ * ```ts
5191
+ * import { BkDialogModule } from '@shared/components/dialog';
5192
+ *
5193
+ * @NgModule({ imports: [BkDialogModule] })
5194
+ * export class FuelCostModule {}
5195
+ * ```
5196
+ *
5197
+ * ───────── Standalone ──────────────────────
5198
+ * ```ts
5199
+ * @Component({
5200
+ * standalone: true,
5201
+ * imports: [BkDialogContent, BkDialogActions, BkDialogClose],
5202
+ * })
5203
+ * export class MyDialog {}
5204
+ * ```
5205
+ *
5206
+ * @see https://github.com/angular/components/blob/main/src/material/dialog/dialog-module.ts
5207
+ */
5208
+ class BkDialogModule {
5209
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
5210
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: BkDialogModule, imports: [
5211
+ // ── CDK foundations ──────────────────────────────────────────────
5212
+ DialogModule,
5213
+ OverlayModule,
5214
+ PortalModule,
5215
+ // ── Our standalone pieces ───────────────────────────────────────
5216
+ DialogContainerComponent,
5217
+ BkDialogTitle,
5218
+ BkDialogContent,
5219
+ BkDialogActions,
5220
+ BkDialogClose], exports: [
5221
+ // ── Public API for template usage ───────────────────────────────
5222
+ // Consumers import BkDialogModule and get these directives in
5223
+ // their templates automatically — just like MatDialogModule.
5224
+ BkDialogTitle,
5225
+ BkDialogContent,
5226
+ BkDialogActions,
5227
+ BkDialogClose] });
5228
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogModule, imports: [
5229
+ // ── CDK foundations ──────────────────────────────────────────────
5230
+ DialogModule,
5231
+ OverlayModule,
5232
+ PortalModule] });
5233
+ }
5234
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogModule, decorators: [{
5235
+ type: NgModule,
5236
+ args: [{
5237
+ imports: [
5238
+ // ── CDK foundations ──────────────────────────────────────────────
5239
+ DialogModule,
5240
+ OverlayModule,
5241
+ PortalModule,
5242
+ // ── Our standalone pieces ───────────────────────────────────────
5243
+ DialogContainerComponent,
5244
+ BkDialogTitle,
5245
+ BkDialogContent,
5246
+ BkDialogActions,
5247
+ BkDialogClose,
5248
+ ],
5249
+ exports: [
5250
+ // ── Public API for template usage ───────────────────────────────
5251
+ // Consumers import BkDialogModule and get these directives in
5252
+ // their templates automatically — just like MatDialogModule.
5253
+ BkDialogTitle,
5254
+ BkDialogContent,
5255
+ BkDialogActions,
5256
+ BkDialogClose,
5257
+ ],
5258
+ }]
5259
+ }] });
5260
+
4025
5261
  /*
4026
5262
  * Public API Surface of brickclay-lib
4027
5263
  */
@@ -4031,5 +5267,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4031
5267
  * Generated bundle index. Do not edit.
4032
5268
  */
4033
5269
 
4034
- export { BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkChips, BkCustomCalendar, BkGrid, BkIconButton, BkInput, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToggle, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule };
5270
+ export { BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogTitle, BkGrid, BkIconButton, BkInput, BkInputChips, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToggle, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule, DEFAULT_DIALOG_CONFIG, DIALOG_DATA, DIALOG_GLOBAL_CONFIG, DialogRef, DialogService, getDialogBackdropAnimation, getDialogPanelAnimation };
4035
5271
  //# sourceMappingURL=brickclay-org-ui.mjs.map