@brickclay-org/ui 0.1.85 → 0.1.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, Output, Input, forwardRef, HostListener, ViewChild, Injectable, NgModule, ViewEncapsulation, Optional, Self, Directive, ChangeDetectionStrategy, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, createComponent, NgZone, ContentChild } from '@angular/core';
2
+ import { Component, EventEmitter, Output, Input, forwardRef, HostListener, ViewChild, Injectable, NgModule, ViewEncapsulation, Optional, Self, Directive, ChangeDetectionStrategy, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, NgZone, ContentChild } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, NgClass, NgTemplateOutlet } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
@@ -10,10 +10,11 @@ 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
- import { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';
17
+ import { CdkPortalOutlet, PortalModule, ComponentPortal } from '@angular/cdk/portal';
17
18
  import { toObservable } from '@angular/core/rxjs-interop';
18
19
 
19
20
  // Icon paths that will be resolved relative to the library's assets folder
@@ -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
  };
@@ -4820,6 +4823,8 @@ class BkGrid {
4820
4823
  noRecordFoundHeight = '';
4821
4824
  /** Custom illustration for the empty state. Falls back to a built-in SVG when omitted. */
4822
4825
  noRecordImgUrl;
4826
+ /** Show the empty-state illustration above the message. Set false to show the message only. */
4827
+ showNoRecordImg = true;
4823
4828
  noRecordMessage = 'Data may be empty, or try adjusting your filter.';
4824
4829
  /** Static row class or a function that returns a class per row. Row data may also include `class` via TableRows. */
4825
4830
  rows;
@@ -4990,14 +4995,14 @@ class BkGrid {
4990
4995
  });
4991
4996
  }
4992
4997
  get noRecordImagePath() {
4993
- return this.noRecordImgUrl || './assets/media/logos/no-data-found.jpg';
4998
+ return this.noRecordImgUrl || './assets/icons/no-data-found.jpg';
4994
4999
  }
4995
5000
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
4996
- 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"] }] });
4997
5002
  }
4998
5003
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, decorators: [{
4999
5004
  type: Component,
5000
- 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"] }]
5001
5006
  }], propDecorators: { draggable: [{
5002
5007
  type: Input
5003
5008
  }], columns: [{
@@ -5018,6 +5023,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5018
5023
  type: Input
5019
5024
  }], noRecordImgUrl: [{
5020
5025
  type: Input
5026
+ }], showNoRecordImg: [{
5027
+ type: Input
5021
5028
  }], noRecordMessage: [{
5022
5029
  type: Input
5023
5030
  }], rows: [{
@@ -5454,10 +5461,21 @@ class BkSelect {
5454
5461
  disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5455
5462
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
5456
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" }] : []));
5457
5470
  dropdownPosition = input('bottom', ...(ngDevMode ? [{ debugName: "dropdownPosition" }] : []));
5458
5471
  hasError = false;
5459
5472
  errorMessage = '';
5460
- // 1. NEW INPUT: Toggle append-to-body behavior
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
+ */
5461
5479
  appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
5462
5480
  // --- Outputs ---
5463
5481
  open = output();
@@ -5474,6 +5492,7 @@ class BkSelect {
5474
5492
  optionsRef;
5475
5493
  controlWrapper;
5476
5494
  dropdownPanel;
5495
+ selectOverlay;
5477
5496
  chipsViewport;
5478
5497
  measureChips;
5479
5498
  measurePlus;
@@ -5487,26 +5506,21 @@ class BkSelect {
5487
5506
  gridDraftOptions = signal([], ...(ngDevMode ? [{ debugName: "gridDraftOptions" }] : []));
5488
5507
  searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
5489
5508
  markedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "markedIndex" }] : []));
5490
- // Side the panel is actually rendered on. Starts from the requested
5491
- // `dropdownPosition` but is auto-flipped based on available viewport space
5492
- // (see applyPlacement). Used by both append-to-body and inline modes.
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.
5493
5512
  placement = signal('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
5494
- // When appendToBody is on we physically relocate the panel to <body> so it
5495
- // escapes any transformed/overflow ancestor (e.g. an animated dialog, whose
5496
- // residual transform would otherwise make position:fixed resolve against the
5497
- // dialog and get clipped). These track the panel's home so we can put it back
5498
- // before Angular removes it on close.
5499
- originalPanelParent = null;
5500
- originalPanelAnchor = null;
5501
- panelInBody = false;
5502
5513
  // Number of multi-select chips currently rendered before collapsing into "+N".
5503
5514
  // Computed dynamically from the available width (see recomputeVisibleChips()).
5504
5515
  visibleCount = signal(0, ...(ngDevMode ? [{ debugName: "visibleCount" }] : []));
5505
5516
  resizeObserver;
5506
- dropdownStyle = signal({
5507
- left: '0px',
5508
- width: 'auto'
5509
- }, ...(ngDevMode ? [{ debugName: "dropdownStyle" }] : []));
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" }] : []));
5510
5524
  filteredItems = computed(() => {
5511
5525
  const term = this.searchTerm().toLowerCase();
5512
5526
  const list = this.items();
@@ -5550,105 +5564,59 @@ class BkSelect {
5550
5564
  });
5551
5565
  }
5552
5566
  ngAfterViewInit() {
5553
- // Recompute visible chips whenever the control is resized (responsive
5554
- // 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.).
5555
5569
  if (typeof ResizeObserver !== 'undefined') {
5556
- this.resizeObserver = new ResizeObserver(() => this.scheduleRecompute());
5570
+ this.resizeObserver = new ResizeObserver(() => {
5571
+ this.scheduleRecompute();
5572
+ if (this.isOpen())
5573
+ this.dropdownWidth.set(this.controlWrapper.nativeElement.offsetWidth);
5574
+ });
5557
5575
  if (this.controlWrapper?.nativeElement) {
5558
5576
  this.resizeObserver.observe(this.controlWrapper.nativeElement);
5559
5577
  }
5560
5578
  }
5561
5579
  this.scheduleRecompute();
5562
- // Keep the append-to-body (fixed) panel glued to the control while any
5563
- // ancestor scrolls or the window resizes. Capture phase (`true`) is what
5564
- // lets us catch scrolling inside nested overflow containers, not just the
5565
- // window — @HostListener('window:scroll') would miss those.
5566
- window.addEventListener('scroll', this.reposition, true);
5567
- window.addEventListener('resize', this.reposition);
5568
5580
  }
5569
5581
  ngOnDestroy() {
5570
5582
  this.resizeObserver?.disconnect();
5571
- window.removeEventListener('scroll', this.reposition, true);
5572
- window.removeEventListener('resize', this.reposition);
5573
- // If we're torn down while open, don't leave the relocated panel orphaned in <body>.
5574
- if (this.panelInBody) {
5575
- this.dropdownPanel?.nativeElement.remove();
5576
- this.panelInBody = false;
5577
- }
5578
- }
5579
- // Re-evaluate placement as the page scrolls/resizes. For append-to-body this
5580
- // recomputes the fixed coordinates so the panel follows the control while it's
5581
- // visible, and closes once the control is fully scrolled out of view (by the
5582
- // viewport OR any scroll container such as a modal body). Inline just re-flips.
5583
- // Bound as an arrow fn so it can be add/removeEventListener'd.
5584
- reposition = () => {
5585
- if (!this.isOpen())
5586
- return;
5587
- if (this.appendToBody()) {
5588
- const rect = this.controlWrapper?.nativeElement.getBoundingClientRect();
5589
- if (rect && this.isControlClipped(rect)) {
5590
- this.closeDropdown();
5591
- return;
5592
- }
5593
- }
5594
- this.applyPlacement();
5595
- };
5596
- /**
5597
- * True when the control is fully outside the visible area — either the
5598
- * viewport or a scrollable/clipping ancestor (e.g. a dialog's scroll body).
5599
- * Used to close the floating (append-to-body) panel once its anchor is no
5600
- * longer on screen, instead of leaving it hanging.
5601
- */
5602
- isControlClipped(rect) {
5603
- // Outside the viewport.
5604
- if (rect.bottom <= 0 || rect.top >= window.innerHeight ||
5605
- rect.right <= 0 || rect.left >= window.innerWidth) {
5606
- return true;
5607
- }
5608
- // Outside any clipping ancestor.
5609
- let el = this.controlWrapper?.nativeElement.parentElement;
5610
- while (el && el !== document.body) {
5611
- const style = getComputedStyle(el);
5612
- const clips = /(auto|scroll|hidden|clip|overlay)/;
5613
- if (clips.test(style.overflowY) || clips.test(style.overflowX)) {
5614
- const r = el.getBoundingClientRect();
5615
- if (rect.bottom <= r.top || rect.top >= r.bottom ||
5616
- rect.right <= r.left || rect.left >= r.right) {
5617
- return true;
5618
- }
5619
- }
5620
- el = el.parentElement;
5621
- }
5622
- return false;
5583
+ this.detachOverlayScrollTracking();
5623
5584
  }
5624
5585
  /**
5625
- * Relocate the panel node to <body> so it truly escapes any transformed or
5626
- * overflow-clipped ancestor (dialogs, drawers, cards with overflow, etc.).
5627
- * Setting position:fixed alone is not enough when an ancestor has a transform.
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.
5628
5593
  */
5629
- movePanelToBody() {
5630
- const panel = this.dropdownPanel?.nativeElement;
5631
- if (!panel || this.panelInBody)
5594
+ overlayScrollRafId = null;
5595
+ onOverlayScroll = () => {
5596
+ if (this.overlayScrollRafId != null)
5632
5597
  return;
5633
- this.originalPanelParent = panel.parentNode;
5634
- this.originalPanelAnchor = panel.nextSibling;
5635
- document.body.appendChild(panel);
5636
- this.panelInBody = true;
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);
5637
5606
  }
5638
- /**
5639
- * Return the panel to its original DOM position so Angular's @if can remove
5640
- * it cleanly on close. Must run before isOpen is set to false.
5641
- */
5642
- restorePanel() {
5643
- const panel = this.dropdownPanel?.nativeElement;
5644
- if (!panel || !this.panelInBody)
5645
- return;
5646
- if (this.originalPanelParent) {
5647
- 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;
5648
5613
  }
5649
- this.panelInBody = false;
5650
- this.originalPanelParent = null;
5651
- this.originalPanelAnchor = null;
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');
5652
5620
  }
5653
5621
  scheduleRecompute() {
5654
5622
  // Defer to the next frame so the hidden measurement row has been laid out.
@@ -5790,6 +5758,7 @@ class BkSelect {
5790
5758
  openDropdown() {
5791
5759
  if (this.isOpen())
5792
5760
  return;
5761
+ this.opening = true;
5793
5762
  this.panelReady.set(false);
5794
5763
  // Close previously opened dropdown
5795
5764
  if (BkSelect.activeInstance && BkSelect.activeInstance !== this) {
@@ -5799,37 +5768,64 @@ class BkSelect {
5799
5768
  if (this.usesGridDraft()) {
5800
5769
  this.gridDraftOptions.set([...this.selectedOptions()]);
5801
5770
  }
5802
- // Decide the initial side before the panel paints (uses an estimated
5803
- // height; corrected after render in the setTimeout below).
5804
- this.applyPlacement();
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();
5805
5779
  this.isOpen.set(true);
5806
5780
  this.open.emit();
5807
5781
  this.focus.emit();
5808
5782
  setTimeout(() => {
5809
5783
  if (!this.isOpen())
5810
5784
  return;
5811
- // Panel is in the DOM now. In appendToBody mode, relocate it to <body>
5812
- // so it escapes any transformed/overflow ancestor, then position it.
5813
- if (this.appendToBody())
5814
- this.movePanelToBody();
5815
- // Recompute with the panel's real height so the initial up/down flip is
5816
- // accurate (openDropdown ran applyPlacement() before the panel existed,
5817
- // using an estimated height).
5818
- this.applyPlacement();
5785
+ // Position/flip is now entirely CDK's job (see selectDropdownPositions +
5786
+ // onPositionChange) nothing to compute here anymore.
5819
5787
  this.panelReady.set(true);
5820
- if (this.searchable()) {
5821
- this.searchInput?.nativeElement.focus();
5822
- }
5823
- else {
5824
- this.controlWrapper?.nativeElement.focus();
5825
- }
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
+ });
5826
5822
  });
5827
5823
  }
5828
5824
  closeDropdown() {
5829
5825
  if (!this.isOpen())
5830
5826
  return;
5831
- // Put the panel back where Angular expects it before the @if removes it.
5832
- this.restorePanel();
5827
+ this.opening = false;
5828
+ this.detachOverlayScrollTracking();
5833
5829
  this.isOpen.set(false);
5834
5830
  this.panelReady.set(false);
5835
5831
  this.searchTerm.set('');
@@ -5840,74 +5836,16 @@ class BkSelect {
5840
5836
  BkSelect.activeInstance = null;
5841
5837
  }
5842
5838
  }
5843
- getTop() {
5844
- if (this.appendToBody()) {
5845
- return this.dropdownStyle().top ?? null;
5846
- }
5847
- // NOT appendToBody — use the auto-flipped placement, not the raw input.
5848
- return this.placement() === 'bottom' ? '105%' : null;
5849
- }
5850
- getBottom() {
5851
- if (this.appendToBody()) {
5852
- return this.dropdownStyle().bottom ?? null;
5853
- }
5854
- // NOT appendToBody — use the auto-flipped placement, not the raw input.
5855
- return this.placement() === 'top' ? 'calc(100% + 4px)' : null;
5856
- }
5857
5839
  /**
5858
- * Decides which side the panel should open on (auto-flip) and, for
5859
- * append-to-body mode, computes the fixed coordinates. Shared by both modes
5860
- * and re-run on open and on every scroll/resize so the panel snaps to
5861
- * 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.
5862
5843
  */
5863
- applyPlacement() {
5864
- const control = this.controlWrapper?.nativeElement;
5865
- if (!control)
5866
- return;
5867
- const rect = control.getBoundingClientRect();
5868
- const gap = 4;
5869
- // Actual panel height once it's rendered; fall back to a sensible estimate
5870
- // on the very first open (panel isn't in the DOM yet at that point — a
5871
- // follow-up call after render corrects it with the real height).
5872
- const panelHeight = this.dropdownPanel?.nativeElement.offsetHeight || 300;
5873
- const spaceBelow = window.innerHeight - rect.bottom - gap;
5874
- const spaceAbove = rect.top - gap;
5875
- // Honour the requested position when it fits; otherwise flip to wherever
5876
- // there's more room.
5877
- const preferred = this.dropdownPosition();
5878
- let placeTop;
5879
- if (preferred === 'top') {
5880
- placeTop = spaceAbove >= panelHeight || spaceAbove > spaceBelow;
5881
- }
5882
- else {
5883
- placeTop = spaceBelow < panelHeight && spaceAbove > spaceBelow;
5884
- }
5885
- this.placement.set(placeTop ? 'top' : 'bottom');
5886
- // Inline (absolute) mode is positioned by CSS relative to the control, so
5887
- // the placement signal above is all it needs. Only append-to-body needs
5888
- // explicit fixed coordinates.
5889
- if (!this.appendToBody())
5890
- return;
5891
- if (placeTop) {
5892
- this.dropdownStyle.set({
5893
- top: undefined,
5894
- bottom: `${window.innerHeight - rect.top + gap}px`,
5895
- left: `${rect.left}px`,
5896
- width: `${rect.width}px`
5897
- });
5898
- }
5899
- else {
5900
- this.dropdownStyle.set({
5901
- top: `${rect.bottom + gap}px`,
5902
- bottom: undefined,
5903
- left: `${rect.left}px`,
5904
- width: `${rect.width}px`
5905
- });
5906
- }
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];
5907
5848
  }
5908
- // Scroll/resize are handled by the capture-phase listeners wired up in
5909
- // ngAfterViewInit (see `reposition`), which keep the panel attached to the
5910
- // control and re-flip it up/down as space allows, instead of closing it.
5911
5849
  // ... (toggleSelectAll, handleSelection, removeOption, handleClear logic same as before) ...
5912
5850
  toggleSelectAll(event) {
5913
5851
  event.stopPropagation();
@@ -6014,6 +5952,43 @@ class BkSelect {
6014
5952
  this.markedIndex.set(0);
6015
5953
  this.search.emit({ term: val, items: this.filteredItems() });
6016
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
+ }
6017
5992
  onKeyDown(event) {
6018
5993
  if (!this.isOpen()) {
6019
5994
  if (event.key === 'Enter' || event.key === ' ') {
@@ -6022,7 +5997,7 @@ class BkSelect {
6022
5997
  }
6023
5998
  return;
6024
5999
  }
6025
- const list = this.filteredItems();
6000
+ const list = this.flatOptions();
6026
6001
  const current = this.markedIndex();
6027
6002
  switch (event.key) {
6028
6003
  case 'Tab':
@@ -6107,22 +6082,108 @@ class BkSelect {
6107
6082
  this.selectedOptions.set(matchedItems);
6108
6083
  }
6109
6084
  el = inject(ElementRef);
6110
- onClickOutside(e) {
6111
- const target = e.target;
6112
- // When appendToBody relocates the panel to <body>, it's no longer inside
6113
- // the host element treat clicks within the panel as "inside" too so
6114
- // interacting with the search box / scrollbar doesn't close it.
6115
- if (this.el.nativeElement.contains(target))
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())
6116
6122
  return;
6117
- if (this.dropdownPanel?.nativeElement.contains(target))
6123
+ if (this.pointerFocus)
6118
6124
  return;
6119
- this.closeDropdown();
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);
6120
6171
  }
6121
6172
  openFromLabel(event) {
6122
6173
  event.preventDefault();
6123
6174
  event.stopPropagation();
6124
6175
  if (this.disabled() || this.readonly())
6125
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
+ }
6126
6187
  this.controlWrapper.nativeElement.focus();
6127
6188
  this.openDropdown();
6128
6189
  }
@@ -6231,23 +6292,23 @@ class BkSelect {
6231
6292
  this.markedIndex.set(index);
6232
6293
  }
6233
6294
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
6234
- 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: { "document:click": "onClickOutside($event)" } }, providers: [
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: [
6235
6296
  {
6236
6297
  provide: NG_VALUE_ACCESSOR,
6237
6298
  useExisting: forwardRef(() => BkSelect),
6238
6299
  multi: true
6239
6300
  }
6240
- ], 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"] }] });
6241
6302
  }
6242
6303
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
6243
6304
  type: Component,
6244
- 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: [
6245
6306
  {
6246
6307
  provide: NG_VALUE_ACCESSOR,
6247
6308
  useExisting: forwardRef(() => BkSelect),
6248
6309
  multi: true
6249
6310
  }
6250
- ], 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"] }]
6251
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: [{
6252
6313
  type: Input
6253
6314
  }], label: [{
@@ -6258,7 +6319,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6258
6319
  type: Input
6259
6320
  }], iconSrc: [{
6260
6321
  type: Input
6261
- }], 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: [{
6262
6323
  type: Input
6263
6324
  }], errorMessage: [{
6264
6325
  type: Input
@@ -6277,6 +6338,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6277
6338
  }], dropdownPanel: [{
6278
6339
  type: ViewChild,
6279
6340
  args: ['dropdownPanel']
6341
+ }], selectOverlay: [{
6342
+ type: ViewChild,
6343
+ args: ['selectOverlay']
6280
6344
  }], chipsViewport: [{
6281
6345
  type: ViewChild,
6282
6346
  args: ['chipsViewport']
@@ -6286,11 +6350,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6286
6350
  }], measurePlus: [{
6287
6351
  type: ViewChild,
6288
6352
  args: ['measurePlus']
6289
- }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onClickOutside: [{
6353
+ }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onPointerDown: [{
6290
6354
  type: HostListener,
6291
- args: ['document:click', ['$event']]
6355
+ args: ['pointerdown']
6356
+ }], onFocusIn: [{
6357
+ type: HostListener,
6358
+ args: ['focusin', ['$event']]
6359
+ }], onFocusOut: [{
6360
+ type: HostListener,
6361
+ args: ['focusout']
6292
6362
  }] } });
6293
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
+ ];
6294
6374
  class BkInput {
6295
6375
  // =================== Inputs (all your original ones) ===================
6296
6376
  id;
@@ -6322,16 +6402,24 @@ class BkInput {
6322
6402
  currencyDecimals = 2;
6323
6403
  allowNegative = false;
6324
6404
  countryCode = 'US';
6325
- countryOptions = [
6326
- { code: 'US', name: 'US', mask: '(000) 000-0000', prefix: '+1 ', placeholder: '(000) 000-0000' },
6327
- { code: 'MT', name: 'MT', mask: '(000) 000-0000', prefix: '+356 ', placeholder: '(000) 000-0000' },
6328
- { code: 'PL', name: 'PL', mask: '(000) 000-0000', prefix: '+48 ', placeholder: '(000) 000-0000' },
6329
- { code: 'CH', name: 'CH', mask: '(000) 000-0000', prefix: '+41 ', placeholder: '(000) 000-0000' },
6330
- { code: 'TR', name: 'TR', mask: '(000) 000-0000', prefix: '+90 ', placeholder: '(000) 000-0000' },
6331
- { code: 'UG', name: 'UG', mask: '(000) 000-0000', prefix: '+256 ', placeholder: '(000) 000-0000' },
6332
- { code: 'ZM', name: 'ZM', mask: '(000) 000-0000', prefix: '+260 ', placeholder: '(000) 000-0000' }
6333
- ];
6334
- selectedCountry = this.countryOptions[0];
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];
6335
6423
  iconOrientation = 'left';
6336
6424
  password = false;
6337
6425
  showPassword = false;
@@ -6342,16 +6430,26 @@ class BkInput {
6342
6430
  maxlength = null;
6343
6431
  minlength = null;
6344
6432
  // =================== ViewChild ===================
6345
- dropdownRef;
6346
- selectRef;
6347
6433
  inputField;
6348
6434
  maskDirective;
6435
+ phoneOverlay;
6349
6436
  // =================== Internal State ===================
6350
6437
  isFocused = false;
6351
6438
  inputValue = '';
6352
6439
  isDropdownOpen = false;
6353
6440
  pendingMaskedValue = null;
6354
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
+ ];
6355
6453
  // =================== Output Emitter ===================
6356
6454
  input = new EventEmitter();
6357
6455
  change = new EventEmitter();
@@ -6360,8 +6458,7 @@ class BkInput {
6360
6458
  clicked = new EventEmitter();
6361
6459
  get placeHolderText() {
6362
6460
  if (this.phone) {
6363
- const country = this.countryOptions.find(c => c.code === this.countryCode);
6364
- return country?.placeholder || '';
6461
+ return this.selectedCountry?.placeholder || this.placeholder || '';
6365
6462
  }
6366
6463
  if (this.currency && !this.placeholder) {
6367
6464
  return this.currencyDecimals > 0 ? `0.${'0'.repeat(this.currencyDecimals)}` : '0';
@@ -6374,15 +6471,13 @@ class BkInput {
6374
6471
  if (this.currency)
6375
6472
  return `separator.${this.currencyDecimals}`;
6376
6473
  if (this.phone) {
6377
- const country = this.countryOptions.find(c => c.code === this.countryCode);
6378
- return country?.mask || '';
6474
+ return this.selectedCountry?.mask || '';
6379
6475
  }
6380
6476
  return '';
6381
6477
  }
6382
6478
  get maskPrefixValue() {
6383
6479
  if (this.phone) {
6384
- const country = this.countryOptions.find(c => c.code === this.countryCode);
6385
- return country?.prefix || '';
6480
+ return this.selectedCountry?.prefix || '';
6386
6481
  }
6387
6482
  return '';
6388
6483
  }
@@ -6454,7 +6549,7 @@ class BkInput {
6454
6549
  // =================== Lifecycle ===================
6455
6550
  closeAllDropdownsHandler = () => {
6456
6551
  if (this.phone && this.isDropdownOpen)
6457
- this.isDropdownOpen = false;
6552
+ this.closeDropdown();
6458
6553
  };
6459
6554
  ngOnInit() {
6460
6555
  if (this.value !== undefined && this.value !== null && this.value !== '') {
@@ -6464,8 +6559,10 @@ class BkInput {
6464
6559
  this.type = 'password';
6465
6560
  if (this.phone) {
6466
6561
  const country = this.countryOptions.find(c => c.code === this.countryCode);
6467
- if (country)
6468
- this.selectedCountry = country;
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;
6469
6566
  document.addEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
6470
6567
  }
6471
6568
  }
@@ -6477,18 +6574,7 @@ class BkInput {
6477
6574
  ngOnDestroy() {
6478
6575
  if (this.phone) {
6479
6576
  document.removeEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
6480
- }
6481
- }
6482
- // =================== Host Listener ===================
6483
- onDocumentClick(event) {
6484
- if (this.phone && this.isDropdownOpen) {
6485
- const target = event.target;
6486
- if (this.selectRef?.nativeElement && this.dropdownRef?.nativeElement) {
6487
- const clickedInside = this.selectRef.nativeElement.contains(target) ||
6488
- this.dropdownRef.nativeElement.contains(target);
6489
- if (!clickedInside)
6490
- this.isDropdownOpen = false;
6491
- }
6577
+ this.detachPhoneOverlayScrollTracking();
6492
6578
  }
6493
6579
  }
6494
6580
  // =================== Event Handlers ===================
@@ -6539,14 +6625,54 @@ class BkInput {
6539
6625
  if (!this.disabled && this.phone) {
6540
6626
  if (!this.isDropdownOpen) {
6541
6627
  document.dispatchEvent(new CustomEvent('closeAllPhoneDropdowns'));
6542
- setTimeout(() => (this.isDropdownOpen = true), 0);
6628
+ this.isDropdownOpen = true;
6629
+ this.attachPhoneOverlayScrollTracking();
6543
6630
  }
6544
6631
  else {
6545
- this.isDropdownOpen = false;
6632
+ this.closeDropdown();
6546
6633
  }
6547
6634
  event?.stopPropagation();
6548
6635
  }
6549
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
+ }
6550
6676
  selectCountry(country) {
6551
6677
  const oldCountry = this.selectedCountry;
6552
6678
  this.selectedCountry = country;
@@ -6624,25 +6750,25 @@ class BkInput {
6624
6750
  this.pendingMaskedValue = null;
6625
6751
  }
6626
6752
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
6627
- 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" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
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: [
6628
6754
  provideNgxMask(),
6629
6755
  {
6630
6756
  provide: NG_VALUE_ACCESSOR,
6631
6757
  useExisting: forwardRef(() => BkInput),
6632
6758
  multi: true
6633
6759
  }
6634
- ], 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"] }] });
6635
6761
  }
6636
6762
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, decorators: [{
6637
6763
  type: Component,
6638
- args: [{ selector: 'bk-input', imports: [CommonModule, NgxMaskDirective, FormsModule], standalone: true, providers: [
6764
+ args: [{ selector: 'bk-input', imports: [CommonModule, NgxMaskDirective, FormsModule, OverlayModule], standalone: true, providers: [
6639
6765
  provideNgxMask(),
6640
6766
  {
6641
6767
  provide: NG_VALUE_ACCESSOR,
6642
6768
  useExisting: forwardRef(() => BkInput),
6643
6769
  multi: true
6644
6770
  }
6645
- ], 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"] }]
6646
6772
  }], propDecorators: { id: [{
6647
6773
  type: Input
6648
6774
  }], name: [{
@@ -6719,18 +6845,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6719
6845
  type: Input
6720
6846
  }], minlength: [{
6721
6847
  type: Input
6722
- }], dropdownRef: [{
6723
- type: ViewChild,
6724
- args: ['dropdownRef']
6725
- }], selectRef: [{
6726
- type: ViewChild,
6727
- args: ['selectRef']
6728
6848
  }], inputField: [{
6729
6849
  type: ViewChild,
6730
6850
  args: ['inputField']
6731
6851
  }], maskDirective: [{
6732
6852
  type: ViewChild,
6733
6853
  args: [NgxMaskDirective]
6854
+ }], phoneOverlay: [{
6855
+ type: ViewChild,
6856
+ args: ['phoneOverlay']
6734
6857
  }], input: [{
6735
6858
  type: Output
6736
6859
  }], change: [{
@@ -6741,9 +6864,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6741
6864
  type: Output
6742
6865
  }], clicked: [{
6743
6866
  type: Output
6744
- }], onDocumentClick: [{
6745
- type: HostListener,
6746
- args: ['document:click', ['$event']]
6747
6867
  }] } });
6748
6868
 
6749
6869
  class BkInputChips {
@@ -8683,7 +8803,12 @@ class BkHierarchicalSelect {
8683
8803
  /** Search placeholder. */
8684
8804
  searchPlaceholder = input('Search', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
8685
8805
  searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
8686
- /** When true, dropdown is positioned fixed and sized to the trigger (use inside modals/popups). */
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
+ */
8687
8812
  appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
8688
8813
  /** Open above or below the trigger (also used when appendToBody is true for fixed coordinates). */
8689
8814
  dropdownPosition = input('bottom', ...(ngDevMode ? [{ debugName: "dropdownPosition" }] : []));
@@ -8714,16 +8839,23 @@ class BkHierarchicalSelect {
8714
8839
  searchInput;
8715
8840
  controlWrapper;
8716
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" }] : []));
8717
8847
  el = inject(ElementRef);
8718
- // Side the panel is actually rendered on. Starts from the requested
8719
- // `dropdownPosition` but is auto-flipped based on available viewport space.
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.
8720
8851
  placement = signal('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
8721
- // When appendToBody is on we physically relocate the panel to <body> so it
8722
- // escapes any transformed/overflow ancestor (e.g. an animated dialog). These
8723
- // track its home so we can put it back before Angular removes it on close.
8724
- originalPanelParent = null;
8725
- originalPanelAnchor = null;
8726
- panelInBody = false;
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;
8727
8859
  constructor() {
8728
8860
  effect(() => {
8729
8861
  const list = this.items();
@@ -8737,101 +8869,188 @@ class BkHierarchicalSelect {
8737
8869
  });
8738
8870
  }
8739
8871
  ngAfterViewInit() {
8740
- // Keep the panel glued to the control while any ancestor scrolls or the
8741
- // window resizes. Capture phase (`true`) catches scrolling inside nested
8742
- // overflow containers (e.g. a modal body), not just the window.
8743
- window.addEventListener('scroll', this.reposition, true);
8744
- window.addEventListener('resize', this.reposition);
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
+ }
8745
8883
  }
8746
8884
  ngOnDestroy() {
8747
- window.removeEventListener('scroll', this.reposition, true);
8748
- window.removeEventListener('resize', this.reposition);
8749
- // If we're torn down while open, don't leave the relocated panel orphaned in <body>.
8750
- if (this.panelInBody) {
8751
- this.dropdownPanel?.nativeElement.remove();
8752
- this.panelInBody = false;
8753
- }
8754
- }
8755
- // Re-evaluate placement as the page scrolls/resizes. For append-to-body this
8756
- // recomputes the fixed coordinates so the panel follows the control while it's
8757
- // visible, and closes once the control is fully scrolled out of view (viewport
8758
- // OR any scroll container such as a modal body). Inline just re-flips up/down.
8759
- reposition = () => {
8760
- if (!this.isOpen())
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)
8761
8900
  return;
8762
- if (this.appendToBody()) {
8763
- const rect = this.controlWrapper?.nativeElement.getBoundingClientRect();
8764
- if (rect && this.isControlClipped(rect)) {
8765
- this.closeDropdown();
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())
8766
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 });
8767
8945
  }
8768
- }
8769
- this.applyPlacement();
8770
- };
8946
+ else {
8947
+ this.controlWrapper?.nativeElement?.focus({ preventScroll: true });
8948
+ }
8949
+ });
8950
+ }
8771
8951
  /**
8772
- * True when the control is fully outside the visible area either the
8773
- * viewport or a scrollable/clipping ancestor (e.g. a dialog's scroll body).
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.
8774
8955
  */
8775
- isControlClipped(rect) {
8776
- if (rect.bottom <= 0 || rect.top >= window.innerHeight ||
8777
- rect.right <= 0 || rect.left >= window.innerWidth) {
8778
- return true;
8779
- }
8780
- let el = this.controlWrapper?.nativeElement.parentElement;
8781
- while (el && el !== document.body) {
8782
- const style = getComputedStyle(el);
8783
- const clips = /(auto|scroll|hidden|clip|overlay)/;
8784
- if (clips.test(style.overflowY) || clips.test(style.overflowX)) {
8785
- const r = el.getBoundingClientRect();
8786
- if (rect.bottom <= r.top || rect.top >= r.bottom ||
8787
- rect.right <= r.left || rect.left >= r.right) {
8788
- return true;
8789
- }
8790
- }
8791
- el = el.parentElement;
8956
+ resetMarked() {
8957
+ const list = this.filteredItems();
8958
+ if (!list.length) {
8959
+ this.markedIndex.set(-1);
8960
+ return;
8792
8961
  }
8793
- return false;
8962
+ const selectedIdx = list.findIndex((node) => this.isSelected(node));
8963
+ this.markedIndex.set(selectedIdx >= 0 ? selectedIdx : 0);
8794
8964
  }
8795
8965
  /**
8796
- * Relocate the panel node to <body> so it truly escapes any transformed or
8797
- * overflow-clipped ancestor (dialogs, drawers, overflow cards, etc.).
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.
8798
8969
  */
8799
- movePanelToBody() {
8800
- const panel = this.dropdownPanel?.nativeElement;
8801
- if (!panel || this.panelInBody)
8970
+ onKeyDown(event) {
8971
+ if (!this.isOpen()) {
8972
+ if (event.key === 'Enter' || event.key === ' ') {
8973
+ event.preventDefault();
8974
+ this.openDropdown();
8975
+ }
8802
8976
  return;
8803
- this.originalPanelParent = panel.parentNode;
8804
- this.originalPanelAnchor = panel.nextSibling;
8805
- document.body.appendChild(panel);
8806
- this.panelInBody = true;
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);
8807
9026
  }
8808
- /** Return the panel to its original DOM position before Angular removes it. */
8809
- restorePanel() {
8810
- const panel = this.dropdownPanel?.nativeElement;
8811
- if (!panel || !this.panelInBody)
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])
8812
9033
  return;
8813
- if (this.originalPanelParent) {
8814
- this.originalPanelParent.insertBefore(panel, this.originalPanelAnchor);
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;
8815
9040
  }
8816
- this.panelInBody = false;
8817
- this.originalPanelParent = null;
8818
- this.originalPanelAnchor = null;
8819
9041
  }
8820
- /** Runs after the panel has rendered: relocate (append mode) + position + focus. */
8821
- afterOpenInit() {
8822
- if (this.appendToBody())
8823
- this.movePanelToBody();
8824
- this.applyPlacement();
8825
- this.panelReady.set(true);
8826
- this.searchInput?.nativeElement?.focus();
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();
8827
9050
  }
8828
9051
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
8829
9052
  /** Hidden until its real height has been measured and final placement applied. */
8830
9053
  panelReady = signal(false, ...(ngDevMode ? [{ debugName: "panelReady" }] : []));
8831
- dropdownStyle = signal({
8832
- left: '0px',
8833
- width: 'auto',
8834
- }, ...(ngDevMode ? [{ debugName: "dropdownStyle" }] : []));
8835
9054
  searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
8836
9055
  /** Breadcrumb stack: each entry is the parent node we navigated into. */
8837
9056
  breadcrumb = signal([], ...(ngDevMode ? [{ debugName: "breadcrumb" }] : []));
@@ -9008,6 +9227,8 @@ class BkHierarchicalSelect {
9008
9227
  }
9009
9228
  }
9010
9229
  openDropdown() {
9230
+ if (this.isOpen())
9231
+ return;
9011
9232
  this.panelReady.set(false);
9012
9233
  if (this.restrictKey() != null) {
9013
9234
  const restrictKey = this.restrictKey();
@@ -9034,12 +9255,7 @@ class BkHierarchicalSelect {
9034
9255
  else {
9035
9256
  this.breadcrumb.set([]);
9036
9257
  }
9037
- // Decide the initial side before the panel paints (estimated height;
9038
- // corrected after render in afterOpenInit).
9039
- this.applyPlacement();
9040
- this.isOpen.set(true);
9041
- this.searchTerm.set('');
9042
- setTimeout(() => this.afterOpenInit(), 0);
9258
+ this.openPanel();
9043
9259
  return;
9044
9260
  }
9045
9261
  const sel = this.selected();
@@ -9050,73 +9266,31 @@ class BkHierarchicalSelect {
9050
9266
  else {
9051
9267
  this.breadcrumb.set([]);
9052
9268
  }
9053
- this.applyPlacement();
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();
9054
9277
  this.isOpen.set(true);
9055
9278
  this.searchTerm.set('');
9056
9279
  setTimeout(() => this.afterOpenInit(), 0);
9057
9280
  }
9058
9281
  /**
9059
- * Decides which side the panel opens on (auto-flip) and, for append-to-body
9060
- * mode, computes the fixed coordinates. Re-run on open and on scroll/resize so
9061
- * the panel snaps to whichever side has room — honouring `dropdownPosition`
9062
- * 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.
9063
9285
  */
9064
- applyPlacement() {
9065
- const el = this.controlWrapper?.nativeElement;
9066
- if (!el)
9067
- return;
9068
- const rect = el.getBoundingClientRect();
9069
- const gap = 4;
9070
- const panelHeight = this.dropdownPanel?.nativeElement.offsetHeight || 300;
9071
- const spaceBelow = window.innerHeight - rect.bottom - gap;
9072
- const spaceAbove = rect.top - gap;
9073
- const preferred = this.dropdownPosition();
9074
- let placeTop;
9075
- if (preferred === 'top') {
9076
- placeTop = spaceAbove >= panelHeight || spaceAbove > spaceBelow;
9077
- }
9078
- else {
9079
- placeTop = spaceBelow < panelHeight && spaceAbove > spaceBelow;
9080
- }
9081
- this.placement.set(placeTop ? 'top' : 'bottom');
9082
- // Inline mode uses CSS (data-position) — the placement signal is enough.
9083
- if (!this.appendToBody())
9084
- return;
9085
- if (placeTop) {
9086
- this.dropdownStyle.set({
9087
- top: undefined,
9088
- bottom: `${window.innerHeight - rect.top + gap}px`,
9089
- left: `${rect.left}px`,
9090
- width: `${rect.width}px`,
9091
- });
9092
- }
9093
- else {
9094
- this.dropdownStyle.set({
9095
- top: `${rect.bottom + gap}px`,
9096
- bottom: undefined,
9097
- left: `${rect.left}px`,
9098
- width: `${rect.width}px`,
9099
- });
9100
- }
9101
- }
9102
- /** Fixed positioning when appendToBody; inset placement uses CSS + .hierarchical-select-field. */
9103
- getTop() {
9104
- if (!this.appendToBody())
9105
- return null;
9106
- 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];
9107
9290
  }
9108
- getBottom() {
9109
- if (!this.appendToBody())
9110
- return null;
9111
- return this.dropdownStyle().bottom ?? null;
9112
- }
9113
- // Scroll/resize are handled by the capture-phase listeners in ngAfterViewInit
9114
- // (see `reposition`): they keep the panel attached, re-flip it, and only close
9115
- // it once the control scrolls fully out of view.
9116
9291
  closeDropdown() {
9117
9292
  const wasOpen = this.isOpen();
9118
- // Put the panel back where Angular expects it before the @if removes it.
9119
- this.restorePanel();
9293
+ this.detachOverlayScrollTracking();
9120
9294
  this.isOpen.set(false);
9121
9295
  this.panelReady.set(false);
9122
9296
  this.searchTerm.set('');
@@ -9130,19 +9304,24 @@ class BkHierarchicalSelect {
9130
9304
  if (stack.length === 0)
9131
9305
  return;
9132
9306
  this.breadcrumb.set(stack.slice(0, -1));
9307
+ this.resetMarked();
9133
9308
  }
9134
9309
  onSearchInput(event) {
9135
9310
  const value = event.target.value;
9136
9311
  this.searchTerm.set(value);
9312
+ this.resetMarked();
9137
9313
  }
9138
9314
  selectItem(node, event) {
9139
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();
9140
9319
  if (node.disabled)
9141
9320
  return;
9142
9321
  // A parent row always navigates. When parents are selectable, that happens
9143
9322
  // through the row's checkbox instead (see `toggleParentSelection`).
9144
9323
  if (this.hasChildren(node)) {
9145
- this.breadcrumb.update((stack) => [...stack, node]);
9324
+ this.enterNode(node);
9146
9325
  return;
9147
9326
  }
9148
9327
  this.selected.set(node);
@@ -9190,14 +9369,11 @@ class BkHierarchicalSelect {
9190
9369
  this.controlWrapper?.nativeElement?.focus();
9191
9370
  this.openDropdown();
9192
9371
  }
9193
- onClickOutside(e) {
9194
- const target = e.target;
9195
- // When appendToBody relocates the panel to <body>, it's no longer inside the
9196
- // host element treat clicks within the panel as "inside" too.
9197
- if (this.el.nativeElement.contains(target))
9198
- return;
9199
- if (this.dropdownPanel?.nativeElement.contains(target))
9200
- 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() {
9201
9377
  this.closeDropdown();
9202
9378
  }
9203
9379
  // --- ControlValueAccessor ---
@@ -9242,23 +9418,23 @@ class BkHierarchicalSelect {
9242
9418
  this.clear.emit(null);
9243
9419
  }
9244
9420
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
9245
- 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" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
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: [
9246
9422
  {
9247
9423
  provide: NG_VALUE_ACCESSOR,
9248
9424
  useExisting: forwardRef(() => BkHierarchicalSelect),
9249
9425
  multi: true,
9250
9426
  },
9251
- ], 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"] }] });
9252
9428
  }
9253
9429
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, decorators: [{
9254
9430
  type: Component,
9255
- 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: [
9256
9432
  {
9257
9433
  provide: NG_VALUE_ACCESSOR,
9258
9434
  useExisting: forwardRef(() => BkHierarchicalSelect),
9259
9435
  multi: true,
9260
9436
  },
9261
- ], 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"] }]
9262
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: [{
9263
9439
  type: ViewChild,
9264
9440
  args: ['searchInput']
@@ -9268,44 +9444,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
9268
9444
  }], dropdownPanel: [{
9269
9445
  type: ViewChild,
9270
9446
  args: ['dropdownPanel']
9271
- }], onClickOutside: [{
9272
- type: HostListener,
9273
- args: ['document:click', ['$event']]
9447
+ }], optionsListContainer: [{
9448
+ type: ViewChild,
9449
+ args: ['optionsListContainer']
9450
+ }], optionEls: [{
9451
+ type: ViewChildren,
9452
+ args: ['optionRef']
9453
+ }], hierarchicalOverlay: [{
9454
+ type: ViewChild,
9455
+ args: ['hierarchicalOverlay']
9274
9456
  }] } });
9275
9457
 
9276
9458
  // ─── Service ─────────────────────────────────────────────────────────────────
9277
9459
  let _toastId = 0;
9460
+ /**
9461
+ * Renders through Angular CDK's Overlay (same primitive `bk-select` / `bk-dialog` / `bk-popover`
9462
+ * already use), positioned with a `GlobalPositionStrategy` rather than a connected one — a toast
9463
+ * has no trigger element to anchor to, it docks to a viewport corner, which is exactly what the
9464
+ * global strategy is for (Angular Material's own snack bar is built the same way).
9465
+ *
9466
+ * The win over the old `document.body.appendChild()` approach isn't just consistency: CDK sets
9467
+ * top/left/right/bottom as inline styles from JS at runtime, via its own prebuilt overlay CSS
9468
+ * (`@angular/cdk/overlay-prebuilt.css`, already imported by consumers) — positioning no longer
9469
+ * depends on this library's own Tailwind `@apply` classes surviving the build pipeline at all.
9470
+ */
9278
9471
  class BkToastrService {
9279
- appRef;
9280
- injector;
9472
+ overlay = inject(Overlay);
9281
9473
  _toasts = signal([], ...(ngDevMode ? [{ debugName: "_toasts" }] : []));
9282
9474
  toasts = computed(() => this._toasts(), ...(ngDevMode ? [{ debugName: "toasts" }] : []));
9283
9475
  _position = signal('top-right', ...(ngDevMode ? [{ debugName: "_position" }] : []));
9284
9476
  position = computed(() => this._position(), ...(ngDevMode ? [{ debugName: "position" }] : []));
9477
+ overlayRef = null;
9285
9478
  componentRef = null;
9286
- constructor(appRef, injector) {
9287
- this.appRef = appRef;
9288
- this.injector = injector;
9479
+ buildPositionStrategy(position) {
9480
+ const strategy = this.overlay.position().global();
9481
+ const [vertical, horizontal] = position.split('-');
9482
+ if (vertical === 'top')
9483
+ strategy.top('1rem');
9484
+ else
9485
+ strategy.bottom('1rem');
9486
+ if (horizontal === 'center')
9487
+ strategy.centerHorizontally();
9488
+ else if (horizontal === 'left')
9489
+ strategy.left('1rem');
9490
+ else
9491
+ strategy.right('1rem');
9492
+ return strategy;
9289
9493
  }
9290
9494
  initializeContainer() {
9291
- if (this.componentRef)
9495
+ if (this.overlayRef)
9292
9496
  return;
9293
- // Check if we're in browser environment
9294
- if (typeof document === 'undefined' || !document.body) {
9295
- // If document.body doesn't exist yet, wait for it
9296
- setTimeout(() => this.initializeContainer(), 0);
9497
+ // SSR / no document yet — nothing to attach an overlay into.
9498
+ if (typeof document === 'undefined')
9297
9499
  return;
9298
- }
9299
- // Create component dynamically
9300
- this.componentRef = createComponent(BkToastr, {
9301
- environmentInjector: this.injector,
9500
+ this.overlayRef = this.overlay.create({
9501
+ positionStrategy: this.buildPositionStrategy(this._position()),
9502
+ scrollStrategy: this.overlay.scrollStrategies.noop(),
9503
+ panelClass: 'bk-toastr-panel',
9302
9504
  });
9303
- // Attach to DOM
9304
- document.body.appendChild(this.componentRef.location.nativeElement);
9305
- // Register for change detection
9306
- // Note: We don't call appRef.tick() here to avoid recursive tick calls
9307
- // Angular will automatically detect changes for the attached view
9308
- this.appRef.attachView(this.componentRef.hostView);
9505
+ this.componentRef = this.overlayRef.attach(new ComponentPortal(BkToastr));
9309
9506
  }
9310
9507
  /** Show a toast with full config */
9311
9508
  show(config) {
@@ -9375,14 +9572,15 @@ class BkToastrService {
9375
9572
  // Initialize container if not already created
9376
9573
  this.initializeContainer();
9377
9574
  this._position.set(position);
9575
+ this.overlayRef?.updatePositionStrategy(this.buildPositionStrategy(position));
9378
9576
  }
9379
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToastrService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
9577
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToastrService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
9380
9578
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToastrService, providedIn: 'root' });
9381
9579
  }
9382
9580
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToastrService, decorators: [{
9383
9581
  type: Injectable,
9384
9582
  args: [{ providedIn: 'root' }]
9385
- }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
9583
+ }] });
9386
9584
 
9387
9585
  class BkToastr {
9388
9586
  svc = inject(BkToastrService);
@@ -9398,11 +9596,11 @@ class BkToastr {
9398
9596
  t.actionCallback?.();
9399
9597
  }
9400
9598
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToastr, deps: [], target: i0.ɵɵFactoryTarget.Component });
9401
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkToastr, isStandalone: true, selector: "bk-toastr", ngImport: i0, template: "<!-- Toast Container \u2013 fixed overlay -->\r\n<div class=\"toast-container\" [attr.data-position]=\"position$ | async\">\r\n\r\n @for (toast of (toasts$ | async) ?? []; track toast.id) {\r\n <div\r\n class=\"toast-item\"\r\n [attr.data-severity]=\"toast.severity\"\r\n [class.toast-item-inline]=\"toast.inline\"\r\n [class.toast-enter]=\"!toast.leaving\"\r\n [class.toast-leave]=\"toast.leaving\">\r\n\r\n <!-- \u2500\u2500 Icon \u2500\u2500 -->\r\n @if (toast.icon) {\r\n <svg class=\"toast-icon shrink-0\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"\r\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <g [attr.clip-path]=\"'url(#clip_' + toast.id + ')'\">\r\n <path\r\n d=\"M10.0001 13.3334V10M10.0001 6.66671H10.0084M18.3334 10C18.3334 5.39767 14.6025 1.66671 10.0001 1.66671C5.39771 1.66671 1.66675 5.39767 1.66675 10C1.66675 14.6024 5.39771 18.3334 10.0001 18.3334C14.6025 18.3334 18.3334 14.6024 18.3334 10Z\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath [attr.id]=\"'clip_' + toast.id\">\r\n <rect width=\"20\" height=\"20\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n }\r\n\r\n <!-- \u2500\u2500 Content \u2500\u2500 -->\r\n <div class=\"toast-content flex-1 min-w-0\">\r\n <p class=\"toast-summary\">{{ toast.summary }}</p>\r\n @if (toast.detail) {\r\n <p class=\"toast-detail\">{{ toast.detail }}</p>\r\n }\r\n </div>\r\n\r\n <!-- \u2500\u2500 Action button \u2500\u2500 -->\r\n @if (toast.actionLabel) {\r\n <button type=\"button\" class=\"toast-action\" (click)=\"onAction($event, toast)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n }\r\n\r\n <!-- \u2500\u2500 Close button \u2500\u2500 -->\r\n <button type=\"button\" class=\"toast-close\" (click)=\"onClose($event, toast.id)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M10.625 0.625L0.625 10.625M0.625 0.625L10.625 10.625\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".toast-container{@apply fixed flex flex-col gap-3 max-w-[100vw-2rem];z-index:2147483647!important;pointer-events:none}.toast-container[data-position=top-right]{@apply top-4 right-4;}.toast-container[data-position=top-left]{@apply top-4 left-4;}.toast-container[data-position=top-center]{@apply top-4 left-1/2 -translate-x-1/2;}.toast-container[data-position=bottom-right]{@apply bottom-4 right-4;}.toast-container[data-position=bottom-left]{@apply bottom-4 left-4;}.toast-container[data-position=bottom-center]{@apply bottom-4 left-1/2 -translate-x-1/2;}.toast-item{@apply flex items-center justify-start gap-3 py-2 px-4 rounded-lg border;box-shadow:0 4px 12px #00000014,0 1px 3px #0000000f;pointer-events:auto}.toast-item[data-severity=info]{@apply bg-[#1434CB] border-[#E5F3FF];}.toast-item[data-severity=info] .toast-icon path{stroke:#fff}.toast-item[data-severity=info] .toast-summary{@apply text-white;}.toast-item[data-severity=info] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=info] .toast-action{@apply bg-white text-[#1434CB] border border-[#1434CB];}.toast-item[data-severity=info] .toast-close path{stroke:#fff}.toast-item[data-severity=default]{@apply bg-gray-500 border-gray-50;}.toast-item[data-severity=default] .toast-icon path{stroke:#fff}.toast-item[data-severity=default] .toast-summary{@apply text-white;}.toast-item[data-severity=default] .toast-action{@apply bg-white text-gray-500;}.toast-item[data-severity=default] .toast-close path{stroke:#fff}.toast-item[data-severity=error]{@apply bg-[#C84144] border-[#FFF1F1];}.toast-item[data-severity=error] .toast-icon path{stroke:#fff}.toast-item[data-severity=error] .toast-summary{@apply text-white;}.toast-item[data-severity=error] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=error] .toast-action{@apply bg-white text-[#CB1432];}.toast-item[data-severity=error] .toast-close path{stroke:#fff}.toast-item[data-severity=warn]{@apply bg-[#CC6401] border-[#FFEED7];}.toast-item[data-severity=warn] .toast-icon path{stroke:#fff}.toast-item[data-severity=warn] .toast-summary{@apply text-white;}.toast-item[data-severity=warn] .toast-action{@apply bg-white text-[#CC6401];}.toast-item[data-severity=warn] .toast-close path{stroke:#fff}.toast-item[data-severity=success]{@apply bg-[#1E7735] border-[#F1FCF3];}.toast-item[data-severity=success] .toast-icon path{stroke:#fff}.toast-item[data-severity=success] .toast-summary{@apply text-white;}.toast-item[data-severity=success] .toast-action{@apply bg-white text-[#22973F];}.toast-item[data-severity=success] .toast-action:hover{@apply bg-[#22973F];}.toast-item[data-severity=success] .toast-close path{stroke:#fff}.toast-summary{@apply text-sm font-medium;}.toast-action{@apply shrink-0 py-1 px-2 text-xs font-medium leading-[18px] rounded-lg cursor-pointer border-none transition-colors;pointer-events:auto}.toast-close{@apply shrink-0 p-1 rounded cursor-pointer border-none bg-transparent transition-opacity;pointer-events:auto;position:relative;z-index:1}.toast-close:hover{@apply opacity-60;}.toast-close svg{display:block;pointer-events:none}.toast-close *{cursor:pointer}@media (max-width: 425px){.toast-container{width:calc(100vw - 2rem);max-width:100%}.toast-container[data-position=top-center],.toast-container[data-position=bottom-center]{left:50%!important;right:auto!important;transform:translate(-50%)!important;align-items:center}.toast-item:not(.toast-item-inline){display:grid;grid-template-areas:\"icon action close\" \"content content content\";grid-template-columns:auto 1fr auto;align-items:center;row-gap:6px}.toast-icon{grid-area:icon}.toast-content{grid-area:content}.toast-action{grid-area:action;justify-self:end}.toast-close{grid-area:close}}.toast-enter{animation:toastIn .3s ease-out forwards}.toast-leave{animation:toastOut .3s ease-in forwards}@keyframes toastIn{0%{opacity:0;transform:translateY(-10px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes toastOut{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-10px) scale(.96)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None });
9599
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkToastr, isStandalone: true, selector: "bk-toastr", ngImport: i0, template: "<!-- Toast Container \u2013 fixed overlay -->\r\n<div class=\"toast-container\" [attr.data-position]=\"position$ | async\">\r\n\r\n @for (toast of (toasts$ | async) ?? []; track toast.id) {\r\n <div\r\n class=\"toast-item\"\r\n [attr.data-severity]=\"toast.severity\"\r\n [class.toast-item-inline]=\"toast.inline\"\r\n [class.toast-enter]=\"!toast.leaving\"\r\n [class.toast-leave]=\"toast.leaving\">\r\n\r\n <!-- \u2500\u2500 Icon \u2500\u2500 -->\r\n @if (toast.icon) {\r\n <svg class=\"toast-icon shrink-0\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"\r\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <g [attr.clip-path]=\"'url(#clip_' + toast.id + ')'\">\r\n <path\r\n d=\"M10.0001 13.3334V10M10.0001 6.66671H10.0084M18.3334 10C18.3334 5.39767 14.6025 1.66671 10.0001 1.66671C5.39771 1.66671 1.66675 5.39767 1.66675 10C1.66675 14.6024 5.39771 18.3334 10.0001 18.3334C14.6025 18.3334 18.3334 14.6024 18.3334 10Z\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath [attr.id]=\"'clip_' + toast.id\">\r\n <rect width=\"20\" height=\"20\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n }\r\n\r\n <!-- \u2500\u2500 Content \u2500\u2500 -->\r\n <div class=\"toast-content flex-1 min-w-0\">\r\n <p class=\"toast-summary\">{{ toast.summary }}</p>\r\n @if (toast.detail) {\r\n <p class=\"toast-detail\">{{ toast.detail }}</p>\r\n }\r\n </div>\r\n\r\n <!-- \u2500\u2500 Action button \u2500\u2500 -->\r\n @if (toast.actionLabel) {\r\n <button type=\"button\" class=\"toast-action\" (click)=\"onAction($event, toast)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n }\r\n\r\n <!-- \u2500\u2500 Close button \u2500\u2500 -->\r\n <button type=\"button\" class=\"toast-close\" (click)=\"onClose($event, toast.id)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M10.625 0.625L0.625 10.625M0.625 0.625L10.625 10.625\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".toast-container{@apply flex flex-col gap-3 max-w-[100vw-2rem];pointer-events:none}.cdk-overlay-pane.bk-toastr-panel{z-index:2147483647!important}.toast-item{@apply flex items-center justify-start gap-3 py-2 px-4 rounded-lg border;box-shadow:0 4px 12px #00000014,0 1px 3px #0000000f;pointer-events:auto}.toast-item[data-severity=info]{@apply bg-[#1434CB] border-[#E5F3FF];}.toast-item[data-severity=info] .toast-icon path{stroke:#fff}.toast-item[data-severity=info] .toast-summary{@apply text-white;}.toast-item[data-severity=info] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=info] .toast-action{@apply bg-white text-[#1434CB] border border-[#1434CB];}.toast-item[data-severity=info] .toast-close path{stroke:#fff}.toast-item[data-severity=default]{@apply bg-gray-500 border-gray-50;}.toast-item[data-severity=default] .toast-icon path{stroke:#fff}.toast-item[data-severity=default] .toast-summary{@apply text-white;}.toast-item[data-severity=default] .toast-action{@apply bg-white text-gray-500;}.toast-item[data-severity=default] .toast-close path{stroke:#fff}.toast-item[data-severity=error]{@apply bg-[#C84144] border-[#FFF1F1];}.toast-item[data-severity=error] .toast-icon path{stroke:#fff}.toast-item[data-severity=error] .toast-summary{@apply text-white;}.toast-item[data-severity=error] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=error] .toast-action{@apply bg-white text-[#CB1432];}.toast-item[data-severity=error] .toast-close path{stroke:#fff}.toast-item[data-severity=warn]{@apply bg-[#CC6401] border-[#FFEED7];}.toast-item[data-severity=warn] .toast-icon path{stroke:#fff}.toast-item[data-severity=warn] .toast-summary{@apply text-white;}.toast-item[data-severity=warn] .toast-action{@apply bg-white text-[#CC6401];}.toast-item[data-severity=warn] .toast-close path{stroke:#fff}.toast-item[data-severity=success]{@apply bg-[#1E7735] border-[#F1FCF3];}.toast-item[data-severity=success] .toast-icon path{stroke:#fff}.toast-item[data-severity=success] .toast-summary{@apply text-white;}.toast-item[data-severity=success] .toast-action{@apply bg-white text-[#22973F];}.toast-item[data-severity=success] .toast-action:hover{@apply bg-[#22973F];}.toast-item[data-severity=success] .toast-close path{stroke:#fff}.toast-summary{@apply text-sm font-medium;}.toast-action{@apply shrink-0 py-1 px-2 text-xs font-medium leading-[18px] rounded-lg cursor-pointer border-none transition-colors;pointer-events:auto}.toast-close{@apply shrink-0 p-1 rounded cursor-pointer border-none bg-transparent transition-opacity;pointer-events:auto;position:relative;z-index:1}.toast-close:hover{@apply opacity-60;}.toast-close svg{display:block;pointer-events:none}.toast-close *{cursor:pointer}@media (max-width: 425px){.toast-container{width:calc(100vw - 2rem);max-width:100%}.toast-container[data-position=top-center],.toast-container[data-position=bottom-center]{align-items:center}.toast-item:not(.toast-item-inline){display:grid;grid-template-areas:\"icon action close\" \"content content content\";grid-template-columns:auto 1fr auto;align-items:center;row-gap:6px}.toast-icon{grid-area:icon}.toast-content{grid-area:content}.toast-action{grid-area:action;justify-self:end}.toast-close{grid-area:close}}.toast-enter{animation:toastIn .3s ease-out forwards}.toast-leave{animation:toastOut .3s ease-in forwards}@keyframes toastIn{0%{opacity:0;transform:translateY(-10px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes toastOut{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-10px) scale(.96)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None });
9402
9600
  }
9403
9601
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToastr, decorators: [{
9404
9602
  type: Component,
9405
- args: [{ selector: 'bk-toastr', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<!-- Toast Container \u2013 fixed overlay -->\r\n<div class=\"toast-container\" [attr.data-position]=\"position$ | async\">\r\n\r\n @for (toast of (toasts$ | async) ?? []; track toast.id) {\r\n <div\r\n class=\"toast-item\"\r\n [attr.data-severity]=\"toast.severity\"\r\n [class.toast-item-inline]=\"toast.inline\"\r\n [class.toast-enter]=\"!toast.leaving\"\r\n [class.toast-leave]=\"toast.leaving\">\r\n\r\n <!-- \u2500\u2500 Icon \u2500\u2500 -->\r\n @if (toast.icon) {\r\n <svg class=\"toast-icon shrink-0\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"\r\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <g [attr.clip-path]=\"'url(#clip_' + toast.id + ')'\">\r\n <path\r\n d=\"M10.0001 13.3334V10M10.0001 6.66671H10.0084M18.3334 10C18.3334 5.39767 14.6025 1.66671 10.0001 1.66671C5.39771 1.66671 1.66675 5.39767 1.66675 10C1.66675 14.6024 5.39771 18.3334 10.0001 18.3334C14.6025 18.3334 18.3334 14.6024 18.3334 10Z\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath [attr.id]=\"'clip_' + toast.id\">\r\n <rect width=\"20\" height=\"20\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n }\r\n\r\n <!-- \u2500\u2500 Content \u2500\u2500 -->\r\n <div class=\"toast-content flex-1 min-w-0\">\r\n <p class=\"toast-summary\">{{ toast.summary }}</p>\r\n @if (toast.detail) {\r\n <p class=\"toast-detail\">{{ toast.detail }}</p>\r\n }\r\n </div>\r\n\r\n <!-- \u2500\u2500 Action button \u2500\u2500 -->\r\n @if (toast.actionLabel) {\r\n <button type=\"button\" class=\"toast-action\" (click)=\"onAction($event, toast)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n }\r\n\r\n <!-- \u2500\u2500 Close button \u2500\u2500 -->\r\n <button type=\"button\" class=\"toast-close\" (click)=\"onClose($event, toast.id)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M10.625 0.625L0.625 10.625M0.625 0.625L10.625 10.625\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".toast-container{@apply fixed flex flex-col gap-3 max-w-[100vw-2rem];z-index:2147483647!important;pointer-events:none}.toast-container[data-position=top-right]{@apply top-4 right-4;}.toast-container[data-position=top-left]{@apply top-4 left-4;}.toast-container[data-position=top-center]{@apply top-4 left-1/2 -translate-x-1/2;}.toast-container[data-position=bottom-right]{@apply bottom-4 right-4;}.toast-container[data-position=bottom-left]{@apply bottom-4 left-4;}.toast-container[data-position=bottom-center]{@apply bottom-4 left-1/2 -translate-x-1/2;}.toast-item{@apply flex items-center justify-start gap-3 py-2 px-4 rounded-lg border;box-shadow:0 4px 12px #00000014,0 1px 3px #0000000f;pointer-events:auto}.toast-item[data-severity=info]{@apply bg-[#1434CB] border-[#E5F3FF];}.toast-item[data-severity=info] .toast-icon path{stroke:#fff}.toast-item[data-severity=info] .toast-summary{@apply text-white;}.toast-item[data-severity=info] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=info] .toast-action{@apply bg-white text-[#1434CB] border border-[#1434CB];}.toast-item[data-severity=info] .toast-close path{stroke:#fff}.toast-item[data-severity=default]{@apply bg-gray-500 border-gray-50;}.toast-item[data-severity=default] .toast-icon path{stroke:#fff}.toast-item[data-severity=default] .toast-summary{@apply text-white;}.toast-item[data-severity=default] .toast-action{@apply bg-white text-gray-500;}.toast-item[data-severity=default] .toast-close path{stroke:#fff}.toast-item[data-severity=error]{@apply bg-[#C84144] border-[#FFF1F1];}.toast-item[data-severity=error] .toast-icon path{stroke:#fff}.toast-item[data-severity=error] .toast-summary{@apply text-white;}.toast-item[data-severity=error] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=error] .toast-action{@apply bg-white text-[#CB1432];}.toast-item[data-severity=error] .toast-close path{stroke:#fff}.toast-item[data-severity=warn]{@apply bg-[#CC6401] border-[#FFEED7];}.toast-item[data-severity=warn] .toast-icon path{stroke:#fff}.toast-item[data-severity=warn] .toast-summary{@apply text-white;}.toast-item[data-severity=warn] .toast-action{@apply bg-white text-[#CC6401];}.toast-item[data-severity=warn] .toast-close path{stroke:#fff}.toast-item[data-severity=success]{@apply bg-[#1E7735] border-[#F1FCF3];}.toast-item[data-severity=success] .toast-icon path{stroke:#fff}.toast-item[data-severity=success] .toast-summary{@apply text-white;}.toast-item[data-severity=success] .toast-action{@apply bg-white text-[#22973F];}.toast-item[data-severity=success] .toast-action:hover{@apply bg-[#22973F];}.toast-item[data-severity=success] .toast-close path{stroke:#fff}.toast-summary{@apply text-sm font-medium;}.toast-action{@apply shrink-0 py-1 px-2 text-xs font-medium leading-[18px] rounded-lg cursor-pointer border-none transition-colors;pointer-events:auto}.toast-close{@apply shrink-0 p-1 rounded cursor-pointer border-none bg-transparent transition-opacity;pointer-events:auto;position:relative;z-index:1}.toast-close:hover{@apply opacity-60;}.toast-close svg{display:block;pointer-events:none}.toast-close *{cursor:pointer}@media (max-width: 425px){.toast-container{width:calc(100vw - 2rem);max-width:100%}.toast-container[data-position=top-center],.toast-container[data-position=bottom-center]{left:50%!important;right:auto!important;transform:translate(-50%)!important;align-items:center}.toast-item:not(.toast-item-inline){display:grid;grid-template-areas:\"icon action close\" \"content content content\";grid-template-columns:auto 1fr auto;align-items:center;row-gap:6px}.toast-icon{grid-area:icon}.toast-content{grid-area:content}.toast-action{grid-area:action;justify-self:end}.toast-close{grid-area:close}}.toast-enter{animation:toastIn .3s ease-out forwards}.toast-leave{animation:toastOut .3s ease-in forwards}@keyframes toastIn{0%{opacity:0;transform:translateY(-10px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes toastOut{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-10px) scale(.96)}}\n"] }]
9603
+ args: [{ selector: 'bk-toastr', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<!-- Toast Container \u2013 fixed overlay -->\r\n<div class=\"toast-container\" [attr.data-position]=\"position$ | async\">\r\n\r\n @for (toast of (toasts$ | async) ?? []; track toast.id) {\r\n <div\r\n class=\"toast-item\"\r\n [attr.data-severity]=\"toast.severity\"\r\n [class.toast-item-inline]=\"toast.inline\"\r\n [class.toast-enter]=\"!toast.leaving\"\r\n [class.toast-leave]=\"toast.leaving\">\r\n\r\n <!-- \u2500\u2500 Icon \u2500\u2500 -->\r\n @if (toast.icon) {\r\n <svg class=\"toast-icon shrink-0\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"\r\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <g [attr.clip-path]=\"'url(#clip_' + toast.id + ')'\">\r\n <path\r\n d=\"M10.0001 13.3334V10M10.0001 6.66671H10.0084M18.3334 10C18.3334 5.39767 14.6025 1.66671 10.0001 1.66671C5.39771 1.66671 1.66675 5.39767 1.66675 10C1.66675 14.6024 5.39771 18.3334 10.0001 18.3334C14.6025 18.3334 18.3334 14.6024 18.3334 10Z\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath [attr.id]=\"'clip_' + toast.id\">\r\n <rect width=\"20\" height=\"20\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n }\r\n\r\n <!-- \u2500\u2500 Content \u2500\u2500 -->\r\n <div class=\"toast-content flex-1 min-w-0\">\r\n <p class=\"toast-summary\">{{ toast.summary }}</p>\r\n @if (toast.detail) {\r\n <p class=\"toast-detail\">{{ toast.detail }}</p>\r\n }\r\n </div>\r\n\r\n <!-- \u2500\u2500 Action button \u2500\u2500 -->\r\n @if (toast.actionLabel) {\r\n <button type=\"button\" class=\"toast-action\" (click)=\"onAction($event, toast)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n }\r\n\r\n <!-- \u2500\u2500 Close button \u2500\u2500 -->\r\n <button type=\"button\" class=\"toast-close\" (click)=\"onClose($event, toast.id)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M10.625 0.625L0.625 10.625M0.625 0.625L10.625 10.625\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".toast-container{@apply flex flex-col gap-3 max-w-[100vw-2rem];pointer-events:none}.cdk-overlay-pane.bk-toastr-panel{z-index:2147483647!important}.toast-item{@apply flex items-center justify-start gap-3 py-2 px-4 rounded-lg border;box-shadow:0 4px 12px #00000014,0 1px 3px #0000000f;pointer-events:auto}.toast-item[data-severity=info]{@apply bg-[#1434CB] border-[#E5F3FF];}.toast-item[data-severity=info] .toast-icon path{stroke:#fff}.toast-item[data-severity=info] .toast-summary{@apply text-white;}.toast-item[data-severity=info] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=info] .toast-action{@apply bg-white text-[#1434CB] border border-[#1434CB];}.toast-item[data-severity=info] .toast-close path{stroke:#fff}.toast-item[data-severity=default]{@apply bg-gray-500 border-gray-50;}.toast-item[data-severity=default] .toast-icon path{stroke:#fff}.toast-item[data-severity=default] .toast-summary{@apply text-white;}.toast-item[data-severity=default] .toast-action{@apply bg-white text-gray-500;}.toast-item[data-severity=default] .toast-close path{stroke:#fff}.toast-item[data-severity=error]{@apply bg-[#C84144] border-[#FFF1F1];}.toast-item[data-severity=error] .toast-icon path{stroke:#fff}.toast-item[data-severity=error] .toast-summary{@apply text-white;}.toast-item[data-severity=error] .toast-detail{@apply text-gray-200 text-xs;}.toast-item[data-severity=error] .toast-action{@apply bg-white text-[#CB1432];}.toast-item[data-severity=error] .toast-close path{stroke:#fff}.toast-item[data-severity=warn]{@apply bg-[#CC6401] border-[#FFEED7];}.toast-item[data-severity=warn] .toast-icon path{stroke:#fff}.toast-item[data-severity=warn] .toast-summary{@apply text-white;}.toast-item[data-severity=warn] .toast-action{@apply bg-white text-[#CC6401];}.toast-item[data-severity=warn] .toast-close path{stroke:#fff}.toast-item[data-severity=success]{@apply bg-[#1E7735] border-[#F1FCF3];}.toast-item[data-severity=success] .toast-icon path{stroke:#fff}.toast-item[data-severity=success] .toast-summary{@apply text-white;}.toast-item[data-severity=success] .toast-action{@apply bg-white text-[#22973F];}.toast-item[data-severity=success] .toast-action:hover{@apply bg-[#22973F];}.toast-item[data-severity=success] .toast-close path{stroke:#fff}.toast-summary{@apply text-sm font-medium;}.toast-action{@apply shrink-0 py-1 px-2 text-xs font-medium leading-[18px] rounded-lg cursor-pointer border-none transition-colors;pointer-events:auto}.toast-close{@apply shrink-0 p-1 rounded cursor-pointer border-none bg-transparent transition-opacity;pointer-events:auto;position:relative;z-index:1}.toast-close:hover{@apply opacity-60;}.toast-close svg{display:block;pointer-events:none}.toast-close *{cursor:pointer}@media (max-width: 425px){.toast-container{width:calc(100vw - 2rem);max-width:100%}.toast-container[data-position=top-center],.toast-container[data-position=bottom-center]{align-items:center}.toast-item:not(.toast-item-inline){display:grid;grid-template-areas:\"icon action close\" \"content content content\";grid-template-columns:auto 1fr auto;align-items:center;row-gap:6px}.toast-icon{grid-area:icon}.toast-content{grid-area:content}.toast-action{grid-area:action;justify-self:end}.toast-close{grid-area:close}}.toast-enter{animation:toastIn .3s ease-out forwards}.toast-leave{animation:toastOut .3s ease-in forwards}@keyframes toastIn{0%{opacity:0;transform:translateY(-10px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes toastOut{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-10px) scale(.96)}}\n"] }]
9406
9604
  }] });
9407
9605
 
9408
9606
  class ColumnFilterOption {
@@ -10070,7 +10268,7 @@ class BkPagination {
10070
10268
  return this.getPageCount();
10071
10269
  }
10072
10270
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
10073
- 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"] }] });
10271
+ 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"] }] });
10074
10272
  }
10075
10273
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, decorators: [{
10076
10274
  type: Component,
@@ -10354,6 +10552,8 @@ class BkMenu {
10354
10552
  * already sets it apart from the page.
10355
10553
  */
10356
10554
  submenuBackground = false;
10555
+ /** Emit parent clicks as selections as well as toggling their inline submenu. */
10556
+ emitParentClick = false;
10357
10557
  /** Id of the currently selected leaf item. Two-way bindable. */
10358
10558
  activeItemId = '';
10359
10559
  /** Tint item icons: dark by default, white on the active (dark) row. */
@@ -10552,6 +10752,11 @@ class BkMenu {
10552
10752
  if (this.hasChildren(item)) {
10553
10753
  if (!this.isPopup) {
10554
10754
  this.toggle(item, siblings);
10755
+ if (this.emitParentClick) {
10756
+ this.activeItemId = item.id;
10757
+ this.activeItemIdChange.emit(item.id);
10758
+ this.itemClick.emit(item);
10759
+ }
10555
10760
  return;
10556
10761
  }
10557
10762
  if (this.trigger !== 'click')
@@ -10575,13 +10780,10 @@ class BkMenu {
10575
10780
  }
10576
10781
  // Pop-up mode: open a parent's fly-out on hover (and close its siblings).
10577
10782
  onItemEnter(item, siblings, event, level, parent) {
10578
- if (!this.isPopup || item.disabled || !this.hasChildren(item))
10579
- return;
10580
- // Click mode still follows the pointer once a panel at this level is open,
10581
- // the way a native menubar does — hovering a sibling switches without a
10582
- // second click. With nothing open, hover does nothing.
10583
- if (this.trigger === 'click'
10584
- && !siblings.some(sibling => sibling.id !== item.id && this.isOpen(sibling)))
10783
+ // Hover only opens/switches fly-outs in hover mode. In click mode every
10784
+ // open and switch must come from a real click, so hover does nothing —
10785
+ // even while a sibling's panel is already open.
10786
+ if (!this.isHoverTrigger || item.disabled || !this.hasChildren(item))
10585
10787
  return;
10586
10788
  // Re-entering after crossing the gap: keep what's already up rather than
10587
10789
  // tearing it down and re-placing it.
@@ -10734,7 +10936,7 @@ class BkMenu {
10734
10936
  this.closeAll();
10735
10937
  }
10736
10938
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
10737
- 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"] }] });
10939
+ 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"] }] });
10738
10940
  }
10739
10941
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, decorators: [{
10740
10942
  type: Component,
@@ -10755,6 +10957,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
10755
10957
  type: Input
10756
10958
  }], submenuBackground: [{
10757
10959
  type: Input
10960
+ }], emitParentClick: [{
10961
+ type: Input
10758
10962
  }], activeItemId: [{
10759
10963
  type: Input
10760
10964
  }], tintIcons: [{
@@ -10777,11 +10981,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
10777
10981
  }] } });
10778
10982
 
10779
10983
  /* =========================================================================
10780
- Placement maths for bk-popover: turns an anchor rectangle plus a requested
10781
- placement into viewport coordinates for the panel and its arrow.
10984
+ Placement vocabulary for bk-popover, plus the one piece of maths CDK's
10985
+ connected-overlay strategy doesn't do for us: keeping the arrow centred on
10986
+ the *trigger* rather than the panel.
10782
10987
 
10783
- Kept free of the DOM so the rules stay readable and testable — the component
10784
- measures, this decides.
10988
+ Flip/push/viewport-clamping used to live here by hand (see git history for
10989
+ computePopoverPosition) Angular CDK Overlay owns all of that now. What's
10990
+ left is DOM-free by design, so the rules stay readable and testable.
10785
10991
  ========================================================================= */
10786
10992
  /** Every placement, in the order a placement picker should show them. */
10787
10993
  const POPOVER_PLACEMENTS = [
@@ -10790,7 +10996,9 @@ const POPOVER_PLACEMENTS = [
10790
10996
  'bottom-left', 'bottom', 'bottom-right',
10791
10997
  'left-top', 'left', 'left-bottom'
10792
10998
  ];
10793
- const OPPOSITE = {
10999
+ /** The side CDK should try when the requested one doesn't fit — only ever the direct
11000
+ * opposite, never a diagonal, so the alignment word stays meaningful after a flip. */
11001
+ const OPPOSITE_SIDE = {
10794
11002
  top: 'bottom',
10795
11003
  bottom: 'top',
10796
11004
  left: 'right',
@@ -10829,81 +11037,12 @@ function joinPlacement(side, align) {
10829
11037
  return side;
10830
11038
  return `${side}-${ALIGN_EDGES[side][align]}`;
10831
11039
  }
11040
+ /** min wins when the range is inverted (arrow limit wider than the panel itself on a very
11041
+ * narrow/maxWidth-constrained panel), which keeps the arrow at the panel's leading edge
11042
+ * rather than pushing it past the trailing one. */
10832
11043
  function clamp(value, min, max) {
10833
- // min wins when the range is inverted (panel larger than the viewport), which
10834
- // keeps the panel's leading edge on screen rather than its trailing one.
10835
11044
  return Math.max(min, Math.min(value, max));
10836
11045
  }
10837
- /** Does the panel clear the viewport edge on this side of the anchor? */
10838
- function fitsOnSide(side, anchor, panel, { offset, viewportPadding: pad, viewport }) {
10839
- switch (side) {
10840
- case 'top':
10841
- return anchor.top - offset - panel.height >= pad;
10842
- case 'bottom':
10843
- return anchor.top + anchor.height + offset + panel.height <= viewport.height - pad;
10844
- case 'left':
10845
- return anchor.left - offset - panel.width >= pad;
10846
- case 'right':
10847
- return anchor.left + anchor.width + offset + panel.width <= viewport.width - pad;
10848
- }
10849
- }
10850
- /** Leading edge of the panel along the cross axis, before any clamping. */
10851
- function alignedStart(align, anchorStart, anchorSize, panelSize) {
10852
- switch (align) {
10853
- case 'start':
10854
- return anchorStart;
10855
- case 'end':
10856
- return anchorStart + anchorSize - panelSize;
10857
- case 'center':
10858
- return anchorStart + anchorSize / 2 - panelSize / 2;
10859
- }
10860
- }
10861
- /**
10862
- * Places the panel against the anchor, then keeps it on screen in two ways:
10863
- *
10864
- * - flip: a panel with no room on the requested side moves to the opposite one,
10865
- * but only if it actually fits there — flipping into a second bad fit just
10866
- * trades one clipped edge for another.
10867
- * - shift: the panel slides along its cross axis to stay inside the viewport.
10868
- * The arrow is measured against the *anchor*, not the panel, so it keeps
10869
- * pointing at the trigger however far the panel had to slide.
10870
- */
10871
- function computePopoverPosition(anchor, panel, placement, options) {
10872
- const { offset, viewportPadding: pad, arrowSize, flip, viewport } = options;
10873
- let { side, align } = splitPlacement(placement);
10874
- if (flip && !fitsOnSide(side, anchor, panel, options) && fitsOnSide(OPPOSITE[side], anchor, panel, options)) {
10875
- side = OPPOSITE[side];
10876
- }
10877
- const vertical = side === 'top' || side === 'bottom';
10878
- let top;
10879
- let left;
10880
- if (vertical) {
10881
- top = side === 'top'
10882
- ? anchor.top - panel.height - offset
10883
- : anchor.top + anchor.height + offset;
10884
- left = clamp(alignedStart(align, anchor.left, anchor.width, panel.width), pad, viewport.width - panel.width - pad);
10885
- }
10886
- else {
10887
- left = side === 'left'
10888
- ? anchor.left - panel.width - offset
10889
- : anchor.left + anchor.width + offset;
10890
- top = clamp(alignedStart(align, anchor.top, anchor.height, panel.height), pad, viewport.height - panel.height - pad);
10891
- }
10892
- const anchorCentre = vertical
10893
- ? anchor.left + anchor.width / 2
10894
- : anchor.top + anchor.height / 2;
10895
- const panelStart = vertical ? left : top;
10896
- const panelSize = vertical ? panel.width : panel.height;
10897
- const arrowLimit = arrowSize / 2 + ARROW_CORNER_GAP;
10898
- return {
10899
- top,
10900
- left,
10901
- side,
10902
- align,
10903
- placement: joinPlacement(side, align),
10904
- arrowOffset: clamp(anchorCentre - panelStart, arrowLimit, panelSize - arrowLimit)
10905
- };
10906
- }
10907
11046
 
10908
11047
  /** Edge length of the arrow square. Mirrored by --bk-popover-arrow in popover.css. */
10909
11048
  const ARROW_SIZE = 10;
@@ -10939,11 +11078,36 @@ class BkPopover {
10939
11078
  openDelay = input(80, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
10940
11079
  closeDelay = input(150, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
10941
11080
  maxWidth = input('280px', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
11081
+ /**
11082
+ * Fixed panel width, e.g. `'320px'`. Unset by default, so the panel sizes to its content
11083
+ * (capped by `maxWidth`) as before. Set this when the content's natural width shouldn't drive
11084
+ * layout — a form, a fixed-column list — so the panel doesn't reflow between opens as content
11085
+ * changes.
11086
+ *
11087
+ * Overrides `maxWidth` entirely while set — a plain CSS `max-width` would otherwise silently
11088
+ * cap a `width` larger than it (280px default), which is never what setting an exact width was
11089
+ * asking for. Raise `maxWidth` too only if you want *both* a starting width and a cap it can
11090
+ * still grow past for some other reason (e.g. a responsive breakpoint override elsewhere).
11091
+ */
11092
+ width = input(null, ...(ngDevMode ? [{ debugName: "width" }] : []));
10942
11093
  panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : []));
10943
11094
  /**
10944
- * Relocate the panel to <body> while open. `position: fixed` alone resolves
10945
- * against a transformed ancestor rather than the viewport, so a popover
10946
- * inside an animated dialog or a transformed card needs this to escape.
11095
+ * The max-width actually applied to the panel: whichever of `width`/`maxWidth` is in effect,
11096
+ * additionally capped to the viewport so the panel can never extend past the screen edge — an
11097
+ * oversized `width` (or a placement CDK could only push so far before running out of room)
11098
+ * shrinks to fit instead of overflowing. Mirrors the old hand-rolled positioner's clamp(), which
11099
+ * guaranteed the panel stayed fully on-screen; a bare CSS `max-width` alone doesn't provide that
11100
+ * once the requested size is close to (or exceeds) the viewport itself.
11101
+ */
11102
+ effectiveMaxWidth = computed(() => {
11103
+ const requested = this.width() ?? this.maxWidth();
11104
+ return `min(${requested}, calc(100vw - 16px))`;
11105
+ }, ...(ngDevMode ? [{ debugName: "effectiveMaxWidth" }] : []));
11106
+ /**
11107
+ * @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break.
11108
+ * The panel now always positions via Angular CDK Overlay, which portals into the shared
11109
+ * `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
11110
+ * to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
10947
11111
  */
10948
11112
  appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
10949
11113
  opened = output();
@@ -10951,50 +11115,73 @@ class BkPopover {
10951
11115
  openChange = output();
10952
11116
  anchorRef;
10953
11117
  panelRef;
11118
+ popoverOverlay;
10954
11119
  static activeInstance = null;
10955
- host = inject(ElementRef);
10956
11120
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
10957
- /**
10958
- * Null until the panel has been measured. The template keeps the panel
10959
- * hidden while it is null: the first frame exists only to measure, and
10960
- * showing it at 0,0 first would flash it in the corner.
10961
- */
10962
- position = signal(null, ...(ngDevMode ? [{ debugName: "position" }] : []));
11121
+ /** True once CDK has positioned the panel at least once since open() — the template keeps
11122
+ * the panel hidden until then, so the first frame (only there to be measured) never flashes
11123
+ * in the corner. */
11124
+ panelReady = signal(false, ...(ngDevMode ? [{ debugName: "panelReady" }] : []));
11125
+ /** Placement actually applied, once known — null before the first (positionChange) fires
11126
+ * (or once closed), in which case activePlacement()/side() fall back to the requested one. */
11127
+ resolvedPlacement = signal(null, ...(ngDevMode ? [{ debugName: "resolvedPlacement" }] : []));
10963
11128
  /** Where the panel actually is, once positioned — may differ from `placement`. */
10964
- activePlacement = computed(() => this.position()?.placement ?? this.placement(), ...(ngDevMode ? [{ debugName: "activePlacement" }] : []));
11129
+ activePlacement = computed(() => this.resolvedPlacement() ?? this.placement(), ...(ngDevMode ? [{ debugName: "activePlacement" }] : []));
10965
11130
  /** Side the panel sits on. Drives which edge the arrow hangs off (see CSS). */
10966
- side = computed(() => this.position()?.side ?? splitPlacement(this.placement()).side, ...(ngDevMode ? [{ debugName: "side" }] : []));
11131
+ side = computed(() => splitPlacement(this.activePlacement()).side, ...(ngDevMode ? [{ debugName: "side" }] : []));
11132
+ /** Distance from the panel's leading edge to the arrow's centre, along the panel's cross
11133
+ * axis — null until measured. Recomputed from the *actual rendered rects*, not derived from
11134
+ * CDK's position strategy, so it's correct however CDK had to push/clamp the panel. */
11135
+ arrowOffsetPx = signal(null, ...(ngDevMode ? [{ debugName: "arrowOffsetPx" }] : []));
11136
+ /** Arrow offset along the panel's cross axis — x on top/bottom, y on left/right. */
11137
+ arrowLeft = computed(() => {
11138
+ const px = this.arrowOffsetPx();
11139
+ if (px == null)
11140
+ return null;
11141
+ const s = this.side();
11142
+ return s === 'top' || s === 'bottom' ? px : null;
11143
+ }, ...(ngDevMode ? [{ debugName: "arrowLeft" }] : []));
11144
+ arrowTop = computed(() => {
11145
+ const px = this.arrowOffsetPx();
11146
+ if (px == null)
11147
+ return null;
11148
+ const s = this.side();
11149
+ return s === 'left' || s === 'right' ? px : null;
11150
+ }, ...(ngDevMode ? [{ debugName: "arrowTop" }] : []));
11151
+ /**
11152
+ * Requested position first, its opposite side as a fallback when `flip` allows it — CDK tries
11153
+ * these in order and only falls to the second when the first genuinely doesn't fit. Push (on
11154
+ * by default) then keeps whichever one it lands on inside the viewport, matching the old
11155
+ * hand-rolled shift-along-the-edge behaviour. Each entry is tagged with the side/align it came
11156
+ * from (see positionMeta) so onPositionChange can read back which one CDK actually used.
11157
+ *
11158
+ * A stable field, computed once per open() — not a template-bound getter. A getter re-runs on
11159
+ * every change-detection pass (several times before CDK ever reads it), reassigning
11160
+ * `positionMeta` with fresh object references each time; onPositionChange would then be matching
11161
+ * against an array CDK was never actually given.
11162
+ */
11163
+ popoverPositions = [];
11164
+ positionMeta = [];
11165
+ computePositions() {
11166
+ const { side, align } = splitPlacement(this.placement());
11167
+ const entries = [
11168
+ { pos: toConnectedPosition(side, align, this.offset()), side, align }
11169
+ ];
11170
+ if (this.flip()) {
11171
+ const oppositeSide = OPPOSITE_SIDE[side];
11172
+ entries.push({ pos: toConnectedPosition(oppositeSide, align, this.offset()), side: oppositeSide, align });
11173
+ }
11174
+ this.positionMeta = entries;
11175
+ this.popoverPositions = entries.map(e => e.pos);
11176
+ }
10967
11177
  openTimer = null;
10968
11178
  closeTimer = null;
10969
11179
  pointerInPanel = false;
10970
11180
  resizeObserver;
10971
- // Panel's home in the DOM, so appendToBody can put it back before Angular's
10972
- // @if removes it.
10973
- originalPanelParent = null;
10974
- originalPanelAnchor = null;
10975
- panelInBody = false;
10976
- ngAfterViewInit() {
10977
- // Capture phase catches scrolling inside nested overflow containers, which
10978
- // a window:scroll listener would miss entirely.
10979
- window.addEventListener('scroll', this.reposition, true);
10980
- window.addEventListener('resize', this.reposition);
10981
- // Content can change size while open (async data, an expanding section),
10982
- // which moves every edge the panel is aligned against.
10983
- if (typeof ResizeObserver !== 'undefined') {
10984
- this.resizeObserver = new ResizeObserver(() => this.measure());
10985
- }
10986
- }
10987
11181
  ngOnDestroy() {
10988
11182
  this.clearTimers();
10989
11183
  this.resizeObserver?.disconnect();
10990
- document.removeEventListener('click', this.onDocumentClick);
10991
- window.removeEventListener('scroll', this.reposition, true);
10992
- window.removeEventListener('resize', this.reposition);
10993
- // Don't leave a relocated panel orphaned in <body> if we're torn down open.
10994
- if (this.panelInBody) {
10995
- this.panelRef?.nativeElement.remove();
10996
- this.panelInBody = false;
10997
- }
11184
+ this.detachOverlayScrollTracking();
10998
11185
  if (BkPopover.activeInstance === this)
10999
11186
  BkPopover.activeInstance = null;
11000
11187
  }
@@ -11008,36 +11195,28 @@ class BkPopover {
11008
11195
  }
11009
11196
  BkPopover.activeInstance = this;
11010
11197
  this.clearTimers();
11011
- this.position.set(null);
11198
+ this.panelReady.set(false);
11199
+ this.resolvedPlacement.set(null);
11200
+ this.arrowOffsetPx.set(null);
11201
+ this.computePositions();
11012
11202
  this.isOpen.set(true);
11013
11203
  this.opened.emit();
11014
11204
  this.openChange.emit(true);
11015
- // The panel doesn't exist until Angular renders it, and it can't be
11016
- // measured before it does — so position on the next tick.
11017
- setTimeout(() => {
11018
- if (!this.isOpen())
11019
- return;
11020
- if (this.appendToBody())
11021
- this.movePanelToBody();
11022
- this.measure();
11023
- if (this.panelRef)
11024
- this.resizeObserver?.observe(this.panelRef.nativeElement);
11025
- // Attached here, not on the host, so the very click that opened the panel
11026
- // has finished bubbling first — otherwise a popover opened by anything
11027
- // outside its own trigger (a toolbar button calling open()) would be shut
11028
- // again by its own opening click.
11029
- document.addEventListener('click', this.onDocumentClick);
11030
- });
11205
+ this.attachOverlayScrollTracking();
11031
11206
  }
11032
11207
  close() {
11033
11208
  if (!this.isOpen())
11034
11209
  return;
11035
11210
  this.clearTimers();
11211
+ this.detachOverlayScrollTracking();
11212
+ // Disconnect rather than leave it observing a panel CDK is about to detach — a fresh
11213
+ // observer is (re)created lazily in onPositionChange on the next open.
11036
11214
  this.resizeObserver?.disconnect();
11037
- document.removeEventListener('click', this.onDocumentClick);
11038
- this.restorePanel();
11215
+ this.resizeObserver = undefined;
11039
11216
  this.isOpen.set(false);
11040
- this.position.set(null);
11217
+ this.panelReady.set(false);
11218
+ this.resolvedPlacement.set(null);
11219
+ this.arrowOffsetPx.set(null);
11041
11220
  this.pointerInPanel = false;
11042
11221
  this.closed.emit();
11043
11222
  this.openChange.emit(false);
@@ -11077,78 +11256,107 @@ class BkPopover {
11077
11256
  this.pointerInPanel = false;
11078
11257
  this.scheduleClose();
11079
11258
  }
11080
- /** Only attached while open — see open(). Arrow fn so it can be removed. */
11081
- onDocumentClick = (event) => {
11259
+ /**
11260
+ * Click-outside-to-close, driven by CDK's document-level outside-pointer-event dispatcher
11261
+ * it already excludes clicks on the cdkOverlayOrigin (the anchor) by design, so onAnchorClick()
11262
+ * stays the sole opener/toggler. No backdrop involved, so it doesn't block page/nested-scroll-
11263
+ * container scroll the way a modal's would (see the phone-dropdown writeup for why that matters).
11264
+ */
11265
+ onOverlayOutsideClick() {
11082
11266
  if (this.trigger() !== 'click' || !this.closeOnClickOutside())
11083
11267
  return;
11084
- const target = event.target;
11085
- if (this.host.nativeElement.contains(target))
11086
- return;
11087
- // appendToBody moves the panel out of the host, so clicking inside it would
11088
- // otherwise read as an outside click.
11089
- if (this.panelRef?.nativeElement.contains(target))
11090
- return;
11091
11268
  this.close();
11092
- };
11269
+ }
11093
11270
  onEscape() {
11094
11271
  if (this.isOpen() && this.closeOnEscape())
11095
11272
  this.close();
11096
11273
  }
11097
11274
  // --- Positioning ---
11098
- reposition = () => {
11099
- if (this.isOpen())
11100
- this.measure();
11275
+ /**
11276
+ * CDK's default `reposition` scroll strategy only reacts to real `document`/`window` scroll —
11277
+ * it has no way to know an app shell might scroll a nested container instead (this one
11278
+ * commonly does — dashboard layouts with a fixed header/sidebar and a scrollable content pane).
11279
+ * A capture-phase listener on `document` still sees scroll events fired on any descendant
11280
+ * scrollable element (scroll doesn't bubble, but capture does) — same trick `bk-select` and the
11281
+ * `bk-input` phone dropdown already use. Also recomputes the arrow, since `updatePosition()`
11282
+ * sliding the panel along the same side doesn't necessarily fire (positionChange) — that only
11283
+ * fires when the *side* changes, not every pixel of a push/slide. rAF-throttled so a fast
11284
+ * scroll doesn't force layout on every tick.
11285
+ */
11286
+ overlayScrollRafId = null;
11287
+ onOverlayScroll = () => {
11288
+ if (this.overlayScrollRafId != null)
11289
+ return;
11290
+ this.overlayScrollRafId = requestAnimationFrame(() => {
11291
+ this.overlayScrollRafId = null;
11292
+ this.popoverOverlay?.overlayRef?.updatePosition();
11293
+ if (this.panelReady())
11294
+ this.arrowOffsetPx.set(this.computeArrowOffset(this.side()));
11295
+ });
11101
11296
  };
11102
- /** Measures the anchor and panel, then hands the maths to the utility. */
11103
- measure() {
11297
+ attachOverlayScrollTracking() {
11298
+ document.addEventListener('scroll', this.onOverlayScroll, true);
11299
+ window.addEventListener('resize', this.onOverlayScroll);
11300
+ }
11301
+ detachOverlayScrollTracking() {
11302
+ document.removeEventListener('scroll', this.onOverlayScroll, true);
11303
+ window.removeEventListener('resize', this.onOverlayScroll);
11304
+ if (this.overlayScrollRafId != null) {
11305
+ cancelAnimationFrame(this.overlayScrollRafId);
11306
+ this.overlayScrollRafId = null;
11307
+ }
11308
+ }
11309
+ /**
11310
+ * Fires whenever CDK (re)applies a position, including the first one after open. Reads back
11311
+ * which of `popoverPositions`' tagged entries CDK actually used — matched by field value
11312
+ * (positionsEqual), not object reference: CDK's position strategy reconstructs its own
11313
+ * ConnectedPosition objects internally, so `event.connectionPair` is never `===` to the object
11314
+ * we handed it even when it's the exact same logical position. Recomputes the arrow from the
11315
+ * real rendered rects, and — on the very first call — starts observing the panel for
11316
+ * content-size changes and reveals it.
11317
+ */
11318
+ onPositionChange(event) {
11319
+ const match = this.positionMeta.find(e => positionsEqual(e.pos, event.connectionPair));
11320
+ const side = match?.side ?? splitPlacement(this.placement()).side;
11321
+ const align = match?.align ?? splitPlacement(this.placement()).align;
11322
+ this.resolvedPlacement.set(joinPlacement(side, align));
11323
+ this.arrowOffsetPx.set(this.computeArrowOffset(side));
11324
+ this.panelReady.set(true);
11325
+ // Content can change size while open (async data, an expanding section), which moves every
11326
+ // edge the panel is aligned against — re-run CDK's own positioning, then ours, when it does.
11327
+ // observe() on an already-observed target is a harmless no-op, so no "have we done this
11328
+ // already" guard is needed here.
11329
+ if (typeof ResizeObserver !== 'undefined' && this.panelRef) {
11330
+ if (!this.resizeObserver) {
11331
+ this.resizeObserver = new ResizeObserver(() => {
11332
+ this.popoverOverlay?.overlayRef?.updatePosition();
11333
+ if (this.panelReady())
11334
+ this.arrowOffsetPx.set(this.computeArrowOffset(this.side()));
11335
+ });
11336
+ }
11337
+ this.resizeObserver.observe(this.panelRef.nativeElement);
11338
+ }
11339
+ }
11340
+ /**
11341
+ * Arrow offset along the panel's cross axis, measured from the actual rendered anchor/panel
11342
+ * rects rather than reverse-engineered from CDK's position strategy — correct however far CDK
11343
+ * had to push/clamp the panel to stay on screen.
11344
+ */
11345
+ computeArrowOffset(side) {
11104
11346
  const anchor = this.anchorRef?.nativeElement;
11105
11347
  const panel = this.panelRef?.nativeElement;
11106
11348
  if (!anchor || !panel)
11107
- return;
11349
+ return 0;
11108
11350
  const anchorRect = anchor.getBoundingClientRect();
11109
- this.position.set(computePopoverPosition({
11110
- top: anchorRect.top,
11111
- left: anchorRect.left,
11112
- width: anchorRect.width,
11113
- height: anchorRect.height
11114
- }, { width: panel.offsetWidth, height: panel.offsetHeight }, this.placement(), {
11115
- offset: this.offset(),
11116
- viewportPadding: 8,
11117
- arrowSize: ARROW_SIZE,
11118
- flip: this.flip(),
11119
- viewport: { width: window.innerWidth, height: window.innerHeight }
11120
- }));
11121
- }
11122
- /** Arrow offset along the panel's cross axis — x on top/bottom, y on left/right. */
11123
- arrowLeft = computed(() => {
11124
- const pos = this.position();
11125
- if (!pos)
11126
- return null;
11127
- return pos.side === 'top' || pos.side === 'bottom' ? pos.arrowOffset : null;
11128
- }, ...(ngDevMode ? [{ debugName: "arrowLeft" }] : []));
11129
- arrowTop = computed(() => {
11130
- const pos = this.position();
11131
- if (!pos)
11132
- return null;
11133
- return pos.side === 'left' || pos.side === 'right' ? pos.arrowOffset : null;
11134
- }, ...(ngDevMode ? [{ debugName: "arrowTop" }] : []));
11135
- movePanelToBody() {
11136
- const panel = this.panelRef?.nativeElement;
11137
- if (!panel || this.panelInBody)
11138
- return;
11139
- this.originalPanelParent = panel.parentNode;
11140
- this.originalPanelAnchor = panel.nextSibling;
11141
- document.body.appendChild(panel);
11142
- this.panelInBody = true;
11143
- }
11144
- restorePanel() {
11145
- const panel = this.panelRef?.nativeElement;
11146
- if (!panel || !this.panelInBody)
11147
- return;
11148
- this.originalPanelParent?.insertBefore(panel, this.originalPanelAnchor);
11149
- this.panelInBody = false;
11150
- this.originalPanelParent = null;
11151
- this.originalPanelAnchor = null;
11351
+ const panelRect = panel.getBoundingClientRect();
11352
+ const vertical = side === 'top' || side === 'bottom';
11353
+ const anchorCentre = vertical
11354
+ ? anchorRect.left + anchorRect.width / 2
11355
+ : anchorRect.top + anchorRect.height / 2;
11356
+ const panelStart = vertical ? panelRect.left : panelRect.top;
11357
+ const panelSize = vertical ? panelRect.width : panelRect.height;
11358
+ const arrowLimit = ARROW_SIZE / 2 + ARROW_CORNER_GAP;
11359
+ return clamp(anchorCentre - panelStart, arrowLimit, panelSize - arrowLimit);
11152
11360
  }
11153
11361
  // --- Timers ---
11154
11362
  scheduleClose() {
@@ -11175,27 +11383,65 @@ class BkPopover {
11175
11383
  this.cancelClose();
11176
11384
  }
11177
11385
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, deps: [], target: i0.ɵɵFactoryTarget.Component });
11178
- 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@if (isOpen()) {\r\n <!-- Hidden until position() lands: the first frame exists only so the panel\r\n can be measured, and painting it at 0,0 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.top.px]=\"position()?.top\"\r\n [style.left.px]=\"position()?.left\"\r\n [style.maxWidth]=\"maxWidth()\"\r\n [class.bk-popover-ready]=\"!!position()\"\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}\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply fixed 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"] }] });
11386
+ 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"] }] });
11179
11387
  }
11180
11388
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, decorators: [{
11181
11389
  type: Component,
11182
- args: [{ selector: 'bk-popover', standalone: true, exportAs: 'bkPopover', imports: [CommonModule], host: {
11390
+ args: [{ selector: 'bk-popover', standalone: true, exportAs: 'bkPopover', imports: [CommonModule, OverlayModule], host: {
11183
11391
  // A static `title="…"` lands on the input *and* stays on the host as a real
11184
11392
  // HTML attribute, which the browser would render as its own native tooltip
11185
11393
  // over the trigger. Stripping it here means the input can keep the obvious
11186
11394
  // name without consumers having to remember to bind it.
11187
11395
  '[attr.title]': 'null'
11188
- }, 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@if (isOpen()) {\r\n <!-- Hidden until position() lands: the first frame exists only so the panel\r\n can be measured, and painting it at 0,0 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.top.px]=\"position()?.top\"\r\n [style.left.px]=\"position()?.left\"\r\n [style.maxWidth]=\"maxWidth()\"\r\n [class.bk-popover-ready]=\"!!position()\"\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}\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply fixed 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"] }]
11189
- }], 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: [{
11396
+ }, 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"] }]
11397
+ }], 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: [{
11190
11398
  type: ViewChild,
11191
11399
  args: ['anchor']
11192
11400
  }], panelRef: [{
11193
11401
  type: ViewChild,
11194
11402
  args: ['panel']
11403
+ }], popoverOverlay: [{
11404
+ type: ViewChild,
11405
+ args: ['popoverOverlay']
11195
11406
  }], onEscape: [{
11196
11407
  type: HostListener,
11197
11408
  args: ['document:keydown.escape']
11198
11409
  }] } });
11410
+ /** CDK's vertical axis speaks `top`/`bottom`/`center`, not `start`/`end` — unlike the
11411
+ * horizontal axis, it isn't RTL-mirrored, so there's no `start`/`end` to flip. */
11412
+ function alignToVertical(align) {
11413
+ if (align === 'start')
11414
+ return 'top';
11415
+ if (align === 'end')
11416
+ return 'bottom';
11417
+ return 'center';
11418
+ }
11419
+ /** One side+align combination, translated into CDK's connected-position language. */
11420
+ function toConnectedPosition(side, align, offsetPx) {
11421
+ if (side === 'top' || side === 'bottom') {
11422
+ return {
11423
+ originX: align, overlayX: align,
11424
+ originY: side === 'top' ? 'top' : 'bottom',
11425
+ overlayY: side === 'top' ? 'bottom' : 'top',
11426
+ offsetY: side === 'top' ? -offsetPx : offsetPx
11427
+ };
11428
+ }
11429
+ const vertical = alignToVertical(align);
11430
+ return {
11431
+ originY: vertical, overlayY: vertical,
11432
+ originX: side === 'left' ? 'start' : 'end',
11433
+ overlayX: side === 'left' ? 'end' : 'start',
11434
+ offsetX: side === 'left' ? -offsetPx : offsetPx
11435
+ };
11436
+ }
11437
+ /** Field-by-field equality for ConnectedPosition — CDK does not preserve object identity for
11438
+ * positions passed via cdkConnectedOverlayPositions, so `event.connectionPair` must be matched
11439
+ * by value against the entries we handed it, never by `===`. */
11440
+ function positionsEqual(a, b) {
11441
+ return a.originX === b.originX && a.originY === b.originY &&
11442
+ a.overlayX === b.overlayX && a.overlayY === b.overlayY &&
11443
+ (a.offsetX ?? 0) === (b.offsetX ?? 0) && (a.offsetY ?? 0) === (b.offsetY ?? 0);
11444
+ }
11199
11445
 
11200
11446
  /**
11201
11447
  * A stacked ("avatar list") group. Renders a set of overlapping `bk-avatar`s and
@@ -12187,7 +12433,7 @@ class BkTh extends BkCellBase {
12187
12433
  popover?.close();
12188
12434
  }
12189
12435
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, deps: null, target: i0.ɵɵFactoryTarget.Component });
12190
- 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 });
12436
+ 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 });
12191
12437
  }
12192
12438
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, decorators: [{
12193
12439
  type: Component,
@@ -12840,5 +13086,5 @@ const BK_TABLE = [
12840
13086
  * Generated bundle index. Do not edit.
12841
13087
  */
12842
13088
 
12843
- 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, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, NEUTRAL_APPEARANCE, POPOVER_PLACEMENTS, computePopoverPosition, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
13089
+ 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 };
12844
13090
  //# sourceMappingURL=brickclay-org-ui.mjs.map