@brickclay-org/ui 0.1.84 → 0.1.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/brickclay-org-ui.mjs +950 -650
- package/fesm2022/brickclay-org-ui.mjs.map +1 -1
- package/index.d.ts +357 -156
- package/package.json +1 -6
- package/src/assets/icons/dollar-icon-script.svg +3 -0
- package/src/assets/icons/dollar-icon-thin.svg +3 -0
- package/src/assets/icons/dollar-icon.svg +2 -4
- package/src/assets/icons/double-chevron-left.svg +4 -0
- package/src/assets/icons/double-chevron-right.svg +4 -0
- package/src/lib/hierarchical-select/hierarchical-select.css +34 -19
- package/src/lib/input/input.css +18 -3
- package/src/lib/popover/popover.css +18 -4
- package/src/lib/select/select.css +27 -3
- package/src/styles.css +13 -0
|
@@ -10,9 +10,10 @@ import * as i2$1 from '@angular/cdk/drag-drop';
|
|
|
10
10
|
import { moveItemInArray, DragDropModule, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
11
11
|
import * as i2$2 from '@angular/cdk/scrolling';
|
|
12
12
|
import { ScrollingModule, CdkScrollable, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
|
13
|
+
import * as i3 from '@angular/cdk/overlay';
|
|
14
|
+
import { OverlayModule, Overlay } from '@angular/cdk/overlay';
|
|
13
15
|
import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
|
|
14
16
|
import { DIALOG_DATA, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
|
|
15
|
-
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
16
17
|
import { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';
|
|
17
18
|
import { toObservable } from '@angular/core/rxjs-interop';
|
|
18
19
|
|
|
@@ -21,6 +22,8 @@ import { toObservable } from '@angular/core/rxjs-interop';
|
|
|
21
22
|
const BrickclayIcons = {
|
|
22
23
|
arrowleft: 'assets/icons/chevron-left.svg',
|
|
23
24
|
arrowRight: 'assets/icons/chevron-right.svg',
|
|
25
|
+
arrowLeftDouble: 'assets/icons/double-chevron-left.svg',
|
|
26
|
+
arrowRightDouble: 'assets/icons/double-chevron-right.svg',
|
|
24
27
|
calenderIcon: 'assets/icons/custom-calender.svg',
|
|
25
28
|
timerIcon: 'assets/icons/timer.svg',
|
|
26
29
|
};
|
|
@@ -4231,9 +4234,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4231
4234
|
type: Output
|
|
4232
4235
|
}] } });
|
|
4233
4236
|
|
|
4237
|
+
/**
|
|
4238
|
+
* Shared document/window listeners for `bkTooltip`.
|
|
4239
|
+
*
|
|
4240
|
+
* Every directive instance used to declare its own `document:mousedown`,
|
|
4241
|
+
* `window:scroll` and `window:resize` host listeners. On dense screens (the ticket
|
|
4242
|
+
* documents page renders several hundred tooltip hosts) a single click therefore ran
|
|
4243
|
+
* several hundred handlers and — because host listeners mark their view dirty —
|
|
4244
|
+
* forced a full application change-detection pass, which is what made rapid clicking
|
|
4245
|
+
* lock up the page.
|
|
4246
|
+
*
|
|
4247
|
+
* Only a tooltip that is currently visible has anything to do, so tooltips subscribe
|
|
4248
|
+
* while shown and unsubscribe when hidden. The listeners are attached outside the
|
|
4249
|
+
* Angular zone: they only mutate tooltip styles through `Renderer2`, so no change
|
|
4250
|
+
* detection is required.
|
|
4251
|
+
*/
|
|
4252
|
+
class BkTooltipInteractionService {
|
|
4253
|
+
zone;
|
|
4254
|
+
visibleTooltips = new Set();
|
|
4255
|
+
listenersAttached = false;
|
|
4256
|
+
constructor(zone) {
|
|
4257
|
+
this.zone = zone;
|
|
4258
|
+
}
|
|
4259
|
+
/** Called when a tooltip becomes visible. */
|
|
4260
|
+
register(tooltip) {
|
|
4261
|
+
this.attachListeners();
|
|
4262
|
+
this.visibleTooltips.add(tooltip);
|
|
4263
|
+
}
|
|
4264
|
+
/** Called when a tooltip is hidden or destroyed. */
|
|
4265
|
+
unregister(tooltip) {
|
|
4266
|
+
this.visibleTooltips.delete(tooltip);
|
|
4267
|
+
}
|
|
4268
|
+
attachListeners() {
|
|
4269
|
+
if (this.listenersAttached) {
|
|
4270
|
+
return;
|
|
4271
|
+
}
|
|
4272
|
+
this.listenersAttached = true;
|
|
4273
|
+
this.zone.runOutsideAngular(() => {
|
|
4274
|
+
const hideAll = () => {
|
|
4275
|
+
this.forEachVisible((tooltip) => tooltip.hideOnGlobalInteraction());
|
|
4276
|
+
};
|
|
4277
|
+
document.addEventListener('mousedown', hideAll);
|
|
4278
|
+
document.addEventListener('touchstart', hideAll);
|
|
4279
|
+
window.addEventListener('scroll', () => {
|
|
4280
|
+
this.forEachVisible((tooltip) => tooltip.repositionOnViewportChange());
|
|
4281
|
+
});
|
|
4282
|
+
window.addEventListener('resize', () => {
|
|
4283
|
+
this.forEachVisible((tooltip) => tooltip.repositionOnViewportChange());
|
|
4284
|
+
});
|
|
4285
|
+
});
|
|
4286
|
+
}
|
|
4287
|
+
forEachVisible(action) {
|
|
4288
|
+
if (this.visibleTooltips.size === 0) {
|
|
4289
|
+
return;
|
|
4290
|
+
}
|
|
4291
|
+
// Copy: hiding a tooltip unregisters it while iterating.
|
|
4292
|
+
for (const tooltip of Array.from(this.visibleTooltips)) {
|
|
4293
|
+
action(tooltip);
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTooltipInteractionService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4297
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTooltipInteractionService, providedIn: 'root' });
|
|
4298
|
+
}
|
|
4299
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTooltipInteractionService, decorators: [{
|
|
4300
|
+
type: Injectable,
|
|
4301
|
+
args: [{ providedIn: 'root' }]
|
|
4302
|
+
}], ctorParameters: () => [{ type: i0.NgZone }] });
|
|
4303
|
+
|
|
4234
4304
|
class BKTooltipDirective {
|
|
4235
4305
|
el;
|
|
4236
4306
|
renderer;
|
|
4307
|
+
tooltipInteraction;
|
|
4237
4308
|
tooltipContent = '';
|
|
4238
4309
|
tooltipPosition = 'right';
|
|
4239
4310
|
scrollable = false;
|
|
@@ -4245,9 +4316,11 @@ class BKTooltipDirective {
|
|
|
4245
4316
|
isHoveringTooltip = false;
|
|
4246
4317
|
hideTimeout = null;
|
|
4247
4318
|
tooltipListeners = [];
|
|
4248
|
-
|
|
4319
|
+
isRegisteredWithInteractionService = false;
|
|
4320
|
+
constructor(el, renderer, tooltipInteraction) {
|
|
4249
4321
|
this.el = el;
|
|
4250
4322
|
this.renderer = renderer;
|
|
4323
|
+
this.tooltipInteraction = tooltipInteraction;
|
|
4251
4324
|
}
|
|
4252
4325
|
ngOnInit() {
|
|
4253
4326
|
this.createTooltip();
|
|
@@ -4262,6 +4335,7 @@ class BKTooltipDirective {
|
|
|
4262
4335
|
clearTimeout(this.hideTimeout);
|
|
4263
4336
|
this.hideTimeout = null;
|
|
4264
4337
|
}
|
|
4338
|
+
this.unregisterFromInteractionService();
|
|
4265
4339
|
this.cleanupTooltipListeners();
|
|
4266
4340
|
this.removeTooltip();
|
|
4267
4341
|
}
|
|
@@ -4314,6 +4388,7 @@ class BKTooltipDirective {
|
|
|
4314
4388
|
opacity: '1',
|
|
4315
4389
|
});
|
|
4316
4390
|
this.renderer.setStyle(document.body, 'overflow-x', 'hidden'); // ✅ temporarily lock horizontal scroll
|
|
4391
|
+
this.registerWithInteractionService();
|
|
4317
4392
|
}
|
|
4318
4393
|
}
|
|
4319
4394
|
onMouseLeave() {
|
|
@@ -4336,24 +4411,34 @@ class BKTooltipDirective {
|
|
|
4336
4411
|
// this.renderer.removeStyle(document.body, 'overflow-x');
|
|
4337
4412
|
// }
|
|
4338
4413
|
// }
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
// can still be mid-fade — mouseleave's hide is debounced 100ms and the
|
|
4342
|
-
// fade itself takes 300ms — when a click elsewhere opens something else
|
|
4343
|
-
// (a dropdown panel, another tooltip's host), so the two stack visibly.
|
|
4344
|
-
// Also covers CDK drag-drop, which steals the element before mouseleave fires.
|
|
4345
|
-
onInteract() {
|
|
4414
|
+
/** @see BkTooltipInteractionService — shared document/window listeners */
|
|
4415
|
+
hideOnGlobalInteraction() {
|
|
4346
4416
|
if (this.hideTimeout) {
|
|
4347
4417
|
clearTimeout(this.hideTimeout);
|
|
4348
4418
|
this.hideTimeout = null;
|
|
4349
4419
|
}
|
|
4350
4420
|
this.hideTooltipInstant();
|
|
4351
4421
|
}
|
|
4352
|
-
|
|
4422
|
+
/** @see BkTooltipInteractionService — shared document/window listeners */
|
|
4423
|
+
repositionOnViewportChange() {
|
|
4353
4424
|
if (this.tooltipElement?.style.visibility === 'visible') {
|
|
4354
4425
|
this.setTooltipPosition();
|
|
4355
4426
|
}
|
|
4356
4427
|
}
|
|
4428
|
+
registerWithInteractionService() {
|
|
4429
|
+
if (this.isRegisteredWithInteractionService) {
|
|
4430
|
+
return;
|
|
4431
|
+
}
|
|
4432
|
+
this.tooltipInteraction.register(this);
|
|
4433
|
+
this.isRegisteredWithInteractionService = true;
|
|
4434
|
+
}
|
|
4435
|
+
unregisterFromInteractionService() {
|
|
4436
|
+
if (!this.isRegisteredWithInteractionService) {
|
|
4437
|
+
return;
|
|
4438
|
+
}
|
|
4439
|
+
this.tooltipInteraction.unregister(this);
|
|
4440
|
+
this.isRegisteredWithInteractionService = false;
|
|
4441
|
+
}
|
|
4357
4442
|
isTooltipContentEmpty() {
|
|
4358
4443
|
if (typeof this.tooltipContent === 'string') {
|
|
4359
4444
|
return !this.tooltipContent.trim();
|
|
@@ -4385,6 +4470,7 @@ class BKTooltipDirective {
|
|
|
4385
4470
|
this.renderer.removeStyle(document.body, 'overflow-x'); // ✅ restore scroll when tooltip hides
|
|
4386
4471
|
}
|
|
4387
4472
|
this.isHoveringTooltip = false;
|
|
4473
|
+
this.unregisterFromInteractionService();
|
|
4388
4474
|
}
|
|
4389
4475
|
setupTooltipHoverListeners() {
|
|
4390
4476
|
if (!this.tooltipElement)
|
|
@@ -4405,6 +4491,7 @@ class BKTooltipDirective {
|
|
|
4405
4491
|
visibility: 'visible',
|
|
4406
4492
|
opacity: '1',
|
|
4407
4493
|
});
|
|
4494
|
+
this.registerWithInteractionService();
|
|
4408
4495
|
}
|
|
4409
4496
|
});
|
|
4410
4497
|
// Add mouseleave listener to tooltip
|
|
@@ -4465,9 +4552,7 @@ class BKTooltipDirective {
|
|
|
4465
4552
|
position: 'fixed',
|
|
4466
4553
|
visibility: 'hidden',
|
|
4467
4554
|
opacity: '0',
|
|
4468
|
-
|
|
4469
|
-
// Keep this transient explanatory layer above its owning overlay.
|
|
4470
|
-
zIndex: '11000',
|
|
4555
|
+
zIndex: '9999',
|
|
4471
4556
|
transition: 'opacity 0.3s ease, visibility 0.3s ease',
|
|
4472
4557
|
maxWidth: '300px',
|
|
4473
4558
|
wordBreak: 'normal', // ← only break at spaces
|
|
@@ -4690,8 +4775,8 @@ class BKTooltipDirective {
|
|
|
4690
4775
|
this.renderer.setStyle(el, prop, value);
|
|
4691
4776
|
});
|
|
4692
4777
|
}
|
|
4693
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
4694
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BKTooltipDirective, isStandalone: true, selector: "[bkTooltip]", inputs: { tooltipContent: ["bkTooltip", "tooltipContent"], tooltipPosition: ["bkTooltipPosition", "tooltipPosition"], scrollable: ["bkTooltipScrollable", "scrollable"], maxHeight: ["bkTooltipMaxHeight", "maxHeight"], tooltipSize: ["bkTooltipSize", "tooltipSize"], autoHeight: ["bkTooltipAutoHeight", "autoHeight"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()"
|
|
4778
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: BkTooltipInteractionService }], target: i0.ɵɵFactoryTarget.Directive });
|
|
4779
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BKTooltipDirective, isStandalone: true, selector: "[bkTooltip]", inputs: { tooltipContent: ["bkTooltip", "tooltipContent"], tooltipPosition: ["bkTooltipPosition", "tooltipPosition"], scrollable: ["bkTooltipScrollable", "scrollable"], maxHeight: ["bkTooltipMaxHeight", "maxHeight"], tooltipSize: ["bkTooltipSize", "tooltipSize"], autoHeight: ["bkTooltipAutoHeight", "autoHeight"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, usesOnChanges: true, ngImport: i0 });
|
|
4695
4780
|
}
|
|
4696
4781
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, decorators: [{
|
|
4697
4782
|
type: Directive,
|
|
@@ -4699,7 +4784,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4699
4784
|
selector: '[bkTooltip]',
|
|
4700
4785
|
standalone: true,
|
|
4701
4786
|
}]
|
|
4702
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { tooltipContent: [{
|
|
4787
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: BkTooltipInteractionService }], propDecorators: { tooltipContent: [{
|
|
4703
4788
|
type: Input,
|
|
4704
4789
|
args: ['bkTooltip']
|
|
4705
4790
|
}], tooltipPosition: [{
|
|
@@ -4723,18 +4808,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4723
4808
|
}], onMouseLeave: [{
|
|
4724
4809
|
type: HostListener,
|
|
4725
4810
|
args: ['mouseleave']
|
|
4726
|
-
}], onInteract: [{
|
|
4727
|
-
type: HostListener,
|
|
4728
|
-
args: ['document:mousedown']
|
|
4729
|
-
}, {
|
|
4730
|
-
type: HostListener,
|
|
4731
|
-
args: ['touchstart']
|
|
4732
|
-
}], onWindowChange: [{
|
|
4733
|
-
type: HostListener,
|
|
4734
|
-
args: ['window:scroll']
|
|
4735
|
-
}, {
|
|
4736
|
-
type: HostListener,
|
|
4737
|
-
args: ['window:resize']
|
|
4738
4811
|
}] } });
|
|
4739
4812
|
|
|
4740
4813
|
class BkGrid {
|
|
@@ -4750,6 +4823,8 @@ class BkGrid {
|
|
|
4750
4823
|
noRecordFoundHeight = '';
|
|
4751
4824
|
/** Custom illustration for the empty state. Falls back to a built-in SVG when omitted. */
|
|
4752
4825
|
noRecordImgUrl;
|
|
4826
|
+
/** Show the empty-state illustration above the message. Set false to show the message only. */
|
|
4827
|
+
showNoRecordImg = true;
|
|
4753
4828
|
noRecordMessage = 'Data may be empty, or try adjusting your filter.';
|
|
4754
4829
|
/** Static row class or a function that returns a class per row. Row data may also include `class` via TableRows. */
|
|
4755
4830
|
rows;
|
|
@@ -4920,14 +4995,14 @@ class BkGrid {
|
|
|
4920
4995
|
});
|
|
4921
4996
|
}
|
|
4922
4997
|
get noRecordImagePath() {
|
|
4923
|
-
return this.noRecordImgUrl || './assets/
|
|
4998
|
+
return this.noRecordImgUrl || './assets/icons/no-data-found.jpg';
|
|
4924
4999
|
}
|
|
4925
5000
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4926
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkGrid, isStandalone: true, selector: "bk-grid", inputs: { draggable: "draggable", columns: "columns", result: "result", actions: "actions", customClass: "customClass", actionIconClass: "actionIconClass", actionClass: "actionClass", showNoRecords: "showNoRecords", noRecordFoundHeight: "noRecordFoundHeight", noRecordImgUrl: "noRecordImgUrl", noRecordMessage: "noRecordMessage", rows: "rows" }, outputs: { change: "change", actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header; let i = $index) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\r\n >\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20 {{actionClass}}\">Action</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\"\r\n >\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\"\r\n [ngClass]=\"{ 'cursor-move ': draggable }\"\r\n >\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2$1.ɵɵCdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i2$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i2$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i2$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
5001
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkGrid, isStandalone: true, selector: "bk-grid", inputs: { draggable: "draggable", columns: "columns", result: "result", actions: "actions", customClass: "customClass", actionIconClass: "actionIconClass", actionClass: "actionClass", showNoRecords: "showNoRecords", noRecordFoundHeight: "noRecordFoundHeight", noRecordImgUrl: "noRecordImgUrl", showNoRecordImg: "showNoRecordImg", noRecordMessage: "noRecordMessage", rows: "rows" }, outputs: { change: "change", actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header; let i = $index) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\r\n >\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20 {{actionClass}}\">Action</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\"\r\n >\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\"\r\n [ngClass]=\"{ 'cursor-move ': draggable }\"\r\n >\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n @if (showNoRecordImg) {\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n }\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2$1.ɵɵCdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i2$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i2$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i2$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
4927
5002
|
}
|
|
4928
5003
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, decorators: [{
|
|
4929
5004
|
type: Component,
|
|
4930
|
-
args: [{ selector: 'bk-grid', standalone: true, imports: [CommonModule, DragDropModule, ScrollingModule, BkBadge, BKTooltipDirective, BkCheckbox, FormsModule], template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header; let i = $index) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\r\n >\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20 {{actionClass}}\">Action</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\"\r\n >\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\"\r\n [ngClass]=\"{ 'cursor-move ': draggable }\"\r\n >\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }]
|
|
5005
|
+
args: [{ selector: 'bk-grid', standalone: true, imports: [CommonModule, DragDropModule, ScrollingModule, BkBadge, BKTooltipDirective, BkCheckbox, FormsModule], template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header; let i = $index) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\r\n >\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20 {{actionClass}}\">Action</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\"\r\n >\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\"\r\n [ngClass]=\"{ 'cursor-move ': draggable }\"\r\n >\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n @if (showNoRecordImg) {\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n }\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }]
|
|
4931
5006
|
}], propDecorators: { draggable: [{
|
|
4932
5007
|
type: Input
|
|
4933
5008
|
}], columns: [{
|
|
@@ -4948,6 +5023,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4948
5023
|
type: Input
|
|
4949
5024
|
}], noRecordImgUrl: [{
|
|
4950
5025
|
type: Input
|
|
5026
|
+
}], showNoRecordImg: [{
|
|
5027
|
+
type: Input
|
|
4951
5028
|
}], noRecordMessage: [{
|
|
4952
5029
|
type: Input
|
|
4953
5030
|
}], rows: [{
|
|
@@ -5384,10 +5461,21 @@ class BkSelect {
|
|
|
5384
5461
|
disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
5385
5462
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
5386
5463
|
closeOnSelect = input(true, ...(ngDevMode ? [{ debugName: "closeOnSelect" }] : []));
|
|
5464
|
+
/**
|
|
5465
|
+
* When on, the dropdown opens as soon as the control receives keyboard focus
|
|
5466
|
+
* (e.g. tabbing to it) and closes once focus leaves it. Off by default so the
|
|
5467
|
+
* existing click/Enter-to-open behaviour is unchanged.
|
|
5468
|
+
*/
|
|
5469
|
+
openOnFocus = input(false, ...(ngDevMode ? [{ debugName: "openOnFocus" }] : []));
|
|
5387
5470
|
dropdownPosition = input('bottom', ...(ngDevMode ? [{ debugName: "dropdownPosition" }] : []));
|
|
5388
5471
|
hasError = false;
|
|
5389
5472
|
errorMessage = '';
|
|
5390
|
-
|
|
5473
|
+
/**
|
|
5474
|
+
* @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break.
|
|
5475
|
+
* The dropdown now always positions via Angular CDK Overlay, which portals into the shared
|
|
5476
|
+
* `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
|
|
5477
|
+
* to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
|
|
5478
|
+
*/
|
|
5391
5479
|
appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
|
|
5392
5480
|
// --- Outputs ---
|
|
5393
5481
|
open = output();
|
|
@@ -5404,6 +5492,7 @@ class BkSelect {
|
|
|
5404
5492
|
optionsRef;
|
|
5405
5493
|
controlWrapper;
|
|
5406
5494
|
dropdownPanel;
|
|
5495
|
+
selectOverlay;
|
|
5407
5496
|
chipsViewport;
|
|
5408
5497
|
measureChips;
|
|
5409
5498
|
measurePlus;
|
|
@@ -5417,26 +5506,21 @@ class BkSelect {
|
|
|
5417
5506
|
gridDraftOptions = signal([], ...(ngDevMode ? [{ debugName: "gridDraftOptions" }] : []));
|
|
5418
5507
|
searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
5419
5508
|
markedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "markedIndex" }] : []));
|
|
5420
|
-
// Side the panel
|
|
5421
|
-
//
|
|
5422
|
-
// (see
|
|
5509
|
+
// Side the panel actually rendered on, purely for the CSS `[data-position="top"]` margin
|
|
5510
|
+
// tweak — driven by CDK's own (positionChange) rather than a hand-rolled space comparison
|
|
5511
|
+
// (see onPositionChange). The fit/flip decision itself lives entirely in CDK now.
|
|
5423
5512
|
placement = signal('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
|
|
5424
|
-
// When appendToBody is on we physically relocate the panel to <body> so it
|
|
5425
|
-
// escapes any transformed/overflow ancestor (e.g. an animated dialog, whose
|
|
5426
|
-
// residual transform would otherwise make position:fixed resolve against the
|
|
5427
|
-
// dialog and get clipped). These track the panel's home so we can put it back
|
|
5428
|
-
// before Angular removes it on close.
|
|
5429
|
-
originalPanelParent = null;
|
|
5430
|
-
originalPanelAnchor = null;
|
|
5431
|
-
panelInBody = false;
|
|
5432
5513
|
// Number of multi-select chips currently rendered before collapsing into "+N".
|
|
5433
5514
|
// Computed dynamically from the available width (see recomputeVisibleChips()).
|
|
5434
5515
|
visibleCount = signal(0, ...(ngDevMode ? [{ debugName: "visibleCount" }] : []));
|
|
5435
5516
|
resizeObserver;
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5517
|
+
/**
|
|
5518
|
+
* Panel width, kept equal to the control's — matches the old `dropdownStyle().width`
|
|
5519
|
+
* behaviour. Set on open and re-measured by the same ResizeObserver that already tracks
|
|
5520
|
+
* the control for chip recomputation, so a responsive layout keeps the panel in sync while
|
|
5521
|
+
* it's open.
|
|
5522
|
+
*/
|
|
5523
|
+
dropdownWidth = signal(null, ...(ngDevMode ? [{ debugName: "dropdownWidth" }] : []));
|
|
5440
5524
|
filteredItems = computed(() => {
|
|
5441
5525
|
const term = this.searchTerm().toLowerCase();
|
|
5442
5526
|
const list = this.items();
|
|
@@ -5480,105 +5564,59 @@ class BkSelect {
|
|
|
5480
5564
|
});
|
|
5481
5565
|
}
|
|
5482
5566
|
ngAfterViewInit() {
|
|
5483
|
-
// Recompute visible chips whenever the control is
|
|
5484
|
-
// layouts, manual width changes, container resizes, etc.).
|
|
5567
|
+
// Recompute visible chips — and, while open, the panel width — whenever the control is
|
|
5568
|
+
// resized (responsive layouts, manual width changes, container resizes, etc.).
|
|
5485
5569
|
if (typeof ResizeObserver !== 'undefined') {
|
|
5486
|
-
this.resizeObserver = new ResizeObserver(() =>
|
|
5570
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
5571
|
+
this.scheduleRecompute();
|
|
5572
|
+
if (this.isOpen())
|
|
5573
|
+
this.dropdownWidth.set(this.controlWrapper.nativeElement.offsetWidth);
|
|
5574
|
+
});
|
|
5487
5575
|
if (this.controlWrapper?.nativeElement) {
|
|
5488
5576
|
this.resizeObserver.observe(this.controlWrapper.nativeElement);
|
|
5489
5577
|
}
|
|
5490
5578
|
}
|
|
5491
5579
|
this.scheduleRecompute();
|
|
5492
|
-
// Keep the append-to-body (fixed) panel glued to the control while any
|
|
5493
|
-
// ancestor scrolls or the window resizes. Capture phase (`true`) is what
|
|
5494
|
-
// lets us catch scrolling inside nested overflow containers, not just the
|
|
5495
|
-
// window — @HostListener('window:scroll') would miss those.
|
|
5496
|
-
window.addEventListener('scroll', this.reposition, true);
|
|
5497
|
-
window.addEventListener('resize', this.reposition);
|
|
5498
5580
|
}
|
|
5499
5581
|
ngOnDestroy() {
|
|
5500
5582
|
this.resizeObserver?.disconnect();
|
|
5501
|
-
|
|
5502
|
-
window.removeEventListener('resize', this.reposition);
|
|
5503
|
-
// If we're torn down while open, don't leave the relocated panel orphaned in <body>.
|
|
5504
|
-
if (this.panelInBody) {
|
|
5505
|
-
this.dropdownPanel?.nativeElement.remove();
|
|
5506
|
-
this.panelInBody = false;
|
|
5507
|
-
}
|
|
5508
|
-
}
|
|
5509
|
-
// Re-evaluate placement as the page scrolls/resizes. For append-to-body this
|
|
5510
|
-
// recomputes the fixed coordinates so the panel follows the control while it's
|
|
5511
|
-
// visible, and closes once the control is fully scrolled out of view (by the
|
|
5512
|
-
// viewport OR any scroll container such as a modal body). Inline just re-flips.
|
|
5513
|
-
// Bound as an arrow fn so it can be add/removeEventListener'd.
|
|
5514
|
-
reposition = () => {
|
|
5515
|
-
if (!this.isOpen())
|
|
5516
|
-
return;
|
|
5517
|
-
if (this.appendToBody()) {
|
|
5518
|
-
const rect = this.controlWrapper?.nativeElement.getBoundingClientRect();
|
|
5519
|
-
if (rect && this.isControlClipped(rect)) {
|
|
5520
|
-
this.closeDropdown();
|
|
5521
|
-
return;
|
|
5522
|
-
}
|
|
5523
|
-
}
|
|
5524
|
-
this.applyPlacement();
|
|
5525
|
-
};
|
|
5526
|
-
/**
|
|
5527
|
-
* True when the control is fully outside the visible area — either the
|
|
5528
|
-
* viewport or a scrollable/clipping ancestor (e.g. a dialog's scroll body).
|
|
5529
|
-
* Used to close the floating (append-to-body) panel once its anchor is no
|
|
5530
|
-
* longer on screen, instead of leaving it hanging.
|
|
5531
|
-
*/
|
|
5532
|
-
isControlClipped(rect) {
|
|
5533
|
-
// Outside the viewport.
|
|
5534
|
-
if (rect.bottom <= 0 || rect.top >= window.innerHeight ||
|
|
5535
|
-
rect.right <= 0 || rect.left >= window.innerWidth) {
|
|
5536
|
-
return true;
|
|
5537
|
-
}
|
|
5538
|
-
// Outside any clipping ancestor.
|
|
5539
|
-
let el = this.controlWrapper?.nativeElement.parentElement;
|
|
5540
|
-
while (el && el !== document.body) {
|
|
5541
|
-
const style = getComputedStyle(el);
|
|
5542
|
-
const clips = /(auto|scroll|hidden|clip|overlay)/;
|
|
5543
|
-
if (clips.test(style.overflowY) || clips.test(style.overflowX)) {
|
|
5544
|
-
const r = el.getBoundingClientRect();
|
|
5545
|
-
if (rect.bottom <= r.top || rect.top >= r.bottom ||
|
|
5546
|
-
rect.right <= r.left || rect.left >= r.right) {
|
|
5547
|
-
return true;
|
|
5548
|
-
}
|
|
5549
|
-
}
|
|
5550
|
-
el = el.parentElement;
|
|
5551
|
-
}
|
|
5552
|
-
return false;
|
|
5583
|
+
this.detachOverlayScrollTracking();
|
|
5553
5584
|
}
|
|
5554
5585
|
/**
|
|
5555
|
-
*
|
|
5556
|
-
*
|
|
5557
|
-
*
|
|
5586
|
+
* CDK's default `reposition` scroll strategy only reacts to real `document`/`window` scroll —
|
|
5587
|
+
* it has no way to know an app shell might scroll a nested container instead (this one
|
|
5588
|
+
* commonly does — dashboard layouts with a fixed header/sidebar and a scrollable content pane).
|
|
5589
|
+
* A capture-phase listener on `document` still sees scroll events fired on any descendant
|
|
5590
|
+
* scrollable element (scroll doesn't bubble, but capture does) — same trick `bk-custom-calendar`
|
|
5591
|
+
* and the `bk-input` phone dropdown already use. rAF-throttled so a fast scroll doesn't force
|
|
5592
|
+
* layout on every tick.
|
|
5558
5593
|
*/
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
if (
|
|
5594
|
+
overlayScrollRafId = null;
|
|
5595
|
+
onOverlayScroll = () => {
|
|
5596
|
+
if (this.overlayScrollRafId != null)
|
|
5562
5597
|
return;
|
|
5563
|
-
this.
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5598
|
+
this.overlayScrollRafId = requestAnimationFrame(() => {
|
|
5599
|
+
this.overlayScrollRafId = null;
|
|
5600
|
+
this.selectOverlay?.overlayRef?.updatePosition();
|
|
5601
|
+
});
|
|
5602
|
+
};
|
|
5603
|
+
attachOverlayScrollTracking() {
|
|
5604
|
+
document.addEventListener('scroll', this.onOverlayScroll, true);
|
|
5605
|
+
window.addEventListener('resize', this.onOverlayScroll);
|
|
5567
5606
|
}
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
if (!panel || !this.panelInBody)
|
|
5575
|
-
return;
|
|
5576
|
-
if (this.originalPanelParent) {
|
|
5577
|
-
this.originalPanelParent.insertBefore(panel, this.originalPanelAnchor);
|
|
5607
|
+
detachOverlayScrollTracking() {
|
|
5608
|
+
document.removeEventListener('scroll', this.onOverlayScroll, true);
|
|
5609
|
+
window.removeEventListener('resize', this.onOverlayScroll);
|
|
5610
|
+
if (this.overlayScrollRafId != null) {
|
|
5611
|
+
cancelAnimationFrame(this.overlayScrollRafId);
|
|
5612
|
+
this.overlayScrollRafId = null;
|
|
5578
5613
|
}
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5614
|
+
}
|
|
5615
|
+
/** Derives `placement` (for the `[data-position="top"]` CSS margin tweak) from which of
|
|
5616
|
+
* `selectDropdownPositions` CDK actually applied — replaces the old hand-rolled space
|
|
5617
|
+
* comparison now that the fit/flip decision itself lives in CDK. */
|
|
5618
|
+
onPositionChange(event) {
|
|
5619
|
+
this.placement.set(event.connectionPair.originY === 'top' ? 'top' : 'bottom');
|
|
5582
5620
|
}
|
|
5583
5621
|
scheduleRecompute() {
|
|
5584
5622
|
// Defer to the next frame so the hidden measurement row has been laid out.
|
|
@@ -5720,6 +5758,7 @@ class BkSelect {
|
|
|
5720
5758
|
openDropdown() {
|
|
5721
5759
|
if (this.isOpen())
|
|
5722
5760
|
return;
|
|
5761
|
+
this.opening = true;
|
|
5723
5762
|
this.panelReady.set(false);
|
|
5724
5763
|
// Close previously opened dropdown
|
|
5725
5764
|
if (BkSelect.activeInstance && BkSelect.activeInstance !== this) {
|
|
@@ -5729,37 +5768,64 @@ class BkSelect {
|
|
|
5729
5768
|
if (this.usesGridDraft()) {
|
|
5730
5769
|
this.gridDraftOptions.set([...this.selectedOptions()]);
|
|
5731
5770
|
}
|
|
5732
|
-
//
|
|
5733
|
-
//
|
|
5734
|
-
|
|
5771
|
+
// Give Up/Down navigation a defined starting point instead of a stale index
|
|
5772
|
+
// from a previous open: highlight the selected option, or the first option
|
|
5773
|
+
// when nothing is selected, so the very first arrow press has something to
|
|
5774
|
+
// move from and the highlight is visible immediately.
|
|
5775
|
+
this.markedIndex.set(this.initialMarkedIndex());
|
|
5776
|
+
// Keep the panel exactly as wide as the control, same as the old dropdownStyle().width.
|
|
5777
|
+
this.dropdownWidth.set(this.controlWrapper.nativeElement.offsetWidth);
|
|
5778
|
+
this.attachOverlayScrollTracking();
|
|
5735
5779
|
this.isOpen.set(true);
|
|
5736
5780
|
this.open.emit();
|
|
5737
5781
|
this.focus.emit();
|
|
5738
5782
|
setTimeout(() => {
|
|
5739
5783
|
if (!this.isOpen())
|
|
5740
5784
|
return;
|
|
5741
|
-
//
|
|
5742
|
-
//
|
|
5743
|
-
if (this.appendToBody())
|
|
5744
|
-
this.movePanelToBody();
|
|
5745
|
-
// Recompute with the panel's real height so the initial up/down flip is
|
|
5746
|
-
// accurate (openDropdown ran applyPlacement() before the panel existed,
|
|
5747
|
-
// using an estimated height).
|
|
5748
|
-
this.applyPlacement();
|
|
5785
|
+
// Position/flip is now entirely CDK's job (see selectDropdownPositions +
|
|
5786
|
+
// onPositionChange) — nothing to compute here anymore.
|
|
5749
5787
|
this.panelReady.set(true);
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5788
|
+
// The panel is `visibility: hidden` until panelReady flips to true, and
|
|
5789
|
+
// that style is only written to the DOM on the next change-detection
|
|
5790
|
+
// pass — not synchronously with the signal write above. Focusing an
|
|
5791
|
+
// element inside a still-hidden subtree is a no-op (focus falls back to
|
|
5792
|
+
// <body>, so Up/Down never reach the options), so defer the focus one
|
|
5793
|
+
// frame, by which point the panel is actually visible.
|
|
5794
|
+
requestAnimationFrame(() => {
|
|
5795
|
+
if (!this.isOpen()) {
|
|
5796
|
+
this.opening = false;
|
|
5797
|
+
return;
|
|
5798
|
+
}
|
|
5799
|
+
// When the search field is visible it is the entry point: focus it so
|
|
5800
|
+
// the user can type immediately, and Up/Down keys navigate the options
|
|
5801
|
+
// from here (the input forwards keydown to onKeyDown). Otherwise keep
|
|
5802
|
+
// keyboard control on the trigger. preventScroll stops the page jumping.
|
|
5803
|
+
// The focusout this triggers (trigger→search) fires synchronously while
|
|
5804
|
+
// `opening` is still true, so onFocusOut ignores it; only after focus
|
|
5805
|
+
// lands do we end the opening window.
|
|
5806
|
+
if (this.searchable()) {
|
|
5807
|
+
this.searchInput?.nativeElement.focus({ preventScroll: true });
|
|
5808
|
+
}
|
|
5809
|
+
else {
|
|
5810
|
+
this.controlWrapper?.nativeElement.focus({ preventScroll: true });
|
|
5811
|
+
}
|
|
5812
|
+
// Bring the initially marked option into view so keyboard navigation
|
|
5813
|
+
// starts from something the user can actually see.
|
|
5814
|
+
if (this.markedIndex() >= 0)
|
|
5815
|
+
this.scrollToMarked();
|
|
5816
|
+
// End the opening window one more frame later. On the very first open the
|
|
5817
|
+
// freshly-rendered field can receive focus a frame late, so its
|
|
5818
|
+
// trigger→search focusout arrives after this rAF — keeping the guard up an
|
|
5819
|
+
// extra frame ensures that focusout is still ignored (no first-open flicker).
|
|
5820
|
+
requestAnimationFrame(() => (this.opening = false));
|
|
5821
|
+
});
|
|
5756
5822
|
});
|
|
5757
5823
|
}
|
|
5758
5824
|
closeDropdown() {
|
|
5759
5825
|
if (!this.isOpen())
|
|
5760
5826
|
return;
|
|
5761
|
-
|
|
5762
|
-
this.
|
|
5827
|
+
this.opening = false;
|
|
5828
|
+
this.detachOverlayScrollTracking();
|
|
5763
5829
|
this.isOpen.set(false);
|
|
5764
5830
|
this.panelReady.set(false);
|
|
5765
5831
|
this.searchTerm.set('');
|
|
@@ -5770,74 +5836,16 @@ class BkSelect {
|
|
|
5770
5836
|
BkSelect.activeInstance = null;
|
|
5771
5837
|
}
|
|
5772
5838
|
}
|
|
5773
|
-
getTop() {
|
|
5774
|
-
if (this.appendToBody()) {
|
|
5775
|
-
return this.dropdownStyle().top ?? null;
|
|
5776
|
-
}
|
|
5777
|
-
// NOT appendToBody — use the auto-flipped placement, not the raw input.
|
|
5778
|
-
return this.placement() === 'bottom' ? '105%' : null;
|
|
5779
|
-
}
|
|
5780
|
-
getBottom() {
|
|
5781
|
-
if (this.appendToBody()) {
|
|
5782
|
-
return this.dropdownStyle().bottom ?? null;
|
|
5783
|
-
}
|
|
5784
|
-
// NOT appendToBody — use the auto-flipped placement, not the raw input.
|
|
5785
|
-
return this.placement() === 'top' ? 'calc(100% + 4px)' : null;
|
|
5786
|
-
}
|
|
5787
5839
|
/**
|
|
5788
|
-
*
|
|
5789
|
-
*
|
|
5790
|
-
*
|
|
5791
|
-
* whichever side has room — honouring `dropdownPosition` when it fits.
|
|
5840
|
+
* Preferred position list handed to CDK, in try-order — honours `dropdownPosition` first,
|
|
5841
|
+
* falling back to the other side only when the preferred one genuinely doesn't fit. Replaces
|
|
5842
|
+
* the old hand-rolled `applyPlacement()` space comparison entirely.
|
|
5792
5843
|
*/
|
|
5793
|
-
|
|
5794
|
-
const
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
const rect = control.getBoundingClientRect();
|
|
5798
|
-
const gap = 4;
|
|
5799
|
-
// Actual panel height once it's rendered; fall back to a sensible estimate
|
|
5800
|
-
// on the very first open (panel isn't in the DOM yet at that point — a
|
|
5801
|
-
// follow-up call after render corrects it with the real height).
|
|
5802
|
-
const panelHeight = this.dropdownPanel?.nativeElement.offsetHeight || 300;
|
|
5803
|
-
const spaceBelow = window.innerHeight - rect.bottom - gap;
|
|
5804
|
-
const spaceAbove = rect.top - gap;
|
|
5805
|
-
// Honour the requested position when it fits; otherwise flip to wherever
|
|
5806
|
-
// there's more room.
|
|
5807
|
-
const preferred = this.dropdownPosition();
|
|
5808
|
-
let placeTop;
|
|
5809
|
-
if (preferred === 'top') {
|
|
5810
|
-
placeTop = spaceAbove >= panelHeight || spaceAbove > spaceBelow;
|
|
5811
|
-
}
|
|
5812
|
-
else {
|
|
5813
|
-
placeTop = spaceBelow < panelHeight && spaceAbove > spaceBelow;
|
|
5814
|
-
}
|
|
5815
|
-
this.placement.set(placeTop ? 'top' : 'bottom');
|
|
5816
|
-
// Inline (absolute) mode is positioned by CSS relative to the control, so
|
|
5817
|
-
// the placement signal above is all it needs. Only append-to-body needs
|
|
5818
|
-
// explicit fixed coordinates.
|
|
5819
|
-
if (!this.appendToBody())
|
|
5820
|
-
return;
|
|
5821
|
-
if (placeTop) {
|
|
5822
|
-
this.dropdownStyle.set({
|
|
5823
|
-
top: undefined,
|
|
5824
|
-
bottom: `${window.innerHeight - rect.top + gap}px`,
|
|
5825
|
-
left: `${rect.left}px`,
|
|
5826
|
-
width: `${rect.width}px`
|
|
5827
|
-
});
|
|
5828
|
-
}
|
|
5829
|
-
else {
|
|
5830
|
-
this.dropdownStyle.set({
|
|
5831
|
-
top: `${rect.bottom + gap}px`,
|
|
5832
|
-
bottom: undefined,
|
|
5833
|
-
left: `${rect.left}px`,
|
|
5834
|
-
width: `${rect.width}px`
|
|
5835
|
-
});
|
|
5836
|
-
}
|
|
5844
|
+
get selectDropdownPositions() {
|
|
5845
|
+
const bottom = { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 };
|
|
5846
|
+
const top = { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 };
|
|
5847
|
+
return this.dropdownPosition() === 'top' ? [top, bottom] : [bottom, top];
|
|
5837
5848
|
}
|
|
5838
|
-
// Scroll/resize are handled by the capture-phase listeners wired up in
|
|
5839
|
-
// ngAfterViewInit (see `reposition`), which keep the panel attached to the
|
|
5840
|
-
// control and re-flip it up/down as space allows, instead of closing it.
|
|
5841
5849
|
// ... (toggleSelectAll, handleSelection, removeOption, handleClear logic same as before) ...
|
|
5842
5850
|
toggleSelectAll(event) {
|
|
5843
5851
|
event.stopPropagation();
|
|
@@ -5944,6 +5952,43 @@ class BkSelect {
|
|
|
5944
5952
|
this.markedIndex.set(0);
|
|
5945
5953
|
this.search.emit({ term: val, items: this.filteredItems() });
|
|
5946
5954
|
}
|
|
5955
|
+
/**
|
|
5956
|
+
* Options in the exact order they are rendered (groups flattened). This is the
|
|
5957
|
+
* space Up/Down navigation and the marked-index operate in — using the flat
|
|
5958
|
+
* `filteredItems()` would desync from the on-screen order once grouping
|
|
5959
|
+
* reshuffles rows. For an ungrouped list this equals `filteredItems()`.
|
|
5960
|
+
*/
|
|
5961
|
+
flatOptions = computed(() => this.groupedItems().flatMap(group => group.items), ...(ngDevMode ? [{ debugName: "flatOptions" }] : []));
|
|
5962
|
+
/** The option the marker currently sits on, or null. */
|
|
5963
|
+
markedOption = computed(() => {
|
|
5964
|
+
const index = this.markedIndex();
|
|
5965
|
+
const list = this.flatOptions();
|
|
5966
|
+
return index >= 0 && index < list.length ? list[index] : null;
|
|
5967
|
+
}, ...(ngDevMode ? [{ debugName: "markedOption" }] : []));
|
|
5968
|
+
/**
|
|
5969
|
+
* Whether an option carries the keyboard/hover marker. Matched by identity
|
|
5970
|
+
* rather than by row position so two groups can't share a highlight just
|
|
5971
|
+
* because the marked item sits at the same index within each group.
|
|
5972
|
+
*/
|
|
5973
|
+
isMarked(item) {
|
|
5974
|
+
return item === this.markedOption();
|
|
5975
|
+
}
|
|
5976
|
+
/** Move the marker to a hovered option by its position in the rendered order. */
|
|
5977
|
+
markOption(item) {
|
|
5978
|
+
this.markedIndex.set(this.flatOptions().indexOf(item));
|
|
5979
|
+
}
|
|
5980
|
+
/**
|
|
5981
|
+
* Rendered-order index that Up/Down navigation starts from when the dropdown
|
|
5982
|
+
* opens: the first already-selected option, or the first option when nothing
|
|
5983
|
+
* is selected. Returns -1 only for an empty list.
|
|
5984
|
+
*/
|
|
5985
|
+
initialMarkedIndex() {
|
|
5986
|
+
const list = this.flatOptions();
|
|
5987
|
+
if (!list.length)
|
|
5988
|
+
return -1;
|
|
5989
|
+
const selected = list.findIndex(item => this.isItemSelected(item));
|
|
5990
|
+
return selected >= 0 ? selected : 0;
|
|
5991
|
+
}
|
|
5947
5992
|
onKeyDown(event) {
|
|
5948
5993
|
if (!this.isOpen()) {
|
|
5949
5994
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
@@ -5952,7 +5997,7 @@ class BkSelect {
|
|
|
5952
5997
|
}
|
|
5953
5998
|
return;
|
|
5954
5999
|
}
|
|
5955
|
-
const list = this.
|
|
6000
|
+
const list = this.flatOptions();
|
|
5956
6001
|
const current = this.markedIndex();
|
|
5957
6002
|
switch (event.key) {
|
|
5958
6003
|
case 'Tab':
|
|
@@ -6037,22 +6082,108 @@ class BkSelect {
|
|
|
6037
6082
|
this.selectedOptions.set(matchedItems);
|
|
6038
6083
|
}
|
|
6039
6084
|
el = inject(ElementRef);
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6085
|
+
// Click-outside-to-close is now `(overlayOutsideClick)` in the template, driven by CDK's
|
|
6086
|
+
// document-level outside-pointer-event dispatcher — it already excludes clicks on the
|
|
6087
|
+
// cdkOverlayOrigin (the control) by design, so toggleDropdown() stays the sole opener. No
|
|
6088
|
+
// backdrop involved, so it doesn't block page/nested-container scroll like a modal would.
|
|
6089
|
+
onOverlayOutsideClick() {
|
|
6090
|
+
this.closeDropdown();
|
|
6091
|
+
}
|
|
6092
|
+
// Set for the moment a pointer press focuses the control, so openOnFocus can
|
|
6093
|
+
// tell a mouse/touch focus apart from a keyboard (Tab) one. openOnFocus is a
|
|
6094
|
+
// keyboard affordance: clicks open through their own toggle (or the label),
|
|
6095
|
+
// and must not also trigger the focus-open path.
|
|
6096
|
+
pointerFocus = false;
|
|
6097
|
+
// True from the moment openDropdown starts until focus has been handed to the
|
|
6098
|
+
// search field (or trigger). The trigger→search focus move fires a focusout
|
|
6099
|
+
// that must NOT be read as "focus left" — otherwise the panel closes the
|
|
6100
|
+
// instant it opens on a Tab-in (openOnFocus), a visible flicker.
|
|
6101
|
+
opening = false;
|
|
6102
|
+
onPointerDown() {
|
|
6103
|
+
if (!this.openOnFocus())
|
|
6104
|
+
return;
|
|
6105
|
+
this.pointerFocus = true;
|
|
6106
|
+
// Clear on the next tick. The focusin that this press causes runs first
|
|
6107
|
+
// (synchronously), so it still sees the flag; this only guards against a
|
|
6108
|
+
// stale flag when the press produces no focusin (e.g. mousedown that calls
|
|
6109
|
+
// preventDefault), which would otherwise swallow a later real Tab focus.
|
|
6110
|
+
setTimeout(() => (this.pointerFocus = false));
|
|
6111
|
+
}
|
|
6112
|
+
/**
|
|
6113
|
+
* Open when *keyboard* focus arrives from outside the control (tabbing to it).
|
|
6114
|
+
* Pointer-initiated focus is ignored — a click opens via its own toggle, so
|
|
6115
|
+
* this stays a keyboard affordance. Focus moves that originate inside the
|
|
6116
|
+
* control or its panel — the panel handing focus to the search field, or focus
|
|
6117
|
+
* falling back to the trigger as the panel closes — must not (re)open it,
|
|
6118
|
+
* which would otherwise trap the user when tabbing backwards out of it.
|
|
6119
|
+
*/
|
|
6120
|
+
onFocusIn(event) {
|
|
6121
|
+
if (!this.openOnFocus())
|
|
6046
6122
|
return;
|
|
6047
|
-
if (this.
|
|
6123
|
+
if (this.pointerFocus)
|
|
6048
6124
|
return;
|
|
6049
|
-
this.
|
|
6125
|
+
if (this.disabled() || this.readonly())
|
|
6126
|
+
return;
|
|
6127
|
+
if (this.isFocusInside(event.relatedTarget))
|
|
6128
|
+
return;
|
|
6129
|
+
if (!this.isOpen())
|
|
6130
|
+
this.openDropdown();
|
|
6131
|
+
}
|
|
6132
|
+
/**
|
|
6133
|
+
* Close when focus leaves the control entirely — tabbing away, or focus moving
|
|
6134
|
+
* to any element outside the control and its (possibly body-appended) panel.
|
|
6135
|
+
* Internal focus moves keep it open.
|
|
6136
|
+
*/
|
|
6137
|
+
onFocusOut() {
|
|
6138
|
+
if (!this.openOnFocus())
|
|
6139
|
+
return;
|
|
6140
|
+
if (!this.isOpen())
|
|
6141
|
+
return;
|
|
6142
|
+
// The open transition is handing focus from the trigger to the search field;
|
|
6143
|
+
// that focusout is internal, not a departure. Ignore it so the panel doesn't
|
|
6144
|
+
// close the instant it opens on a Tab-in.
|
|
6145
|
+
if (this.opening)
|
|
6146
|
+
return;
|
|
6147
|
+
// A pointer press inside the control is in progress (e.g. clicking an option,
|
|
6148
|
+
// which blurs the search input because the option isn't focusable). That's an
|
|
6149
|
+
// interaction, not a departure — keep the panel open.
|
|
6150
|
+
if (this.pointerFocus)
|
|
6151
|
+
return;
|
|
6152
|
+
// Defer until focus settles, then decide from where it actually landed
|
|
6153
|
+
// (document.activeElement). relatedTarget is unreliable here: some browsers
|
|
6154
|
+
// report it as null for the programmatic focus move that hands focus from the
|
|
6155
|
+
// trigger to the search field on open, which would otherwise close the panel
|
|
6156
|
+
// the instant it opens — a flicker when tabbing in with openOnFocus.
|
|
6157
|
+
setTimeout(() => {
|
|
6158
|
+
if (!this.isOpen())
|
|
6159
|
+
return;
|
|
6160
|
+
if (this.isFocusInside(document.activeElement))
|
|
6161
|
+
return;
|
|
6162
|
+
this.closeDropdown();
|
|
6163
|
+
});
|
|
6164
|
+
}
|
|
6165
|
+
/** True when a node lives inside the control host or its detached panel. */
|
|
6166
|
+
isFocusInside(node) {
|
|
6167
|
+
if (!node)
|
|
6168
|
+
return false;
|
|
6169
|
+
return this.el.nativeElement.contains(node) ||
|
|
6170
|
+
!!this.dropdownPanel?.nativeElement.contains(node);
|
|
6050
6171
|
}
|
|
6051
6172
|
openFromLabel(event) {
|
|
6052
6173
|
event.preventDefault();
|
|
6053
6174
|
event.stopPropagation();
|
|
6054
6175
|
if (this.disabled() || this.readonly())
|
|
6055
6176
|
return;
|
|
6177
|
+
// In openOnFocus mode, opening is reserved for clicking the control itself
|
|
6178
|
+
// or tabbing in — a label click only focuses the control. The focus is
|
|
6179
|
+
// flagged as pointer-driven so openOnFocus doesn't mistake it for a Tab and
|
|
6180
|
+
// auto-open. Without openOnFocus the label keeps its existing behaviour of
|
|
6181
|
+
// opening the dropdown on click.
|
|
6182
|
+
if (this.openOnFocus()) {
|
|
6183
|
+
this.pointerFocus = true;
|
|
6184
|
+
this.controlWrapper.nativeElement.focus();
|
|
6185
|
+
return;
|
|
6186
|
+
}
|
|
6056
6187
|
this.controlWrapper.nativeElement.focus();
|
|
6057
6188
|
this.openDropdown();
|
|
6058
6189
|
}
|
|
@@ -6161,23 +6292,23 @@ class BkSelect {
|
|
|
6161
6292
|
this.markedIndex.set(index);
|
|
6162
6293
|
}
|
|
6163
6294
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6164
|
-
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 }, bindIcon: { classPropertyName: "bindIcon", publicName: "bindIcon", isSignal: true, isRequired: false, transformFunction: null }, isResponsive: { classPropertyName: "isResponsive", publicName: "isResponsive", 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 }, dropdownView: { classPropertyName: "dropdownView", publicName: "dropdownView", isSignal: true, isRequired: false, transformFunction: null }, gridColumns: { classPropertyName: "gridColumns", publicName: "gridColumns", isSignal: true, isRequired: false, transformFunction: null }, gridVariation: { classPropertyName: "gridVariation", publicName: "gridVariation", isSignal: true, isRequired: false, transformFunction: null }, gridSelectionActions: { classPropertyName: "gridSelectionActions", publicName: "gridSelectionActions", isSignal: true, isRequired: false, transformFunction: null }, gridMinWidth: { classPropertyName: "gridMinWidth", publicName: "gridMinWidth", isSignal: true, isRequired: false, transformFunction: null }, gridMaxHeight: { classPropertyName: "gridMaxHeight", publicName: "gridMaxHeight", isSignal: true, isRequired: false, transformFunction: null }, gridSelectedLabelKeys: { classPropertyName: "gridSelectedLabelKeys", publicName: "gridSelectedLabelKeys", isSignal: true, isRequired: false, transformFunction: null }, gridSelectedLabelSeparator: { classPropertyName: "gridSelectedLabelSeparator", publicName: "gridSelectedLabelSeparator", isSignal: true, isRequired: false, transformFunction: null }, gridApplyText: { classPropertyName: "gridApplyText", publicName: "gridApplyText", isSignal: true, isRequired: false, transformFunction: null }, gridClearText: { classPropertyName: "gridClearText", publicName: "gridClearText", isSignal: true, isRequired: false, transformFunction: null }, showDots: { classPropertyName: "showDots", publicName: "showDots", isSignal: true, isRequired: false, transformFunction: null }, showAvatar: { classPropertyName: "showAvatar", publicName: "showAvatar", isSignal: true, isRequired: false, transformFunction: null }, avatarKey: { classPropertyName: "avatarKey", publicName: "avatarKey", 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 }, variation: { classPropertyName: "variation", publicName: "variation", 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 }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: false, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: false, 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: { "
|
|
6295
|
+
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 }, bindIcon: { classPropertyName: "bindIcon", publicName: "bindIcon", isSignal: true, isRequired: false, transformFunction: null }, isResponsive: { classPropertyName: "isResponsive", publicName: "isResponsive", 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 }, dropdownView: { classPropertyName: "dropdownView", publicName: "dropdownView", isSignal: true, isRequired: false, transformFunction: null }, gridColumns: { classPropertyName: "gridColumns", publicName: "gridColumns", isSignal: true, isRequired: false, transformFunction: null }, gridVariation: { classPropertyName: "gridVariation", publicName: "gridVariation", isSignal: true, isRequired: false, transformFunction: null }, gridSelectionActions: { classPropertyName: "gridSelectionActions", publicName: "gridSelectionActions", isSignal: true, isRequired: false, transformFunction: null }, gridMinWidth: { classPropertyName: "gridMinWidth", publicName: "gridMinWidth", isSignal: true, isRequired: false, transformFunction: null }, gridMaxHeight: { classPropertyName: "gridMaxHeight", publicName: "gridMaxHeight", isSignal: true, isRequired: false, transformFunction: null }, gridSelectedLabelKeys: { classPropertyName: "gridSelectedLabelKeys", publicName: "gridSelectedLabelKeys", isSignal: true, isRequired: false, transformFunction: null }, gridSelectedLabelSeparator: { classPropertyName: "gridSelectedLabelSeparator", publicName: "gridSelectedLabelSeparator", isSignal: true, isRequired: false, transformFunction: null }, gridApplyText: { classPropertyName: "gridApplyText", publicName: "gridApplyText", isSignal: true, isRequired: false, transformFunction: null }, gridClearText: { classPropertyName: "gridClearText", publicName: "gridClearText", isSignal: true, isRequired: false, transformFunction: null }, showDots: { classPropertyName: "showDots", publicName: "showDots", isSignal: true, isRequired: false, transformFunction: null }, showAvatar: { classPropertyName: "showAvatar", publicName: "showAvatar", isSignal: true, isRequired: false, transformFunction: null }, avatarKey: { classPropertyName: "avatarKey", publicName: "avatarKey", 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 }, variation: { classPropertyName: "variation", publicName: "variation", 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 }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: false, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: false, 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: { "pointerdown": "onPointerDown()", "focusin": "onFocusIn($event)", "focusout": "onFocusOut()" } }, providers: [
|
|
6165
6296
|
{
|
|
6166
6297
|
provide: NG_VALUE_ACCESSOR,
|
|
6167
6298
|
useExisting: forwardRef(() => BkSelect),
|
|
6168
6299
|
multi: true
|
|
6169
6300
|
}
|
|
6170
|
-
], 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: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "chipsViewport", first: true, predicate: ["chipsViewport"], descendants: true }, { propertyName: "measurePlus", first: true, predicate: ["measurePlus"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }, { propertyName: "measureChips", predicate: ["measureChip"], descendants: true }], ngImport: i0, template: "<div class=\"bk-select-container\" [ngClass]=\"variation\" [class.bk-grid-view]=\"dropdownView() === 'grid'\">\r\n @if (label) {\r\n <label class=\"bk-select-label\" (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"bk-select-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <!-- controlStyle() resolves the tint: the selected option's accent normally,\r\n a soft red one while hasError. It's a method rather than a computed\r\n because hasError is a plain @Input, not a signal. -->\r\n <div\r\n #controlWrapper\r\n class=\"bk-select-control\"\r\n [ngClass]=\"{ 'bk-has-error': hasError }\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.bk-focused]=\"isOpen()\"\r\n [class.bk-disabled]=\"disabled()\"\r\n [class.bk-filled]=\"!!controlStyle().backgroundColor\"\r\n [style.backgroundColor]=\"controlStyle().backgroundColor\"\r\n [style.color]=\"controlStyle().color\"\r\n [style.borderColor]=\"controlStyle().borderColor\"\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=\"bk-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"bk-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div\r\n #chipsViewport\r\n class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap overflow-hidden h-[18px]\"\r\n >\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(opt)\"\r\n [textColor]=\"avatarTextFor(opt)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\" [style.backgroundColor]=\"accentFor(opt)\"></span>\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"optionTextColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\r\n <!-- A locked control must not offer a way to drop a value. -->\r\n @if (isEditable()) {\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (visibleCount() < selectedOptions().length) {\r\n <div class=\"bk-multi-badge-item\">\r\n <span\r\n class=\"bk-multi-badge-item-text\"\r\n bkTooltipPosition=\"top\"\r\n [bkTooltip]=\"getRemainingItems()\"\r\n [bkTooltipScrollable]=\"true\"\r\n bkTooltipMaxHeight=\"240px\"\r\n >+{{ selectedOptions().length - visibleCount() }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hidden off-screen row used only to measure each chip's natural\r\n width so we can decide how many fit on a single line. -->\r\n <div class=\"bk-value-chips bk-chips-measure flex gap-0.5 flex-nowrap\" aria-hidden=\"true\">\r\n @for (opt of selectedOptions(); track $index) {\r\n <div #measureChip class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- Must mirror the visible chip exactly \u2014 same leading visual\r\n and same precedence \u2014 or the measured width is wrong and\r\n \"+N\" collapses at the wrong point. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\"></span>\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\r\n @if (isEditable()) {\r\n <button type=\"button\" tabindex=\"-1\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <div #measurePlus class=\"bk-multi-badge-item\">\r\n <span class=\"bk-multi-badge-item-text\">+{{ selectedOptions().length }}</span>\r\n </div>\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"flex items-center gap-1.5 min-w-0 w-full\">\r\n <!-- One leading visual only: avatar > icon > dot.\r\n `flex` on the host: bk-avatar's host is display:inline by\r\n default, so its inline-flex body sits on a baseline and the\r\n host gains descender space \u2014 which knocks the avatar out of\r\n vertical centre against the label. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(selectedOptions()[0])\"\r\n [name]=\"resolveLabel(selectedOptions()[0])\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(selectedOptions()[0])\"\r\n [textColor]=\"avatarTextFor(selectedOptions()[0])\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(selectedOptions()[0])) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(selectedOptions()[0])\"></span>\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.color]=\"controlStyle().color ?? resolveColor(selectedOptions()[0])\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(singleValueEl, resolveLabel(selectedOptions()[0]))\"\r\n bkTooltipPosition=\"top\">\r\n {{ resolveLabel(selectedOptions()[0]) }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"bk-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && isEditable()) {\r\n <span class=\"bk-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"bk-arrow-wrapper\" [class.bk-open]=\"isOpen()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\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 [style.zIndex]=\"appendToBody() ? 10000 : null\"\r\n [class.bk-grouped]=\"groupBy()\"\r\n [class.bk-grid-panel]=\"dropdownView() === 'grid'\"\r\n [class.bk-grid-compact]=\"dropdownView() === 'grid' && isGridCompact()\"\r\n >\r\n @if (searchable()) {\r\n <div class=\"bk-dropdown-search mb-1\">\r\n <div class=\"bk-search-wrapper\">\r\n <svg\r\n class=\"text-[#BBBDC5] mr-2\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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\r\n #searchInput\r\n tabindex=\"-1\"\r\n type=\"text\"\r\n class=\"bk-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @if (dropdownView() === 'grid') {\r\n <div\r\n #optionsListContainer\r\n class=\"bk-grid-scroll\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n [style.maxHeight]=\"gridMaxHeight()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n <table class=\"bk-select-grid\" [style.minWidth]=\"gridMinWidth()\">\r\n <thead>\r\n <tr>\r\n @if (multiple()) {\r\n <th class=\"bk-grid-checkbox-column\" aria-label=\"Selection\"></th>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <th [ngStyle]=\"gridColumnStyle(column)\">{{ column.label }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ loadingText() }}</td></tr>\r\n } @else {\r\n @for (item of filteredItems(); track resolveValue(item); let rowIndex = $index) {\r\n <tr\r\n #optionsRef\r\n tabindex=\"-1\"\r\n [class.bk-selected]=\"isGridItemSelected(item)\"\r\n [class.bk-marked]=\"rowIndex === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n (click)=\"handleGridSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover(rowIndex)\"\r\n >\r\n @if (multiple()) {\r\n <td class=\"bk-grid-checkbox-column\">\r\n <bk-checkbox\r\n class=\"pointer-events-none flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"isItemDisabled(item)\"\r\n [ngModel]=\"isGridItemSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </td>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <td [ngStyle]=\"gridColumnStyle(column)\">\r\n @if (column.type === 'badge') {\r\n <bk-badge\r\n [label]=\"resolveGridCell(item, column)\"\r\n [color]=\"gridBadgeColor(item, column)\"\r\n [variant]=\"column.badgeVariant ?? 'Light'\"\r\n [size]=\"isGridCompact() ? 'xsm' : 'sm'\"\r\n ></bk-badge>\r\n } @else {\r\n <span class=\"bk-grid-cell-text\">{{ resolveGridCell(item, column) }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ notFoundText() }}</td></tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if (multiple()) {\r\n <div class=\"bk-grid-footer\">\r\n <span>{{ gridSelectedCount() }} selected</span>\r\n @if (gridSelectionActions()) {\r\n <div class=\"bk-grid-footer-actions\">\r\n <bk-button variant=\"secondary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridClearText()\" (clicked)=\"clearGridDraft()\"></bk-button>\r\n <bk-button variant=\"primary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridApplyText()\" (clicked)=\"applyGridDraft()\"></bk-button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div\r\n #optionsListContainer\r\n tabindex=\"-1\"\r\n class=\"bk-options-list\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n @if (loading()) {\r\n <div class=\"bk-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()) {\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div\r\n class=\"bk-option\"\r\n (mousedown)=\"toggleSelectAll($event)\"\r\n [class.bk-selected]=\"isAllSelected()\"\r\n >\r\n <div class=\"flex-1 flex items-center gap-2 min-w-0\">\r\n <!-- Reflects state only: pointer-events-none lets the row's\r\n mousedown own the toggle, so the box can't fire twice.\r\n standalone keeps this ngModel out of any parent <form>\r\n bk-select is rendered inside. -->\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"isAllSelected()\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n <span class=\"line-clamp-1\">Select All</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n @if (group.group) {\r\n <div class=\"bk-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\r\n #optionsRef\r\n tabindex=\"-1\"\r\n class=\"bk-option\"\r\n [class.bk-selected]=\"isItemSelected(item)\"\r\n [class.bk-marked]=\"$index === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n [class.cursor-not-allowed]=\"isItemDisabled(item)\"\r\n (click)=\"handleSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover($index)\"\r\n >\r\n <div class=\"flex-1 flex justify-between gap-2 min-w-0\">\r\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(item)\"\r\n [name]=\"resolveLabel(item)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(item)\"\r\n [textColor]=\"avatarTextFor(item)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(item)) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(optionLabelEl, resolveLabel(item))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(item)\r\n }}</span>\r\n </div>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg\r\n class=\"text-[#141414] shrink-0\"\r\n width=\"17\"\r\n height=\"17\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n >\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 @if (filteredItems().length === 0) {\r\n <div class=\"bk-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n @if (hasError) {\r\n @if (errorMessage) {\r\n <p class=\"bk-select-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".bk-select-container{@apply relative w-full box-border flex flex-col gap-1.5;}.bk-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded cursor-pointer focus:border-[#E3E3E7] focus-visible:!outline-[.1px] focus-visible:!outline-[#6B7080];transition:border-color .2s,box-shadow .2s;box-shadow:0 1px 2px #1018280d}.bk-select-control:focus-visible{outline-style:solid!important}.bk-select-control.bk-focused{@apply shadow-none z-10;outline:none!important}.bk-select-control.bk-focused:not(.bk-filled){@apply border-[#6B7080];}.bk-select-control.bk-filled{box-shadow:none}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7!important;background-color:#f4f4f6!important;color:#a1a3ae!important}.bk-select-control.bk-disabled .bk-placeholder{color:#a1a3ae}.bk-select-container.default .bk-select-control{@apply px-3 py-2.5;}.bk-select-container.sm .bk-select-control{@apply px-3 py-[5px];}.bk-select-control.bk-has-error{border-color:#d11e14!important}.bk-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.bk-placeholder{@apply text-[#6B7080] font-normal text-[14px] truncate w-full pointer-events-none !leading-[18px];}.bk-value-label-single{@apply font-normal text-[#141414] truncate w-full;}.bk-select-container.default .bk-select-control .bk-value-label-single{@apply text-[14px] !leading-[18px];}.bk-select-container.sm .bk-select-control .bk-value-label-single{@apply text-xs !leading-[18px];}.bk-chips-viewport{flex:1 1 0%;min-width:0;max-width:100%}.bk-chips-measure{position:absolute;top:0;left:0;visibility:hidden;pointer-events:none;white-space:nowrap;z-index:-1}.bk-multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];max-width:120px;min-width:0}.bk-multi-badge-item.bk-chip-has-avatar{@apply py-0 ps-0.5;max-width:140px}.bk-select-container.bk-grid-view .bk-multi-badge-item{max-width:175px}.bk-multi-badge-item-text{@apply text-[10px] leading-[12px] font-normal text-[#6B7080];white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bk-multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.bk-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.bk-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.bk-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.bk-arrow-wrapper.bk-open{@apply rotate-180;}.bk-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[100] overflow-hidden cursor-default p-2.5;}.bk-grid-scroll{@apply overflow-auto -mx-2.5;scrollbar-width:thin;scrollbar-color:#D6D7DC transparent}.bk-grid-scroll::-webkit-scrollbar{width:6px;height:6px}.bk-grid-scroll::-webkit-scrollbar-track{background:transparent}.bk-grid-scroll::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:999px}.bk-grid-scroll::-webkit-scrollbar-thumb:hover{background:#909090}.bk-grid-scroll::-webkit-scrollbar-button{display:none}.bk-dropdown-panel.bk-grid-panel{padding-top:0;padding-bottom:0}.bk-select-grid{@apply w-full border-collapse text-sm text-[#141414];table-layout:fixed}.bk-select-grid th{@apply sticky top-0 z-10 bg-[#F1F1F3] px-4 py-2.5 font-semibold whitespace-nowrap border-b border-[#E3E3E7];}.bk-select-grid td{@apply px-4 py-2.5 border-b border-[#E3E3E7] align-middle;}.bk-select-grid tbody tr{@apply cursor-pointer transition-colors;}.bk-select-grid tbody tr:hover,.bk-select-grid tbody tr.bk-marked{@apply bg-[#F8F8F8];}.bk-select-grid tbody tr.bk-selected{background-color:#f8f8f8}.bk-select-grid tbody tr.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-grid-checkbox-column{width:48px;min-width:48px;@apply !px-4;}.bk-grid-cell-text{@apply block truncate;}.bk-grid-message{@apply !px-4 !py-4 text-center text-gray-400;}.bk-grid-footer{@apply flex items-center justify-between gap-4 px-1 py-2.5 text-xs text-[#6B7080];}.bk-grid-footer-actions{@apply flex items-center gap-2;}.bk-dropdown-panel.bk-grid-compact{padding:0 .5rem}.bk-dropdown-panel.bk-grid-compact .bk-dropdown-search{@apply px-1 pt-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-wrapper{@apply px-2 py-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-input{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-grid-scroll{@apply -mx-2;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid th,.bk-dropdown-panel.bk-grid-compact .bk-select-grid td{@apply px-3 py-1.5;}.bk-dropdown-panel.bk-grid-compact .bk-grid-checkbox-column{width:40px;min-width:40px;@apply !px-3;}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer{@apply gap-3 px-0 py-1.5 text-[11px];}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer-actions{@apply gap-1.5;}@media (max-width: 640px){.bk-grid-scroll{max-width:calc(100vw - 32px)}}.bk-dropdown-search{@apply px-2 pt-2;}.bk-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.bk-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.bk-options-list{@apply overflow-y-auto overflow-x-hidden relative flex flex-col gap-0.5;}@media (max-height: 700px){.bk-options-list{max-height:125px}}@media (min-height: 701px) and (max-height: 900px){.bk-options-list{max-height:166px}}@media (min-height: 901px){.bk-options-list{max-height:210px}}.bk-options-list.bk-no-responsive{max-height:166px!important}.bk-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] min-w-0;}.bk-option:hover,.bk-option.bk-marked,.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.bk-option.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-option.bk-option-disabled:hover{@apply bg-transparent;}.bk-option .bk-option-label{@apply line-clamp-1 break-all;}.bk-grouped .bk-option{@apply ps-5;}.bk-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.bk-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];}.bk-select-all-option:hover{@apply bg-gray-100;}.bk-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.bk-select-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] inline-block;}.bk-select-label-required{@apply text-[#E7000B];}.bk-options-list ::-webkit-scrollbar{width:10px}.bk-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.bk-option-group:not(:first-child){@apply mt-4;}.bk-select-error{@apply text-xs text-[#E7000B] font-normal;}.bk-select-hint{@apply text-xs text-[#868997] font-normal;}.bk-search-input:focus-visible{outline:2px solid transparent}.bk-option-icon{@apply w-4 h-4 object-contain rounded-sm;}.bk-chip-icon{@apply w-3 h-3 object-contain rounded-sm;}.bk-value-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.bk-chip-dot{@apply inline-block w-1.5 h-1.5 rounded-full shrink-0;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkAvatar, selector: "bk-avatar", inputs: ["src", "alt", "name", "initialsOverride", "tooltipContent", "bgColor", "textColor", "size", "variant", "fallback", "dot", "dotPosition"], outputs: ["imageLoadError"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }] });
|
|
6301
|
+
], 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: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "selectOverlay", first: true, predicate: ["selectOverlay"], descendants: true }, { propertyName: "chipsViewport", first: true, predicate: ["chipsViewport"], descendants: true }, { propertyName: "measurePlus", first: true, predicate: ["measurePlus"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }, { propertyName: "measureChips", predicate: ["measureChip"], descendants: true }], ngImport: i0, template: "<div class=\"bk-select-container\" [ngClass]=\"variation\" [class.bk-grid-view]=\"dropdownView() === 'grid'\">\r\n @if (label) {\r\n <label class=\"bk-select-label\" (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"bk-select-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <!-- controlStyle() resolves the tint: the selected option's accent normally,\r\n a soft red one while hasError. It's a method rather than a computed\r\n because hasError is a plain @Input, not a signal. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #selectOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-select-control\"\r\n [ngClass]=\"{ 'bk-has-error': hasError }\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.bk-focused]=\"isOpen()\"\r\n [class.bk-disabled]=\"disabled()\"\r\n [class.bk-filled]=\"!!controlStyle().backgroundColor\"\r\n [style.backgroundColor]=\"controlStyle().backgroundColor\"\r\n [style.color]=\"controlStyle().color\"\r\n [style.borderColor]=\"controlStyle().borderColor\"\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=\"bk-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"bk-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div\r\n #chipsViewport\r\n class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap overflow-hidden h-[18px]\"\r\n >\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(opt)\"\r\n [textColor]=\"avatarTextFor(opt)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\" [style.backgroundColor]=\"accentFor(opt)\"></span>\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"optionTextColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\r\n <!-- A locked control must not offer a way to drop a value. -->\r\n @if (isEditable()) {\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (visibleCount() < selectedOptions().length) {\r\n <div class=\"bk-multi-badge-item\">\r\n <span\r\n class=\"bk-multi-badge-item-text\"\r\n bkTooltipPosition=\"top\"\r\n [bkTooltip]=\"getRemainingItems()\"\r\n [bkTooltipScrollable]=\"true\"\r\n bkTooltipMaxHeight=\"240px\"\r\n >+{{ selectedOptions().length - visibleCount() }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hidden off-screen row used only to measure each chip's natural\r\n width so we can decide how many fit on a single line. -->\r\n <div class=\"bk-value-chips bk-chips-measure flex gap-0.5 flex-nowrap\" aria-hidden=\"true\">\r\n @for (opt of selectedOptions(); track $index) {\r\n <div #measureChip class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- Must mirror the visible chip exactly \u2014 same leading visual\r\n and same precedence \u2014 or the measured width is wrong and\r\n \"+N\" collapses at the wrong point. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\"></span>\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\r\n @if (isEditable()) {\r\n <button type=\"button\" tabindex=\"-1\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <div #measurePlus class=\"bk-multi-badge-item\">\r\n <span class=\"bk-multi-badge-item-text\">+{{ selectedOptions().length }}</span>\r\n </div>\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"flex items-center gap-1.5 min-w-0 w-full\">\r\n <!-- One leading visual only: avatar > icon > dot.\r\n `flex` on the host: bk-avatar's host is display:inline by\r\n default, so its inline-flex body sits on a baseline and the\r\n host gains descender space \u2014 which knocks the avatar out of\r\n vertical centre against the label. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(selectedOptions()[0])\"\r\n [name]=\"resolveLabel(selectedOptions()[0])\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(selectedOptions()[0])\"\r\n [textColor]=\"avatarTextFor(selectedOptions()[0])\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(selectedOptions()[0])) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(selectedOptions()[0])\"></span>\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.color]=\"controlStyle().color ?? resolveColor(selectedOptions()[0])\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(singleValueEl, resolveLabel(selectedOptions()[0]))\"\r\n bkTooltipPosition=\"top\">\r\n {{ resolveLabel(selectedOptions()[0]) }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"bk-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && isEditable()) {\r\n <span class=\"bk-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"bk-arrow-wrapper\" [class.bk-open]=\"isOpen()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #selectOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"selectOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"selectDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\r\n [class.bk-grouped]=\"groupBy()\"\r\n [class.bk-grid-panel]=\"dropdownView() === 'grid'\"\r\n [class.bk-grid-compact]=\"dropdownView() === 'grid' && isGridCompact()\"\r\n >\r\n @if (searchable()) {\r\n <div class=\"bk-dropdown-search mb-1\">\r\n <div class=\"bk-search-wrapper\">\r\n <svg\r\n class=\"text-[#BBBDC5] mr-2\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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\r\n #searchInput\r\n tabindex=\"0\"\r\n type=\"text\"\r\n class=\"bk-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @if (dropdownView() === 'grid') {\r\n <div\r\n #optionsListContainer\r\n class=\"bk-grid-scroll\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n [style.maxHeight]=\"gridMaxHeight()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n <table class=\"bk-select-grid\" [style.minWidth]=\"gridMinWidth()\">\r\n <thead>\r\n <tr>\r\n @if (multiple()) {\r\n <th class=\"bk-grid-checkbox-column\" aria-label=\"Selection\"></th>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <th [ngStyle]=\"gridColumnStyle(column)\">{{ column.label }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ loadingText() }}</td></tr>\r\n } @else {\r\n @for (item of filteredItems(); track resolveValue(item); let rowIndex = $index) {\r\n <tr\r\n #optionsRef\r\n tabindex=\"-1\"\r\n [class.bk-selected]=\"isGridItemSelected(item)\"\r\n [class.bk-marked]=\"rowIndex === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n (click)=\"handleGridSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover(rowIndex)\"\r\n >\r\n @if (multiple()) {\r\n <td class=\"bk-grid-checkbox-column\">\r\n <bk-checkbox\r\n class=\"pointer-events-none flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"isItemDisabled(item)\"\r\n [ngModel]=\"isGridItemSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </td>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <td [ngStyle]=\"gridColumnStyle(column)\">\r\n @if (column.type === 'badge') {\r\n <bk-badge\r\n [label]=\"resolveGridCell(item, column)\"\r\n [color]=\"gridBadgeColor(item, column)\"\r\n [variant]=\"column.badgeVariant ?? 'Light'\"\r\n [size]=\"isGridCompact() ? 'xsm' : 'sm'\"\r\n ></bk-badge>\r\n } @else {\r\n <span class=\"bk-grid-cell-text\">{{ resolveGridCell(item, column) }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ notFoundText() }}</td></tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if (multiple()) {\r\n <div class=\"bk-grid-footer\">\r\n <span>{{ gridSelectedCount() }} selected</span>\r\n @if (gridSelectionActions()) {\r\n <div class=\"bk-grid-footer-actions\">\r\n <bk-button variant=\"secondary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridClearText()\" (clicked)=\"clearGridDraft()\"></bk-button>\r\n <bk-button variant=\"primary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridApplyText()\" (clicked)=\"applyGridDraft()\"></bk-button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div\r\n #optionsListContainer\r\n tabindex=\"-1\"\r\n class=\"bk-options-list\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n @if (loading()) {\r\n <div class=\"bk-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()) {\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div\r\n class=\"bk-option\"\r\n (mousedown)=\"toggleSelectAll($event)\"\r\n [class.bk-selected]=\"isAllSelected()\"\r\n >\r\n <div class=\"flex-1 flex items-center gap-2 min-w-0\">\r\n <!-- Reflects state only: pointer-events-none lets the row's\r\n mousedown own the toggle, so the box can't fire twice.\r\n standalone keeps this ngModel out of any parent <form>\r\n bk-select is rendered inside. -->\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"isAllSelected()\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n <span class=\"line-clamp-1\">Select All</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n @if (group.group) {\r\n <div class=\"bk-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\r\n #optionsRef\r\n tabindex=\"-1\"\r\n class=\"bk-option\"\r\n [class.bk-selected]=\"isItemSelected(item)\"\r\n [class.bk-marked]=\"isMarked(item)\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n [class.cursor-not-allowed]=\"isItemDisabled(item)\"\r\n (click)=\"handleSelection(item, $event)\"\r\n (mouseenter)=\"markOption(item)\"\r\n >\r\n <div class=\"flex-1 flex justify-between gap-2 min-w-0\">\r\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(item)\"\r\n [name]=\"resolveLabel(item)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(item)\"\r\n [textColor]=\"avatarTextFor(item)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(item)) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(optionLabelEl, resolveLabel(item))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(item)\r\n }}</span>\r\n </div>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg\r\n class=\"text-[#141414] shrink-0\"\r\n width=\"17\"\r\n height=\"17\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n >\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 @if (filteredItems().length === 0) {\r\n <div class=\"bk-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </div>\r\n @if (hasError) {\r\n @if (errorMessage) {\r\n <p class=\"bk-select-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".bk-select-container{@apply relative w-full box-border flex flex-col gap-1.5;}.bk-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded cursor-pointer focus:border-[#E3E3E7] focus-visible:!outline-[.1px] focus-visible:!outline-[#6B7080];transition:border-color .2s,box-shadow .2s;box-shadow:0 1px 2px #1018280d}.bk-select-control:focus-visible{outline-style:solid!important}.bk-select-control.bk-focused{@apply shadow-none z-10;outline:none!important}.bk-select-control.bk-focused:not(.bk-filled){@apply border-[#6B7080];}.bk-select-control.bk-filled{box-shadow:none}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7!important;background-color:#f4f4f6!important;color:#a1a3ae!important}.bk-select-control.bk-disabled .bk-placeholder{color:#a1a3ae}.bk-select-container.default .bk-select-control{@apply px-3 py-2.5;}.bk-select-container.sm .bk-select-control{@apply px-3 py-[5px];}.bk-select-control.bk-has-error{border-color:#d11e14!important}.bk-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.bk-placeholder{@apply text-[#6B7080] font-normal text-[14px] truncate w-full pointer-events-none !leading-[18px];}.bk-value-label-single{@apply font-normal text-[#141414] truncate w-full;}.bk-select-container.default .bk-select-control .bk-value-label-single{@apply text-[14px] !leading-[18px];}.bk-select-container.sm .bk-select-control .bk-value-label-single{@apply text-xs !leading-[18px];}.bk-chips-viewport{flex:1 1 0%;min-width:0;max-width:100%}.bk-chips-measure{position:absolute;top:0;left:0;visibility:hidden;pointer-events:none;white-space:nowrap;z-index:-1}.bk-multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];max-width:120px;min-width:0}.bk-multi-badge-item.bk-chip-has-avatar{@apply py-0 ps-0.5;max-width:140px}.bk-select-container.bk-grid-view .bk-multi-badge-item{max-width:175px}.bk-multi-badge-item-text{@apply text-[10px] leading-[12px] font-normal text-[#6B7080];white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bk-multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.bk-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.bk-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.bk-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.bk-arrow-wrapper.bk-open{@apply rotate-180;}.bk-dropdown-panel{@apply static left-auto w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.bk-grid-scroll{@apply overflow-auto -mx-2.5;scrollbar-width:thin;scrollbar-color:#D6D7DC transparent}.bk-grid-scroll::-webkit-scrollbar{width:6px;height:6px}.bk-grid-scroll::-webkit-scrollbar-track{background:transparent}.bk-grid-scroll::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:999px}.bk-grid-scroll::-webkit-scrollbar-thumb:hover{background:#909090}.bk-grid-scroll::-webkit-scrollbar-button{display:none}.bk-dropdown-panel.bk-grid-panel{padding-top:0;padding-bottom:0}.bk-select-grid{@apply w-full border-collapse text-sm text-[#141414];table-layout:fixed}.bk-select-grid th{@apply sticky top-0 z-10 bg-[#F1F1F3] px-4 py-2.5 font-semibold whitespace-nowrap border-b border-[#E3E3E7];}.bk-select-grid td{@apply px-4 py-2.5 border-b border-[#E3E3E7] align-middle;}.bk-select-grid tbody tr{@apply cursor-pointer transition-colors;}.bk-select-grid tbody tr:hover,.bk-select-grid tbody tr.bk-marked{@apply bg-[#F8F8F8];}.bk-select-grid tbody tr.bk-selected{background-color:#f8f8f8}.bk-select-grid tbody tr.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-grid-checkbox-column{width:48px;min-width:48px;@apply !px-4;}.bk-grid-cell-text{@apply block truncate;}.bk-grid-message{@apply !px-4 !py-4 text-center text-gray-400;}.bk-grid-footer{@apply flex items-center justify-between gap-4 px-1 py-2.5 text-xs text-[#6B7080];}.bk-grid-footer-actions{@apply flex items-center gap-2;}.bk-dropdown-panel.bk-grid-compact{padding:0 .5rem}.bk-dropdown-panel.bk-grid-compact .bk-dropdown-search{@apply px-1 pt-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-wrapper{@apply px-2 py-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-input{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-grid-scroll{@apply -mx-2;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid th,.bk-dropdown-panel.bk-grid-compact .bk-select-grid td{@apply px-3 py-1.5;}.bk-dropdown-panel.bk-grid-compact .bk-grid-checkbox-column{width:40px;min-width:40px;@apply !px-3;}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer{@apply gap-3 px-0 py-1.5 text-[11px];}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer-actions{@apply gap-1.5;}@media (max-width: 640px){.bk-grid-scroll{max-width:calc(100vw - 32px)}}.bk-dropdown-search{@apply px-2 pt-2;}.bk-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.bk-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.bk-options-list{@apply overflow-y-auto overflow-x-hidden relative flex flex-col gap-0.5;}@media (max-height: 700px){.bk-options-list{max-height:125px}}@media (min-height: 701px) and (max-height: 900px){.bk-options-list{max-height:166px}}@media (min-height: 901px){.bk-options-list{max-height:210px}}.bk-options-list.bk-no-responsive{max-height:166px!important}.bk-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] min-w-0;}.bk-option:hover,.bk-option.bk-marked{@apply bg-[#F1F1F3] rounded-md;}.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.bk-option.bk-selected:hover,.bk-option.bk-selected.bk-marked{@apply bg-[#F1F1F3];}.bk-option.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-option.bk-option-disabled:hover{@apply bg-transparent;}.bk-option .bk-option-label{@apply line-clamp-1 break-all;}.bk-grouped .bk-option{@apply ps-5;}.bk-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.bk-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];}.bk-select-all-option:hover{@apply bg-gray-100;}.bk-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.bk-select-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] inline-block;}.bk-select-label-required{@apply text-[#E7000B];}.bk-options-list ::-webkit-scrollbar{width:10px}.bk-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.bk-option-group:not(:first-child){@apply mt-4;}.bk-select-error{@apply text-xs text-[#E7000B] font-normal;}.bk-select-hint{@apply text-xs text-[#868997] font-normal;}.bk-search-input:focus-visible{outline:2px solid transparent}.bk-option-icon{@apply w-4 h-4 object-contain rounded-sm;}.bk-chip-icon{@apply w-3 h-3 object-contain rounded-sm;}.bk-value-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.bk-chip-dot{@apply inline-block w-1.5 h-1.5 rounded-full shrink-0;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkAvatar, selector: "bk-avatar", inputs: ["src", "alt", "name", "initialsOverride", "tooltipContent", "bgColor", "textColor", "size", "variant", "fallback", "dot", "dotPosition"], outputs: ["imageLoadError"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
|
|
6171
6302
|
}
|
|
6172
6303
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
|
|
6173
6304
|
type: Component,
|
|
6174
|
-
args: [{ selector: 'bk-select', standalone: true, imports: [CommonModule, FormsModule, BKTooltipDirective, BkCheckbox, BkAvatar, BkButton, BkBadge], providers: [
|
|
6305
|
+
args: [{ selector: 'bk-select', standalone: true, imports: [CommonModule, FormsModule, BKTooltipDirective, BkCheckbox, BkAvatar, BkButton, BkBadge, OverlayModule], providers: [
|
|
6175
6306
|
{
|
|
6176
6307
|
provide: NG_VALUE_ACCESSOR,
|
|
6177
6308
|
useExisting: forwardRef(() => BkSelect),
|
|
6178
6309
|
multi: true
|
|
6179
6310
|
}
|
|
6180
|
-
], template: "<div class=\"bk-select-container\" [ngClass]=\"variation\" [class.bk-grid-view]=\"dropdownView() === 'grid'\">\r\n @if (label) {\r\n <label class=\"bk-select-label\" (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"bk-select-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <!-- controlStyle() resolves the tint: the selected option's accent normally,\r\n a soft red one while hasError. It's a method rather than a computed\r\n because hasError is a plain @Input, not a signal. -->\r\n <div\r\n #controlWrapper\r\n class=\"bk-select-control\"\r\n [ngClass]=\"{ 'bk-has-error': hasError }\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.bk-focused]=\"isOpen()\"\r\n [class.bk-disabled]=\"disabled()\"\r\n [class.bk-filled]=\"!!controlStyle().backgroundColor\"\r\n [style.backgroundColor]=\"controlStyle().backgroundColor\"\r\n [style.color]=\"controlStyle().color\"\r\n [style.borderColor]=\"controlStyle().borderColor\"\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=\"bk-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"bk-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div\r\n #chipsViewport\r\n class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap overflow-hidden h-[18px]\"\r\n >\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(opt)\"\r\n [textColor]=\"avatarTextFor(opt)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\" [style.backgroundColor]=\"accentFor(opt)\"></span>\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"optionTextColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\r\n <!-- A locked control must not offer a way to drop a value. -->\r\n @if (isEditable()) {\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (visibleCount() < selectedOptions().length) {\r\n <div class=\"bk-multi-badge-item\">\r\n <span\r\n class=\"bk-multi-badge-item-text\"\r\n bkTooltipPosition=\"top\"\r\n [bkTooltip]=\"getRemainingItems()\"\r\n [bkTooltipScrollable]=\"true\"\r\n bkTooltipMaxHeight=\"240px\"\r\n >+{{ selectedOptions().length - visibleCount() }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hidden off-screen row used only to measure each chip's natural\r\n width so we can decide how many fit on a single line. -->\r\n <div class=\"bk-value-chips bk-chips-measure flex gap-0.5 flex-nowrap\" aria-hidden=\"true\">\r\n @for (opt of selectedOptions(); track $index) {\r\n <div #measureChip class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- Must mirror the visible chip exactly \u2014 same leading visual\r\n and same precedence \u2014 or the measured width is wrong and\r\n \"+N\" collapses at the wrong point. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\"></span>\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\r\n @if (isEditable()) {\r\n <button type=\"button\" tabindex=\"-1\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <div #measurePlus class=\"bk-multi-badge-item\">\r\n <span class=\"bk-multi-badge-item-text\">+{{ selectedOptions().length }}</span>\r\n </div>\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"flex items-center gap-1.5 min-w-0 w-full\">\r\n <!-- One leading visual only: avatar > icon > dot.\r\n `flex` on the host: bk-avatar's host is display:inline by\r\n default, so its inline-flex body sits on a baseline and the\r\n host gains descender space \u2014 which knocks the avatar out of\r\n vertical centre against the label. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(selectedOptions()[0])\"\r\n [name]=\"resolveLabel(selectedOptions()[0])\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(selectedOptions()[0])\"\r\n [textColor]=\"avatarTextFor(selectedOptions()[0])\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(selectedOptions()[0])) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(selectedOptions()[0])\"></span>\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.color]=\"controlStyle().color ?? resolveColor(selectedOptions()[0])\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(singleValueEl, resolveLabel(selectedOptions()[0]))\"\r\n bkTooltipPosition=\"top\">\r\n {{ resolveLabel(selectedOptions()[0]) }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"bk-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && isEditable()) {\r\n <span class=\"bk-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"bk-arrow-wrapper\" [class.bk-open]=\"isOpen()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\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 [style.zIndex]=\"appendToBody() ? 10000 : null\"\r\n [class.bk-grouped]=\"groupBy()\"\r\n [class.bk-grid-panel]=\"dropdownView() === 'grid'\"\r\n [class.bk-grid-compact]=\"dropdownView() === 'grid' && isGridCompact()\"\r\n >\r\n @if (searchable()) {\r\n <div class=\"bk-dropdown-search mb-1\">\r\n <div class=\"bk-search-wrapper\">\r\n <svg\r\n class=\"text-[#BBBDC5] mr-2\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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\r\n #searchInput\r\n tabindex=\"-1\"\r\n type=\"text\"\r\n class=\"bk-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @if (dropdownView() === 'grid') {\r\n <div\r\n #optionsListContainer\r\n class=\"bk-grid-scroll\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n [style.maxHeight]=\"gridMaxHeight()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n <table class=\"bk-select-grid\" [style.minWidth]=\"gridMinWidth()\">\r\n <thead>\r\n <tr>\r\n @if (multiple()) {\r\n <th class=\"bk-grid-checkbox-column\" aria-label=\"Selection\"></th>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <th [ngStyle]=\"gridColumnStyle(column)\">{{ column.label }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ loadingText() }}</td></tr>\r\n } @else {\r\n @for (item of filteredItems(); track resolveValue(item); let rowIndex = $index) {\r\n <tr\r\n #optionsRef\r\n tabindex=\"-1\"\r\n [class.bk-selected]=\"isGridItemSelected(item)\"\r\n [class.bk-marked]=\"rowIndex === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n (click)=\"handleGridSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover(rowIndex)\"\r\n >\r\n @if (multiple()) {\r\n <td class=\"bk-grid-checkbox-column\">\r\n <bk-checkbox\r\n class=\"pointer-events-none flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"isItemDisabled(item)\"\r\n [ngModel]=\"isGridItemSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </td>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <td [ngStyle]=\"gridColumnStyle(column)\">\r\n @if (column.type === 'badge') {\r\n <bk-badge\r\n [label]=\"resolveGridCell(item, column)\"\r\n [color]=\"gridBadgeColor(item, column)\"\r\n [variant]=\"column.badgeVariant ?? 'Light'\"\r\n [size]=\"isGridCompact() ? 'xsm' : 'sm'\"\r\n ></bk-badge>\r\n } @else {\r\n <span class=\"bk-grid-cell-text\">{{ resolveGridCell(item, column) }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ notFoundText() }}</td></tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if (multiple()) {\r\n <div class=\"bk-grid-footer\">\r\n <span>{{ gridSelectedCount() }} selected</span>\r\n @if (gridSelectionActions()) {\r\n <div class=\"bk-grid-footer-actions\">\r\n <bk-button variant=\"secondary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridClearText()\" (clicked)=\"clearGridDraft()\"></bk-button>\r\n <bk-button variant=\"primary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridApplyText()\" (clicked)=\"applyGridDraft()\"></bk-button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div\r\n #optionsListContainer\r\n tabindex=\"-1\"\r\n class=\"bk-options-list\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n @if (loading()) {\r\n <div class=\"bk-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()) {\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div\r\n class=\"bk-option\"\r\n (mousedown)=\"toggleSelectAll($event)\"\r\n [class.bk-selected]=\"isAllSelected()\"\r\n >\r\n <div class=\"flex-1 flex items-center gap-2 min-w-0\">\r\n <!-- Reflects state only: pointer-events-none lets the row's\r\n mousedown own the toggle, so the box can't fire twice.\r\n standalone keeps this ngModel out of any parent <form>\r\n bk-select is rendered inside. -->\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"isAllSelected()\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n <span class=\"line-clamp-1\">Select All</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n @if (group.group) {\r\n <div class=\"bk-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\r\n #optionsRef\r\n tabindex=\"-1\"\r\n class=\"bk-option\"\r\n [class.bk-selected]=\"isItemSelected(item)\"\r\n [class.bk-marked]=\"$index === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n [class.cursor-not-allowed]=\"isItemDisabled(item)\"\r\n (click)=\"handleSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover($index)\"\r\n >\r\n <div class=\"flex-1 flex justify-between gap-2 min-w-0\">\r\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(item)\"\r\n [name]=\"resolveLabel(item)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(item)\"\r\n [textColor]=\"avatarTextFor(item)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(item)) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(optionLabelEl, resolveLabel(item))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(item)\r\n }}</span>\r\n </div>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg\r\n class=\"text-[#141414] shrink-0\"\r\n width=\"17\"\r\n height=\"17\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n >\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 @if (filteredItems().length === 0) {\r\n <div class=\"bk-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n @if (hasError) {\r\n @if (errorMessage) {\r\n <p class=\"bk-select-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".bk-select-container{@apply relative w-full box-border flex flex-col gap-1.5;}.bk-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded cursor-pointer focus:border-[#E3E3E7] focus-visible:!outline-[.1px] focus-visible:!outline-[#6B7080];transition:border-color .2s,box-shadow .2s;box-shadow:0 1px 2px #1018280d}.bk-select-control:focus-visible{outline-style:solid!important}.bk-select-control.bk-focused{@apply shadow-none z-10;outline:none!important}.bk-select-control.bk-focused:not(.bk-filled){@apply border-[#6B7080];}.bk-select-control.bk-filled{box-shadow:none}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7!important;background-color:#f4f4f6!important;color:#a1a3ae!important}.bk-select-control.bk-disabled .bk-placeholder{color:#a1a3ae}.bk-select-container.default .bk-select-control{@apply px-3 py-2.5;}.bk-select-container.sm .bk-select-control{@apply px-3 py-[5px];}.bk-select-control.bk-has-error{border-color:#d11e14!important}.bk-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.bk-placeholder{@apply text-[#6B7080] font-normal text-[14px] truncate w-full pointer-events-none !leading-[18px];}.bk-value-label-single{@apply font-normal text-[#141414] truncate w-full;}.bk-select-container.default .bk-select-control .bk-value-label-single{@apply text-[14px] !leading-[18px];}.bk-select-container.sm .bk-select-control .bk-value-label-single{@apply text-xs !leading-[18px];}.bk-chips-viewport{flex:1 1 0%;min-width:0;max-width:100%}.bk-chips-measure{position:absolute;top:0;left:0;visibility:hidden;pointer-events:none;white-space:nowrap;z-index:-1}.bk-multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];max-width:120px;min-width:0}.bk-multi-badge-item.bk-chip-has-avatar{@apply py-0 ps-0.5;max-width:140px}.bk-select-container.bk-grid-view .bk-multi-badge-item{max-width:175px}.bk-multi-badge-item-text{@apply text-[10px] leading-[12px] font-normal text-[#6B7080];white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bk-multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.bk-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.bk-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.bk-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.bk-arrow-wrapper.bk-open{@apply rotate-180;}.bk-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[100] overflow-hidden cursor-default p-2.5;}.bk-grid-scroll{@apply overflow-auto -mx-2.5;scrollbar-width:thin;scrollbar-color:#D6D7DC transparent}.bk-grid-scroll::-webkit-scrollbar{width:6px;height:6px}.bk-grid-scroll::-webkit-scrollbar-track{background:transparent}.bk-grid-scroll::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:999px}.bk-grid-scroll::-webkit-scrollbar-thumb:hover{background:#909090}.bk-grid-scroll::-webkit-scrollbar-button{display:none}.bk-dropdown-panel.bk-grid-panel{padding-top:0;padding-bottom:0}.bk-select-grid{@apply w-full border-collapse text-sm text-[#141414];table-layout:fixed}.bk-select-grid th{@apply sticky top-0 z-10 bg-[#F1F1F3] px-4 py-2.5 font-semibold whitespace-nowrap border-b border-[#E3E3E7];}.bk-select-grid td{@apply px-4 py-2.5 border-b border-[#E3E3E7] align-middle;}.bk-select-grid tbody tr{@apply cursor-pointer transition-colors;}.bk-select-grid tbody tr:hover,.bk-select-grid tbody tr.bk-marked{@apply bg-[#F8F8F8];}.bk-select-grid tbody tr.bk-selected{background-color:#f8f8f8}.bk-select-grid tbody tr.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-grid-checkbox-column{width:48px;min-width:48px;@apply !px-4;}.bk-grid-cell-text{@apply block truncate;}.bk-grid-message{@apply !px-4 !py-4 text-center text-gray-400;}.bk-grid-footer{@apply flex items-center justify-between gap-4 px-1 py-2.5 text-xs text-[#6B7080];}.bk-grid-footer-actions{@apply flex items-center gap-2;}.bk-dropdown-panel.bk-grid-compact{padding:0 .5rem}.bk-dropdown-panel.bk-grid-compact .bk-dropdown-search{@apply px-1 pt-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-wrapper{@apply px-2 py-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-input{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-grid-scroll{@apply -mx-2;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid th,.bk-dropdown-panel.bk-grid-compact .bk-select-grid td{@apply px-3 py-1.5;}.bk-dropdown-panel.bk-grid-compact .bk-grid-checkbox-column{width:40px;min-width:40px;@apply !px-3;}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer{@apply gap-3 px-0 py-1.5 text-[11px];}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer-actions{@apply gap-1.5;}@media (max-width: 640px){.bk-grid-scroll{max-width:calc(100vw - 32px)}}.bk-dropdown-search{@apply px-2 pt-2;}.bk-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.bk-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.bk-options-list{@apply overflow-y-auto overflow-x-hidden relative flex flex-col gap-0.5;}@media (max-height: 700px){.bk-options-list{max-height:125px}}@media (min-height: 701px) and (max-height: 900px){.bk-options-list{max-height:166px}}@media (min-height: 901px){.bk-options-list{max-height:210px}}.bk-options-list.bk-no-responsive{max-height:166px!important}.bk-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] min-w-0;}.bk-option:hover,.bk-option.bk-marked,.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.bk-option.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-option.bk-option-disabled:hover{@apply bg-transparent;}.bk-option .bk-option-label{@apply line-clamp-1 break-all;}.bk-grouped .bk-option{@apply ps-5;}.bk-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.bk-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];}.bk-select-all-option:hover{@apply bg-gray-100;}.bk-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.bk-select-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] inline-block;}.bk-select-label-required{@apply text-[#E7000B];}.bk-options-list ::-webkit-scrollbar{width:10px}.bk-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.bk-option-group:not(:first-child){@apply mt-4;}.bk-select-error{@apply text-xs text-[#E7000B] font-normal;}.bk-select-hint{@apply text-xs text-[#868997] font-normal;}.bk-search-input:focus-visible{outline:2px solid transparent}.bk-option-icon{@apply w-4 h-4 object-contain rounded-sm;}.bk-chip-icon{@apply w-3 h-3 object-contain rounded-sm;}.bk-value-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.bk-chip-dot{@apply inline-block w-1.5 h-1.5 rounded-full shrink-0;}\n"] }]
|
|
6311
|
+
], template: "<div class=\"bk-select-container\" [ngClass]=\"variation\" [class.bk-grid-view]=\"dropdownView() === 'grid'\">\r\n @if (label) {\r\n <label class=\"bk-select-label\" (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"bk-select-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <!-- controlStyle() resolves the tint: the selected option's accent normally,\r\n a soft red one while hasError. It's a method rather than a computed\r\n because hasError is a plain @Input, not a signal. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #selectOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-select-control\"\r\n [ngClass]=\"{ 'bk-has-error': hasError }\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.bk-focused]=\"isOpen()\"\r\n [class.bk-disabled]=\"disabled()\"\r\n [class.bk-filled]=\"!!controlStyle().backgroundColor\"\r\n [style.backgroundColor]=\"controlStyle().backgroundColor\"\r\n [style.color]=\"controlStyle().color\"\r\n [style.borderColor]=\"controlStyle().borderColor\"\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=\"bk-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"bk-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div\r\n #chipsViewport\r\n class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap overflow-hidden h-[18px]\"\r\n >\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(opt)\"\r\n [textColor]=\"avatarTextFor(opt)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\" [style.backgroundColor]=\"accentFor(opt)\"></span>\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"optionTextColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\r\n <!-- A locked control must not offer a way to drop a value. -->\r\n @if (isEditable()) {\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (visibleCount() < selectedOptions().length) {\r\n <div class=\"bk-multi-badge-item\">\r\n <span\r\n class=\"bk-multi-badge-item-text\"\r\n bkTooltipPosition=\"top\"\r\n [bkTooltip]=\"getRemainingItems()\"\r\n [bkTooltipScrollable]=\"true\"\r\n bkTooltipMaxHeight=\"240px\"\r\n >+{{ selectedOptions().length - visibleCount() }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hidden off-screen row used only to measure each chip's natural\r\n width so we can decide how many fit on a single line. -->\r\n <div class=\"bk-value-chips bk-chips-measure flex gap-0.5 flex-nowrap\" aria-hidden=\"true\">\r\n @for (opt of selectedOptions(); track $index) {\r\n <div #measureChip class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- Must mirror the visible chip exactly \u2014 same leading visual\r\n and same precedence \u2014 or the measured width is wrong and\r\n \"+N\" collapses at the wrong point. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\"></span>\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\r\n @if (isEditable()) {\r\n <button type=\"button\" tabindex=\"-1\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <div #measurePlus class=\"bk-multi-badge-item\">\r\n <span class=\"bk-multi-badge-item-text\">+{{ selectedOptions().length }}</span>\r\n </div>\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"flex items-center gap-1.5 min-w-0 w-full\">\r\n <!-- One leading visual only: avatar > icon > dot.\r\n `flex` on the host: bk-avatar's host is display:inline by\r\n default, so its inline-flex body sits on a baseline and the\r\n host gains descender space \u2014 which knocks the avatar out of\r\n vertical centre against the label. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(selectedOptions()[0])\"\r\n [name]=\"resolveLabel(selectedOptions()[0])\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(selectedOptions()[0])\"\r\n [textColor]=\"avatarTextFor(selectedOptions()[0])\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(selectedOptions()[0])) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(selectedOptions()[0])\"></span>\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.color]=\"controlStyle().color ?? resolveColor(selectedOptions()[0])\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(singleValueEl, resolveLabel(selectedOptions()[0]))\"\r\n bkTooltipPosition=\"top\">\r\n {{ resolveLabel(selectedOptions()[0]) }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"bk-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && isEditable()) {\r\n <span class=\"bk-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"bk-arrow-wrapper\" [class.bk-open]=\"isOpen()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #selectOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"selectOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"selectDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\r\n [class.bk-grouped]=\"groupBy()\"\r\n [class.bk-grid-panel]=\"dropdownView() === 'grid'\"\r\n [class.bk-grid-compact]=\"dropdownView() === 'grid' && isGridCompact()\"\r\n >\r\n @if (searchable()) {\r\n <div class=\"bk-dropdown-search mb-1\">\r\n <div class=\"bk-search-wrapper\">\r\n <svg\r\n class=\"text-[#BBBDC5] mr-2\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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\r\n #searchInput\r\n tabindex=\"0\"\r\n type=\"text\"\r\n class=\"bk-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @if (dropdownView() === 'grid') {\r\n <div\r\n #optionsListContainer\r\n class=\"bk-grid-scroll\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n [style.maxHeight]=\"gridMaxHeight()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n <table class=\"bk-select-grid\" [style.minWidth]=\"gridMinWidth()\">\r\n <thead>\r\n <tr>\r\n @if (multiple()) {\r\n <th class=\"bk-grid-checkbox-column\" aria-label=\"Selection\"></th>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <th [ngStyle]=\"gridColumnStyle(column)\">{{ column.label }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ loadingText() }}</td></tr>\r\n } @else {\r\n @for (item of filteredItems(); track resolveValue(item); let rowIndex = $index) {\r\n <tr\r\n #optionsRef\r\n tabindex=\"-1\"\r\n [class.bk-selected]=\"isGridItemSelected(item)\"\r\n [class.bk-marked]=\"rowIndex === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n (click)=\"handleGridSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover(rowIndex)\"\r\n >\r\n @if (multiple()) {\r\n <td class=\"bk-grid-checkbox-column\">\r\n <bk-checkbox\r\n class=\"pointer-events-none flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"isItemDisabled(item)\"\r\n [ngModel]=\"isGridItemSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </td>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <td [ngStyle]=\"gridColumnStyle(column)\">\r\n @if (column.type === 'badge') {\r\n <bk-badge\r\n [label]=\"resolveGridCell(item, column)\"\r\n [color]=\"gridBadgeColor(item, column)\"\r\n [variant]=\"column.badgeVariant ?? 'Light'\"\r\n [size]=\"isGridCompact() ? 'xsm' : 'sm'\"\r\n ></bk-badge>\r\n } @else {\r\n <span class=\"bk-grid-cell-text\">{{ resolveGridCell(item, column) }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ notFoundText() }}</td></tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if (multiple()) {\r\n <div class=\"bk-grid-footer\">\r\n <span>{{ gridSelectedCount() }} selected</span>\r\n @if (gridSelectionActions()) {\r\n <div class=\"bk-grid-footer-actions\">\r\n <bk-button variant=\"secondary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridClearText()\" (clicked)=\"clearGridDraft()\"></bk-button>\r\n <bk-button variant=\"primary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridApplyText()\" (clicked)=\"applyGridDraft()\"></bk-button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div\r\n #optionsListContainer\r\n tabindex=\"-1\"\r\n class=\"bk-options-list\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n @if (loading()) {\r\n <div class=\"bk-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()) {\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div\r\n class=\"bk-option\"\r\n (mousedown)=\"toggleSelectAll($event)\"\r\n [class.bk-selected]=\"isAllSelected()\"\r\n >\r\n <div class=\"flex-1 flex items-center gap-2 min-w-0\">\r\n <!-- Reflects state only: pointer-events-none lets the row's\r\n mousedown own the toggle, so the box can't fire twice.\r\n standalone keeps this ngModel out of any parent <form>\r\n bk-select is rendered inside. -->\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"isAllSelected()\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n <span class=\"line-clamp-1\">Select All</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n @if (group.group) {\r\n <div class=\"bk-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\r\n #optionsRef\r\n tabindex=\"-1\"\r\n class=\"bk-option\"\r\n [class.bk-selected]=\"isItemSelected(item)\"\r\n [class.bk-marked]=\"isMarked(item)\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n [class.cursor-not-allowed]=\"isItemDisabled(item)\"\r\n (click)=\"handleSelection(item, $event)\"\r\n (mouseenter)=\"markOption(item)\"\r\n >\r\n <div class=\"flex-1 flex justify-between gap-2 min-w-0\">\r\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(item)\"\r\n [name]=\"resolveLabel(item)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(item)\"\r\n [textColor]=\"avatarTextFor(item)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(item)) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(optionLabelEl, resolveLabel(item))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(item)\r\n }}</span>\r\n </div>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg\r\n class=\"text-[#141414] shrink-0\"\r\n width=\"17\"\r\n height=\"17\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n >\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 @if (filteredItems().length === 0) {\r\n <div class=\"bk-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </div>\r\n @if (hasError) {\r\n @if (errorMessage) {\r\n <p class=\"bk-select-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".bk-select-container{@apply relative w-full box-border flex flex-col gap-1.5;}.bk-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded cursor-pointer focus:border-[#E3E3E7] focus-visible:!outline-[.1px] focus-visible:!outline-[#6B7080];transition:border-color .2s,box-shadow .2s;box-shadow:0 1px 2px #1018280d}.bk-select-control:focus-visible{outline-style:solid!important}.bk-select-control.bk-focused{@apply shadow-none z-10;outline:none!important}.bk-select-control.bk-focused:not(.bk-filled){@apply border-[#6B7080];}.bk-select-control.bk-filled{box-shadow:none}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7!important;background-color:#f4f4f6!important;color:#a1a3ae!important}.bk-select-control.bk-disabled .bk-placeholder{color:#a1a3ae}.bk-select-container.default .bk-select-control{@apply px-3 py-2.5;}.bk-select-container.sm .bk-select-control{@apply px-3 py-[5px];}.bk-select-control.bk-has-error{border-color:#d11e14!important}.bk-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.bk-placeholder{@apply text-[#6B7080] font-normal text-[14px] truncate w-full pointer-events-none !leading-[18px];}.bk-value-label-single{@apply font-normal text-[#141414] truncate w-full;}.bk-select-container.default .bk-select-control .bk-value-label-single{@apply text-[14px] !leading-[18px];}.bk-select-container.sm .bk-select-control .bk-value-label-single{@apply text-xs !leading-[18px];}.bk-chips-viewport{flex:1 1 0%;min-width:0;max-width:100%}.bk-chips-measure{position:absolute;top:0;left:0;visibility:hidden;pointer-events:none;white-space:nowrap;z-index:-1}.bk-multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];max-width:120px;min-width:0}.bk-multi-badge-item.bk-chip-has-avatar{@apply py-0 ps-0.5;max-width:140px}.bk-select-container.bk-grid-view .bk-multi-badge-item{max-width:175px}.bk-multi-badge-item-text{@apply text-[10px] leading-[12px] font-normal text-[#6B7080];white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bk-multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.bk-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.bk-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.bk-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.bk-arrow-wrapper.bk-open{@apply rotate-180;}.bk-dropdown-panel{@apply static left-auto w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.bk-grid-scroll{@apply overflow-auto -mx-2.5;scrollbar-width:thin;scrollbar-color:#D6D7DC transparent}.bk-grid-scroll::-webkit-scrollbar{width:6px;height:6px}.bk-grid-scroll::-webkit-scrollbar-track{background:transparent}.bk-grid-scroll::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:999px}.bk-grid-scroll::-webkit-scrollbar-thumb:hover{background:#909090}.bk-grid-scroll::-webkit-scrollbar-button{display:none}.bk-dropdown-panel.bk-grid-panel{padding-top:0;padding-bottom:0}.bk-select-grid{@apply w-full border-collapse text-sm text-[#141414];table-layout:fixed}.bk-select-grid th{@apply sticky top-0 z-10 bg-[#F1F1F3] px-4 py-2.5 font-semibold whitespace-nowrap border-b border-[#E3E3E7];}.bk-select-grid td{@apply px-4 py-2.5 border-b border-[#E3E3E7] align-middle;}.bk-select-grid tbody tr{@apply cursor-pointer transition-colors;}.bk-select-grid tbody tr:hover,.bk-select-grid tbody tr.bk-marked{@apply bg-[#F8F8F8];}.bk-select-grid tbody tr.bk-selected{background-color:#f8f8f8}.bk-select-grid tbody tr.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-grid-checkbox-column{width:48px;min-width:48px;@apply !px-4;}.bk-grid-cell-text{@apply block truncate;}.bk-grid-message{@apply !px-4 !py-4 text-center text-gray-400;}.bk-grid-footer{@apply flex items-center justify-between gap-4 px-1 py-2.5 text-xs text-[#6B7080];}.bk-grid-footer-actions{@apply flex items-center gap-2;}.bk-dropdown-panel.bk-grid-compact{padding:0 .5rem}.bk-dropdown-panel.bk-grid-compact .bk-dropdown-search{@apply px-1 pt-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-wrapper{@apply px-2 py-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-input{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-grid-scroll{@apply -mx-2;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid th,.bk-dropdown-panel.bk-grid-compact .bk-select-grid td{@apply px-3 py-1.5;}.bk-dropdown-panel.bk-grid-compact .bk-grid-checkbox-column{width:40px;min-width:40px;@apply !px-3;}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer{@apply gap-3 px-0 py-1.5 text-[11px];}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer-actions{@apply gap-1.5;}@media (max-width: 640px){.bk-grid-scroll{max-width:calc(100vw - 32px)}}.bk-dropdown-search{@apply px-2 pt-2;}.bk-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.bk-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.bk-options-list{@apply overflow-y-auto overflow-x-hidden relative flex flex-col gap-0.5;}@media (max-height: 700px){.bk-options-list{max-height:125px}}@media (min-height: 701px) and (max-height: 900px){.bk-options-list{max-height:166px}}@media (min-height: 901px){.bk-options-list{max-height:210px}}.bk-options-list.bk-no-responsive{max-height:166px!important}.bk-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] min-w-0;}.bk-option:hover,.bk-option.bk-marked{@apply bg-[#F1F1F3] rounded-md;}.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.bk-option.bk-selected:hover,.bk-option.bk-selected.bk-marked{@apply bg-[#F1F1F3];}.bk-option.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-option.bk-option-disabled:hover{@apply bg-transparent;}.bk-option .bk-option-label{@apply line-clamp-1 break-all;}.bk-grouped .bk-option{@apply ps-5;}.bk-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.bk-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];}.bk-select-all-option:hover{@apply bg-gray-100;}.bk-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.bk-select-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] inline-block;}.bk-select-label-required{@apply text-[#E7000B];}.bk-options-list ::-webkit-scrollbar{width:10px}.bk-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.bk-option-group:not(:first-child){@apply mt-4;}.bk-select-error{@apply text-xs text-[#E7000B] font-normal;}.bk-select-hint{@apply text-xs text-[#868997] font-normal;}.bk-search-input:focus-visible{outline:2px solid transparent}.bk-option-icon{@apply w-4 h-4 object-contain rounded-sm;}.bk-chip-icon{@apply w-3 h-3 object-contain rounded-sm;}.bk-value-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.bk-chip-dot{@apply inline-block w-1.5 h-1.5 rounded-full shrink-0;}\n"] }]
|
|
6181
6312
|
}], 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 }] }], bindIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindIcon", required: false }] }], isResponsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "isResponsive", 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 }] }], dropdownView: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownView", required: false }] }], gridColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridColumns", required: false }] }], gridVariation: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridVariation", required: false }] }], gridSelectionActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridSelectionActions", required: false }] }], gridMinWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridMinWidth", required: false }] }], gridMaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridMaxHeight", required: false }] }], gridSelectedLabelKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridSelectedLabelKeys", required: false }] }], gridSelectedLabelSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridSelectedLabelSeparator", required: false }] }], gridApplyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridApplyText", required: false }] }], gridClearText: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridClearText", required: false }] }], showDots: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDots", required: false }] }], showAvatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatar", required: false }] }], avatarKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarKey", required: false }] }], iconAlt: [{
|
|
6182
6313
|
type: Input
|
|
6183
6314
|
}], label: [{
|
|
@@ -6188,7 +6319,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6188
6319
|
type: Input
|
|
6189
6320
|
}], iconSrc: [{
|
|
6190
6321
|
type: Input
|
|
6191
|
-
}], 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 }] }], hasError: [{
|
|
6322
|
+
}], 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 }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnFocus", required: false }] }], dropdownPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownPosition", required: false }] }], hasError: [{
|
|
6192
6323
|
type: Input
|
|
6193
6324
|
}], errorMessage: [{
|
|
6194
6325
|
type: Input
|
|
@@ -6207,6 +6338,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6207
6338
|
}], dropdownPanel: [{
|
|
6208
6339
|
type: ViewChild,
|
|
6209
6340
|
args: ['dropdownPanel']
|
|
6341
|
+
}], selectOverlay: [{
|
|
6342
|
+
type: ViewChild,
|
|
6343
|
+
args: ['selectOverlay']
|
|
6210
6344
|
}], chipsViewport: [{
|
|
6211
6345
|
type: ViewChild,
|
|
6212
6346
|
args: ['chipsViewport']
|
|
@@ -6216,11 +6350,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6216
6350
|
}], measurePlus: [{
|
|
6217
6351
|
type: ViewChild,
|
|
6218
6352
|
args: ['measurePlus']
|
|
6219
|
-
}], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }],
|
|
6353
|
+
}], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onPointerDown: [{
|
|
6220
6354
|
type: HostListener,
|
|
6221
|
-
args: ['
|
|
6355
|
+
args: ['pointerdown']
|
|
6356
|
+
}], onFocusIn: [{
|
|
6357
|
+
type: HostListener,
|
|
6358
|
+
args: ['focusin', ['$event']]
|
|
6359
|
+
}], onFocusOut: [{
|
|
6360
|
+
type: HostListener,
|
|
6361
|
+
args: ['focusout']
|
|
6222
6362
|
}] } });
|
|
6223
6363
|
|
|
6364
|
+
/** Default country list used when a consumer does not provide their own via `[countryOptions]`. */
|
|
6365
|
+
const DEFAULT_COUNTRY_OPTIONS = [
|
|
6366
|
+
{ code: 'US', name: 'US', mask: '(000) 000-0000', prefix: '+1 ', placeholder: '(000) 000-0000' },
|
|
6367
|
+
{ code: 'MT', name: 'MT', mask: '(000) 000-0000', prefix: '+356 ', placeholder: '(000) 000-0000' },
|
|
6368
|
+
{ code: 'PL', name: 'PL', mask: '(000) 000-0000', prefix: '+48 ', placeholder: '(000) 000-0000' },
|
|
6369
|
+
{ code: 'CH', name: 'CH', mask: '(000) 000-0000', prefix: '+41 ', placeholder: '(000) 000-0000' },
|
|
6370
|
+
{ code: 'TR', name: 'TR', mask: '(000) 000-0000', prefix: '+90 ', placeholder: '(000) 000-0000' },
|
|
6371
|
+
{ code: 'UG', name: 'UG', mask: '(000) 000-0000', prefix: '+256 ', placeholder: '(000) 000-0000' },
|
|
6372
|
+
{ code: 'ZM', name: 'ZM', mask: '(000) 000-0000', prefix: '+260 ', placeholder: '(000) 000-0000' }
|
|
6373
|
+
];
|
|
6224
6374
|
class BkInput {
|
|
6225
6375
|
// =================== Inputs (all your original ones) ===================
|
|
6226
6376
|
id;
|
|
@@ -6252,16 +6402,24 @@ class BkInput {
|
|
|
6252
6402
|
currencyDecimals = 2;
|
|
6253
6403
|
allowNegative = false;
|
|
6254
6404
|
countryCode = 'US';
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6405
|
+
/**
|
|
6406
|
+
* Consumer-supplied country list. When a non-empty list is provided it replaces the
|
|
6407
|
+
* built-in list; when omitted (or given a null/empty value) the DEFAULT_COUNTRY_OPTIONS
|
|
6408
|
+
* are used so the selector always has values to show.
|
|
6409
|
+
*/
|
|
6410
|
+
_countryOptions = DEFAULT_COUNTRY_OPTIONS;
|
|
6411
|
+
set countryOptions(value) {
|
|
6412
|
+
this._countryOptions = (value && value.length) ? value : DEFAULT_COUNTRY_OPTIONS;
|
|
6413
|
+
// Keep the selected country valid against the (possibly new/custom) list so the
|
|
6414
|
+
// placeholder, mask and prefix always resolve to a real entry.
|
|
6415
|
+
const match = this._countryOptions.find(c => c.code === this.countryCode);
|
|
6416
|
+
this.selectedCountry = match ?? this._countryOptions[0];
|
|
6417
|
+
this.countryCode = this.selectedCountry?.code ?? this.countryCode;
|
|
6418
|
+
}
|
|
6419
|
+
get countryOptions() {
|
|
6420
|
+
return this._countryOptions;
|
|
6421
|
+
}
|
|
6422
|
+
selectedCountry = DEFAULT_COUNTRY_OPTIONS[0];
|
|
6265
6423
|
iconOrientation = 'left';
|
|
6266
6424
|
password = false;
|
|
6267
6425
|
showPassword = false;
|
|
@@ -6272,16 +6430,26 @@ class BkInput {
|
|
|
6272
6430
|
maxlength = null;
|
|
6273
6431
|
minlength = null;
|
|
6274
6432
|
// =================== ViewChild ===================
|
|
6275
|
-
dropdownRef;
|
|
6276
|
-
selectRef;
|
|
6277
6433
|
inputField;
|
|
6278
6434
|
maskDirective;
|
|
6435
|
+
phoneOverlay;
|
|
6279
6436
|
// =================== Internal State ===================
|
|
6280
6437
|
isFocused = false;
|
|
6281
6438
|
inputValue = '';
|
|
6282
6439
|
isDropdownOpen = false;
|
|
6283
6440
|
pendingMaskedValue = null;
|
|
6284
6441
|
isPropagatingViewValue = false;
|
|
6442
|
+
/**
|
|
6443
|
+
* Country dropdown panel, positioned via CDK Overlay instead of an inline absolute-positioned
|
|
6444
|
+
* div. This escapes clipping inside dialogs/scroll containers and stacks correctly above CDK
|
|
6445
|
+
* Overlay-based content (e.g. `bk-dialog`) regardless of Angular version — see the
|
|
6446
|
+
* "Dropdown & Calendar Overlay Strategy" doc. Primary: below the trigger, left-aligned (mirrors
|
|
6447
|
+
* the old `top-full left-0 mt-1`). Fallback: above the trigger when there's no room below.
|
|
6448
|
+
*/
|
|
6449
|
+
phoneDropdownPositions = [
|
|
6450
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
6451
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 }
|
|
6452
|
+
];
|
|
6285
6453
|
// =================== Output Emitter ===================
|
|
6286
6454
|
input = new EventEmitter();
|
|
6287
6455
|
change = new EventEmitter();
|
|
@@ -6290,8 +6458,7 @@ class BkInput {
|
|
|
6290
6458
|
clicked = new EventEmitter();
|
|
6291
6459
|
get placeHolderText() {
|
|
6292
6460
|
if (this.phone) {
|
|
6293
|
-
|
|
6294
|
-
return country?.placeholder || '';
|
|
6461
|
+
return this.selectedCountry?.placeholder || this.placeholder || '';
|
|
6295
6462
|
}
|
|
6296
6463
|
if (this.currency && !this.placeholder) {
|
|
6297
6464
|
return this.currencyDecimals > 0 ? `0.${'0'.repeat(this.currencyDecimals)}` : '0';
|
|
@@ -6304,15 +6471,13 @@ class BkInput {
|
|
|
6304
6471
|
if (this.currency)
|
|
6305
6472
|
return `separator.${this.currencyDecimals}`;
|
|
6306
6473
|
if (this.phone) {
|
|
6307
|
-
|
|
6308
|
-
return country?.mask || '';
|
|
6474
|
+
return this.selectedCountry?.mask || '';
|
|
6309
6475
|
}
|
|
6310
6476
|
return '';
|
|
6311
6477
|
}
|
|
6312
6478
|
get maskPrefixValue() {
|
|
6313
6479
|
if (this.phone) {
|
|
6314
|
-
|
|
6315
|
-
return country?.prefix || '';
|
|
6480
|
+
return this.selectedCountry?.prefix || '';
|
|
6316
6481
|
}
|
|
6317
6482
|
return '';
|
|
6318
6483
|
}
|
|
@@ -6384,7 +6549,7 @@ class BkInput {
|
|
|
6384
6549
|
// =================== Lifecycle ===================
|
|
6385
6550
|
closeAllDropdownsHandler = () => {
|
|
6386
6551
|
if (this.phone && this.isDropdownOpen)
|
|
6387
|
-
this.
|
|
6552
|
+
this.closeDropdown();
|
|
6388
6553
|
};
|
|
6389
6554
|
ngOnInit() {
|
|
6390
6555
|
if (this.value !== undefined && this.value !== null && this.value !== '') {
|
|
@@ -6394,8 +6559,10 @@ class BkInput {
|
|
|
6394
6559
|
this.type = 'password';
|
|
6395
6560
|
if (this.phone) {
|
|
6396
6561
|
const country = this.countryOptions.find(c => c.code === this.countryCode);
|
|
6397
|
-
|
|
6398
|
-
|
|
6562
|
+
// Prefer the matching country; otherwise default to the first available option so the
|
|
6563
|
+
// selector text is always consistent with the (possibly custom) country list.
|
|
6564
|
+
this.selectedCountry = country ?? this.countryOptions[0];
|
|
6565
|
+
this.countryCode = this.selectedCountry?.code ?? this.countryCode;
|
|
6399
6566
|
document.addEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
|
|
6400
6567
|
}
|
|
6401
6568
|
}
|
|
@@ -6407,18 +6574,7 @@ class BkInput {
|
|
|
6407
6574
|
ngOnDestroy() {
|
|
6408
6575
|
if (this.phone) {
|
|
6409
6576
|
document.removeEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
|
|
6410
|
-
|
|
6411
|
-
}
|
|
6412
|
-
// =================== Host Listener ===================
|
|
6413
|
-
onDocumentClick(event) {
|
|
6414
|
-
if (this.phone && this.isDropdownOpen) {
|
|
6415
|
-
const target = event.target;
|
|
6416
|
-
if (this.selectRef?.nativeElement && this.dropdownRef?.nativeElement) {
|
|
6417
|
-
const clickedInside = this.selectRef.nativeElement.contains(target) ||
|
|
6418
|
-
this.dropdownRef.nativeElement.contains(target);
|
|
6419
|
-
if (!clickedInside)
|
|
6420
|
-
this.isDropdownOpen = false;
|
|
6421
|
-
}
|
|
6577
|
+
this.detachPhoneOverlayScrollTracking();
|
|
6422
6578
|
}
|
|
6423
6579
|
}
|
|
6424
6580
|
// =================== Event Handlers ===================
|
|
@@ -6469,14 +6625,54 @@ class BkInput {
|
|
|
6469
6625
|
if (!this.disabled && this.phone) {
|
|
6470
6626
|
if (!this.isDropdownOpen) {
|
|
6471
6627
|
document.dispatchEvent(new CustomEvent('closeAllPhoneDropdowns'));
|
|
6472
|
-
|
|
6628
|
+
this.isDropdownOpen = true;
|
|
6629
|
+
this.attachPhoneOverlayScrollTracking();
|
|
6473
6630
|
}
|
|
6474
6631
|
else {
|
|
6475
|
-
this.
|
|
6632
|
+
this.closeDropdown();
|
|
6476
6633
|
}
|
|
6477
6634
|
event?.stopPropagation();
|
|
6478
6635
|
}
|
|
6479
6636
|
}
|
|
6637
|
+
/**
|
|
6638
|
+
* Shared close path for the CDK overlay: outside click, the overlay detaching (e.g. on
|
|
6639
|
+
* destroy), and another `bk-input` phone field opening (see closeAllDropdownsHandler).
|
|
6640
|
+
*/
|
|
6641
|
+
closeDropdown() {
|
|
6642
|
+
this.isDropdownOpen = false;
|
|
6643
|
+
this.detachPhoneOverlayScrollTracking();
|
|
6644
|
+
}
|
|
6645
|
+
/**
|
|
6646
|
+
* CDK's `reposition` scroll strategy (the default, and what we want — no `block`/`close`
|
|
6647
|
+
* behaviour) only reacts to real `document`/`window` scroll. It has no way to know about an
|
|
6648
|
+
* app shell that scrolls a nested container instead (this one does — see the layout's
|
|
6649
|
+
* `overflow-y-auto` content wrapper), so without this the panel would stay frozen in place
|
|
6650
|
+
* while its trigger scrolls out from under it. A capture-phase listener on `document` still
|
|
6651
|
+
* sees scroll events fired on any descendant scrollable element (scroll doesn't bubble, but
|
|
6652
|
+
* capture does), same trick `bk-custom-calendar` uses for its own popup. rAF-throttled so a
|
|
6653
|
+
* fast scroll doesn't force layout on every tick.
|
|
6654
|
+
*/
|
|
6655
|
+
phoneOverlayScrollRafId = null;
|
|
6656
|
+
onPhoneOverlayScroll = () => {
|
|
6657
|
+
if (this.phoneOverlayScrollRafId != null)
|
|
6658
|
+
return;
|
|
6659
|
+
this.phoneOverlayScrollRafId = requestAnimationFrame(() => {
|
|
6660
|
+
this.phoneOverlayScrollRafId = null;
|
|
6661
|
+
this.phoneOverlay?.overlayRef?.updatePosition();
|
|
6662
|
+
});
|
|
6663
|
+
};
|
|
6664
|
+
attachPhoneOverlayScrollTracking() {
|
|
6665
|
+
document.addEventListener('scroll', this.onPhoneOverlayScroll, true);
|
|
6666
|
+
window.addEventListener('resize', this.onPhoneOverlayScroll);
|
|
6667
|
+
}
|
|
6668
|
+
detachPhoneOverlayScrollTracking() {
|
|
6669
|
+
document.removeEventListener('scroll', this.onPhoneOverlayScroll, true);
|
|
6670
|
+
window.removeEventListener('resize', this.onPhoneOverlayScroll);
|
|
6671
|
+
if (this.phoneOverlayScrollRafId != null) {
|
|
6672
|
+
cancelAnimationFrame(this.phoneOverlayScrollRafId);
|
|
6673
|
+
this.phoneOverlayScrollRafId = null;
|
|
6674
|
+
}
|
|
6675
|
+
}
|
|
6480
6676
|
selectCountry(country) {
|
|
6481
6677
|
const oldCountry = this.selectedCountry;
|
|
6482
6678
|
this.selectedCountry = country;
|
|
@@ -6554,25 +6750,25 @@ class BkInput {
|
|
|
6554
6750
|
this.pendingMaskedValue = null;
|
|
6555
6751
|
}
|
|
6556
6752
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6557
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkInput, isStandalone: true, selector: "bk-input", inputs: { id: "id", name: "name", mask: "mask", dropSpecialCharacters: "dropSpecialCharacters", autoComplete: "autoComplete", label: "label", placeholder: "placeholder", hint: "hint", required: "required", type: "type", size: "size", value: "value", hasError: "hasError", showErrorIcon: "showErrorIcon", errorMessage: "errorMessage", disabled: "disabled", tabIndex: "tabIndex", readOnly: "readOnly", autoCapitalize: "autoCapitalize", inputMode: "inputMode", iconSrc: "iconSrc", iconAlt: "iconAlt", showIcon: "showIcon", phone: "phone", currency: "currency", currencyDecimals: "currencyDecimals", allowNegative: "allowNegative", countryCode: "countryCode", countryOptions: "countryOptions", iconOrientation: "iconOrientation", password: "password", showPassword: "showPassword", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur", clicked: "clicked" },
|
|
6753
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkInput, isStandalone: true, selector: "bk-input", inputs: { id: "id", name: "name", mask: "mask", dropSpecialCharacters: "dropSpecialCharacters", autoComplete: "autoComplete", label: "label", placeholder: "placeholder", hint: "hint", required: "required", type: "type", size: "size", value: "value", hasError: "hasError", showErrorIcon: "showErrorIcon", errorMessage: "errorMessage", disabled: "disabled", tabIndex: "tabIndex", readOnly: "readOnly", autoCapitalize: "autoCapitalize", inputMode: "inputMode", iconSrc: "iconSrc", iconAlt: "iconAlt", showIcon: "showIcon", phone: "phone", currency: "currency", currencyDecimals: "currencyDecimals", allowNegative: "allowNegative", countryCode: "countryCode", countryOptions: "countryOptions", iconOrientation: "iconOrientation", password: "password", showPassword: "showPassword", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur", clicked: "clicked" }, providers: [
|
|
6558
6754
|
provideNgxMask(),
|
|
6559
6755
|
{
|
|
6560
6756
|
provide: NG_VALUE_ACCESSOR,
|
|
6561
6757
|
useExisting: forwardRef(() => BkInput),
|
|
6562
6758
|
multi: true
|
|
6563
6759
|
}
|
|
6564
|
-
], viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true }, { propertyName: "selectRef", first: true, predicate: ["selectRef"], descendants: true }, { propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }, { propertyName: "maskDirective", first: true, predicate: NgxMaskDirective, descendants: true }], ngImport: i0, template: "<div class=\"input-container\" [class.input-container--sm]=\"size === 'sm'\">\r\n @if(label){\r\n <label [for]=\"id\" class=\"input-label\">\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 class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--password': password,\r\n 'input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n @if (maskValue) {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n } @else {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n }\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'input-search-icon--left': iconOrientation === 'left',\r\n 'input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div #selectRef class=\"input-phone-selector\" [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n }\r\n\r\n @if(phone && isDropdownOpen){\r\n <div #dropdownRef class=\"input-phone-dropdown\" (click)=\"$event.stopPropagation()\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country); $event.stopPropagation()\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"input-currency-icon\" [ngClass]=\"{\r\n 'input-currency-icon--default': inputState === 'default',\r\n 'input-currency-icon--focused': inputState === 'focused',\r\n 'input-currency-icon--filled': inputState === 'filled',\r\n 'input-currency-icon--error': inputState === 'error',\r\n 'input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box;box-shadow:0 1px 2px #1018280d}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--currency{@apply pl-[3.5rem];}.input-field--icon-left{@apply pl-[48px];}.input-field--icon-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply absolute left-0 top-full mt-1 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg z-50 max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent truncate;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-currency-icon img{@apply w-5 h-5;}.input-currency-icon--default{@apply border-[#E3E3E7];}.input-currency-icon--focused{@apply border-[#6B7080];}.input-currency-icon--filled{@apply border-[#E3E3E7];}.input-currency-icon--error{@apply border-[#E7000B];}.input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}.input-container ::-webkit-scrollbar{width:4px}.input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.input-container--sm .input-label{@apply text-xs;}.input-container--sm .input-hint,.input-container--sm .input-error{@apply text-[11px];}.input-container--sm .input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.input-container--sm .input-field--icon,.input-container--sm .input-field--icon-left{@apply pl-8;}.input-container--sm .input-field--icon-right,.input-container--sm .input-field--password{@apply pr-8;}.input-container--sm .input-field--phone,.input-container--sm .input-field--url{@apply pl-16;}.input-container--sm .input-field--currency{@apply pl-9;}.input-container--sm .input-currency-icon{@apply w-8;}.input-container--sm .input-currency-icon img{@apply w-4 h-4;}.input-container--sm .input-field--icon.input-field--url,.input-container--sm .input-field--phone.input-field--icon{@apply pl-24;}.input-container--sm .input-search-icon{@apply w-4 h-4;}.input-container--sm .input-search-icon--left{@apply left-2;}.input-container--sm .input-search-icon--right{@apply right-2;}.input-container--sm .input-password-toggle{@apply right-2 w-4 h-4;}.input-container--sm .input-password-icon{@apply w-4 h-4;}.input-container--sm .input-phone-selector{@apply px-2;}.input-container--sm .input-phone-selector-text{@apply text-[11px];}.input-container--sm .input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.input-container--sm .input-phone-dropdown{@apply w-[68px] mt-0.5;}.input-container--sm .input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.input-container--sm .input-phone-selector-arrow{@apply w-3 h-3;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix"], outputs: ["maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "ngmodule", type: FormsModule }] });
|
|
6760
|
+
], viewQueries: [{ propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }, { propertyName: "maskDirective", first: true, predicate: NgxMaskDirective, descendants: true }, { propertyName: "phoneOverlay", first: true, predicate: ["phoneOverlay"], descendants: true }], ngImport: i0, template: "<div class=\"input-container\" [class.input-container--sm]=\"size === 'sm'\">\r\n @if(label){\r\n <label [for]=\"id\" class=\"input-label\">\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 class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--password': password,\r\n 'input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n @if (maskValue) {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n } @else {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n }\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'input-search-icon--left': iconOrientation === 'left',\r\n 'input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div\r\n cdkOverlayOrigin\r\n #phoneOrigin=\"cdkOverlayOrigin\"\r\n class=\"input-phone-selector\"\r\n [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute` div, so it escapes clipping inside dialogs/scroll containers\r\n and stacks correctly above other CDK-overlay content. Deliberately no backdrop: a backdrop\r\n is a full-viewport, click-catching layer appended to <body> \u2014 right for a true modal, wrong\r\n for a plain dropdown. In a shell that scrolls a nested container (not the window/body), a\r\n backdrop's wheel events have no scrollable ancestor to chain to and swallow ALL page scroll\r\n while open. `overlayOutsideClick` gives \"click outside to close\" without that cost \u2014 it\r\n already excludes clicks on the trigger itself, so toggleDropdown() stays the sole opener.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #phoneOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"phoneOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isDropdownOpen\"\r\n [cdkConnectedOverlayPositions]=\"phoneDropdownPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (overlayOutsideClick)=\"closeDropdown()\"\r\n (detach)=\"closeDropdown()\">\r\n <div class=\"input-phone-dropdown\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country)\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"input-currency-icon\" [ngClass]=\"{\r\n 'input-currency-icon--default': inputState === 'default',\r\n 'input-currency-icon--focused': inputState === 'focused',\r\n 'input-currency-icon--filled': inputState === 'filled',\r\n 'input-currency-icon--error': inputState === 'error',\r\n 'input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box;box-shadow:0 1px 2px #1018280d}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--currency{@apply pl-[3.5rem];}.input-field--icon-left{@apply pl-[48px];}.input-field--icon-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply static left-auto top-auto mt-0 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent truncate;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-currency-icon img{@apply w-5 h-5;}.input-currency-icon--default{@apply border-[#E3E3E7];}.input-currency-icon--focused{@apply border-[#6B7080];}.input-currency-icon--filled{@apply border-[#E3E3E7];}.input-currency-icon--error{@apply border-[#E7000B];}.input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}.input-container ::-webkit-scrollbar{width:4px}.input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.input-container--sm .input-label{@apply text-xs;}.input-container--sm .input-hint,.input-container--sm .input-error{@apply text-[11px];}.input-container--sm .input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.input-container--sm .input-field--icon,.input-container--sm .input-field--icon-left{@apply pl-8;}.input-container--sm .input-field--icon-right,.input-container--sm .input-field--password{@apply pr-8;}.input-container--sm .input-field--phone,.input-container--sm .input-field--url{@apply pl-16;}.input-container--sm .input-field--currency{@apply pl-9;}.input-container--sm .input-currency-icon{@apply w-8;}.input-container--sm .input-currency-icon img{@apply w-4 h-4;}.input-container--sm .input-field--icon.input-field--url,.input-container--sm .input-field--phone.input-field--icon{@apply pl-24;}.input-container--sm .input-search-icon{@apply w-4 h-4;}.input-container--sm .input-search-icon--left{@apply left-2;}.input-container--sm .input-search-icon--right{@apply right-2;}.input-container--sm .input-password-toggle{@apply right-2 w-4 h-4;}.input-container--sm .input-password-icon{@apply w-4 h-4;}.input-container--sm .input-phone-selector{@apply px-2;}.input-container--sm .input-phone-selector-text{@apply text-[11px];}.input-container--sm .input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.input-container--sm .input-phone-dropdown{@apply w-[68px] mt-0.5;}.input-container--sm .input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.input-container--sm .input-phone-selector-arrow{@apply w-3 h-3;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix"], outputs: ["maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
|
|
6565
6761
|
}
|
|
6566
6762
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, decorators: [{
|
|
6567
6763
|
type: Component,
|
|
6568
|
-
args: [{ selector: 'bk-input', imports: [CommonModule, NgxMaskDirective, FormsModule], standalone: true, providers: [
|
|
6764
|
+
args: [{ selector: 'bk-input', imports: [CommonModule, NgxMaskDirective, FormsModule, OverlayModule], standalone: true, providers: [
|
|
6569
6765
|
provideNgxMask(),
|
|
6570
6766
|
{
|
|
6571
6767
|
provide: NG_VALUE_ACCESSOR,
|
|
6572
6768
|
useExisting: forwardRef(() => BkInput),
|
|
6573
6769
|
multi: true
|
|
6574
6770
|
}
|
|
6575
|
-
], template: "<div class=\"input-container\" [class.input-container--sm]=\"size === 'sm'\">\r\n @if(label){\r\n <label [for]=\"id\" class=\"input-label\">\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 class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--password': password,\r\n 'input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n @if (maskValue) {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n } @else {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n }\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'input-search-icon--left': iconOrientation === 'left',\r\n 'input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div #selectRef class=\"input-phone-selector\" [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n }\r\n\r\n @if(phone && isDropdownOpen){\r\n <div #dropdownRef class=\"input-phone-dropdown\" (click)=\"$event.stopPropagation()\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country); $event.stopPropagation()\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"input-currency-icon\" [ngClass]=\"{\r\n 'input-currency-icon--default': inputState === 'default',\r\n 'input-currency-icon--focused': inputState === 'focused',\r\n 'input-currency-icon--filled': inputState === 'filled',\r\n 'input-currency-icon--error': inputState === 'error',\r\n 'input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box;box-shadow:0 1px 2px #1018280d}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--currency{@apply pl-[3.5rem];}.input-field--icon-left{@apply pl-[48px];}.input-field--icon-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply absolute left-0 top-full mt-1 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg z-50 max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent truncate;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-currency-icon img{@apply w-5 h-5;}.input-currency-icon--default{@apply border-[#E3E3E7];}.input-currency-icon--focused{@apply border-[#6B7080];}.input-currency-icon--filled{@apply border-[#E3E3E7];}.input-currency-icon--error{@apply border-[#E7000B];}.input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}.input-container ::-webkit-scrollbar{width:4px}.input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.input-container--sm .input-label{@apply text-xs;}.input-container--sm .input-hint,.input-container--sm .input-error{@apply text-[11px];}.input-container--sm .input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.input-container--sm .input-field--icon,.input-container--sm .input-field--icon-left{@apply pl-8;}.input-container--sm .input-field--icon-right,.input-container--sm .input-field--password{@apply pr-8;}.input-container--sm .input-field--phone,.input-container--sm .input-field--url{@apply pl-16;}.input-container--sm .input-field--currency{@apply pl-9;}.input-container--sm .input-currency-icon{@apply w-8;}.input-container--sm .input-currency-icon img{@apply w-4 h-4;}.input-container--sm .input-field--icon.input-field--url,.input-container--sm .input-field--phone.input-field--icon{@apply pl-24;}.input-container--sm .input-search-icon{@apply w-4 h-4;}.input-container--sm .input-search-icon--left{@apply left-2;}.input-container--sm .input-search-icon--right{@apply right-2;}.input-container--sm .input-password-toggle{@apply right-2 w-4 h-4;}.input-container--sm .input-password-icon{@apply w-4 h-4;}.input-container--sm .input-phone-selector{@apply px-2;}.input-container--sm .input-phone-selector-text{@apply text-[11px];}.input-container--sm .input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.input-container--sm .input-phone-dropdown{@apply w-[68px] mt-0.5;}.input-container--sm .input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.input-container--sm .input-phone-selector-arrow{@apply w-3 h-3;}\n"] }]
|
|
6771
|
+
], template: "<div class=\"input-container\" [class.input-container--sm]=\"size === 'sm'\">\r\n @if(label){\r\n <label [for]=\"id\" class=\"input-label\">\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 class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--password': password,\r\n 'input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n @if (maskValue) {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n } @else {\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--currency': currency,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n }\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'input-search-icon--left': iconOrientation === 'left',\r\n 'input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div\r\n cdkOverlayOrigin\r\n #phoneOrigin=\"cdkOverlayOrigin\"\r\n class=\"input-phone-selector\"\r\n [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute` div, so it escapes clipping inside dialogs/scroll containers\r\n and stacks correctly above other CDK-overlay content. Deliberately no backdrop: a backdrop\r\n is a full-viewport, click-catching layer appended to <body> \u2014 right for a true modal, wrong\r\n for a plain dropdown. In a shell that scrolls a nested container (not the window/body), a\r\n backdrop's wheel events have no scrollable ancestor to chain to and swallow ALL page scroll\r\n while open. `overlayOutsideClick` gives \"click outside to close\" without that cost \u2014 it\r\n already excludes clicks on the trigger itself, so toggleDropdown() stays the sole opener.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #phoneOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"phoneOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isDropdownOpen\"\r\n [cdkConnectedOverlayPositions]=\"phoneDropdownPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (overlayOutsideClick)=\"closeDropdown()\"\r\n (detach)=\"closeDropdown()\">\r\n <div class=\"input-phone-dropdown\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country)\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"input-currency-icon\" [ngClass]=\"{\r\n 'input-currency-icon--default': inputState === 'default',\r\n 'input-currency-icon--focused': inputState === 'focused',\r\n 'input-currency-icon--filled': inputState === 'filled',\r\n 'input-currency-icon--error': inputState === 'error',\r\n 'input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box;box-shadow:0 1px 2px #1018280d}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--currency{@apply pl-[3.5rem];}.input-field--icon-left{@apply pl-[48px];}.input-field--icon-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply static left-auto top-auto mt-0 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent truncate;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-currency-icon img{@apply w-5 h-5;}.input-currency-icon--default{@apply border-[#E3E3E7];}.input-currency-icon--focused{@apply border-[#6B7080];}.input-currency-icon--filled{@apply border-[#E3E3E7];}.input-currency-icon--error{@apply border-[#E7000B];}.input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}.input-container ::-webkit-scrollbar{width:4px}.input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.input-container--sm .input-label{@apply text-xs;}.input-container--sm .input-hint,.input-container--sm .input-error{@apply text-[11px];}.input-container--sm .input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.input-container--sm .input-field--icon,.input-container--sm .input-field--icon-left{@apply pl-8;}.input-container--sm .input-field--icon-right,.input-container--sm .input-field--password{@apply pr-8;}.input-container--sm .input-field--phone,.input-container--sm .input-field--url{@apply pl-16;}.input-container--sm .input-field--currency{@apply pl-9;}.input-container--sm .input-currency-icon{@apply w-8;}.input-container--sm .input-currency-icon img{@apply w-4 h-4;}.input-container--sm .input-field--icon.input-field--url,.input-container--sm .input-field--phone.input-field--icon{@apply pl-24;}.input-container--sm .input-search-icon{@apply w-4 h-4;}.input-container--sm .input-search-icon--left{@apply left-2;}.input-container--sm .input-search-icon--right{@apply right-2;}.input-container--sm .input-password-toggle{@apply right-2 w-4 h-4;}.input-container--sm .input-password-icon{@apply w-4 h-4;}.input-container--sm .input-phone-selector{@apply px-2;}.input-container--sm .input-phone-selector-text{@apply text-[11px];}.input-container--sm .input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.input-container--sm .input-phone-dropdown{@apply w-[68px] mt-0.5;}.input-container--sm .input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.input-container--sm .input-phone-selector-arrow{@apply w-3 h-3;}\n"] }]
|
|
6576
6772
|
}], propDecorators: { id: [{
|
|
6577
6773
|
type: Input
|
|
6578
6774
|
}], name: [{
|
|
@@ -6649,18 +6845,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6649
6845
|
type: Input
|
|
6650
6846
|
}], minlength: [{
|
|
6651
6847
|
type: Input
|
|
6652
|
-
}], dropdownRef: [{
|
|
6653
|
-
type: ViewChild,
|
|
6654
|
-
args: ['dropdownRef']
|
|
6655
|
-
}], selectRef: [{
|
|
6656
|
-
type: ViewChild,
|
|
6657
|
-
args: ['selectRef']
|
|
6658
6848
|
}], inputField: [{
|
|
6659
6849
|
type: ViewChild,
|
|
6660
6850
|
args: ['inputField']
|
|
6661
6851
|
}], maskDirective: [{
|
|
6662
6852
|
type: ViewChild,
|
|
6663
6853
|
args: [NgxMaskDirective]
|
|
6854
|
+
}], phoneOverlay: [{
|
|
6855
|
+
type: ViewChild,
|
|
6856
|
+
args: ['phoneOverlay']
|
|
6664
6857
|
}], input: [{
|
|
6665
6858
|
type: Output
|
|
6666
6859
|
}], change: [{
|
|
@@ -6671,9 +6864,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6671
6864
|
type: Output
|
|
6672
6865
|
}], clicked: [{
|
|
6673
6866
|
type: Output
|
|
6674
|
-
}], onDocumentClick: [{
|
|
6675
|
-
type: HostListener,
|
|
6676
|
-
args: ['document:click', ['$event']]
|
|
6677
6867
|
}] } });
|
|
6678
6868
|
|
|
6679
6869
|
class BkInputChips {
|
|
@@ -8613,7 +8803,12 @@ class BkHierarchicalSelect {
|
|
|
8613
8803
|
/** Search placeholder. */
|
|
8614
8804
|
searchPlaceholder = input('Search', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
|
|
8615
8805
|
searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
|
|
8616
|
-
/**
|
|
8806
|
+
/**
|
|
8807
|
+
* @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break.
|
|
8808
|
+
* The dropdown now always positions via Angular CDK Overlay, which portals into the shared
|
|
8809
|
+
* `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
|
|
8810
|
+
* to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
|
|
8811
|
+
*/
|
|
8617
8812
|
appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
|
|
8618
8813
|
/** Open above or below the trigger (also used when appendToBody is true for fixed coordinates). */
|
|
8619
8814
|
dropdownPosition = input('bottom', ...(ngDevMode ? [{ debugName: "dropdownPosition" }] : []));
|
|
@@ -8644,16 +8839,23 @@ class BkHierarchicalSelect {
|
|
|
8644
8839
|
searchInput;
|
|
8645
8840
|
controlWrapper;
|
|
8646
8841
|
dropdownPanel;
|
|
8842
|
+
optionsListContainer;
|
|
8843
|
+
optionEls;
|
|
8844
|
+
hierarchicalOverlay;
|
|
8845
|
+
/** Index of the keyboard-highlighted option within the current level (`filteredItems`). */
|
|
8846
|
+
markedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "markedIndex" }] : []));
|
|
8647
8847
|
el = inject(ElementRef);
|
|
8648
|
-
// Side the panel
|
|
8649
|
-
//
|
|
8848
|
+
// Side the panel actually rendered on, purely for the CSS `[data-position]` inset styling —
|
|
8849
|
+
// driven by CDK's own (positionChange) rather than a hand-rolled space comparison (see
|
|
8850
|
+
// onPositionChange). The fit/flip decision itself lives entirely in CDK now.
|
|
8650
8851
|
placement = signal('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8852
|
+
/**
|
|
8853
|
+
* Panel width, kept equal to the control's — matches the old `dropdownStyle().width`
|
|
8854
|
+
* behaviour. Set on open and re-measured by a ResizeObserver on the control while open, so a
|
|
8855
|
+
* responsive layout keeps the panel in sync.
|
|
8856
|
+
*/
|
|
8857
|
+
dropdownWidth = signal(null, ...(ngDevMode ? [{ debugName: "dropdownWidth" }] : []));
|
|
8858
|
+
resizeObserver;
|
|
8657
8859
|
constructor() {
|
|
8658
8860
|
effect(() => {
|
|
8659
8861
|
const list = this.items();
|
|
@@ -8667,101 +8869,188 @@ class BkHierarchicalSelect {
|
|
|
8667
8869
|
});
|
|
8668
8870
|
}
|
|
8669
8871
|
ngAfterViewInit() {
|
|
8670
|
-
// Keep the panel
|
|
8671
|
-
//
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8872
|
+
// Keep the panel width in sync with the control's while open (responsive layouts, manual
|
|
8873
|
+
// width changes, container resizes, etc.) — matches the old dropdownStyle().width upkeep.
|
|
8874
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
8875
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
8876
|
+
if (this.isOpen())
|
|
8877
|
+
this.dropdownWidth.set(this.controlWrapper.nativeElement.offsetWidth);
|
|
8878
|
+
});
|
|
8879
|
+
if (this.controlWrapper?.nativeElement) {
|
|
8880
|
+
this.resizeObserver.observe(this.controlWrapper.nativeElement);
|
|
8881
|
+
}
|
|
8882
|
+
}
|
|
8675
8883
|
}
|
|
8676
8884
|
ngOnDestroy() {
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8885
|
+
this.resizeObserver?.disconnect();
|
|
8886
|
+
this.detachOverlayScrollTracking();
|
|
8887
|
+
}
|
|
8888
|
+
/**
|
|
8889
|
+
* CDK's default `reposition` scroll strategy only reacts to real `document`/`window` scroll —
|
|
8890
|
+
* it has no way to know an app shell might scroll a nested container instead (this one
|
|
8891
|
+
* commonly does — dashboard layouts with a fixed header/sidebar and a scrollable content pane).
|
|
8892
|
+
* A capture-phase listener on `document` still sees scroll events fired on any descendant
|
|
8893
|
+
* scrollable element (scroll doesn't bubble, but capture does) — same trick `bk-custom-calendar`,
|
|
8894
|
+
* `bk-input`'s phone dropdown, and `bk-select` already use. rAF-throttled so a fast scroll
|
|
8895
|
+
* doesn't force layout on every tick.
|
|
8896
|
+
*/
|
|
8897
|
+
overlayScrollRafId = null;
|
|
8898
|
+
onOverlayScroll = () => {
|
|
8899
|
+
if (this.overlayScrollRafId != null)
|
|
8691
8900
|
return;
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8901
|
+
this.overlayScrollRafId = requestAnimationFrame(() => {
|
|
8902
|
+
this.overlayScrollRafId = null;
|
|
8903
|
+
this.hierarchicalOverlay?.overlayRef?.updatePosition();
|
|
8904
|
+
});
|
|
8905
|
+
};
|
|
8906
|
+
attachOverlayScrollTracking() {
|
|
8907
|
+
document.addEventListener('scroll', this.onOverlayScroll, true);
|
|
8908
|
+
window.addEventListener('resize', this.onOverlayScroll);
|
|
8909
|
+
}
|
|
8910
|
+
detachOverlayScrollTracking() {
|
|
8911
|
+
document.removeEventListener('scroll', this.onOverlayScroll, true);
|
|
8912
|
+
window.removeEventListener('resize', this.onOverlayScroll);
|
|
8913
|
+
if (this.overlayScrollRafId != null) {
|
|
8914
|
+
cancelAnimationFrame(this.overlayScrollRafId);
|
|
8915
|
+
this.overlayScrollRafId = null;
|
|
8916
|
+
}
|
|
8917
|
+
}
|
|
8918
|
+
/** Derives `placement` (for the `[data-position]` inset CSS) from which of
|
|
8919
|
+
* `hierarchicalDropdownPositions` CDK actually applied — replaces the old hand-rolled space
|
|
8920
|
+
* comparison now that the fit/flip decision itself lives in CDK. */
|
|
8921
|
+
onPositionChange(event) {
|
|
8922
|
+
this.placement.set(event.connectionPair.originY === 'top' ? 'top' : 'bottom');
|
|
8923
|
+
}
|
|
8924
|
+
/** Runs after the panel has rendered: reset the level highlight + focus. Position/flip is
|
|
8925
|
+
* entirely CDK's job now (see hierarchicalDropdownPositions + onPositionChange). */
|
|
8926
|
+
afterOpenInit() {
|
|
8927
|
+
this.resetMarked();
|
|
8928
|
+
// Scroll the highlighted option into view WHILE the panel is still hidden, so
|
|
8929
|
+
// it's revealed already in place instead of appearing at the top and then
|
|
8930
|
+
// visibly jumping to the selection. The panel is only `visibility: hidden`
|
|
8931
|
+
// (not display:none), so it's laid out and offsets are already valid.
|
|
8932
|
+
this.scrollMarkedIntoView();
|
|
8933
|
+
this.panelReady.set(true);
|
|
8934
|
+
// panelReady's `visibility: visible` only reaches the DOM on the next
|
|
8935
|
+
// change-detection pass, and focusing a still-hidden subtree is a no-op, so
|
|
8936
|
+
// defer the focus one frame — by which point the panel is actually visible.
|
|
8937
|
+
requestAnimationFrame(() => {
|
|
8938
|
+
if (!this.isOpen())
|
|
8696
8939
|
return;
|
|
8940
|
+
// Focus the search field when present so typing works and Up/Down navigate
|
|
8941
|
+
// from there; otherwise keep keyboard focus on the trigger so the arrow
|
|
8942
|
+
// keys still reach onKeyDown.
|
|
8943
|
+
if (this.searchable()) {
|
|
8944
|
+
this.searchInput?.nativeElement?.focus({ preventScroll: true });
|
|
8697
8945
|
}
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8946
|
+
else {
|
|
8947
|
+
this.controlWrapper?.nativeElement?.focus({ preventScroll: true });
|
|
8948
|
+
}
|
|
8949
|
+
});
|
|
8950
|
+
}
|
|
8701
8951
|
/**
|
|
8702
|
-
*
|
|
8703
|
-
*
|
|
8952
|
+
* Set the keyboard highlight for the level now on screen: the selected node if
|
|
8953
|
+
* it's in this level, otherwise the first option. -1 when the level is empty,
|
|
8954
|
+
* which keeps nothing highlighted.
|
|
8704
8955
|
*/
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
let el = this.controlWrapper?.nativeElement.parentElement;
|
|
8711
|
-
while (el && el !== document.body) {
|
|
8712
|
-
const style = getComputedStyle(el);
|
|
8713
|
-
const clips = /(auto|scroll|hidden|clip|overlay)/;
|
|
8714
|
-
if (clips.test(style.overflowY) || clips.test(style.overflowX)) {
|
|
8715
|
-
const r = el.getBoundingClientRect();
|
|
8716
|
-
if (rect.bottom <= r.top || rect.top >= r.bottom ||
|
|
8717
|
-
rect.right <= r.left || rect.left >= r.right) {
|
|
8718
|
-
return true;
|
|
8719
|
-
}
|
|
8720
|
-
}
|
|
8721
|
-
el = el.parentElement;
|
|
8956
|
+
resetMarked() {
|
|
8957
|
+
const list = this.filteredItems();
|
|
8958
|
+
if (!list.length) {
|
|
8959
|
+
this.markedIndex.set(-1);
|
|
8960
|
+
return;
|
|
8722
8961
|
}
|
|
8723
|
-
|
|
8962
|
+
const selectedIdx = list.findIndex((node) => this.isSelected(node));
|
|
8963
|
+
this.markedIndex.set(selectedIdx >= 0 ? selectedIdx : 0);
|
|
8724
8964
|
}
|
|
8725
8965
|
/**
|
|
8726
|
-
*
|
|
8727
|
-
*
|
|
8966
|
+
* Keyboard navigation. Up/Down move the highlight within the current level;
|
|
8967
|
+
* Right (or Enter on a parent) drills into children; Left goes back a level;
|
|
8968
|
+
* Enter on a leaf selects it; Escape/Tab close.
|
|
8728
8969
|
*/
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8970
|
+
onKeyDown(event) {
|
|
8971
|
+
if (!this.isOpen()) {
|
|
8972
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
8973
|
+
event.preventDefault();
|
|
8974
|
+
this.openDropdown();
|
|
8975
|
+
}
|
|
8732
8976
|
return;
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8977
|
+
}
|
|
8978
|
+
const list = this.filteredItems();
|
|
8979
|
+
const current = this.markedIndex();
|
|
8980
|
+
const marked = current >= 0 ? list[current] : undefined;
|
|
8981
|
+
switch (event.key) {
|
|
8982
|
+
case 'ArrowDown':
|
|
8983
|
+
event.preventDefault();
|
|
8984
|
+
if (current < list.length - 1) {
|
|
8985
|
+
this.markedIndex.set(current + 1);
|
|
8986
|
+
this.scrollToMarked();
|
|
8987
|
+
}
|
|
8988
|
+
break;
|
|
8989
|
+
case 'ArrowUp':
|
|
8990
|
+
event.preventDefault();
|
|
8991
|
+
if (current > 0) {
|
|
8992
|
+
this.markedIndex.set(current - 1);
|
|
8993
|
+
this.scrollToMarked();
|
|
8994
|
+
}
|
|
8995
|
+
break;
|
|
8996
|
+
case 'ArrowRight':
|
|
8997
|
+
// Drill into a parent's children without selecting it.
|
|
8998
|
+
if (marked && this.hasChildren(marked) && !marked.disabled) {
|
|
8999
|
+
event.preventDefault();
|
|
9000
|
+
this.enterNode(marked);
|
|
9001
|
+
}
|
|
9002
|
+
break;
|
|
9003
|
+
case 'ArrowLeft':
|
|
9004
|
+
if (this.showBack()) {
|
|
9005
|
+
event.preventDefault();
|
|
9006
|
+
this.goBack();
|
|
9007
|
+
}
|
|
9008
|
+
break;
|
|
9009
|
+
case 'Enter':
|
|
9010
|
+
event.preventDefault();
|
|
9011
|
+
if (marked)
|
|
9012
|
+
this.selectItem(marked);
|
|
9013
|
+
break;
|
|
9014
|
+
case 'Escape':
|
|
9015
|
+
event.preventDefault();
|
|
9016
|
+
this.closeDropdown();
|
|
9017
|
+
break;
|
|
9018
|
+
case 'Tab':
|
|
9019
|
+
this.closeDropdown();
|
|
9020
|
+
break;
|
|
9021
|
+
}
|
|
9022
|
+
}
|
|
9023
|
+
/** Sync the highlight to a hovered option so mouse and keyboard agree. */
|
|
9024
|
+
markOption(index) {
|
|
9025
|
+
this.markedIndex.set(index);
|
|
8737
9026
|
}
|
|
8738
|
-
/**
|
|
8739
|
-
|
|
8740
|
-
const
|
|
8741
|
-
|
|
9027
|
+
/** Scroll the highlighted option into view within the options list (immediate). */
|
|
9028
|
+
scrollMarkedIntoView() {
|
|
9029
|
+
const container = this.optionsListContainer?.nativeElement;
|
|
9030
|
+
const els = this.optionEls?.toArray();
|
|
9031
|
+
const index = this.markedIndex();
|
|
9032
|
+
if (!container || !els || !els[index])
|
|
8742
9033
|
return;
|
|
8743
|
-
|
|
8744
|
-
|
|
9034
|
+
const el = els[index].nativeElement;
|
|
9035
|
+
if (el.offsetTop < container.scrollTop) {
|
|
9036
|
+
container.scrollTop = el.offsetTop;
|
|
9037
|
+
}
|
|
9038
|
+
else if (el.offsetTop + el.clientHeight > container.scrollTop + container.clientHeight) {
|
|
9039
|
+
container.scrollTop = el.offsetTop + el.clientHeight - container.clientHeight;
|
|
8745
9040
|
}
|
|
8746
|
-
this.panelInBody = false;
|
|
8747
|
-
this.originalPanelParent = null;
|
|
8748
|
-
this.originalPanelAnchor = null;
|
|
8749
9041
|
}
|
|
8750
|
-
/**
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
this.
|
|
9042
|
+
/** Defer a scroll to the marked option (after a keyboard move re-lays the row). */
|
|
9043
|
+
scrollToMarked() {
|
|
9044
|
+
setTimeout(() => this.scrollMarkedIntoView());
|
|
9045
|
+
}
|
|
9046
|
+
/** Navigate into a node's children and reset the highlight for the new level. */
|
|
9047
|
+
enterNode(node) {
|
|
9048
|
+
this.breadcrumb.update((stack) => [...stack, node]);
|
|
9049
|
+
this.resetMarked();
|
|
8757
9050
|
}
|
|
8758
9051
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
8759
9052
|
/** Hidden until its real height has been measured and final placement applied. */
|
|
8760
9053
|
panelReady = signal(false, ...(ngDevMode ? [{ debugName: "panelReady" }] : []));
|
|
8761
|
-
dropdownStyle = signal({
|
|
8762
|
-
left: '0px',
|
|
8763
|
-
width: 'auto',
|
|
8764
|
-
}, ...(ngDevMode ? [{ debugName: "dropdownStyle" }] : []));
|
|
8765
9054
|
searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
8766
9055
|
/** Breadcrumb stack: each entry is the parent node we navigated into. */
|
|
8767
9056
|
breadcrumb = signal([], ...(ngDevMode ? [{ debugName: "breadcrumb" }] : []));
|
|
@@ -8938,6 +9227,8 @@ class BkHierarchicalSelect {
|
|
|
8938
9227
|
}
|
|
8939
9228
|
}
|
|
8940
9229
|
openDropdown() {
|
|
9230
|
+
if (this.isOpen())
|
|
9231
|
+
return;
|
|
8941
9232
|
this.panelReady.set(false);
|
|
8942
9233
|
if (this.restrictKey() != null) {
|
|
8943
9234
|
const restrictKey = this.restrictKey();
|
|
@@ -8964,12 +9255,7 @@ class BkHierarchicalSelect {
|
|
|
8964
9255
|
else {
|
|
8965
9256
|
this.breadcrumb.set([]);
|
|
8966
9257
|
}
|
|
8967
|
-
|
|
8968
|
-
// corrected after render in afterOpenInit).
|
|
8969
|
-
this.applyPlacement();
|
|
8970
|
-
this.isOpen.set(true);
|
|
8971
|
-
this.searchTerm.set('');
|
|
8972
|
-
setTimeout(() => this.afterOpenInit(), 0);
|
|
9258
|
+
this.openPanel();
|
|
8973
9259
|
return;
|
|
8974
9260
|
}
|
|
8975
9261
|
const sel = this.selected();
|
|
@@ -8980,73 +9266,31 @@ class BkHierarchicalSelect {
|
|
|
8980
9266
|
else {
|
|
8981
9267
|
this.breadcrumb.set([]);
|
|
8982
9268
|
}
|
|
8983
|
-
this.
|
|
9269
|
+
this.openPanel();
|
|
9270
|
+
}
|
|
9271
|
+
/** Shared tail of openDropdown(): keep the panel exactly as wide as the control (matches the
|
|
9272
|
+
* old dropdownStyle().width), start scroll tracking, and flip on. Position/flip itself is
|
|
9273
|
+
* entirely CDK's job — see hierarchicalDropdownPositions + onPositionChange. */
|
|
9274
|
+
openPanel() {
|
|
9275
|
+
this.dropdownWidth.set(this.controlWrapper.nativeElement.offsetWidth);
|
|
9276
|
+
this.attachOverlayScrollTracking();
|
|
8984
9277
|
this.isOpen.set(true);
|
|
8985
9278
|
this.searchTerm.set('');
|
|
8986
9279
|
setTimeout(() => this.afterOpenInit(), 0);
|
|
8987
9280
|
}
|
|
8988
9281
|
/**
|
|
8989
|
-
*
|
|
8990
|
-
*
|
|
8991
|
-
* the
|
|
8992
|
-
* when it fits. Inline mode is positioned by CSS via the `placement` signal.
|
|
9282
|
+
* Preferred position list handed to CDK, in try-order — honours `dropdownPosition` first,
|
|
9283
|
+
* falling back to the other side only when the preferred one genuinely doesn't fit. Replaces
|
|
9284
|
+
* the old hand-rolled `applyPlacement()` space comparison entirely.
|
|
8993
9285
|
*/
|
|
8994
|
-
|
|
8995
|
-
const
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
const rect = el.getBoundingClientRect();
|
|
8999
|
-
const gap = 4;
|
|
9000
|
-
const panelHeight = this.dropdownPanel?.nativeElement.offsetHeight || 300;
|
|
9001
|
-
const spaceBelow = window.innerHeight - rect.bottom - gap;
|
|
9002
|
-
const spaceAbove = rect.top - gap;
|
|
9003
|
-
const preferred = this.dropdownPosition();
|
|
9004
|
-
let placeTop;
|
|
9005
|
-
if (preferred === 'top') {
|
|
9006
|
-
placeTop = spaceAbove >= panelHeight || spaceAbove > spaceBelow;
|
|
9007
|
-
}
|
|
9008
|
-
else {
|
|
9009
|
-
placeTop = spaceBelow < panelHeight && spaceAbove > spaceBelow;
|
|
9010
|
-
}
|
|
9011
|
-
this.placement.set(placeTop ? 'top' : 'bottom');
|
|
9012
|
-
// Inline mode uses CSS (data-position) — the placement signal is enough.
|
|
9013
|
-
if (!this.appendToBody())
|
|
9014
|
-
return;
|
|
9015
|
-
if (placeTop) {
|
|
9016
|
-
this.dropdownStyle.set({
|
|
9017
|
-
top: undefined,
|
|
9018
|
-
bottom: `${window.innerHeight - rect.top + gap}px`,
|
|
9019
|
-
left: `${rect.left}px`,
|
|
9020
|
-
width: `${rect.width}px`,
|
|
9021
|
-
});
|
|
9022
|
-
}
|
|
9023
|
-
else {
|
|
9024
|
-
this.dropdownStyle.set({
|
|
9025
|
-
top: `${rect.bottom + gap}px`,
|
|
9026
|
-
bottom: undefined,
|
|
9027
|
-
left: `${rect.left}px`,
|
|
9028
|
-
width: `${rect.width}px`,
|
|
9029
|
-
});
|
|
9030
|
-
}
|
|
9031
|
-
}
|
|
9032
|
-
/** Fixed positioning when appendToBody; inset placement uses CSS + .hierarchical-select-field. */
|
|
9033
|
-
getTop() {
|
|
9034
|
-
if (!this.appendToBody())
|
|
9035
|
-
return null;
|
|
9036
|
-
return this.dropdownStyle().top ?? null;
|
|
9286
|
+
get hierarchicalDropdownPositions() {
|
|
9287
|
+
const bottom = { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 };
|
|
9288
|
+
const top = { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 };
|
|
9289
|
+
return this.dropdownPosition() === 'top' ? [top, bottom] : [bottom, top];
|
|
9037
9290
|
}
|
|
9038
|
-
getBottom() {
|
|
9039
|
-
if (!this.appendToBody())
|
|
9040
|
-
return null;
|
|
9041
|
-
return this.dropdownStyle().bottom ?? null;
|
|
9042
|
-
}
|
|
9043
|
-
// Scroll/resize are handled by the capture-phase listeners in ngAfterViewInit
|
|
9044
|
-
// (see `reposition`): they keep the panel attached, re-flip it, and only close
|
|
9045
|
-
// it once the control scrolls fully out of view.
|
|
9046
9291
|
closeDropdown() {
|
|
9047
9292
|
const wasOpen = this.isOpen();
|
|
9048
|
-
|
|
9049
|
-
this.restorePanel();
|
|
9293
|
+
this.detachOverlayScrollTracking();
|
|
9050
9294
|
this.isOpen.set(false);
|
|
9051
9295
|
this.panelReady.set(false);
|
|
9052
9296
|
this.searchTerm.set('');
|
|
@@ -9060,19 +9304,24 @@ class BkHierarchicalSelect {
|
|
|
9060
9304
|
if (stack.length === 0)
|
|
9061
9305
|
return;
|
|
9062
9306
|
this.breadcrumb.set(stack.slice(0, -1));
|
|
9307
|
+
this.resetMarked();
|
|
9063
9308
|
}
|
|
9064
9309
|
onSearchInput(event) {
|
|
9065
9310
|
const value = event.target.value;
|
|
9066
9311
|
this.searchTerm.set(value);
|
|
9312
|
+
this.resetMarked();
|
|
9067
9313
|
}
|
|
9068
9314
|
selectItem(node, event) {
|
|
9069
9315
|
event?.stopPropagation();
|
|
9316
|
+
// Don't let the row's mousedown blur the search input — keep focus on it so
|
|
9317
|
+
// keyboard (Up/Down/Enter) navigation still works after a mouse click.
|
|
9318
|
+
event?.preventDefault();
|
|
9070
9319
|
if (node.disabled)
|
|
9071
9320
|
return;
|
|
9072
9321
|
// A parent row always navigates. When parents are selectable, that happens
|
|
9073
9322
|
// through the row's checkbox instead (see `toggleParentSelection`).
|
|
9074
9323
|
if (this.hasChildren(node)) {
|
|
9075
|
-
this.
|
|
9324
|
+
this.enterNode(node);
|
|
9076
9325
|
return;
|
|
9077
9326
|
}
|
|
9078
9327
|
this.selected.set(node);
|
|
@@ -9120,14 +9369,11 @@ class BkHierarchicalSelect {
|
|
|
9120
9369
|
this.controlWrapper?.nativeElement?.focus();
|
|
9121
9370
|
this.openDropdown();
|
|
9122
9371
|
}
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
return;
|
|
9129
|
-
if (this.dropdownPanel?.nativeElement.contains(target))
|
|
9130
|
-
return;
|
|
9372
|
+
// Click-outside-to-close is now `(overlayOutsideClick)` in the template, driven by CDK's
|
|
9373
|
+
// document-level outside-pointer-event dispatcher — it already excludes clicks on the
|
|
9374
|
+
// cdkOverlayOrigin (the control) by design, so toggleDropdown() stays the sole opener. No
|
|
9375
|
+
// backdrop involved, so it doesn't block page/nested-container scroll like a modal would.
|
|
9376
|
+
onOverlayOutsideClick() {
|
|
9131
9377
|
this.closeDropdown();
|
|
9132
9378
|
}
|
|
9133
9379
|
// --- ControlValueAccessor ---
|
|
@@ -9172,23 +9418,23 @@ class BkHierarchicalSelect {
|
|
|
9172
9418
|
this.clear.emit(null);
|
|
9173
9419
|
}
|
|
9174
9420
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9175
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkHierarchicalSelect, isStandalone: true, selector: "bk-hierarchical-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, valueKey: { classPropertyName: "valueKey", publicName: "valueKey", isSignal: true, isRequired: false, transformFunction: null }, childrenKey: { classPropertyName: "childrenKey", publicName: "childrenKey", isSignal: true, isRequired: false, transformFunction: null }, clearTooltip: { classPropertyName: "clearTooltip", publicName: "clearTooltip", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, allowParentSelection: { classPropertyName: "allowParentSelection", publicName: "allowParentSelection", isSignal: true, isRequired: false, transformFunction: null }, backToMainText: { classPropertyName: "backToMainText", publicName: "backToMainText", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, showDots: { classPropertyName: "showDots", publicName: "showDots", isSignal: true, isRequired: false, transformFunction: null }, inheritColor: { classPropertyName: "inheritColor", publicName: "inheritColor", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, restrictKey: { classPropertyName: "restrictKey", publicName: "restrictKey", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", valueChange: "valueChange", clear: "clear" },
|
|
9421
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkHierarchicalSelect, isStandalone: true, selector: "bk-hierarchical-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, valueKey: { classPropertyName: "valueKey", publicName: "valueKey", isSignal: true, isRequired: false, transformFunction: null }, childrenKey: { classPropertyName: "childrenKey", publicName: "childrenKey", isSignal: true, isRequired: false, transformFunction: null }, clearTooltip: { classPropertyName: "clearTooltip", publicName: "clearTooltip", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, allowParentSelection: { classPropertyName: "allowParentSelection", publicName: "allowParentSelection", isSignal: true, isRequired: false, transformFunction: null }, backToMainText: { classPropertyName: "backToMainText", publicName: "backToMainText", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, showDots: { classPropertyName: "showDots", publicName: "showDots", isSignal: true, isRequired: false, transformFunction: null }, inheritColor: { classPropertyName: "inheritColor", publicName: "inheritColor", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, restrictKey: { classPropertyName: "restrictKey", publicName: "restrictKey", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", valueChange: "valueChange", clear: "clear" }, providers: [
|
|
9176
9422
|
{
|
|
9177
9423
|
provide: NG_VALUE_ACCESSOR,
|
|
9178
9424
|
useExisting: forwardRef(() => BkHierarchicalSelect),
|
|
9179
9425
|
multi: true,
|
|
9180
9426
|
},
|
|
9181
|
-
], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }], ngImport: i0, template: "<div class=\"hierarchical-select-container\">\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 class=\"hierarchical-select-field\">\r\n <!-- With showDots on, the control is tinted by the selected node's accent.\r\n An errored control drops the tint entirely and goes neutral, so the red\r\n border reads as an error rather than competing with the accent. -->\r\n <div\r\n #controlWrapper\r\n class=\"hierarchical-select-control\"\r\n [ngClass]=\"{ 'hierarchical-select-control-has-error': hasError() }\"\r\n tabindex=\"0\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"isDisabled()\"\r\n [class.filled]=\"!hasError() && !!controlAppearance().backgroundColor\"\r\n [style.backgroundColor]=\"hasError() ? null : controlAppearance().backgroundColor\"\r\n [style.color]=\"hasError() ? null : controlAppearance().color\"\r\n [style.borderColor]=\"hasError() ? null : controlAppearance().borderColor\"\r\n (mousedown)=\"toggleDropdown($event)\">\r\n @if (iconSrc()) {\r\n <img [src]=\"iconSrc()\" [alt]=\"iconAlt()\" class=\"shrink-0\" />\r\n }\r\n <div class=\"hierarchical-value-container\">\r\n @if (!selected()) {\r\n <div class=\"hierarchical-placeholder\">{{ placeholder() }}</div>\r\n } @else {\r\n <!-- Single row: the container is flex-wrap and the label is w-full, so\r\n a bare sibling dot would push the label onto a second line. -->\r\n <div class=\"hierarchical-value-row\">\r\n @if (showDots() && accentFor(selected()!)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(selected()!)\"></span>\r\n }\r\n <div class=\"hierarchical-value-label\" [style.color]=\"controlAppearance().color ?? resolveColor(selected())\">\r\n @for (node of displayPath(); track getValue(node); let last = $last) {\r\n <span\r\n #breadNode\r\n class=\"hierarchical-breadcrumb-node\"\r\n [bkTooltip]=\"breadNode.scrollWidth > breadNode.clientWidth ? getLabel(node) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(node) }}</span>\r\n\r\n @if (!last) {\r\n <svg\r\n class=\"breadcrumb-separator\"\r\n width=\"5\"\r\n height=\"8\"\r\n viewBox=\"0 0 5 8\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\"\r\n fill=\"#BBBDC5\"/>\r\n </svg>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n }\r\n </div>\r\n <div class=\"hierarchical-actions\">\r\n @if (clearable() && selected() && !isDisabled()) {\r\n <span class=\"hierarchical-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\" [bkTooltip]=\"clearTooltip()\" bkTooltipPosition=\"top\">\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\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"hierarchical-arrow\" [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\">\r\n <path d=\"m6 9 6 6 6-6\"/>\r\n </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=\"hierarchical-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\r\n [class.hierarchical-dropdown-panel-fixed]=\"appendToBody()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"appendToBody() ? getTop() : null\"\r\n [style.bottom]=\"appendToBody() ? getBottom() : null\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\">\r\n @if (searchable()) {\r\n <div class=\"hierarchical-search\">\r\n <div class=\"hierarchical-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\r\n #searchInput\r\n type=\"text\"\r\n class=\"hierarchical-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n (input)=\"onSearchInput($event)\"\r\n (click)=\"$event.stopPropagation()\" />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"hierarchical-back\"\r\n (click)=\"goBack(); $event.stopPropagation()\">\r\n <span>\r\n <svg width=\"6\" height=\"10\" viewBox=\"0 0 6 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M4.59961 0.599976L0.599609 4.59998L4.59961 8.59998\" stroke=\"#141414\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>\r\n\r\n </span>\r\n {{ backToMainText() }}\r\n </button>\r\n }\r\n\r\n <div class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <!-- Grouped so the row's justify-between still has exactly two\r\n children (body + trailing chevron/tick). -->\r\n <div class=\"hierarchical-option-body\">\r\n @if (allowParentSelection()) {\r\n @if (hasChildren(item)) {\r\n <!-- Only nodes with children get a box \u2014 a leaf is already\r\n selected by clicking its row. It owns its own mousedown so\r\n the row still navigates; the box itself is inert\r\n (pointer-events-none) so it can't toggle twice. standalone\r\n keeps this ngModel out of any parent <form> the select is\r\n rendered inside. -->\r\n <span\r\n class=\"hierarchical-option-checkbox\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Select ' + getLabel(item)\"\r\n (mousedown)=\"toggleParentSelection(item, $event)\">\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"!!item.disabled\"\r\n [ngModel]=\"isSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </span>\r\n } @else {\r\n <!-- Holds the checkbox column open so leaf labels line up with\r\n the parents' above them. -->\r\n <span class=\"hierarchical-option-checkbox-spacer\" aria-hidden=\"true\"></span>\r\n }\r\n }\r\n @if (showDots() && accentFor(item)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\r\n </div>\r\n @if (hasChildren(item)) {\r\n <svg width=\"5\" height=\"8\" viewBox=\"0 0 5 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\" fill=\"#BBBDC5\"/>\r\n </svg>\r\n } @else if (isSelected(item)) {\r\n <svg width=\"10\" height=\"7\" viewBox=\"0 0 10 7\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M3.72939 6.28273C3.64166 6.28324 3.55468 6.26642 3.47346 6.23324C3.39223 6.20007 3.31835 6.15118 3.25606 6.08939L0.196061 3.00273C0.0705253 2.87719 -1.32274e-09 2.70693 0 2.52939C1.32273e-09 2.35186 0.0705253 2.1816 0.196061 2.05606C0.321597 1.93053 0.49186 1.86 0.669394 1.86C0.846929 1.86 1.01719 1.93053 1.14273 2.05606L3.72939 4.64939L8.17606 0.196061C8.3016 0.0705253 8.47186 -3.49963e-09 8.64939 0C8.82693 3.49963e-09 8.99719 0.0705253 9.12273 0.196061C9.24826 0.321597 9.31879 0.49186 9.31879 0.669395C9.31879 0.846929 9.24826 1.01719 9.12273 1.14273L4.20273 6.06273C4.07921 6.19434 3.90963 6.27316 3.72939 6.28273V6.28273Z\" fill=\"#141414\"/>\r\n </svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <div class=\"hierarchical-option-empty\">No records found</div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".hierarchical-select-container{@apply relative w-full box-border;}.hierarchical-select-field{@apply relative w-full;}.hierarchical-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;}.hierarchical-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.hierarchical-select-control.disabled{@apply cursor-not-allowed;background-color:#f4f4f6!important;border-color:#e3e3e7!important;color:#a1a3ae!important}.hierarchical-select-control.disabled .hierarchical-placeholder{@apply text-gray-400;}.hierarchical-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full min-w-0;}.hierarchical-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.hierarchical-value-row{@apply flex items-center gap-1.5 w-full min-w-0;}.hierarchical-value-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.hierarchical-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.hierarchical-option-body{@apply flex items-center gap-2 min-w-0 flex-1;}.hierarchical-actions{@apply flex items-center gap-2 flex-shrink-0;}.hierarchical-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.hierarchical-arrow{@apply flex-shrink-0 text-gray-400 transition-transform duration-200;}.hierarchical-arrow.open{@apply rotate-180;}.hierarchical-dropdown-panel{@apply absolute left-0 w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.hierarchical-dropdown-panel[data-position=bottom]{top:calc(100% + 4px);bottom:auto}.hierarchical-dropdown-panel[data-position=top]{bottom:calc(100% + 4px);top:auto}.hierarchical-dropdown-panel-fixed{z-index:10050}.hierarchical-search{@apply px-2 pt-2;}.hierarchical-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.hierarchical-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.hierarchical-back{@apply w-full text-left px-2.5 py-2 text-sm text-[#141414] bg-[#F8F8F8] rounded-md transition-colors mt-1 flex items-center gap-1.5;}.hierarchical-options-list{@apply overflow-auto relative flex flex-col gap-0.5 mt-1;}@media (max-height: 700px){.hierarchical-options-list{max-height:124px}}@media (min-height: 701px) and (max-height: 900px){.hierarchical-options-list{max-height:164px}}@media (min-height: 901px){.hierarchical-options-list{max-height:204px}}.hierarchical-option{@apply flex items-center justify-between gap-2 p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] rounded-md;}.hierarchical-option.disabled-item{@apply opacity-50 cursor-not-allowed;}.hierarchical-option.disabled-item:hover{@apply bg-transparent;}.hierarchical-option:hover{@apply bg-[#f9f9f9];}.hierarchical-option.selected{@apply bg-[#f7f7f7];}.hierarchical-option.selected.disabled-item{@apply bg-transparent;}.hierarchical-option-label{@apply flex-1 truncate;}.hierarchical-option-chevron{@apply flex-shrink-0 text-[#6B7080];}.hierarchical-option-check{@apply flex-shrink-0 text-[#141414];}.hierarchical-option-checkbox{@apply flex-shrink-0 flex items-center cursor-pointer;}.hierarchical-option-checkbox-spacer{@apply flex-shrink-0 w-4;}.hierarchical-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.hierarchical-options-list::-webkit-scrollbar{width:6px}.hierarchical-options-list::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.hierarchical-options-list::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.hierarchical-options-list::-webkit-scrollbar-thumb:hover{background:#909090}.hierarchical-breadcrumb-node{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.breadcrumb-separator{margin:0 6px;flex-shrink:0}.hierarchical-select-control.hierarchical-select-control-has-error{border-color:#d11e14!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }] });
|
|
9427
|
+
], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "optionsListContainer", first: true, predicate: ["optionsListContainer"], descendants: true }, { propertyName: "hierarchicalOverlay", first: true, predicate: ["hierarchicalOverlay"], descendants: true }, { propertyName: "optionEls", predicate: ["optionRef"], descendants: true }], ngImport: i0, template: "<div class=\"hierarchical-select-container\">\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 class=\"hierarchical-select-field\">\r\n <!-- With showDots on, the control is tinted by the selected node's accent.\r\n An errored control drops the tint entirely and goes neutral, so the red\r\n border reads as an error rather than competing with the accent. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #hierarchicalOrigin=\"cdkOverlayOrigin\"\r\n class=\"hierarchical-select-control\"\r\n [ngClass]=\"{ 'hierarchical-select-control-has-error': hasError() }\"\r\n tabindex=\"0\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"isDisabled()\"\r\n [class.filled]=\"!hasError() && !!controlAppearance().backgroundColor\"\r\n [style.backgroundColor]=\"hasError() ? null : controlAppearance().backgroundColor\"\r\n [style.color]=\"hasError() ? null : controlAppearance().color\"\r\n [style.borderColor]=\"hasError() ? null : controlAppearance().borderColor\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (mousedown)=\"toggleDropdown($event)\">\r\n @if (iconSrc()) {\r\n <img [src]=\"iconSrc()\" [alt]=\"iconAlt()\" class=\"shrink-0\" />\r\n }\r\n <div class=\"hierarchical-value-container\">\r\n @if (!selected()) {\r\n <div class=\"hierarchical-placeholder\">{{ placeholder() }}</div>\r\n } @else {\r\n <!-- Single row: the container is flex-wrap and the label is w-full, so\r\n a bare sibling dot would push the label onto a second line. -->\r\n <div class=\"hierarchical-value-row\">\r\n @if (showDots() && accentFor(selected()!)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(selected()!)\"></span>\r\n }\r\n <div class=\"hierarchical-value-label\" [style.color]=\"controlAppearance().color ?? resolveColor(selected())\">\r\n @for (node of displayPath(); track getValue(node); let last = $last) {\r\n <span\r\n #breadNode\r\n class=\"hierarchical-breadcrumb-node\"\r\n [bkTooltip]=\"breadNode.scrollWidth > breadNode.clientWidth ? getLabel(node) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(node) }}</span>\r\n\r\n @if (!last) {\r\n <svg\r\n class=\"breadcrumb-separator\"\r\n width=\"5\"\r\n height=\"8\"\r\n viewBox=\"0 0 5 8\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\"\r\n fill=\"#BBBDC5\"/>\r\n </svg>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n }\r\n </div>\r\n <div class=\"hierarchical-actions\">\r\n @if (clearable() && selected() && !isDisabled()) {\r\n <span class=\"hierarchical-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\" [bkTooltip]=\"clearTooltip()\" bkTooltipPosition=\"top\">\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\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"hierarchical-arrow\" [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\">\r\n <path d=\"m6 9 6 6 6-6\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #hierarchicalOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"hierarchicalOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"hierarchicalDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n class=\"hierarchical-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\">\r\n @if (searchable()) {\r\n <div class=\"hierarchical-search\">\r\n <div class=\"hierarchical-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\r\n #searchInput\r\n type=\"text\"\r\n class=\"hierarchical-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\" />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"hierarchical-back\"\r\n (mousedown)=\"goBack(); $event.preventDefault(); $event.stopPropagation()\">\r\n <span>\r\n <svg width=\"6\" height=\"10\" viewBox=\"0 0 6 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M4.59961 0.599976L0.599609 4.59998L4.59961 8.59998\" stroke=\"#141414\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>\r\n\r\n </span>\r\n {{ backToMainText() }}\r\n </button>\r\n }\r\n\r\n <div #optionsListContainer class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n #optionRef\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.marked]=\"$index === markedIndex()\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mouseenter)=\"markOption($index)\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <!-- Grouped so the row's justify-between still has exactly two\r\n children (body + trailing chevron/tick). -->\r\n <div class=\"hierarchical-option-body\">\r\n @if (allowParentSelection()) {\r\n @if (hasChildren(item)) {\r\n <!-- Only nodes with children get a box \u2014 a leaf is already\r\n selected by clicking its row. It owns its own mousedown so\r\n the row still navigates; the box itself is inert\r\n (pointer-events-none) so it can't toggle twice. standalone\r\n keeps this ngModel out of any parent <form> the select is\r\n rendered inside. -->\r\n <span\r\n class=\"hierarchical-option-checkbox\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Select ' + getLabel(item)\"\r\n (mousedown)=\"toggleParentSelection(item, $event)\">\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"!!item.disabled\"\r\n [ngModel]=\"isSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </span>\r\n } @else {\r\n <!-- Holds the checkbox column open so leaf labels line up with\r\n the parents' above them. -->\r\n <span class=\"hierarchical-option-checkbox-spacer\" aria-hidden=\"true\"></span>\r\n }\r\n }\r\n @if (showDots() && accentFor(item)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\r\n </div>\r\n @if (hasChildren(item)) {\r\n <svg width=\"5\" height=\"8\" viewBox=\"0 0 5 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\" fill=\"#BBBDC5\"/>\r\n </svg>\r\n } @else if (isSelected(item)) {\r\n <svg width=\"10\" height=\"7\" viewBox=\"0 0 10 7\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M3.72939 6.28273C3.64166 6.28324 3.55468 6.26642 3.47346 6.23324C3.39223 6.20007 3.31835 6.15118 3.25606 6.08939L0.196061 3.00273C0.0705253 2.87719 -1.32274e-09 2.70693 0 2.52939C1.32273e-09 2.35186 0.0705253 2.1816 0.196061 2.05606C0.321597 1.93053 0.49186 1.86 0.669394 1.86C0.846929 1.86 1.01719 1.93053 1.14273 2.05606L3.72939 4.64939L8.17606 0.196061C8.3016 0.0705253 8.47186 -3.49963e-09 8.64939 0C8.82693 3.49963e-09 8.99719 0.0705253 9.12273 0.196061C9.24826 0.321597 9.31879 0.49186 9.31879 0.669395C9.31879 0.846929 9.24826 1.01719 9.12273 1.14273L4.20273 6.06273C4.07921 6.19434 3.90963 6.27316 3.72939 6.28273V6.28273Z\" fill=\"#141414\"/>\r\n </svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <div class=\"hierarchical-option-empty\">No records found</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n</div>\r\n", styles: [".hierarchical-select-container{@apply relative w-full box-border;}.hierarchical-select-field{@apply relative w-full;}.hierarchical-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;}.hierarchical-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.hierarchical-select-control.disabled{@apply cursor-not-allowed;background-color:#f4f4f6!important;border-color:#e3e3e7!important;color:#a1a3ae!important}.hierarchical-select-control.disabled .hierarchical-placeholder{@apply text-gray-400;}.hierarchical-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full min-w-0;}.hierarchical-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.hierarchical-value-row{@apply flex items-center gap-1.5 w-full min-w-0;}.hierarchical-value-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.hierarchical-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.hierarchical-option-body{@apply flex items-center gap-2 min-w-0 flex-1;}.hierarchical-actions{@apply flex items-center gap-2 flex-shrink-0;}.hierarchical-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.hierarchical-arrow{@apply flex-shrink-0 text-gray-400 transition-transform duration-200;}.hierarchical-arrow.open{@apply rotate-180;}.hierarchical-dropdown-panel{@apply static left-auto w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.hierarchical-search{@apply px-2 pt-2;}.hierarchical-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.hierarchical-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.hierarchical-back{@apply w-full text-left px-2.5 py-2 text-sm text-[#141414] bg-[#F8F8F8] rounded-md transition-colors mt-1 flex items-center gap-1.5;}.hierarchical-options-list{@apply overflow-auto relative flex flex-col gap-0.5 mt-1;}@media (max-height: 700px){.hierarchical-options-list{max-height:124px}}@media (min-height: 701px) and (max-height: 900px){.hierarchical-options-list{max-height:164px}}@media (min-height: 901px){.hierarchical-options-list{max-height:204px}}.hierarchical-option{@apply flex items-center justify-between gap-2 p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] rounded-md;}.hierarchical-option.disabled-item{@apply opacity-50 cursor-not-allowed;}.hierarchical-option.disabled-item:hover{@apply bg-transparent;}.hierarchical-option:hover,.hierarchical-option.marked{@apply bg-[#F1F1F3];}.hierarchical-option.marked.disabled-item{@apply bg-transparent;}.hierarchical-option.selected{@apply bg-[#F8F8F8];}.hierarchical-option.selected:hover,.hierarchical-option.selected.marked{@apply bg-[#F1F1F3];}.hierarchical-option.selected.disabled-item{@apply bg-transparent;}.hierarchical-option-label{@apply flex-1 truncate;}.hierarchical-option-chevron{@apply flex-shrink-0 text-[#6B7080];}.hierarchical-option-check{@apply flex-shrink-0 text-[#141414];}.hierarchical-option-checkbox{@apply flex-shrink-0 flex items-center cursor-pointer;}.hierarchical-option-checkbox-spacer{@apply flex-shrink-0 w-4;}.hierarchical-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.hierarchical-options-list::-webkit-scrollbar{width:6px}.hierarchical-options-list::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.hierarchical-options-list::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.hierarchical-options-list::-webkit-scrollbar-thumb:hover{background:#909090}.hierarchical-breadcrumb-node{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.breadcrumb-separator{margin:0 6px;flex-shrink:0}.hierarchical-select-control.hierarchical-select-control-has-error{border-color:#d11e14!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
|
|
9182
9428
|
}
|
|
9183
9429
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, decorators: [{
|
|
9184
9430
|
type: Component,
|
|
9185
|
-
args: [{ selector: 'bk-hierarchical-select', standalone: true, imports: [CommonModule, FormsModule, BKTooltipDirective, BkCheckbox], providers: [
|
|
9431
|
+
args: [{ selector: 'bk-hierarchical-select', standalone: true, imports: [CommonModule, FormsModule, BKTooltipDirective, BkCheckbox, OverlayModule], providers: [
|
|
9186
9432
|
{
|
|
9187
9433
|
provide: NG_VALUE_ACCESSOR,
|
|
9188
9434
|
useExisting: forwardRef(() => BkHierarchicalSelect),
|
|
9189
9435
|
multi: true,
|
|
9190
9436
|
},
|
|
9191
|
-
], template: "<div class=\"hierarchical-select-container\">\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 class=\"hierarchical-select-field\">\r\n <!-- With showDots on, the control is tinted by the selected node's accent.\r\n An errored control drops the tint entirely and goes neutral, so the red\r\n border reads as an error rather than competing with the accent. -->\r\n <div\r\n #controlWrapper\r\n class=\"hierarchical-select-control\"\r\n [ngClass]=\"{ 'hierarchical-select-control-has-error': hasError() }\"\r\n tabindex=\"0\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"isDisabled()\"\r\n [class.filled]=\"!hasError() && !!controlAppearance().backgroundColor\"\r\n [style.backgroundColor]=\"hasError() ? null : controlAppearance().backgroundColor\"\r\n [style.color]=\"hasError() ? null : controlAppearance().color\"\r\n [style.borderColor]=\"hasError() ? null : controlAppearance().borderColor\"\r\n (mousedown)=\"toggleDropdown($event)\">\r\n @if (iconSrc()) {\r\n <img [src]=\"iconSrc()\" [alt]=\"iconAlt()\" class=\"shrink-0\" />\r\n }\r\n <div class=\"hierarchical-value-container\">\r\n @if (!selected()) {\r\n <div class=\"hierarchical-placeholder\">{{ placeholder() }}</div>\r\n } @else {\r\n <!-- Single row: the container is flex-wrap and the label is w-full, so\r\n a bare sibling dot would push the label onto a second line. -->\r\n <div class=\"hierarchical-value-row\">\r\n @if (showDots() && accentFor(selected()!)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(selected()!)\"></span>\r\n }\r\n <div class=\"hierarchical-value-label\" [style.color]=\"controlAppearance().color ?? resolveColor(selected())\">\r\n @for (node of displayPath(); track getValue(node); let last = $last) {\r\n <span\r\n #breadNode\r\n class=\"hierarchical-breadcrumb-node\"\r\n [bkTooltip]=\"breadNode.scrollWidth > breadNode.clientWidth ? getLabel(node) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(node) }}</span>\r\n\r\n @if (!last) {\r\n <svg\r\n class=\"breadcrumb-separator\"\r\n width=\"5\"\r\n height=\"8\"\r\n viewBox=\"0 0 5 8\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\"\r\n fill=\"#BBBDC5\"/>\r\n </svg>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n }\r\n </div>\r\n <div class=\"hierarchical-actions\">\r\n @if (clearable() && selected() && !isDisabled()) {\r\n <span class=\"hierarchical-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\" [bkTooltip]=\"clearTooltip()\" bkTooltipPosition=\"top\">\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\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"hierarchical-arrow\" [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\">\r\n <path d=\"m6 9 6 6 6-6\"/>\r\n </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=\"hierarchical-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\r\n [class.hierarchical-dropdown-panel-fixed]=\"appendToBody()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"appendToBody() ? getTop() : null\"\r\n [style.bottom]=\"appendToBody() ? getBottom() : null\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\">\r\n @if (searchable()) {\r\n <div class=\"hierarchical-search\">\r\n <div class=\"hierarchical-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\r\n #searchInput\r\n type=\"text\"\r\n class=\"hierarchical-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n (input)=\"onSearchInput($event)\"\r\n (click)=\"$event.stopPropagation()\" />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"hierarchical-back\"\r\n (click)=\"goBack(); $event.stopPropagation()\">\r\n <span>\r\n <svg width=\"6\" height=\"10\" viewBox=\"0 0 6 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M4.59961 0.599976L0.599609 4.59998L4.59961 8.59998\" stroke=\"#141414\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>\r\n\r\n </span>\r\n {{ backToMainText() }}\r\n </button>\r\n }\r\n\r\n <div class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <!-- Grouped so the row's justify-between still has exactly two\r\n children (body + trailing chevron/tick). -->\r\n <div class=\"hierarchical-option-body\">\r\n @if (allowParentSelection()) {\r\n @if (hasChildren(item)) {\r\n <!-- Only nodes with children get a box \u2014 a leaf is already\r\n selected by clicking its row. It owns its own mousedown so\r\n the row still navigates; the box itself is inert\r\n (pointer-events-none) so it can't toggle twice. standalone\r\n keeps this ngModel out of any parent <form> the select is\r\n rendered inside. -->\r\n <span\r\n class=\"hierarchical-option-checkbox\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Select ' + getLabel(item)\"\r\n (mousedown)=\"toggleParentSelection(item, $event)\">\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"!!item.disabled\"\r\n [ngModel]=\"isSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </span>\r\n } @else {\r\n <!-- Holds the checkbox column open so leaf labels line up with\r\n the parents' above them. -->\r\n <span class=\"hierarchical-option-checkbox-spacer\" aria-hidden=\"true\"></span>\r\n }\r\n }\r\n @if (showDots() && accentFor(item)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\r\n </div>\r\n @if (hasChildren(item)) {\r\n <svg width=\"5\" height=\"8\" viewBox=\"0 0 5 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\" fill=\"#BBBDC5\"/>\r\n </svg>\r\n } @else if (isSelected(item)) {\r\n <svg width=\"10\" height=\"7\" viewBox=\"0 0 10 7\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M3.72939 6.28273C3.64166 6.28324 3.55468 6.26642 3.47346 6.23324C3.39223 6.20007 3.31835 6.15118 3.25606 6.08939L0.196061 3.00273C0.0705253 2.87719 -1.32274e-09 2.70693 0 2.52939C1.32273e-09 2.35186 0.0705253 2.1816 0.196061 2.05606C0.321597 1.93053 0.49186 1.86 0.669394 1.86C0.846929 1.86 1.01719 1.93053 1.14273 2.05606L3.72939 4.64939L8.17606 0.196061C8.3016 0.0705253 8.47186 -3.49963e-09 8.64939 0C8.82693 3.49963e-09 8.99719 0.0705253 9.12273 0.196061C9.24826 0.321597 9.31879 0.49186 9.31879 0.669395C9.31879 0.846929 9.24826 1.01719 9.12273 1.14273L4.20273 6.06273C4.07921 6.19434 3.90963 6.27316 3.72939 6.28273V6.28273Z\" fill=\"#141414\"/>\r\n </svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <div class=\"hierarchical-option-empty\">No records found</div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".hierarchical-select-container{@apply relative w-full box-border;}.hierarchical-select-field{@apply relative w-full;}.hierarchical-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;}.hierarchical-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.hierarchical-select-control.disabled{@apply cursor-not-allowed;background-color:#f4f4f6!important;border-color:#e3e3e7!important;color:#a1a3ae!important}.hierarchical-select-control.disabled .hierarchical-placeholder{@apply text-gray-400;}.hierarchical-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full min-w-0;}.hierarchical-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.hierarchical-value-row{@apply flex items-center gap-1.5 w-full min-w-0;}.hierarchical-value-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.hierarchical-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.hierarchical-option-body{@apply flex items-center gap-2 min-w-0 flex-1;}.hierarchical-actions{@apply flex items-center gap-2 flex-shrink-0;}.hierarchical-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.hierarchical-arrow{@apply flex-shrink-0 text-gray-400 transition-transform duration-200;}.hierarchical-arrow.open{@apply rotate-180;}.hierarchical-dropdown-panel{@apply absolute left-0 w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.hierarchical-dropdown-panel[data-position=bottom]{top:calc(100% + 4px);bottom:auto}.hierarchical-dropdown-panel[data-position=top]{bottom:calc(100% + 4px);top:auto}.hierarchical-dropdown-panel-fixed{z-index:10050}.hierarchical-search{@apply px-2 pt-2;}.hierarchical-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.hierarchical-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.hierarchical-back{@apply w-full text-left px-2.5 py-2 text-sm text-[#141414] bg-[#F8F8F8] rounded-md transition-colors mt-1 flex items-center gap-1.5;}.hierarchical-options-list{@apply overflow-auto relative flex flex-col gap-0.5 mt-1;}@media (max-height: 700px){.hierarchical-options-list{max-height:124px}}@media (min-height: 701px) and (max-height: 900px){.hierarchical-options-list{max-height:164px}}@media (min-height: 901px){.hierarchical-options-list{max-height:204px}}.hierarchical-option{@apply flex items-center justify-between gap-2 p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] rounded-md;}.hierarchical-option.disabled-item{@apply opacity-50 cursor-not-allowed;}.hierarchical-option.disabled-item:hover{@apply bg-transparent;}.hierarchical-option:hover{@apply bg-[#f9f9f9];}.hierarchical-option.selected{@apply bg-[#f7f7f7];}.hierarchical-option.selected.disabled-item{@apply bg-transparent;}.hierarchical-option-label{@apply flex-1 truncate;}.hierarchical-option-chevron{@apply flex-shrink-0 text-[#6B7080];}.hierarchical-option-check{@apply flex-shrink-0 text-[#141414];}.hierarchical-option-checkbox{@apply flex-shrink-0 flex items-center cursor-pointer;}.hierarchical-option-checkbox-spacer{@apply flex-shrink-0 w-4;}.hierarchical-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.hierarchical-options-list::-webkit-scrollbar{width:6px}.hierarchical-options-list::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.hierarchical-options-list::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.hierarchical-options-list::-webkit-scrollbar-thumb:hover{background:#909090}.hierarchical-breadcrumb-node{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.breadcrumb-separator{margin:0 6px;flex-shrink:0}.hierarchical-select-control.hierarchical-select-control-has-error{border-color:#d11e14!important}\n"] }]
|
|
9437
|
+
], template: "<div class=\"hierarchical-select-container\">\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 class=\"hierarchical-select-field\">\r\n <!-- With showDots on, the control is tinted by the selected node's accent.\r\n An errored control drops the tint entirely and goes neutral, so the red\r\n border reads as an error rather than competing with the accent. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #hierarchicalOrigin=\"cdkOverlayOrigin\"\r\n class=\"hierarchical-select-control\"\r\n [ngClass]=\"{ 'hierarchical-select-control-has-error': hasError() }\"\r\n tabindex=\"0\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"isDisabled()\"\r\n [class.filled]=\"!hasError() && !!controlAppearance().backgroundColor\"\r\n [style.backgroundColor]=\"hasError() ? null : controlAppearance().backgroundColor\"\r\n [style.color]=\"hasError() ? null : controlAppearance().color\"\r\n [style.borderColor]=\"hasError() ? null : controlAppearance().borderColor\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (mousedown)=\"toggleDropdown($event)\">\r\n @if (iconSrc()) {\r\n <img [src]=\"iconSrc()\" [alt]=\"iconAlt()\" class=\"shrink-0\" />\r\n }\r\n <div class=\"hierarchical-value-container\">\r\n @if (!selected()) {\r\n <div class=\"hierarchical-placeholder\">{{ placeholder() }}</div>\r\n } @else {\r\n <!-- Single row: the container is flex-wrap and the label is w-full, so\r\n a bare sibling dot would push the label onto a second line. -->\r\n <div class=\"hierarchical-value-row\">\r\n @if (showDots() && accentFor(selected()!)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(selected()!)\"></span>\r\n }\r\n <div class=\"hierarchical-value-label\" [style.color]=\"controlAppearance().color ?? resolveColor(selected())\">\r\n @for (node of displayPath(); track getValue(node); let last = $last) {\r\n <span\r\n #breadNode\r\n class=\"hierarchical-breadcrumb-node\"\r\n [bkTooltip]=\"breadNode.scrollWidth > breadNode.clientWidth ? getLabel(node) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(node) }}</span>\r\n\r\n @if (!last) {\r\n <svg\r\n class=\"breadcrumb-separator\"\r\n width=\"5\"\r\n height=\"8\"\r\n viewBox=\"0 0 5 8\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\"\r\n fill=\"#BBBDC5\"/>\r\n </svg>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n }\r\n </div>\r\n <div class=\"hierarchical-actions\">\r\n @if (clearable() && selected() && !isDisabled()) {\r\n <span class=\"hierarchical-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\" [bkTooltip]=\"clearTooltip()\" bkTooltipPosition=\"top\">\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\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"hierarchical-arrow\" [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\">\r\n <path d=\"m6 9 6 6 6-6\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #hierarchicalOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"hierarchicalOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"hierarchicalDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n class=\"hierarchical-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\">\r\n @if (searchable()) {\r\n <div class=\"hierarchical-search\">\r\n <div class=\"hierarchical-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\r\n #searchInput\r\n type=\"text\"\r\n class=\"hierarchical-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\" />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"hierarchical-back\"\r\n (mousedown)=\"goBack(); $event.preventDefault(); $event.stopPropagation()\">\r\n <span>\r\n <svg width=\"6\" height=\"10\" viewBox=\"0 0 6 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M4.59961 0.599976L0.599609 4.59998L4.59961 8.59998\" stroke=\"#141414\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>\r\n\r\n </span>\r\n {{ backToMainText() }}\r\n </button>\r\n }\r\n\r\n <div #optionsListContainer class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n #optionRef\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.marked]=\"$index === markedIndex()\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mouseenter)=\"markOption($index)\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <!-- Grouped so the row's justify-between still has exactly two\r\n children (body + trailing chevron/tick). -->\r\n <div class=\"hierarchical-option-body\">\r\n @if (allowParentSelection()) {\r\n @if (hasChildren(item)) {\r\n <!-- Only nodes with children get a box \u2014 a leaf is already\r\n selected by clicking its row. It owns its own mousedown so\r\n the row still navigates; the box itself is inert\r\n (pointer-events-none) so it can't toggle twice. standalone\r\n keeps this ngModel out of any parent <form> the select is\r\n rendered inside. -->\r\n <span\r\n class=\"hierarchical-option-checkbox\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Select ' + getLabel(item)\"\r\n (mousedown)=\"toggleParentSelection(item, $event)\">\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"!!item.disabled\"\r\n [ngModel]=\"isSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </span>\r\n } @else {\r\n <!-- Holds the checkbox column open so leaf labels line up with\r\n the parents' above them. -->\r\n <span class=\"hierarchical-option-checkbox-spacer\" aria-hidden=\"true\"></span>\r\n }\r\n }\r\n @if (showDots() && accentFor(item)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\r\n </div>\r\n @if (hasChildren(item)) {\r\n <svg width=\"5\" height=\"8\" viewBox=\"0 0 5 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\" fill=\"#BBBDC5\"/>\r\n </svg>\r\n } @else if (isSelected(item)) {\r\n <svg width=\"10\" height=\"7\" viewBox=\"0 0 10 7\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M3.72939 6.28273C3.64166 6.28324 3.55468 6.26642 3.47346 6.23324C3.39223 6.20007 3.31835 6.15118 3.25606 6.08939L0.196061 3.00273C0.0705253 2.87719 -1.32274e-09 2.70693 0 2.52939C1.32273e-09 2.35186 0.0705253 2.1816 0.196061 2.05606C0.321597 1.93053 0.49186 1.86 0.669394 1.86C0.846929 1.86 1.01719 1.93053 1.14273 2.05606L3.72939 4.64939L8.17606 0.196061C8.3016 0.0705253 8.47186 -3.49963e-09 8.64939 0C8.82693 3.49963e-09 8.99719 0.0705253 9.12273 0.196061C9.24826 0.321597 9.31879 0.49186 9.31879 0.669395C9.31879 0.846929 9.24826 1.01719 9.12273 1.14273L4.20273 6.06273C4.07921 6.19434 3.90963 6.27316 3.72939 6.28273V6.28273Z\" fill=\"#141414\"/>\r\n </svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <div class=\"hierarchical-option-empty\">No records found</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n</div>\r\n", styles: [".hierarchical-select-container{@apply relative w-full box-border;}.hierarchical-select-field{@apply relative w-full;}.hierarchical-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;}.hierarchical-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.hierarchical-select-control.disabled{@apply cursor-not-allowed;background-color:#f4f4f6!important;border-color:#e3e3e7!important;color:#a1a3ae!important}.hierarchical-select-control.disabled .hierarchical-placeholder{@apply text-gray-400;}.hierarchical-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full min-w-0;}.hierarchical-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.hierarchical-value-row{@apply flex items-center gap-1.5 w-full min-w-0;}.hierarchical-value-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.hierarchical-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.hierarchical-option-body{@apply flex items-center gap-2 min-w-0 flex-1;}.hierarchical-actions{@apply flex items-center gap-2 flex-shrink-0;}.hierarchical-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.hierarchical-arrow{@apply flex-shrink-0 text-gray-400 transition-transform duration-200;}.hierarchical-arrow.open{@apply rotate-180;}.hierarchical-dropdown-panel{@apply static left-auto w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.hierarchical-search{@apply px-2 pt-2;}.hierarchical-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.hierarchical-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.hierarchical-back{@apply w-full text-left px-2.5 py-2 text-sm text-[#141414] bg-[#F8F8F8] rounded-md transition-colors mt-1 flex items-center gap-1.5;}.hierarchical-options-list{@apply overflow-auto relative flex flex-col gap-0.5 mt-1;}@media (max-height: 700px){.hierarchical-options-list{max-height:124px}}@media (min-height: 701px) and (max-height: 900px){.hierarchical-options-list{max-height:164px}}@media (min-height: 901px){.hierarchical-options-list{max-height:204px}}.hierarchical-option{@apply flex items-center justify-between gap-2 p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] rounded-md;}.hierarchical-option.disabled-item{@apply opacity-50 cursor-not-allowed;}.hierarchical-option.disabled-item:hover{@apply bg-transparent;}.hierarchical-option:hover,.hierarchical-option.marked{@apply bg-[#F1F1F3];}.hierarchical-option.marked.disabled-item{@apply bg-transparent;}.hierarchical-option.selected{@apply bg-[#F8F8F8];}.hierarchical-option.selected:hover,.hierarchical-option.selected.marked{@apply bg-[#F1F1F3];}.hierarchical-option.selected.disabled-item{@apply bg-transparent;}.hierarchical-option-label{@apply flex-1 truncate;}.hierarchical-option-chevron{@apply flex-shrink-0 text-[#6B7080];}.hierarchical-option-check{@apply flex-shrink-0 text-[#141414];}.hierarchical-option-checkbox{@apply flex-shrink-0 flex items-center cursor-pointer;}.hierarchical-option-checkbox-spacer{@apply flex-shrink-0 w-4;}.hierarchical-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.hierarchical-options-list::-webkit-scrollbar{width:6px}.hierarchical-options-list::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.hierarchical-options-list::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.hierarchical-options-list::-webkit-scrollbar-thumb:hover{background:#909090}.hierarchical-breadcrumb-node{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.breadcrumb-separator{margin:0 6px;flex-shrink:0}.hierarchical-select-control.hierarchical-select-control-has-error{border-color:#d11e14!important}\n"] }]
|
|
9192
9438
|
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], labelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelKey", required: false }] }], valueKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueKey", required: false }] }], childrenKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenKey", required: false }] }], clearTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearTooltip", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], iconSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconSrc", required: false }] }], iconAlt: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconAlt", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], allowParentSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowParentSelection", required: false }] }], backToMainText: [{ type: i0.Input, args: [{ isSignal: true, alias: "backToMainText", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], dropdownPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownPosition", required: false }] }], colorKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorKey", required: false }] }], showDots: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDots", required: false }] }], inheritColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "inheritColor", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], restrictKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "restrictKey", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], clear: [{ type: i0.Output, args: ["clear"] }], searchInput: [{
|
|
9193
9439
|
type: ViewChild,
|
|
9194
9440
|
args: ['searchInput']
|
|
@@ -9198,9 +9444,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9198
9444
|
}], dropdownPanel: [{
|
|
9199
9445
|
type: ViewChild,
|
|
9200
9446
|
args: ['dropdownPanel']
|
|
9201
|
-
}],
|
|
9202
|
-
type:
|
|
9203
|
-
args: ['
|
|
9447
|
+
}], optionsListContainer: [{
|
|
9448
|
+
type: ViewChild,
|
|
9449
|
+
args: ['optionsListContainer']
|
|
9450
|
+
}], optionEls: [{
|
|
9451
|
+
type: ViewChildren,
|
|
9452
|
+
args: ['optionRef']
|
|
9453
|
+
}], hierarchicalOverlay: [{
|
|
9454
|
+
type: ViewChild,
|
|
9455
|
+
args: ['hierarchicalOverlay']
|
|
9204
9456
|
}] } });
|
|
9205
9457
|
|
|
9206
9458
|
// ─── Service ─────────────────────────────────────────────────────────────────
|
|
@@ -10000,7 +10252,7 @@ class BkPagination {
|
|
|
10000
10252
|
return this.getPageCount();
|
|
10001
10253
|
}
|
|
10002
10254
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10003
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPagination, isStandalone: true, selector: "bk-pagination", inputs: { pageSize: "pageSize", total: "total", activePage: "activePage", showPageSize: "showPageSize", showRecordsText: "showRecordsText", showPageCount: "showPageCount", customClass: "customClass" }, outputs: { changePageSize: "changePageSize", pageChanged: "pageChanged", activePageChange: "activePageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"md:px-4 px-2 md:py-3 py-2 border-t border-[#EBEDF3] rounded-b-xl\">\r\n <div class=\"flex flex-row items-center justify-between md:gap-3 gap-1 {{ customClass }}\">\r\n\r\n <!-- Page size dropdown -->\r\n\r\n @if (!pageSizeHidden) {\r\n <div class=\"flex gap-3 items-center pagination\">\r\n @if (showPageSizeLabel) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">Rows per page</p>\r\n }\r\n @if (showPageSizeInput) {\r\n <bk-select\r\n [items]=\"pageSizesList\"\r\n [searchable]=\"false\"\r\n bindLabel=\"key\"\r\n bindValue=\"value\"\r\n [clearable]=\"false\"\r\n [(ngModel)]=\"pageSize\"\r\n [dropdownPosition]=\"'top'\"\r\n (change)=\"changeSize($event)\"\r\n [variation]=\"'sm'\"\r\n [isResponsive]=\"false\"\r\n class=\"!min-w-[90px] lg:!min-w-[131px]\"\r\n >\r\n </bk-select>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- showing entries -->\r\n @if (showRecordsText) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n Showing <span>{{ startIndex }}</span> to\r\n <span>{{ endIndex > totalItems ? totalItems : endIndex }}</span> of\r\n <span>{{ totalItems }}</span> Records\r\n </p>\r\n }\r\n\r\n <!-- Pagination main -->\r\n <!-- With 2+ top-level blocks visible, the parent row's justify-between already\r\n pins this to the end on its own; customClass on the row (e.g. \"justify-end\")\r\n controls arrangement among those blocks.\r\n Hidden down to just this one, there's nothing left for the row to distribute\r\n against, so it grows to fill the row (flex-1) instead \u2014 letting customClass\r\n act here on its own two children (page count text vs. the page-number list)\r\n via e.g. \"justify-between\" or \"justify-around\". -->\r\n <nav\r\n class=\"flex gap-1.5 items-center {{ customClass }}\"\r\n [class.flex-1]=\"pageSizeHidden && !showRecordsText\"\r\n >\r\n\r\n @if (showPageCount) {\r\n <!-- Page count -->\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n\r\n\r\n <!-- Page count mobile version -->\r\n <p class=\"text-xs text-[#141414] font-medium md:hidden block\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n }\r\n\r\n <ul class=\"flex items-center space-x-1 text-[13px] text-[#B9BBC6]\">\r\n\r\n <!-- Previous -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- Previous -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage - 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n\r\n <!-- Page Numbers -->\r\n <li *ngFor=\"let item of paginate()\">\r\n <a\r\n (click)=\"onClickPage(item)\"\r\n href=\"javascript:void(0)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 leading-6 rounded-lg\"\r\n [ngClass]=\"item === activePage\r\n ? 'text-[#15191E] bg-[#F8F8FA] hover:bg-[#F8F8FA]'\r\n : 'hover:bg-[#F8F8FA] hover:text-[#15191E]'\">\r\n {{ item }}\r\n </a>\r\n </li>\r\n\r\n <!-- Next -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage + 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- next double arrow -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(getTotalPages())\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkSelect, selector: "bk-select", inputs: ["items", "bindLabel", "bindValue", "bindIcon", "isResponsive", "placeholder", "notFoundText", "loadingText", "clearAllText", "groupBy", "colorKey", "dropdownView", "gridColumns", "gridVariation", "gridSelectionActions", "gridMinWidth", "gridMaxHeight", "gridSelectedLabelKeys", "gridSelectedLabelSeparator", "gridApplyText", "gridClearText", "showDots", "showAvatar", "avatarKey", "iconAlt", "label", "required", "variation", "iconSrc", "multiple", "maxLabels", "searchable", "allSelect", "clearable", "readonly", "disabled", "loading", "closeOnSelect", "dropdownPosition", "hasError", "errorMessage", "appendToBody", "compareWith"], outputs: ["disabledChange", "open", "close", "focus", "blur", "search", "clear", "change", "scrollToEnd"] }] });
|
|
10255
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPagination, isStandalone: true, selector: "bk-pagination", inputs: { pageSize: "pageSize", total: "total", activePage: "activePage", showPageSize: "showPageSize", showRecordsText: "showRecordsText", showPageCount: "showPageCount", customClass: "customClass" }, outputs: { changePageSize: "changePageSize", pageChanged: "pageChanged", activePageChange: "activePageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"md:px-4 px-2 md:py-3 py-2 border-t border-[#EBEDF3] rounded-b-xl\">\r\n <div class=\"flex flex-row items-center justify-between md:gap-3 gap-1 {{ customClass }}\">\r\n\r\n <!-- Page size dropdown -->\r\n\r\n @if (!pageSizeHidden) {\r\n <div class=\"flex gap-3 items-center pagination\">\r\n @if (showPageSizeLabel) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">Rows per page</p>\r\n }\r\n @if (showPageSizeInput) {\r\n <bk-select\r\n [items]=\"pageSizesList\"\r\n [searchable]=\"false\"\r\n bindLabel=\"key\"\r\n bindValue=\"value\"\r\n [clearable]=\"false\"\r\n [(ngModel)]=\"pageSize\"\r\n [dropdownPosition]=\"'top'\"\r\n (change)=\"changeSize($event)\"\r\n [variation]=\"'sm'\"\r\n [isResponsive]=\"false\"\r\n class=\"!min-w-[90px] lg:!min-w-[131px]\"\r\n >\r\n </bk-select>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- showing entries -->\r\n @if (showRecordsText) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n Showing <span>{{ startIndex }}</span> to\r\n <span>{{ endIndex > totalItems ? totalItems : endIndex }}</span> of\r\n <span>{{ totalItems }}</span> Records\r\n </p>\r\n }\r\n\r\n <!-- Pagination main -->\r\n <!-- With 2+ top-level blocks visible, the parent row's justify-between already\r\n pins this to the end on its own; customClass on the row (e.g. \"justify-end\")\r\n controls arrangement among those blocks.\r\n Hidden down to just this one, there's nothing left for the row to distribute\r\n against, so it grows to fill the row (flex-1) instead \u2014 letting customClass\r\n act here on its own two children (page count text vs. the page-number list)\r\n via e.g. \"justify-between\" or \"justify-around\". -->\r\n <nav\r\n class=\"flex gap-1.5 items-center {{ customClass }}\"\r\n [class.flex-1]=\"pageSizeHidden && !showRecordsText\"\r\n >\r\n\r\n @if (showPageCount) {\r\n <!-- Page count -->\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n\r\n\r\n <!-- Page count mobile version -->\r\n <p class=\"text-xs text-[#141414] font-medium md:hidden block\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n }\r\n\r\n <ul class=\"flex items-center space-x-1 text-[13px] text-[#B9BBC6]\">\r\n\r\n <!-- Previous -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- Previous -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage - 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n\r\n <!-- Page Numbers -->\r\n <li *ngFor=\"let item of paginate()\">\r\n <a\r\n (click)=\"onClickPage(item)\"\r\n href=\"javascript:void(0)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 leading-6 rounded-lg\"\r\n [ngClass]=\"item === activePage\r\n ? 'text-[#15191E] bg-[#F8F8FA] hover:bg-[#F8F8FA]'\r\n : 'hover:bg-[#F8F8FA] hover:text-[#15191E]'\">\r\n {{ item }}\r\n </a>\r\n </li>\r\n\r\n <!-- Next -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage + 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- next double arrow -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(getTotalPages())\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkSelect, selector: "bk-select", inputs: ["items", "bindLabel", "bindValue", "bindIcon", "isResponsive", "placeholder", "notFoundText", "loadingText", "clearAllText", "groupBy", "colorKey", "dropdownView", "gridColumns", "gridVariation", "gridSelectionActions", "gridMinWidth", "gridMaxHeight", "gridSelectedLabelKeys", "gridSelectedLabelSeparator", "gridApplyText", "gridClearText", "showDots", "showAvatar", "avatarKey", "iconAlt", "label", "required", "variation", "iconSrc", "multiple", "maxLabels", "searchable", "allSelect", "clearable", "readonly", "disabled", "loading", "closeOnSelect", "openOnFocus", "dropdownPosition", "hasError", "errorMessage", "appendToBody", "compareWith"], outputs: ["disabledChange", "open", "close", "focus", "blur", "search", "clear", "change", "scrollToEnd"] }] });
|
|
10004
10256
|
}
|
|
10005
10257
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, decorators: [{
|
|
10006
10258
|
type: Component,
|
|
@@ -10284,6 +10536,8 @@ class BkMenu {
|
|
|
10284
10536
|
* already sets it apart from the page.
|
|
10285
10537
|
*/
|
|
10286
10538
|
submenuBackground = false;
|
|
10539
|
+
/** Emit parent clicks as selections as well as toggling their inline submenu. */
|
|
10540
|
+
emitParentClick = false;
|
|
10287
10541
|
/** Id of the currently selected leaf item. Two-way bindable. */
|
|
10288
10542
|
activeItemId = '';
|
|
10289
10543
|
/** Tint item icons: dark by default, white on the active (dark) row. */
|
|
@@ -10482,6 +10736,11 @@ class BkMenu {
|
|
|
10482
10736
|
if (this.hasChildren(item)) {
|
|
10483
10737
|
if (!this.isPopup) {
|
|
10484
10738
|
this.toggle(item, siblings);
|
|
10739
|
+
if (this.emitParentClick) {
|
|
10740
|
+
this.activeItemId = item.id;
|
|
10741
|
+
this.activeItemIdChange.emit(item.id);
|
|
10742
|
+
this.itemClick.emit(item);
|
|
10743
|
+
}
|
|
10485
10744
|
return;
|
|
10486
10745
|
}
|
|
10487
10746
|
if (this.trigger !== 'click')
|
|
@@ -10505,13 +10764,10 @@ class BkMenu {
|
|
|
10505
10764
|
}
|
|
10506
10765
|
// Pop-up mode: open a parent's fly-out on hover (and close its siblings).
|
|
10507
10766
|
onItemEnter(item, siblings, event, level, parent) {
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
//
|
|
10511
|
-
|
|
10512
|
-
// second click. With nothing open, hover does nothing.
|
|
10513
|
-
if (this.trigger === 'click'
|
|
10514
|
-
&& !siblings.some(sibling => sibling.id !== item.id && this.isOpen(sibling)))
|
|
10767
|
+
// Hover only opens/switches fly-outs in hover mode. In click mode every
|
|
10768
|
+
// open and switch must come from a real click, so hover does nothing —
|
|
10769
|
+
// even while a sibling's panel is already open.
|
|
10770
|
+
if (!this.isHoverTrigger || item.disabled || !this.hasChildren(item))
|
|
10515
10771
|
return;
|
|
10516
10772
|
// Re-entering after crossing the gap: keep what's already up rather than
|
|
10517
10773
|
// tearing it down and re-placing it.
|
|
@@ -10664,7 +10920,7 @@ class BkMenu {
|
|
|
10664
10920
|
this.closeAll();
|
|
10665
10921
|
}
|
|
10666
10922
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
10667
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkMenu, isStandalone: true, selector: "bk-menu", inputs: { items: "items", orientation: "orientation", submenuMode: "submenuMode", trigger: "trigger", size: "size", hoverCloseDelay: "hoverCloseDelay", singleOpen: "singleOpen", submenuBackground: "submenuBackground", activeItemId: "activeItemId", tintIcons: "tintIcons", maxHeight: "maxHeight" }, outputs: { activeItemIdChange: "activeItemIdChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)", "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, usesOnChanges: true, ngImport: i0, template: "<nav\r\n class=\"bk-menu\"\r\n [class.bk-menu--vertical]=\"isVertical\"\r\n [class.bk-menu--horizontal]=\"!isVertical\"\r\n [class.bk-menu--popup]=\"isPopup\"\r\n [class.bk-menu--compact]=\"isCompact\"\r\n [class.bk-menu--tint]=\"tintIcons\"\r\n role=\"menubar\"\r\n [attr.aria-orientation]=\"orientation\">\r\n <ul\r\n class=\"bk-menu__list\"\r\n [class.bk-menu__list--scroll]=\"maxHeightStyle\"\r\n [style.maxHeight]=\"maxHeightStyle\">\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl; context: { $implicit: items, level: 0, parent: null }\">\r\n </ng-container>\r\n </ul>\r\n</nav>\r\n\r\n<!-- Recursive item renderer. Context: $implicit = items at this level,\r\n level = depth, parent = the item they hang off (null at the top). -->\r\n<ng-template #itemTpl let-items let-level=\"level\" let-parent=\"parent\">\r\n @for (item of items; track item.id; let i = $index) {\r\n @if (isGroupStart(items, i)) {\r\n <li\r\n class=\"bk-menu__group-title bk-menu__group-title--section\"\r\n [class.bk-menu__group-title--divider]=\"i > 0\"\r\n [style.paddingLeft.px]=\"groupTitleIndent(level)\"\r\n role=\"presentation\">\r\n {{ item.groupLabel }}\r\n </li>\r\n }\r\n <li\r\n class=\"bk-menu__item\"\r\n [class.bk-menu__item--has-children]=\"hasChildren(item)\"\r\n [class.bk-menu__item--open]=\"isOpen(item)\"\r\n (mouseenter)=\"onItemEnter(item, items, $event, level, parent)\"\r\n (mouseleave)=\"onItemLeave(item)\"\r\n role=\"none\">\r\n <button\r\n type=\"button\"\r\n class=\"bk-menu__button\"\r\n [class.bk-menu__button--active]=\"isHighlighted(item)\"\r\n [class.bk-menu__button--disabled]=\"item.disabled\"\r\n [class.bk-menu__button--parent]=\"hasChildren(item)\"\r\n [style.paddingLeft.px]=\"inlineIndent(level)\"\r\n [disabled]=\"item.disabled\"\r\n [attr.aria-haspopup]=\"hasChildren(item) ? 'true' : null\"\r\n [attr.aria-expanded]=\"hasChildren(item) ? isOpen(item) : null\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item, items, $event, level, parent)\">\r\n @if (item.icon) {\r\n <img class=\"bk-menu__icon\" [attr.src]=\"item.icon\" [alt]=\"item.iconAlt || item.label\" />\r\n }\r\n <span class=\"bk-menu__label\" (mouseenter)=\"onLabelEnter($event)\">{{ item.label }}</span>\r\n @if (hasChildren(item)) {\r\n <svg\r\n class=\"bk-menu__chevron\"\r\n [class.bk-menu__chevron--open]=\"!isPopup && isOpen(item)\"\r\n [class.bk-menu__chevron--right]=\"chevronDir(item, level) === 'right'\"\r\n [class.bk-menu__chevron--left]=\"chevronDir(item, level) === 'left'\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\">\r\n <path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n }\r\n </button>\r\n\r\n @if (hasChildren(item)) {\r\n <ul\r\n class=\"bk-menu__submenu\"\r\n [class.bk-menu__submenu--inline]=\"!isPopup\"\r\n [class.bk-menu__submenu--bg]=\"submenuBackground && !isPopup\"\r\n [class.bk-menu__submenu--popup]=\"isPopup\"\r\n [class.bk-menu__submenu--open]=\"isOpen(item)\"\r\n [class.bk-menu__submenu--placing]=\"isPlacing(item)\"\r\n [class.bk-menu__submenu--side-right]=\"submenuSide(item) === 'right'\"\r\n [class.bk-menu__submenu--side-left]=\"submenuSide(item) === 'left'\"\r\n [class.bk-menu__submenu--side-down]=\"submenuSide(item) === 'down'\"\r\n [class.bk-menu__submenu--side-up]=\"submenuSide(item) === 'up'\"\r\n [style.top.px]=\"popupTop(item)\"\r\n [style.left.px]=\"popupLeft(item)\"\r\n [style.maxWidth]=\"popupMaxWidth(item)\"\r\n [style.maxHeight]=\"popupMaxHeight(item)\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"item.childrenLabel || item.label\">\r\n @if (item.childrenLabel) {\r\n <li\r\n class=\"bk-menu__group-title\"\r\n [style.paddingLeft.px]=\"groupTitleIndent(level)\"\r\n (mouseenter)=\"onLabelEnter($event)\"\r\n role=\"presentation\">\r\n {{ item.childrenLabel }}\r\n </li>\r\n }\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl;\r\n context: { $implicit: item.children, level: level + 1, parent: item }\">\r\n </ng-container>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n", styles: [".bk-menu{--menu-bg: #ffffff;--menu-submenu-bg: #f8f8f8;--menu-text: #141414;--menu-subtext: #6b7080;--menu-hover-bg: #edeef0;--menu-hover-text: #141414;--menu-active-bg: #141414;--menu-active-text: #ffffff;--menu-border: #efeff1;--menu-shadow: 0 7px 18px 0 rgba(0, 0, 0, .09);--menu-radius: 8px;--menu-disabled: .5;--menu-font-size: 14px;--menu-tracking: -.28px;--menu-pad-y: 10px;--menu-submenu-pad-y: 8px;--menu-pad-x: 12px;--menu-gap: 8px;--menu-icon-size: 16px;--menu-chevron-size: 16px;--menu-group-font-size: 11px;--menu-title-outdent: 8px;--menu-popup-pad: 4px;--menu-popup-pad-y: 8px;--menu-popup-item-pad-x: 16px;--menu-popup-min-w: 200px;--menu-popup-max-w: 280px;@apply block w-full max-w-full font-medium bg-[var(--menu-bg)] text-[color:var(--menu-text)] border border-[var(--menu-border)] rounded-[var(--menu-radius)] overflow-hidden;font-size:var(--menu-font-size);letter-spacing:var(--menu-tracking)}.bk-menu--compact{--menu-radius: 6px;--menu-font-size: 12px;--menu-tracking: -.24px;--menu-pad-y: 6px;--menu-submenu-pad-y: 4px;--menu-pad-x: 8px;--menu-gap: 6px;--menu-icon-size: 14px;--menu-chevron-size: 14px;--menu-group-font-size: 10px;--menu-title-outdent: 6px;--menu-popup-pad: 3px;--menu-popup-pad-y: 6px;--menu-popup-item-pad-x: 14px;--menu-popup-min-w: 160px;--menu-popup-max-w: 240px}.bk-menu__list,.bk-menu__submenu{@apply list-none m-0 p-0;}.bk-menu__list--scroll{@apply overflow-auto;}.bk-menu--horizontal>.bk-menu__list{@apply flex flex-row items-stretch overflow-x-auto;}.bk-menu__item{@apply relative;}.bk-menu__button{@apply flex items-center w-full m-0 border-0 bg-transparent text-inherit text-left cursor-pointer whitespace-nowrap transition-colors duration-100;font:inherit;letter-spacing:inherit;gap:var(--menu-gap);padding:var(--menu-pad-y) var(--menu-pad-x)}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{@apply w-auto;}.bk-menu--vertical>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{@apply rounded-t-[var(--menu-radius)];}.bk-menu--vertical>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{@apply rounded-b-[var(--menu-radius)];}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{@apply rounded-l-[var(--menu-radius)];}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{@apply rounded-r-[var(--menu-radius)];}.bk-menu__button:hover:not(:disabled):not(.bk-menu__button--active){@apply bg-[var(--menu-hover-bg)] text-[color:var(--menu-hover-text)];}.bk-menu__button--active{@apply bg-[var(--menu-active-bg)] text-[color:var(--menu-active-text)];}.bk-menu__button--disabled,.bk-menu__button:disabled{@apply opacity-[var(--menu-disabled)] cursor-not-allowed;}.bk-menu__submenu .bk-menu__button{@apply text-[color:var(--menu-subtext)] font-normal;padding-top:var(--menu-submenu-pad-y);padding-bottom:var(--menu-submenu-pad-y)}.bk-menu__submenu--popup .bk-menu__button{padding-left:var(--menu-popup-item-pad-x);padding-right:var(--menu-popup-item-pad-x)}.bk-menu__submenu .bk-menu__button--active{@apply text-[color:var(--menu-active-text)];}.bk-menu__group-title{@apply font-semibold uppercase tracking-wider text-[color:var(--menu-subtext)] whitespace-nowrap overflow-hidden text-ellipsis select-none;font-size:var(--menu-group-font-size);padding:var(--menu-pad-y) var(--menu-pad-x) calc(var(--menu-pad-y) / 2);padding-left:calc(var(--menu-pad-x) - var(--menu-title-outdent))}.bk-menu__submenu--popup>.bk-menu__group-title{margin-left:calc(var(--menu-popup-pad) * -1);margin-right:calc(var(--menu-popup-pad) * -1);padding-left:calc(var(--menu-popup-item-pad-x) - var(--menu-title-outdent) + var(--menu-popup-pad) + 2px);padding-right:calc(var(--menu-popup-item-pad-x) + var(--menu-popup-pad) + 2px)}.bk-menu__group-title--section{@apply mb-0 tracking-wide;padding-top:calc(var(--menu-pad-y) * 1.25)}.bk-menu__group-title--divider{@apply border-t border-[var(--menu-border)];margin-top:calc(var(--menu-pad-y) / 2)}.bk-menu__icon{@apply shrink-0 object-contain;width:var(--menu-icon-size);height:var(--menu-icon-size)}.bk-menu--tint .bk-menu__icon{@apply [filter:brightness(0)_saturate(0)];}.bk-menu--tint .bk-menu__button--active .bk-menu__icon{@apply [filter:brightness(0)_invert(1)];}.bk-menu__label{@apply flex-auto min-w-0 overflow-hidden text-ellipsis;}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button>.bk-menu__label{@apply flex-none overflow-visible;}.bk-menu__chevron{@apply shrink-0 opacity-80 transition-transform duration-[.18s];width:var(--menu-chevron-size);height:var(--menu-chevron-size)}.bk-menu__chevron--open{@apply rotate-180;}.bk-menu__chevron--right{@apply -rotate-90;}.bk-menu__chevron--left{@apply rotate-90;}.bk-menu__submenu--inline{@apply overflow-hidden max-h-0 transition-[max-height] duration-200;}.bk-menu__submenu--inline.bk-menu__submenu--open{@apply max-h-[1000px];}.bk-menu__submenu--inline.bk-menu__submenu--bg{background-color:var(--menu-submenu-bg)}.bk-menu__submenu--popup{@apply fixed z-[1000] max-h-[100vh-16px] overflow-y-auto overflow-x-hidden bg-[var(--menu-bg)] border border-[var(--menu-border)] rounded-xl shadow-[var(--menu-shadow)] hidden;padding:var(--menu-popup-pad-y) var(--menu-popup-pad);min-width:var(--menu-popup-min-w);max-width:var(--menu-popup-max-w)}.bk-menu__submenu--popup.bk-menu__submenu--open{@apply block;}.bk-menu__submenu--placing{@apply opacity-0 pointer-events-none;}@media (max-width: 640px){.bk-menu--horizontal>.bk-menu__list{@apply overflow-x-auto;-webkit-overflow-scrolling:touch}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
10923
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkMenu, isStandalone: true, selector: "bk-menu", inputs: { items: "items", orientation: "orientation", submenuMode: "submenuMode", trigger: "trigger", size: "size", hoverCloseDelay: "hoverCloseDelay", singleOpen: "singleOpen", submenuBackground: "submenuBackground", emitParentClick: "emitParentClick", activeItemId: "activeItemId", tintIcons: "tintIcons", maxHeight: "maxHeight" }, outputs: { activeItemIdChange: "activeItemIdChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)", "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, usesOnChanges: true, ngImport: i0, template: "<nav\r\n class=\"bk-menu\"\r\n [class.bk-menu--vertical]=\"isVertical\"\r\n [class.bk-menu--horizontal]=\"!isVertical\"\r\n [class.bk-menu--popup]=\"isPopup\"\r\n [class.bk-menu--compact]=\"isCompact\"\r\n [class.bk-menu--tint]=\"tintIcons\"\r\n role=\"menubar\"\r\n [attr.aria-orientation]=\"orientation\">\r\n <ul\r\n class=\"bk-menu__list\"\r\n [class.bk-menu__list--scroll]=\"maxHeightStyle\"\r\n [style.maxHeight]=\"maxHeightStyle\">\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl; context: { $implicit: items, level: 0, parent: null }\">\r\n </ng-container>\r\n </ul>\r\n</nav>\r\n\r\n<!-- Recursive item renderer. Context: $implicit = items at this level,\r\n level = depth, parent = the item they hang off (null at the top). -->\r\n<ng-template #itemTpl let-items let-level=\"level\" let-parent=\"parent\">\r\n @for (item of items; track item.id; let i = $index) {\r\n @if (isGroupStart(items, i)) {\r\n <li\r\n class=\"bk-menu__group-title bk-menu__group-title--section\"\r\n [class.bk-menu__group-title--divider]=\"i > 0\"\r\n [style.paddingLeft.px]=\"groupTitleIndent(level)\"\r\n role=\"presentation\">\r\n {{ item.groupLabel }}\r\n </li>\r\n }\r\n <li\r\n class=\"bk-menu__item\"\r\n [class.bk-menu__item--has-children]=\"hasChildren(item)\"\r\n [class.bk-menu__item--open]=\"isOpen(item)\"\r\n (mouseenter)=\"onItemEnter(item, items, $event, level, parent)\"\r\n (mouseleave)=\"onItemLeave(item)\"\r\n role=\"none\">\r\n <button\r\n type=\"button\"\r\n class=\"bk-menu__button\"\r\n [class.bk-menu__button--active]=\"isHighlighted(item)\"\r\n [class.bk-menu__button--disabled]=\"item.disabled\"\r\n [class.bk-menu__button--parent]=\"hasChildren(item)\"\r\n [style.paddingLeft.px]=\"inlineIndent(level)\"\r\n [disabled]=\"item.disabled\"\r\n [attr.aria-haspopup]=\"hasChildren(item) ? 'true' : null\"\r\n [attr.aria-expanded]=\"hasChildren(item) ? isOpen(item) : null\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item, items, $event, level, parent)\">\r\n @if (item.icon) {\r\n <img class=\"bk-menu__icon\" [attr.src]=\"item.icon\" [alt]=\"item.iconAlt || item.label\" />\r\n }\r\n <span class=\"bk-menu__label\" (mouseenter)=\"onLabelEnter($event)\">{{ item.label }}</span>\r\n @if (hasChildren(item)) {\r\n <svg\r\n class=\"bk-menu__chevron\"\r\n [class.bk-menu__chevron--open]=\"!isPopup && isOpen(item)\"\r\n [class.bk-menu__chevron--right]=\"chevronDir(item, level) === 'right'\"\r\n [class.bk-menu__chevron--left]=\"chevronDir(item, level) === 'left'\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\">\r\n <path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n }\r\n </button>\r\n\r\n @if (hasChildren(item)) {\r\n <ul\r\n class=\"bk-menu__submenu\"\r\n [class.bk-menu__submenu--inline]=\"!isPopup\"\r\n [class.bk-menu__submenu--bg]=\"submenuBackground && !isPopup\"\r\n [class.bk-menu__submenu--popup]=\"isPopup\"\r\n [class.bk-menu__submenu--open]=\"isOpen(item)\"\r\n [class.bk-menu__submenu--placing]=\"isPlacing(item)\"\r\n [class.bk-menu__submenu--side-right]=\"submenuSide(item) === 'right'\"\r\n [class.bk-menu__submenu--side-left]=\"submenuSide(item) === 'left'\"\r\n [class.bk-menu__submenu--side-down]=\"submenuSide(item) === 'down'\"\r\n [class.bk-menu__submenu--side-up]=\"submenuSide(item) === 'up'\"\r\n [style.top.px]=\"popupTop(item)\"\r\n [style.left.px]=\"popupLeft(item)\"\r\n [style.maxWidth]=\"popupMaxWidth(item)\"\r\n [style.maxHeight]=\"popupMaxHeight(item)\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"item.childrenLabel || item.label\">\r\n @if (item.childrenLabel) {\r\n <li\r\n class=\"bk-menu__group-title\"\r\n [style.paddingLeft.px]=\"groupTitleIndent(level)\"\r\n (mouseenter)=\"onLabelEnter($event)\"\r\n role=\"presentation\">\r\n {{ item.childrenLabel }}\r\n </li>\r\n }\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl;\r\n context: { $implicit: item.children, level: level + 1, parent: item }\">\r\n </ng-container>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n", styles: [".bk-menu{--menu-bg: #ffffff;--menu-submenu-bg: #f8f8f8;--menu-text: #141414;--menu-subtext: #6b7080;--menu-hover-bg: #edeef0;--menu-hover-text: #141414;--menu-active-bg: #141414;--menu-active-text: #ffffff;--menu-border: #efeff1;--menu-shadow: 0 7px 18px 0 rgba(0, 0, 0, .09);--menu-radius: 8px;--menu-disabled: .5;--menu-font-size: 14px;--menu-tracking: -.28px;--menu-pad-y: 10px;--menu-submenu-pad-y: 8px;--menu-pad-x: 12px;--menu-gap: 8px;--menu-icon-size: 16px;--menu-chevron-size: 16px;--menu-group-font-size: 11px;--menu-title-outdent: 8px;--menu-popup-pad: 4px;--menu-popup-pad-y: 8px;--menu-popup-item-pad-x: 16px;--menu-popup-min-w: 200px;--menu-popup-max-w: 280px;@apply block w-full max-w-full font-medium bg-[var(--menu-bg)] text-[color:var(--menu-text)] border border-[var(--menu-border)] rounded-[var(--menu-radius)] overflow-hidden;font-size:var(--menu-font-size);letter-spacing:var(--menu-tracking)}.bk-menu--compact{--menu-radius: 6px;--menu-font-size: 12px;--menu-tracking: -.24px;--menu-pad-y: 6px;--menu-submenu-pad-y: 4px;--menu-pad-x: 8px;--menu-gap: 6px;--menu-icon-size: 14px;--menu-chevron-size: 14px;--menu-group-font-size: 10px;--menu-title-outdent: 6px;--menu-popup-pad: 3px;--menu-popup-pad-y: 6px;--menu-popup-item-pad-x: 14px;--menu-popup-min-w: 160px;--menu-popup-max-w: 240px}.bk-menu__list,.bk-menu__submenu{@apply list-none m-0 p-0;}.bk-menu__list--scroll{@apply overflow-auto;}.bk-menu--horizontal>.bk-menu__list{@apply flex flex-row items-stretch overflow-x-auto;}.bk-menu__item{@apply relative;}.bk-menu__button{@apply flex items-center w-full m-0 border-0 bg-transparent text-inherit text-left cursor-pointer whitespace-nowrap transition-colors duration-100;font:inherit;letter-spacing:inherit;gap:var(--menu-gap);padding:var(--menu-pad-y) var(--menu-pad-x)}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{@apply w-auto;}.bk-menu--vertical>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{@apply rounded-t-[var(--menu-radius)];}.bk-menu--vertical>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{@apply rounded-b-[var(--menu-radius)];}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{@apply rounded-l-[var(--menu-radius)];}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{@apply rounded-r-[var(--menu-radius)];}.bk-menu__button:hover:not(:disabled):not(.bk-menu__button--active){@apply bg-[var(--menu-hover-bg)] text-[color:var(--menu-hover-text)];}.bk-menu__button--active{@apply bg-[var(--menu-active-bg)] text-[color:var(--menu-active-text)];}.bk-menu__button--disabled,.bk-menu__button:disabled{@apply opacity-[var(--menu-disabled)] cursor-not-allowed;}.bk-menu__submenu .bk-menu__button{@apply text-[color:var(--menu-subtext)] font-normal;padding-top:var(--menu-submenu-pad-y);padding-bottom:var(--menu-submenu-pad-y)}.bk-menu__submenu--popup .bk-menu__button{padding-left:var(--menu-popup-item-pad-x);padding-right:var(--menu-popup-item-pad-x)}.bk-menu__submenu .bk-menu__button--active{@apply text-[color:var(--menu-active-text)];}.bk-menu__group-title{@apply font-semibold uppercase tracking-wider text-[color:var(--menu-subtext)] whitespace-nowrap overflow-hidden text-ellipsis select-none;font-size:var(--menu-group-font-size);padding:var(--menu-pad-y) var(--menu-pad-x) calc(var(--menu-pad-y) / 2);padding-left:calc(var(--menu-pad-x) - var(--menu-title-outdent))}.bk-menu__submenu--popup>.bk-menu__group-title{margin-left:calc(var(--menu-popup-pad) * -1);margin-right:calc(var(--menu-popup-pad) * -1);padding-left:calc(var(--menu-popup-item-pad-x) - var(--menu-title-outdent) + var(--menu-popup-pad) + 2px);padding-right:calc(var(--menu-popup-item-pad-x) + var(--menu-popup-pad) + 2px)}.bk-menu__group-title--section{@apply mb-0 tracking-wide;padding-top:calc(var(--menu-pad-y) * 1.25)}.bk-menu__group-title--divider{@apply border-t border-[var(--menu-border)];margin-top:calc(var(--menu-pad-y) / 2)}.bk-menu__icon{@apply shrink-0 object-contain;width:var(--menu-icon-size);height:var(--menu-icon-size)}.bk-menu--tint .bk-menu__icon{@apply [filter:brightness(0)_saturate(0)];}.bk-menu--tint .bk-menu__button--active .bk-menu__icon{@apply [filter:brightness(0)_invert(1)];}.bk-menu__label{@apply flex-auto min-w-0 overflow-hidden text-ellipsis;}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button>.bk-menu__label{@apply flex-none overflow-visible;}.bk-menu__chevron{@apply shrink-0 opacity-80 transition-transform duration-[.18s];width:var(--menu-chevron-size);height:var(--menu-chevron-size)}.bk-menu__chevron--open{@apply rotate-180;}.bk-menu__chevron--right{@apply -rotate-90;}.bk-menu__chevron--left{@apply rotate-90;}.bk-menu__submenu--inline{@apply overflow-hidden max-h-0 transition-[max-height] duration-200;}.bk-menu__submenu--inline.bk-menu__submenu--open{@apply max-h-[1000px];}.bk-menu__submenu--inline.bk-menu__submenu--bg{background-color:var(--menu-submenu-bg)}.bk-menu__submenu--popup{@apply fixed z-[1000] max-h-[100vh-16px] overflow-y-auto overflow-x-hidden bg-[var(--menu-bg)] border border-[var(--menu-border)] rounded-xl shadow-[var(--menu-shadow)] hidden;padding:var(--menu-popup-pad-y) var(--menu-popup-pad);min-width:var(--menu-popup-min-w);max-width:var(--menu-popup-max-w)}.bk-menu__submenu--popup.bk-menu__submenu--open{@apply block;}.bk-menu__submenu--placing{@apply opacity-0 pointer-events-none;}@media (max-width: 640px){.bk-menu--horizontal>.bk-menu__list{@apply overflow-x-auto;-webkit-overflow-scrolling:touch}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
10668
10924
|
}
|
|
10669
10925
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, decorators: [{
|
|
10670
10926
|
type: Component,
|
|
@@ -10685,6 +10941,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10685
10941
|
type: Input
|
|
10686
10942
|
}], submenuBackground: [{
|
|
10687
10943
|
type: Input
|
|
10944
|
+
}], emitParentClick: [{
|
|
10945
|
+
type: Input
|
|
10688
10946
|
}], activeItemId: [{
|
|
10689
10947
|
type: Input
|
|
10690
10948
|
}], tintIcons: [{
|
|
@@ -10707,11 +10965,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10707
10965
|
}] } });
|
|
10708
10966
|
|
|
10709
10967
|
/* =========================================================================
|
|
10710
|
-
Placement
|
|
10711
|
-
|
|
10968
|
+
Placement vocabulary for bk-popover, plus the one piece of maths CDK's
|
|
10969
|
+
connected-overlay strategy doesn't do for us: keeping the arrow centred on
|
|
10970
|
+
the *trigger* rather than the panel.
|
|
10712
10971
|
|
|
10713
|
-
|
|
10714
|
-
|
|
10972
|
+
Flip/push/viewport-clamping used to live here by hand (see git history for
|
|
10973
|
+
computePopoverPosition) — Angular CDK Overlay owns all of that now. What's
|
|
10974
|
+
left is DOM-free by design, so the rules stay readable and testable.
|
|
10715
10975
|
========================================================================= */
|
|
10716
10976
|
/** Every placement, in the order a placement picker should show them. */
|
|
10717
10977
|
const POPOVER_PLACEMENTS = [
|
|
@@ -10720,7 +10980,9 @@ const POPOVER_PLACEMENTS = [
|
|
|
10720
10980
|
'bottom-left', 'bottom', 'bottom-right',
|
|
10721
10981
|
'left-top', 'left', 'left-bottom'
|
|
10722
10982
|
];
|
|
10723
|
-
|
|
10983
|
+
/** The side CDK should try when the requested one doesn't fit — only ever the direct
|
|
10984
|
+
* opposite, never a diagonal, so the alignment word stays meaningful after a flip. */
|
|
10985
|
+
const OPPOSITE_SIDE = {
|
|
10724
10986
|
top: 'bottom',
|
|
10725
10987
|
bottom: 'top',
|
|
10726
10988
|
left: 'right',
|
|
@@ -10759,81 +11021,12 @@ function joinPlacement(side, align) {
|
|
|
10759
11021
|
return side;
|
|
10760
11022
|
return `${side}-${ALIGN_EDGES[side][align]}`;
|
|
10761
11023
|
}
|
|
11024
|
+
/** min wins when the range is inverted (arrow limit wider than the panel itself on a very
|
|
11025
|
+
* narrow/maxWidth-constrained panel), which keeps the arrow at the panel's leading edge
|
|
11026
|
+
* rather than pushing it past the trailing one. */
|
|
10762
11027
|
function clamp(value, min, max) {
|
|
10763
|
-
// min wins when the range is inverted (panel larger than the viewport), which
|
|
10764
|
-
// keeps the panel's leading edge on screen rather than its trailing one.
|
|
10765
11028
|
return Math.max(min, Math.min(value, max));
|
|
10766
11029
|
}
|
|
10767
|
-
/** Does the panel clear the viewport edge on this side of the anchor? */
|
|
10768
|
-
function fitsOnSide(side, anchor, panel, { offset, viewportPadding: pad, viewport }) {
|
|
10769
|
-
switch (side) {
|
|
10770
|
-
case 'top':
|
|
10771
|
-
return anchor.top - offset - panel.height >= pad;
|
|
10772
|
-
case 'bottom':
|
|
10773
|
-
return anchor.top + anchor.height + offset + panel.height <= viewport.height - pad;
|
|
10774
|
-
case 'left':
|
|
10775
|
-
return anchor.left - offset - panel.width >= pad;
|
|
10776
|
-
case 'right':
|
|
10777
|
-
return anchor.left + anchor.width + offset + panel.width <= viewport.width - pad;
|
|
10778
|
-
}
|
|
10779
|
-
}
|
|
10780
|
-
/** Leading edge of the panel along the cross axis, before any clamping. */
|
|
10781
|
-
function alignedStart(align, anchorStart, anchorSize, panelSize) {
|
|
10782
|
-
switch (align) {
|
|
10783
|
-
case 'start':
|
|
10784
|
-
return anchorStart;
|
|
10785
|
-
case 'end':
|
|
10786
|
-
return anchorStart + anchorSize - panelSize;
|
|
10787
|
-
case 'center':
|
|
10788
|
-
return anchorStart + anchorSize / 2 - panelSize / 2;
|
|
10789
|
-
}
|
|
10790
|
-
}
|
|
10791
|
-
/**
|
|
10792
|
-
* Places the panel against the anchor, then keeps it on screen in two ways:
|
|
10793
|
-
*
|
|
10794
|
-
* - flip: a panel with no room on the requested side moves to the opposite one,
|
|
10795
|
-
* but only if it actually fits there — flipping into a second bad fit just
|
|
10796
|
-
* trades one clipped edge for another.
|
|
10797
|
-
* - shift: the panel slides along its cross axis to stay inside the viewport.
|
|
10798
|
-
* The arrow is measured against the *anchor*, not the panel, so it keeps
|
|
10799
|
-
* pointing at the trigger however far the panel had to slide.
|
|
10800
|
-
*/
|
|
10801
|
-
function computePopoverPosition(anchor, panel, placement, options) {
|
|
10802
|
-
const { offset, viewportPadding: pad, arrowSize, flip, viewport } = options;
|
|
10803
|
-
let { side, align } = splitPlacement(placement);
|
|
10804
|
-
if (flip && !fitsOnSide(side, anchor, panel, options) && fitsOnSide(OPPOSITE[side], anchor, panel, options)) {
|
|
10805
|
-
side = OPPOSITE[side];
|
|
10806
|
-
}
|
|
10807
|
-
const vertical = side === 'top' || side === 'bottom';
|
|
10808
|
-
let top;
|
|
10809
|
-
let left;
|
|
10810
|
-
if (vertical) {
|
|
10811
|
-
top = side === 'top'
|
|
10812
|
-
? anchor.top - panel.height - offset
|
|
10813
|
-
: anchor.top + anchor.height + offset;
|
|
10814
|
-
left = clamp(alignedStart(align, anchor.left, anchor.width, panel.width), pad, viewport.width - panel.width - pad);
|
|
10815
|
-
}
|
|
10816
|
-
else {
|
|
10817
|
-
left = side === 'left'
|
|
10818
|
-
? anchor.left - panel.width - offset
|
|
10819
|
-
: anchor.left + anchor.width + offset;
|
|
10820
|
-
top = clamp(alignedStart(align, anchor.top, anchor.height, panel.height), pad, viewport.height - panel.height - pad);
|
|
10821
|
-
}
|
|
10822
|
-
const anchorCentre = vertical
|
|
10823
|
-
? anchor.left + anchor.width / 2
|
|
10824
|
-
: anchor.top + anchor.height / 2;
|
|
10825
|
-
const panelStart = vertical ? left : top;
|
|
10826
|
-
const panelSize = vertical ? panel.width : panel.height;
|
|
10827
|
-
const arrowLimit = arrowSize / 2 + ARROW_CORNER_GAP;
|
|
10828
|
-
return {
|
|
10829
|
-
top,
|
|
10830
|
-
left,
|
|
10831
|
-
side,
|
|
10832
|
-
align,
|
|
10833
|
-
placement: joinPlacement(side, align),
|
|
10834
|
-
arrowOffset: clamp(anchorCentre - panelStart, arrowLimit, panelSize - arrowLimit)
|
|
10835
|
-
};
|
|
10836
|
-
}
|
|
10837
11030
|
|
|
10838
11031
|
/** Edge length of the arrow square. Mirrored by --bk-popover-arrow in popover.css. */
|
|
10839
11032
|
const ARROW_SIZE = 10;
|
|
@@ -10869,11 +11062,36 @@ class BkPopover {
|
|
|
10869
11062
|
openDelay = input(80, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
|
|
10870
11063
|
closeDelay = input(150, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
|
|
10871
11064
|
maxWidth = input('280px', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
|
|
11065
|
+
/**
|
|
11066
|
+
* Fixed panel width, e.g. `'320px'`. Unset by default, so the panel sizes to its content
|
|
11067
|
+
* (capped by `maxWidth`) as before. Set this when the content's natural width shouldn't drive
|
|
11068
|
+
* layout — a form, a fixed-column list — so the panel doesn't reflow between opens as content
|
|
11069
|
+
* changes.
|
|
11070
|
+
*
|
|
11071
|
+
* Overrides `maxWidth` entirely while set — a plain CSS `max-width` would otherwise silently
|
|
11072
|
+
* cap a `width` larger than it (280px default), which is never what setting an exact width was
|
|
11073
|
+
* asking for. Raise `maxWidth` too only if you want *both* a starting width and a cap it can
|
|
11074
|
+
* still grow past for some other reason (e.g. a responsive breakpoint override elsewhere).
|
|
11075
|
+
*/
|
|
11076
|
+
width = input(null, ...(ngDevMode ? [{ debugName: "width" }] : []));
|
|
10872
11077
|
panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : []));
|
|
10873
11078
|
/**
|
|
10874
|
-
*
|
|
10875
|
-
*
|
|
10876
|
-
*
|
|
11079
|
+
* The max-width actually applied to the panel: whichever of `width`/`maxWidth` is in effect,
|
|
11080
|
+
* additionally capped to the viewport so the panel can never extend past the screen edge — an
|
|
11081
|
+
* oversized `width` (or a placement CDK could only push so far before running out of room)
|
|
11082
|
+
* shrinks to fit instead of overflowing. Mirrors the old hand-rolled positioner's clamp(), which
|
|
11083
|
+
* guaranteed the panel stayed fully on-screen; a bare CSS `max-width` alone doesn't provide that
|
|
11084
|
+
* once the requested size is close to (or exceeds) the viewport itself.
|
|
11085
|
+
*/
|
|
11086
|
+
effectiveMaxWidth = computed(() => {
|
|
11087
|
+
const requested = this.width() ?? this.maxWidth();
|
|
11088
|
+
return `min(${requested}, calc(100vw - 16px))`;
|
|
11089
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveMaxWidth" }] : []));
|
|
11090
|
+
/**
|
|
11091
|
+
* @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break.
|
|
11092
|
+
* The panel now always positions via Angular CDK Overlay, which portals into the shared
|
|
11093
|
+
* `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
|
|
11094
|
+
* to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
|
|
10877
11095
|
*/
|
|
10878
11096
|
appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
|
|
10879
11097
|
opened = output();
|
|
@@ -10881,50 +11099,73 @@ class BkPopover {
|
|
|
10881
11099
|
openChange = output();
|
|
10882
11100
|
anchorRef;
|
|
10883
11101
|
panelRef;
|
|
11102
|
+
popoverOverlay;
|
|
10884
11103
|
static activeInstance = null;
|
|
10885
|
-
host = inject(ElementRef);
|
|
10886
11104
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
10887
|
-
/**
|
|
10888
|
-
*
|
|
10889
|
-
*
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
11105
|
+
/** True once CDK has positioned the panel at least once since open() — the template keeps
|
|
11106
|
+
* the panel hidden until then, so the first frame (only there to be measured) never flashes
|
|
11107
|
+
* in the corner. */
|
|
11108
|
+
panelReady = signal(false, ...(ngDevMode ? [{ debugName: "panelReady" }] : []));
|
|
11109
|
+
/** Placement actually applied, once known — null before the first (positionChange) fires
|
|
11110
|
+
* (or once closed), in which case activePlacement()/side() fall back to the requested one. */
|
|
11111
|
+
resolvedPlacement = signal(null, ...(ngDevMode ? [{ debugName: "resolvedPlacement" }] : []));
|
|
10893
11112
|
/** Where the panel actually is, once positioned — may differ from `placement`. */
|
|
10894
|
-
activePlacement = computed(() => this.
|
|
11113
|
+
activePlacement = computed(() => this.resolvedPlacement() ?? this.placement(), ...(ngDevMode ? [{ debugName: "activePlacement" }] : []));
|
|
10895
11114
|
/** Side the panel sits on. Drives which edge the arrow hangs off (see CSS). */
|
|
10896
|
-
side = computed(() =>
|
|
11115
|
+
side = computed(() => splitPlacement(this.activePlacement()).side, ...(ngDevMode ? [{ debugName: "side" }] : []));
|
|
11116
|
+
/** Distance from the panel's leading edge to the arrow's centre, along the panel's cross
|
|
11117
|
+
* axis — null until measured. Recomputed from the *actual rendered rects*, not derived from
|
|
11118
|
+
* CDK's position strategy, so it's correct however CDK had to push/clamp the panel. */
|
|
11119
|
+
arrowOffsetPx = signal(null, ...(ngDevMode ? [{ debugName: "arrowOffsetPx" }] : []));
|
|
11120
|
+
/** Arrow offset along the panel's cross axis — x on top/bottom, y on left/right. */
|
|
11121
|
+
arrowLeft = computed(() => {
|
|
11122
|
+
const px = this.arrowOffsetPx();
|
|
11123
|
+
if (px == null)
|
|
11124
|
+
return null;
|
|
11125
|
+
const s = this.side();
|
|
11126
|
+
return s === 'top' || s === 'bottom' ? px : null;
|
|
11127
|
+
}, ...(ngDevMode ? [{ debugName: "arrowLeft" }] : []));
|
|
11128
|
+
arrowTop = computed(() => {
|
|
11129
|
+
const px = this.arrowOffsetPx();
|
|
11130
|
+
if (px == null)
|
|
11131
|
+
return null;
|
|
11132
|
+
const s = this.side();
|
|
11133
|
+
return s === 'left' || s === 'right' ? px : null;
|
|
11134
|
+
}, ...(ngDevMode ? [{ debugName: "arrowTop" }] : []));
|
|
11135
|
+
/**
|
|
11136
|
+
* Requested position first, its opposite side as a fallback when `flip` allows it — CDK tries
|
|
11137
|
+
* these in order and only falls to the second when the first genuinely doesn't fit. Push (on
|
|
11138
|
+
* by default) then keeps whichever one it lands on inside the viewport, matching the old
|
|
11139
|
+
* hand-rolled shift-along-the-edge behaviour. Each entry is tagged with the side/align it came
|
|
11140
|
+
* from (see positionMeta) so onPositionChange can read back which one CDK actually used.
|
|
11141
|
+
*
|
|
11142
|
+
* A stable field, computed once per open() — not a template-bound getter. A getter re-runs on
|
|
11143
|
+
* every change-detection pass (several times before CDK ever reads it), reassigning
|
|
11144
|
+
* `positionMeta` with fresh object references each time; onPositionChange would then be matching
|
|
11145
|
+
* against an array CDK was never actually given.
|
|
11146
|
+
*/
|
|
11147
|
+
popoverPositions = [];
|
|
11148
|
+
positionMeta = [];
|
|
11149
|
+
computePositions() {
|
|
11150
|
+
const { side, align } = splitPlacement(this.placement());
|
|
11151
|
+
const entries = [
|
|
11152
|
+
{ pos: toConnectedPosition(side, align, this.offset()), side, align }
|
|
11153
|
+
];
|
|
11154
|
+
if (this.flip()) {
|
|
11155
|
+
const oppositeSide = OPPOSITE_SIDE[side];
|
|
11156
|
+
entries.push({ pos: toConnectedPosition(oppositeSide, align, this.offset()), side: oppositeSide, align });
|
|
11157
|
+
}
|
|
11158
|
+
this.positionMeta = entries;
|
|
11159
|
+
this.popoverPositions = entries.map(e => e.pos);
|
|
11160
|
+
}
|
|
10897
11161
|
openTimer = null;
|
|
10898
11162
|
closeTimer = null;
|
|
10899
11163
|
pointerInPanel = false;
|
|
10900
11164
|
resizeObserver;
|
|
10901
|
-
// Panel's home in the DOM, so appendToBody can put it back before Angular's
|
|
10902
|
-
// @if removes it.
|
|
10903
|
-
originalPanelParent = null;
|
|
10904
|
-
originalPanelAnchor = null;
|
|
10905
|
-
panelInBody = false;
|
|
10906
|
-
ngAfterViewInit() {
|
|
10907
|
-
// Capture phase catches scrolling inside nested overflow containers, which
|
|
10908
|
-
// a window:scroll listener would miss entirely.
|
|
10909
|
-
window.addEventListener('scroll', this.reposition, true);
|
|
10910
|
-
window.addEventListener('resize', this.reposition);
|
|
10911
|
-
// Content can change size while open (async data, an expanding section),
|
|
10912
|
-
// which moves every edge the panel is aligned against.
|
|
10913
|
-
if (typeof ResizeObserver !== 'undefined') {
|
|
10914
|
-
this.resizeObserver = new ResizeObserver(() => this.measure());
|
|
10915
|
-
}
|
|
10916
|
-
}
|
|
10917
11165
|
ngOnDestroy() {
|
|
10918
11166
|
this.clearTimers();
|
|
10919
11167
|
this.resizeObserver?.disconnect();
|
|
10920
|
-
|
|
10921
|
-
window.removeEventListener('scroll', this.reposition, true);
|
|
10922
|
-
window.removeEventListener('resize', this.reposition);
|
|
10923
|
-
// Don't leave a relocated panel orphaned in <body> if we're torn down open.
|
|
10924
|
-
if (this.panelInBody) {
|
|
10925
|
-
this.panelRef?.nativeElement.remove();
|
|
10926
|
-
this.panelInBody = false;
|
|
10927
|
-
}
|
|
11168
|
+
this.detachOverlayScrollTracking();
|
|
10928
11169
|
if (BkPopover.activeInstance === this)
|
|
10929
11170
|
BkPopover.activeInstance = null;
|
|
10930
11171
|
}
|
|
@@ -10938,36 +11179,28 @@ class BkPopover {
|
|
|
10938
11179
|
}
|
|
10939
11180
|
BkPopover.activeInstance = this;
|
|
10940
11181
|
this.clearTimers();
|
|
10941
|
-
this.
|
|
11182
|
+
this.panelReady.set(false);
|
|
11183
|
+
this.resolvedPlacement.set(null);
|
|
11184
|
+
this.arrowOffsetPx.set(null);
|
|
11185
|
+
this.computePositions();
|
|
10942
11186
|
this.isOpen.set(true);
|
|
10943
11187
|
this.opened.emit();
|
|
10944
11188
|
this.openChange.emit(true);
|
|
10945
|
-
|
|
10946
|
-
// measured before it does — so position on the next tick.
|
|
10947
|
-
setTimeout(() => {
|
|
10948
|
-
if (!this.isOpen())
|
|
10949
|
-
return;
|
|
10950
|
-
if (this.appendToBody())
|
|
10951
|
-
this.movePanelToBody();
|
|
10952
|
-
this.measure();
|
|
10953
|
-
if (this.panelRef)
|
|
10954
|
-
this.resizeObserver?.observe(this.panelRef.nativeElement);
|
|
10955
|
-
// Attached here, not on the host, so the very click that opened the panel
|
|
10956
|
-
// has finished bubbling first — otherwise a popover opened by anything
|
|
10957
|
-
// outside its own trigger (a toolbar button calling open()) would be shut
|
|
10958
|
-
// again by its own opening click.
|
|
10959
|
-
document.addEventListener('click', this.onDocumentClick);
|
|
10960
|
-
});
|
|
11189
|
+
this.attachOverlayScrollTracking();
|
|
10961
11190
|
}
|
|
10962
11191
|
close() {
|
|
10963
11192
|
if (!this.isOpen())
|
|
10964
11193
|
return;
|
|
10965
11194
|
this.clearTimers();
|
|
11195
|
+
this.detachOverlayScrollTracking();
|
|
11196
|
+
// Disconnect rather than leave it observing a panel CDK is about to detach — a fresh
|
|
11197
|
+
// observer is (re)created lazily in onPositionChange on the next open.
|
|
10966
11198
|
this.resizeObserver?.disconnect();
|
|
10967
|
-
|
|
10968
|
-
this.restorePanel();
|
|
11199
|
+
this.resizeObserver = undefined;
|
|
10969
11200
|
this.isOpen.set(false);
|
|
10970
|
-
this.
|
|
11201
|
+
this.panelReady.set(false);
|
|
11202
|
+
this.resolvedPlacement.set(null);
|
|
11203
|
+
this.arrowOffsetPx.set(null);
|
|
10971
11204
|
this.pointerInPanel = false;
|
|
10972
11205
|
this.closed.emit();
|
|
10973
11206
|
this.openChange.emit(false);
|
|
@@ -11007,78 +11240,107 @@ class BkPopover {
|
|
|
11007
11240
|
this.pointerInPanel = false;
|
|
11008
11241
|
this.scheduleClose();
|
|
11009
11242
|
}
|
|
11010
|
-
/**
|
|
11011
|
-
|
|
11243
|
+
/**
|
|
11244
|
+
* Click-outside-to-close, driven by CDK's document-level outside-pointer-event dispatcher —
|
|
11245
|
+
* it already excludes clicks on the cdkOverlayOrigin (the anchor) by design, so onAnchorClick()
|
|
11246
|
+
* stays the sole opener/toggler. No backdrop involved, so it doesn't block page/nested-scroll-
|
|
11247
|
+
* container scroll the way a modal's would (see the phone-dropdown writeup for why that matters).
|
|
11248
|
+
*/
|
|
11249
|
+
onOverlayOutsideClick() {
|
|
11012
11250
|
if (this.trigger() !== 'click' || !this.closeOnClickOutside())
|
|
11013
11251
|
return;
|
|
11014
|
-
const target = event.target;
|
|
11015
|
-
if (this.host.nativeElement.contains(target))
|
|
11016
|
-
return;
|
|
11017
|
-
// appendToBody moves the panel out of the host, so clicking inside it would
|
|
11018
|
-
// otherwise read as an outside click.
|
|
11019
|
-
if (this.panelRef?.nativeElement.contains(target))
|
|
11020
|
-
return;
|
|
11021
11252
|
this.close();
|
|
11022
|
-
}
|
|
11253
|
+
}
|
|
11023
11254
|
onEscape() {
|
|
11024
11255
|
if (this.isOpen() && this.closeOnEscape())
|
|
11025
11256
|
this.close();
|
|
11026
11257
|
}
|
|
11027
11258
|
// --- Positioning ---
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11259
|
+
/**
|
|
11260
|
+
* CDK's default `reposition` scroll strategy only reacts to real `document`/`window` scroll —
|
|
11261
|
+
* it has no way to know an app shell might scroll a nested container instead (this one
|
|
11262
|
+
* commonly does — dashboard layouts with a fixed header/sidebar and a scrollable content pane).
|
|
11263
|
+
* A capture-phase listener on `document` still sees scroll events fired on any descendant
|
|
11264
|
+
* scrollable element (scroll doesn't bubble, but capture does) — same trick `bk-select` and the
|
|
11265
|
+
* `bk-input` phone dropdown already use. Also recomputes the arrow, since `updatePosition()`
|
|
11266
|
+
* sliding the panel along the same side doesn't necessarily fire (positionChange) — that only
|
|
11267
|
+
* fires when the *side* changes, not every pixel of a push/slide. rAF-throttled so a fast
|
|
11268
|
+
* scroll doesn't force layout on every tick.
|
|
11269
|
+
*/
|
|
11270
|
+
overlayScrollRafId = null;
|
|
11271
|
+
onOverlayScroll = () => {
|
|
11272
|
+
if (this.overlayScrollRafId != null)
|
|
11273
|
+
return;
|
|
11274
|
+
this.overlayScrollRafId = requestAnimationFrame(() => {
|
|
11275
|
+
this.overlayScrollRafId = null;
|
|
11276
|
+
this.popoverOverlay?.overlayRef?.updatePosition();
|
|
11277
|
+
if (this.panelReady())
|
|
11278
|
+
this.arrowOffsetPx.set(this.computeArrowOffset(this.side()));
|
|
11279
|
+
});
|
|
11031
11280
|
};
|
|
11032
|
-
|
|
11033
|
-
|
|
11281
|
+
attachOverlayScrollTracking() {
|
|
11282
|
+
document.addEventListener('scroll', this.onOverlayScroll, true);
|
|
11283
|
+
window.addEventListener('resize', this.onOverlayScroll);
|
|
11284
|
+
}
|
|
11285
|
+
detachOverlayScrollTracking() {
|
|
11286
|
+
document.removeEventListener('scroll', this.onOverlayScroll, true);
|
|
11287
|
+
window.removeEventListener('resize', this.onOverlayScroll);
|
|
11288
|
+
if (this.overlayScrollRafId != null) {
|
|
11289
|
+
cancelAnimationFrame(this.overlayScrollRafId);
|
|
11290
|
+
this.overlayScrollRafId = null;
|
|
11291
|
+
}
|
|
11292
|
+
}
|
|
11293
|
+
/**
|
|
11294
|
+
* Fires whenever CDK (re)applies a position, including the first one after open. Reads back
|
|
11295
|
+
* which of `popoverPositions`' tagged entries CDK actually used — matched by field value
|
|
11296
|
+
* (positionsEqual), not object reference: CDK's position strategy reconstructs its own
|
|
11297
|
+
* ConnectedPosition objects internally, so `event.connectionPair` is never `===` to the object
|
|
11298
|
+
* we handed it even when it's the exact same logical position. Recomputes the arrow from the
|
|
11299
|
+
* real rendered rects, and — on the very first call — starts observing the panel for
|
|
11300
|
+
* content-size changes and reveals it.
|
|
11301
|
+
*/
|
|
11302
|
+
onPositionChange(event) {
|
|
11303
|
+
const match = this.positionMeta.find(e => positionsEqual(e.pos, event.connectionPair));
|
|
11304
|
+
const side = match?.side ?? splitPlacement(this.placement()).side;
|
|
11305
|
+
const align = match?.align ?? splitPlacement(this.placement()).align;
|
|
11306
|
+
this.resolvedPlacement.set(joinPlacement(side, align));
|
|
11307
|
+
this.arrowOffsetPx.set(this.computeArrowOffset(side));
|
|
11308
|
+
this.panelReady.set(true);
|
|
11309
|
+
// Content can change size while open (async data, an expanding section), which moves every
|
|
11310
|
+
// edge the panel is aligned against — re-run CDK's own positioning, then ours, when it does.
|
|
11311
|
+
// observe() on an already-observed target is a harmless no-op, so no "have we done this
|
|
11312
|
+
// already" guard is needed here.
|
|
11313
|
+
if (typeof ResizeObserver !== 'undefined' && this.panelRef) {
|
|
11314
|
+
if (!this.resizeObserver) {
|
|
11315
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
11316
|
+
this.popoverOverlay?.overlayRef?.updatePosition();
|
|
11317
|
+
if (this.panelReady())
|
|
11318
|
+
this.arrowOffsetPx.set(this.computeArrowOffset(this.side()));
|
|
11319
|
+
});
|
|
11320
|
+
}
|
|
11321
|
+
this.resizeObserver.observe(this.panelRef.nativeElement);
|
|
11322
|
+
}
|
|
11323
|
+
}
|
|
11324
|
+
/**
|
|
11325
|
+
* Arrow offset along the panel's cross axis, measured from the actual rendered anchor/panel
|
|
11326
|
+
* rects rather than reverse-engineered from CDK's position strategy — correct however far CDK
|
|
11327
|
+
* had to push/clamp the panel to stay on screen.
|
|
11328
|
+
*/
|
|
11329
|
+
computeArrowOffset(side) {
|
|
11034
11330
|
const anchor = this.anchorRef?.nativeElement;
|
|
11035
11331
|
const panel = this.panelRef?.nativeElement;
|
|
11036
11332
|
if (!anchor || !panel)
|
|
11037
|
-
return;
|
|
11333
|
+
return 0;
|
|
11038
11334
|
const anchorRect = anchor.getBoundingClientRect();
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
flip: this.flip(),
|
|
11049
|
-
viewport: { width: window.innerWidth, height: window.innerHeight }
|
|
11050
|
-
}));
|
|
11051
|
-
}
|
|
11052
|
-
/** Arrow offset along the panel's cross axis — x on top/bottom, y on left/right. */
|
|
11053
|
-
arrowLeft = computed(() => {
|
|
11054
|
-
const pos = this.position();
|
|
11055
|
-
if (!pos)
|
|
11056
|
-
return null;
|
|
11057
|
-
return pos.side === 'top' || pos.side === 'bottom' ? pos.arrowOffset : null;
|
|
11058
|
-
}, ...(ngDevMode ? [{ debugName: "arrowLeft" }] : []));
|
|
11059
|
-
arrowTop = computed(() => {
|
|
11060
|
-
const pos = this.position();
|
|
11061
|
-
if (!pos)
|
|
11062
|
-
return null;
|
|
11063
|
-
return pos.side === 'left' || pos.side === 'right' ? pos.arrowOffset : null;
|
|
11064
|
-
}, ...(ngDevMode ? [{ debugName: "arrowTop" }] : []));
|
|
11065
|
-
movePanelToBody() {
|
|
11066
|
-
const panel = this.panelRef?.nativeElement;
|
|
11067
|
-
if (!panel || this.panelInBody)
|
|
11068
|
-
return;
|
|
11069
|
-
this.originalPanelParent = panel.parentNode;
|
|
11070
|
-
this.originalPanelAnchor = panel.nextSibling;
|
|
11071
|
-
document.body.appendChild(panel);
|
|
11072
|
-
this.panelInBody = true;
|
|
11073
|
-
}
|
|
11074
|
-
restorePanel() {
|
|
11075
|
-
const panel = this.panelRef?.nativeElement;
|
|
11076
|
-
if (!panel || !this.panelInBody)
|
|
11077
|
-
return;
|
|
11078
|
-
this.originalPanelParent?.insertBefore(panel, this.originalPanelAnchor);
|
|
11079
|
-
this.panelInBody = false;
|
|
11080
|
-
this.originalPanelParent = null;
|
|
11081
|
-
this.originalPanelAnchor = null;
|
|
11335
|
+
const panelRect = panel.getBoundingClientRect();
|
|
11336
|
+
const vertical = side === 'top' || side === 'bottom';
|
|
11337
|
+
const anchorCentre = vertical
|
|
11338
|
+
? anchorRect.left + anchorRect.width / 2
|
|
11339
|
+
: anchorRect.top + anchorRect.height / 2;
|
|
11340
|
+
const panelStart = vertical ? panelRect.left : panelRect.top;
|
|
11341
|
+
const panelSize = vertical ? panelRect.width : panelRect.height;
|
|
11342
|
+
const arrowLimit = ARROW_SIZE / 2 + ARROW_CORNER_GAP;
|
|
11343
|
+
return clamp(anchorCentre - panelStart, arrowLimit, panelSize - arrowLimit);
|
|
11082
11344
|
}
|
|
11083
11345
|
// --- Timers ---
|
|
11084
11346
|
scheduleClose() {
|
|
@@ -11105,27 +11367,65 @@ class BkPopover {
|
|
|
11105
11367
|
this.cancelClose();
|
|
11106
11368
|
}
|
|
11107
11369
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11108
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPopover, isStandalone: true, selector: "bk-popover", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "flip", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed", openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "attr.title": "null" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchor"], descendants: true }, { propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true }], exportAs: ["bkPopover"], ngImport: i0, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n@
|
|
11370
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPopover, isStandalone: true, selector: "bk-popover", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "flip", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed", openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "attr.title": "null" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchor"], descendants: true }, { propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true }, { propertyName: "popoverOverlay", first: true, predicate: ["popoverOverlay"], descendants: true }], exportAs: ["bkPopover"], ngImport: i0, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n cdkOverlayOrigin\r\n #popoverOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n<!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of an\r\n inline `position:fixed` div, so it escapes clipping inside dialogs/scroll containers and\r\n stacks correctly above other CDK-overlay content, regardless of the old appendToBody flag (see\r\n its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n-->\r\n<ng-template\r\n cdkConnectedOverlay\r\n #popoverOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"popoverOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"popoverPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\"\r\n>\r\n <!-- Hidden until panelReady(): the first frame exists only so CDK/we can measure it, and\r\n painting it at its initial position first flashes it in the corner. -->\r\n <div\r\n #panel\r\n class=\"bk-popover-panel\"\r\n [ngClass]=\"panelClass()\"\r\n role=\"dialog\"\r\n [attr.data-side]=\"side()\"\r\n [style.width]=\"width()\"\r\n [style.maxWidth]=\"effectiveMaxWidth()\"\r\n [class.bk-popover-ready]=\"panelReady()\"\r\n (mouseenter)=\"onPanelEnter()\"\r\n (mouseleave)=\"onPanelLeave()\"\r\n >\r\n @if (showArrow()) {\r\n <!-- A rotated square, not a border triangle: it inherits the panel's\r\n background and border, so the tip matches the panel on every side.\r\n Sits above the panel's own border, hiding the segment it crosses. -->\r\n <span\r\n class=\"bk-popover-arrow\"\r\n [style.left.px]=\"arrowLeft()\"\r\n [style.top.px]=\"arrowTop()\"\r\n ></span>\r\n }\r\n\r\n @if (title()) {\r\n <div class=\"bk-popover-header\">\r\n <span class=\"bk-popover-title\">{{ title() }}</span>\r\n @if (closable()) {\r\n <button type=\"button\" class=\"bk-popover-close\" aria-label=\"Close\" (click)=\"close()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"bk-popover-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply static z-[10000] bg-white border border-[#E3E3E7] rounded-lg p-3 cursor-default;box-shadow:0 12px 24px -6px #1018281f,0 4px 8px -4px #1018280f;visibility:hidden;opacity:0}.bk-popover-panel.bk-popover-ready{visibility:visible;opacity:1;transition:opacity .12s ease-out}.bk-popover-arrow{@apply absolute block w-2.5 h-2.5 bg-white border border-[#E3E3E7];}.bk-popover-panel[data-side=top] .bk-popover-arrow{bottom:-5px;border-top:none;border-left:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=bottom] .bk-popover-arrow{top:-5px;border-bottom:none;border-right:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=left] .bk-popover-arrow{right:-5px;border-bottom:none;border-left:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-panel[data-side=right] .bk-popover-arrow{left:-5px;border-top:none;border-right:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-header{@apply flex items-start justify-between gap-3 mb-1;}.bk-popover-title{@apply text-sm font-semibold text-[#141414];}.bk-popover-close{@apply shrink-0 text-gray-400 hover:text-[#141414] cursor-pointer -me-1 -mt-0.5;}.bk-popover-body{@apply text-sm font-normal text-[#6B7080];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
|
|
11109
11371
|
}
|
|
11110
11372
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, decorators: [{
|
|
11111
11373
|
type: Component,
|
|
11112
|
-
args: [{ selector: 'bk-popover', standalone: true, exportAs: 'bkPopover', imports: [CommonModule], host: {
|
|
11374
|
+
args: [{ selector: 'bk-popover', standalone: true, exportAs: 'bkPopover', imports: [CommonModule, OverlayModule], host: {
|
|
11113
11375
|
// A static `title="…"` lands on the input *and* stays on the host as a real
|
|
11114
11376
|
// HTML attribute, which the browser would render as its own native tooltip
|
|
11115
11377
|
// over the trigger. Stripping it here means the input can keep the obvious
|
|
11116
11378
|
// name without consumers having to remember to bind it.
|
|
11117
11379
|
'[attr.title]': 'null'
|
|
11118
|
-
}, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n@
|
|
11119
|
-
}], propDecorators: { placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], flip: [{ type: i0.Input, args: [{ isSignal: true, alias: "flip", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], openChange: [{ type: i0.Output, args: ["openChange"] }], anchorRef: [{
|
|
11380
|
+
}, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n cdkOverlayOrigin\r\n #popoverOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n<!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of an\r\n inline `position:fixed` div, so it escapes clipping inside dialogs/scroll containers and\r\n stacks correctly above other CDK-overlay content, regardless of the old appendToBody flag (see\r\n its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n-->\r\n<ng-template\r\n cdkConnectedOverlay\r\n #popoverOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"popoverOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"popoverPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\"\r\n>\r\n <!-- Hidden until panelReady(): the first frame exists only so CDK/we can measure it, and\r\n painting it at its initial position first flashes it in the corner. -->\r\n <div\r\n #panel\r\n class=\"bk-popover-panel\"\r\n [ngClass]=\"panelClass()\"\r\n role=\"dialog\"\r\n [attr.data-side]=\"side()\"\r\n [style.width]=\"width()\"\r\n [style.maxWidth]=\"effectiveMaxWidth()\"\r\n [class.bk-popover-ready]=\"panelReady()\"\r\n (mouseenter)=\"onPanelEnter()\"\r\n (mouseleave)=\"onPanelLeave()\"\r\n >\r\n @if (showArrow()) {\r\n <!-- A rotated square, not a border triangle: it inherits the panel's\r\n background and border, so the tip matches the panel on every side.\r\n Sits above the panel's own border, hiding the segment it crosses. -->\r\n <span\r\n class=\"bk-popover-arrow\"\r\n [style.left.px]=\"arrowLeft()\"\r\n [style.top.px]=\"arrowTop()\"\r\n ></span>\r\n }\r\n\r\n @if (title()) {\r\n <div class=\"bk-popover-header\">\r\n <span class=\"bk-popover-title\">{{ title() }}</span>\r\n @if (closable()) {\r\n <button type=\"button\" class=\"bk-popover-close\" aria-label=\"Close\" (click)=\"close()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"bk-popover-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply static z-[10000] bg-white border border-[#E3E3E7] rounded-lg p-3 cursor-default;box-shadow:0 12px 24px -6px #1018281f,0 4px 8px -4px #1018280f;visibility:hidden;opacity:0}.bk-popover-panel.bk-popover-ready{visibility:visible;opacity:1;transition:opacity .12s ease-out}.bk-popover-arrow{@apply absolute block w-2.5 h-2.5 bg-white border border-[#E3E3E7];}.bk-popover-panel[data-side=top] .bk-popover-arrow{bottom:-5px;border-top:none;border-left:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=bottom] .bk-popover-arrow{top:-5px;border-bottom:none;border-right:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=left] .bk-popover-arrow{right:-5px;border-bottom:none;border-left:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-panel[data-side=right] .bk-popover-arrow{left:-5px;border-top:none;border-right:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-header{@apply flex items-start justify-between gap-3 mb-1;}.bk-popover-title{@apply text-sm font-semibold text-[#141414];}.bk-popover-close{@apply shrink-0 text-gray-400 hover:text-[#141414] cursor-pointer -me-1 -mt-0.5;}.bk-popover-body{@apply text-sm font-normal text-[#6B7080];}\n"] }]
|
|
11381
|
+
}], propDecorators: { placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], flip: [{ type: i0.Input, args: [{ isSignal: true, alias: "flip", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], openChange: [{ type: i0.Output, args: ["openChange"] }], anchorRef: [{
|
|
11120
11382
|
type: ViewChild,
|
|
11121
11383
|
args: ['anchor']
|
|
11122
11384
|
}], panelRef: [{
|
|
11123
11385
|
type: ViewChild,
|
|
11124
11386
|
args: ['panel']
|
|
11387
|
+
}], popoverOverlay: [{
|
|
11388
|
+
type: ViewChild,
|
|
11389
|
+
args: ['popoverOverlay']
|
|
11125
11390
|
}], onEscape: [{
|
|
11126
11391
|
type: HostListener,
|
|
11127
11392
|
args: ['document:keydown.escape']
|
|
11128
11393
|
}] } });
|
|
11394
|
+
/** CDK's vertical axis speaks `top`/`bottom`/`center`, not `start`/`end` — unlike the
|
|
11395
|
+
* horizontal axis, it isn't RTL-mirrored, so there's no `start`/`end` to flip. */
|
|
11396
|
+
function alignToVertical(align) {
|
|
11397
|
+
if (align === 'start')
|
|
11398
|
+
return 'top';
|
|
11399
|
+
if (align === 'end')
|
|
11400
|
+
return 'bottom';
|
|
11401
|
+
return 'center';
|
|
11402
|
+
}
|
|
11403
|
+
/** One side+align combination, translated into CDK's connected-position language. */
|
|
11404
|
+
function toConnectedPosition(side, align, offsetPx) {
|
|
11405
|
+
if (side === 'top' || side === 'bottom') {
|
|
11406
|
+
return {
|
|
11407
|
+
originX: align, overlayX: align,
|
|
11408
|
+
originY: side === 'top' ? 'top' : 'bottom',
|
|
11409
|
+
overlayY: side === 'top' ? 'bottom' : 'top',
|
|
11410
|
+
offsetY: side === 'top' ? -offsetPx : offsetPx
|
|
11411
|
+
};
|
|
11412
|
+
}
|
|
11413
|
+
const vertical = alignToVertical(align);
|
|
11414
|
+
return {
|
|
11415
|
+
originY: vertical, overlayY: vertical,
|
|
11416
|
+
originX: side === 'left' ? 'start' : 'end',
|
|
11417
|
+
overlayX: side === 'left' ? 'end' : 'start',
|
|
11418
|
+
offsetX: side === 'left' ? -offsetPx : offsetPx
|
|
11419
|
+
};
|
|
11420
|
+
}
|
|
11421
|
+
/** Field-by-field equality for ConnectedPosition — CDK does not preserve object identity for
|
|
11422
|
+
* positions passed via cdkConnectedOverlayPositions, so `event.connectionPair` must be matched
|
|
11423
|
+
* by value against the entries we handed it, never by `===`. */
|
|
11424
|
+
function positionsEqual(a, b) {
|
|
11425
|
+
return a.originX === b.originX && a.originY === b.originY &&
|
|
11426
|
+
a.overlayX === b.overlayX && a.overlayY === b.overlayY &&
|
|
11427
|
+
(a.offsetX ?? 0) === (b.offsetX ?? 0) && (a.offsetY ?? 0) === (b.offsetY ?? 0);
|
|
11428
|
+
}
|
|
11129
11429
|
|
|
11130
11430
|
/**
|
|
11131
11431
|
* A stacked ("avatar list") group. Renders a set of overlapping `bk-avatar`s and
|
|
@@ -12117,7 +12417,7 @@ class BkTh extends BkCellBase {
|
|
|
12117
12417
|
popover?.close();
|
|
12118
12418
|
}
|
|
12119
12419
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
12120
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTh, isStandalone: true, selector: "th[bk-th]", inputs: { columnKeyInput: { classPropertyName: "columnKeyInput", publicName: "columnKey", isSignal: true, isRequired: false, transformFunction: null }, widthInput: { classPropertyName: "widthInput", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, sortOrder: { classPropertyName: "sortOrder", publicName: "sortOrder", isSignal: true, isRequired: false, transformFunction: null }, sortDirections: { classPropertyName: "sortDirections", publicName: "sortDirections", isSignal: true, isRequired: false, transformFunction: null }, sortPriorityInput: { classPropertyName: "sortPriorityInput", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, filterMultiple: { classPropertyName: "filterMultiple", publicName: "filterMultiple", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortOrder: "sortOrderChange", checked: "checkedChange" }, host: { properties: { "class.bk-th-sortable": "showSort()", "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "class.bk-th-align-right": "align() === 'right'", "class.bk-th-align-center": "align() === 'center'", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.width": "widthInput()", "style.text-align": "align()" }, classAttribute: "bk-th" }, usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <!-- Selection column: checkbox, plus a caret when custom selections exist. -->\r\n <div class=\"bk-th-selection\">\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n\r\n @if (selections().length) {\r\n <!-- appendToBody: see the filter popover below \u2014 same containment problem. -->\r\n <bk-popover\r\n #selectionPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-left\"\r\n [showArrow]=\"false\"\r\n [appendToBody]=\"true\"\r\n >\r\n <button type=\"button\" bkPopoverTrigger class=\"bk-th-selection-caret\" aria-label=\"Selection options\">\r\n <svg width=\"8\" height=\"5\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"#78829D\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <ul class=\"bk-table-menu\">\r\n @for (selection of selections(); track selection.text) {\r\n <li>\r\n <button type=\"button\" class=\"bk-table-menu-item\" (click)=\"runSelection(selection, selectionPop)\">\r\n {{ selection.text }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </bk-popover>\r\n }\r\n </div>\r\n} @else {\r\n <div class=\"bk-th-content\" [class.bk-th-clickable]=\"showSort()\">\r\n <!--\r\n Only the label triggers sorting. The filter icon sits outside this span so\r\n opening the menu doesn't also flip the sort order.\r\n -->\r\n <span class=\"bk-th-label\" (click)=\"onSortClick()\">\r\n <ng-content></ng-content>\r\n\r\n @if (showSort()) {\r\n <span\r\n class=\"bk-sort-icon\"\r\n [class.bk-sort-asc]=\"sortOrder() === 'ascend'\"\r\n [class.bk-sort-desc]=\"sortOrder() === 'descend'\"\r\n ></span>\r\n }\r\n\r\n @if (showSort() && sortPriority !== null && sortOrder() !== null) {\r\n <!-- Rank badge: without it, multi-sort gives no clue which column wins. -->\r\n <span class=\"bk-sort-priority\">{{ sortPriority }}</span>\r\n }\r\n </span>\r\n\r\n @if (showFilter()) {\r\n <!--\r\n appendToBody is not optional here. The panel is `position: fixed`, and a\r\n table puts two things in its way: the header cell is inside\r\n `.bk-table-container`, which scrolls, and any transformed ancestor would\r\n turn the panel's viewport coordinates into cell-relative ones. Relocating\r\n it to <body> is the only placement that survives both.\r\n -->\r\n <bk-popover\r\n #filterPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-right\"\r\n [showArrow]=\"false\"\r\n panelClass=\"bk-filter-popover\"\r\n [appendToBody]=\"true\"\r\n (opened)=\"onFilterMenuOpen()\"\r\n >\r\n <button\r\n type=\"button\"\r\n bkPopoverTrigger\r\n class=\"bk-filter-trigger\"\r\n [class.bk-filter-active]=\"isFiltered()\"\r\n aria-label=\"Filter column\"\r\n >\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M1.5 2.5h13L9.5 8.2v4.6l-3 1.7V8.2L1.5 2.5Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.3\"\r\n stroke-linejoin=\"round\"\r\n [attr.fill]=\"isFiltered() ? 'currentColor' : 'none'\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"bk-filter-menu\">\r\n <ul class=\"bk-filter-list\">\r\n @for (option of filters(); track option.value) {\r\n <li class=\"bk-filter-option\">\r\n @if (filterMultiple()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [label]=\"option.text\"\r\n [ngModel]=\"isPending(option.value)\"\r\n (ngModelChange)=\"toggleFilterOption(option.value, $event)\"\r\n ></bk-checkbox>\r\n } @else {\r\n <bk-radio-button\r\n [label]=\"option.text\"\r\n [value]=\"option.value\"\r\n [ngModel]=\"singleFilter\"\r\n (ngModelChange)=\"singleFilter = $event\"\r\n ></bk-radio-button>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <div class=\"bk-filter-actions\">\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-link\" (click)=\"resetFilter(filterPop)\">\r\n Reset\r\n </button>\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-primary\" (click)=\"applyFilter(filterPop)\">\r\n OK\r\n </button>\r\n </div>\r\n </div>\r\n </bk-popover>\r\n }\r\n </div>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkRadioButton, selector: "bk-radio-button", inputs: ["radioClass", "label", "labelClass", "value", "uncheckedValue", "allowDeselect", "disabled", "variant"], outputs: ["change"] }, { kind: "component", type: BkPopover, selector: "bk-popover", inputs: ["placement", "trigger", "title", "closable", "disabled", "showArrow", "offset", "flip", "closeOnClickOutside", "closeOnEscape", "openDelay", "closeDelay", "maxWidth", "panelClass", "appendToBody"], outputs: ["opened", "closed", "openChange"], exportAs: ["bkPopover"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
12420
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTh, isStandalone: true, selector: "th[bk-th]", inputs: { columnKeyInput: { classPropertyName: "columnKeyInput", publicName: "columnKey", isSignal: true, isRequired: false, transformFunction: null }, widthInput: { classPropertyName: "widthInput", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, sortOrder: { classPropertyName: "sortOrder", publicName: "sortOrder", isSignal: true, isRequired: false, transformFunction: null }, sortDirections: { classPropertyName: "sortDirections", publicName: "sortDirections", isSignal: true, isRequired: false, transformFunction: null }, sortPriorityInput: { classPropertyName: "sortPriorityInput", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, filterMultiple: { classPropertyName: "filterMultiple", publicName: "filterMultiple", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortOrder: "sortOrderChange", checked: "checkedChange" }, host: { properties: { "class.bk-th-sortable": "showSort()", "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "class.bk-th-align-right": "align() === 'right'", "class.bk-th-align-center": "align() === 'center'", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.width": "widthInput()", "style.text-align": "align()" }, classAttribute: "bk-th" }, usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <!-- Selection column: checkbox, plus a caret when custom selections exist. -->\r\n <div class=\"bk-th-selection\">\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n\r\n @if (selections().length) {\r\n <!-- appendToBody: see the filter popover below \u2014 same containment problem. -->\r\n <bk-popover\r\n #selectionPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-left\"\r\n [showArrow]=\"false\"\r\n [appendToBody]=\"true\"\r\n >\r\n <button type=\"button\" bkPopoverTrigger class=\"bk-th-selection-caret\" aria-label=\"Selection options\">\r\n <svg width=\"8\" height=\"5\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"#78829D\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <ul class=\"bk-table-menu\">\r\n @for (selection of selections(); track selection.text) {\r\n <li>\r\n <button type=\"button\" class=\"bk-table-menu-item\" (click)=\"runSelection(selection, selectionPop)\">\r\n {{ selection.text }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </bk-popover>\r\n }\r\n </div>\r\n} @else {\r\n <div class=\"bk-th-content\" [class.bk-th-clickable]=\"showSort()\">\r\n <!--\r\n Only the label triggers sorting. The filter icon sits outside this span so\r\n opening the menu doesn't also flip the sort order.\r\n -->\r\n <span class=\"bk-th-label\" (click)=\"onSortClick()\">\r\n <ng-content></ng-content>\r\n\r\n @if (showSort()) {\r\n <span\r\n class=\"bk-sort-icon\"\r\n [class.bk-sort-asc]=\"sortOrder() === 'ascend'\"\r\n [class.bk-sort-desc]=\"sortOrder() === 'descend'\"\r\n ></span>\r\n }\r\n\r\n @if (showSort() && sortPriority !== null && sortOrder() !== null) {\r\n <!-- Rank badge: without it, multi-sort gives no clue which column wins. -->\r\n <span class=\"bk-sort-priority\">{{ sortPriority }}</span>\r\n }\r\n </span>\r\n\r\n @if (showFilter()) {\r\n <!--\r\n appendToBody is not optional here. The panel is `position: fixed`, and a\r\n table puts two things in its way: the header cell is inside\r\n `.bk-table-container`, which scrolls, and any transformed ancestor would\r\n turn the panel's viewport coordinates into cell-relative ones. Relocating\r\n it to <body> is the only placement that survives both.\r\n -->\r\n <bk-popover\r\n #filterPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-right\"\r\n [showArrow]=\"false\"\r\n panelClass=\"bk-filter-popover\"\r\n [appendToBody]=\"true\"\r\n (opened)=\"onFilterMenuOpen()\"\r\n >\r\n <button\r\n type=\"button\"\r\n bkPopoverTrigger\r\n class=\"bk-filter-trigger\"\r\n [class.bk-filter-active]=\"isFiltered()\"\r\n aria-label=\"Filter column\"\r\n >\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M1.5 2.5h13L9.5 8.2v4.6l-3 1.7V8.2L1.5 2.5Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.3\"\r\n stroke-linejoin=\"round\"\r\n [attr.fill]=\"isFiltered() ? 'currentColor' : 'none'\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"bk-filter-menu\">\r\n <ul class=\"bk-filter-list\">\r\n @for (option of filters(); track option.value) {\r\n <li class=\"bk-filter-option\">\r\n @if (filterMultiple()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [label]=\"option.text\"\r\n [ngModel]=\"isPending(option.value)\"\r\n (ngModelChange)=\"toggleFilterOption(option.value, $event)\"\r\n ></bk-checkbox>\r\n } @else {\r\n <bk-radio-button\r\n [label]=\"option.text\"\r\n [value]=\"option.value\"\r\n [ngModel]=\"singleFilter\"\r\n (ngModelChange)=\"singleFilter = $event\"\r\n ></bk-radio-button>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <div class=\"bk-filter-actions\">\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-link\" (click)=\"resetFilter(filterPop)\">\r\n Reset\r\n </button>\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-primary\" (click)=\"applyFilter(filterPop)\">\r\n OK\r\n </button>\r\n </div>\r\n </div>\r\n </bk-popover>\r\n }\r\n </div>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkRadioButton, selector: "bk-radio-button", inputs: ["radioClass", "label", "labelClass", "value", "uncheckedValue", "allowDeselect", "disabled", "variant"], outputs: ["change"] }, { kind: "component", type: BkPopover, selector: "bk-popover", inputs: ["placement", "trigger", "title", "closable", "disabled", "showArrow", "offset", "flip", "closeOnClickOutside", "closeOnEscape", "openDelay", "closeDelay", "maxWidth", "width", "panelClass", "appendToBody"], outputs: ["opened", "closed", "openChange"], exportAs: ["bkPopover"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
12121
12421
|
}
|
|
12122
12422
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, decorators: [{
|
|
12123
12423
|
type: Component,
|
|
@@ -12770,5 +13070,5 @@ const BK_TABLE = [
|
|
|
12770
13070
|
* Generated bundle index. Do not edit.
|
|
12771
13071
|
*/
|
|
12772
13072
|
|
|
12773
|
-
export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, NEUTRAL_APPEARANCE, POPOVER_PLACEMENTS,
|
|
13073
|
+
export { ARROW_CORNER_GAP, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, DEFAULT_COUNTRY_OPTIONS, NEUTRAL_APPEARANCE, OPPOSITE_SIDE, POPOVER_PLACEMENTS, clamp, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
|
|
12774
13074
|
//# sourceMappingURL=brickclay-org-ui.mjs.map
|