@brickclay-org/ui 0.1.85 → 0.1.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/brickclay-org-ui.mjs +853 -623
- package/fesm2022/brickclay-org-ui.mjs.map +1 -1
- package/index.d.ts +311 -151
- package/package.json +1 -6
- package/src/assets/icons/double-chevron-left.svg +4 -0
- package/src/assets/icons/double-chevron-right.svg +4 -0
- package/src/lib/hierarchical-select/hierarchical-select.css +34 -19
- package/src/lib/input/input.css +18 -3
- package/src/lib/popover/popover.css +18 -4
- package/src/lib/select/select.css +27 -3
- package/src/styles.css +13 -0
|
@@ -10,9 +10,10 @@ import * as i2$1 from '@angular/cdk/drag-drop';
|
|
|
10
10
|
import { moveItemInArray, DragDropModule, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
11
11
|
import * as i2$2 from '@angular/cdk/scrolling';
|
|
12
12
|
import { ScrollingModule, CdkScrollable, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
|
13
|
+
import * as i3 from '@angular/cdk/overlay';
|
|
14
|
+
import { OverlayModule, Overlay } from '@angular/cdk/overlay';
|
|
13
15
|
import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
|
|
14
16
|
import { DIALOG_DATA, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
|
|
15
|
-
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
16
17
|
import { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';
|
|
17
18
|
import { toObservable } from '@angular/core/rxjs-interop';
|
|
18
19
|
|
|
@@ -21,6 +22,8 @@ import { toObservable } from '@angular/core/rxjs-interop';
|
|
|
21
22
|
const BrickclayIcons = {
|
|
22
23
|
arrowleft: 'assets/icons/chevron-left.svg',
|
|
23
24
|
arrowRight: 'assets/icons/chevron-right.svg',
|
|
25
|
+
arrowLeftDouble: 'assets/icons/double-chevron-left.svg',
|
|
26
|
+
arrowRightDouble: 'assets/icons/double-chevron-right.svg',
|
|
24
27
|
calenderIcon: 'assets/icons/custom-calender.svg',
|
|
25
28
|
timerIcon: 'assets/icons/timer.svg',
|
|
26
29
|
};
|
|
@@ -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/
|
|
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
|
-
|
|
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
|
|
5491
|
-
//
|
|
5492
|
-
// (see
|
|
5509
|
+
// Side the panel actually rendered on, purely for the CSS `[data-position="top"]` margin
|
|
5510
|
+
// tweak — driven by CDK's own (positionChange) rather than a hand-rolled space comparison
|
|
5511
|
+
// (see onPositionChange). The fit/flip decision itself lives entirely in CDK now.
|
|
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
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
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
|
|
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(() =>
|
|
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
|
-
|
|
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
|
-
*
|
|
5626
|
-
*
|
|
5627
|
-
*
|
|
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
|
-
|
|
5630
|
-
|
|
5631
|
-
if (
|
|
5594
|
+
overlayScrollRafId = null;
|
|
5595
|
+
onOverlayScroll = () => {
|
|
5596
|
+
if (this.overlayScrollRafId != null)
|
|
5632
5597
|
return;
|
|
5633
|
-
this.
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
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
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
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
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
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
|
-
//
|
|
5803
|
-
//
|
|
5804
|
-
|
|
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
|
-
//
|
|
5812
|
-
//
|
|
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
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
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
|
-
|
|
5832
|
-
this.
|
|
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
|
-
*
|
|
5859
|
-
*
|
|
5860
|
-
*
|
|
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
|
-
|
|
5864
|
-
const
|
|
5865
|
-
|
|
5866
|
-
|
|
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.
|
|
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
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
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.
|
|
6123
|
+
if (this.pointerFocus)
|
|
6118
6124
|
return;
|
|
6119
|
-
this.
|
|
6125
|
+
if (this.disabled() || this.readonly())
|
|
6126
|
+
return;
|
|
6127
|
+
if (this.isFocusInside(event.relatedTarget))
|
|
6128
|
+
return;
|
|
6129
|
+
if (!this.isOpen())
|
|
6130
|
+
this.openDropdown();
|
|
6131
|
+
}
|
|
6132
|
+
/**
|
|
6133
|
+
* Close when focus leaves the control entirely — tabbing away, or focus moving
|
|
6134
|
+
* to any element outside the control and its (possibly body-appended) panel.
|
|
6135
|
+
* Internal focus moves keep it open.
|
|
6136
|
+
*/
|
|
6137
|
+
onFocusOut() {
|
|
6138
|
+
if (!this.openOnFocus())
|
|
6139
|
+
return;
|
|
6140
|
+
if (!this.isOpen())
|
|
6141
|
+
return;
|
|
6142
|
+
// The open transition is handing focus from the trigger to the search field;
|
|
6143
|
+
// that focusout is internal, not a departure. Ignore it so the panel doesn't
|
|
6144
|
+
// close the instant it opens on a Tab-in.
|
|
6145
|
+
if (this.opening)
|
|
6146
|
+
return;
|
|
6147
|
+
// A pointer press inside the control is in progress (e.g. clicking an option,
|
|
6148
|
+
// which blurs the search input because the option isn't focusable). That's an
|
|
6149
|
+
// interaction, not a departure — keep the panel open.
|
|
6150
|
+
if (this.pointerFocus)
|
|
6151
|
+
return;
|
|
6152
|
+
// Defer until focus settles, then decide from where it actually landed
|
|
6153
|
+
// (document.activeElement). relatedTarget is unreliable here: some browsers
|
|
6154
|
+
// report it as null for the programmatic focus move that hands focus from the
|
|
6155
|
+
// trigger to the search field on open, which would otherwise close the panel
|
|
6156
|
+
// the instant it opens — a flicker when tabbing in with openOnFocus.
|
|
6157
|
+
setTimeout(() => {
|
|
6158
|
+
if (!this.isOpen())
|
|
6159
|
+
return;
|
|
6160
|
+
if (this.isFocusInside(document.activeElement))
|
|
6161
|
+
return;
|
|
6162
|
+
this.closeDropdown();
|
|
6163
|
+
});
|
|
6164
|
+
}
|
|
6165
|
+
/** True when a node lives inside the control host or its detached panel. */
|
|
6166
|
+
isFocusInside(node) {
|
|
6167
|
+
if (!node)
|
|
6168
|
+
return false;
|
|
6169
|
+
return this.el.nativeElement.contains(node) ||
|
|
6170
|
+
!!this.dropdownPanel?.nativeElement.contains(node);
|
|
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: { "
|
|
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 }] }],
|
|
6353
|
+
}], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onPointerDown: [{
|
|
6290
6354
|
type: HostListener,
|
|
6291
|
-
args: ['
|
|
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
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
6468
|
-
|
|
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
|
-
|
|
6628
|
+
this.isDropdownOpen = true;
|
|
6629
|
+
this.attachPhoneOverlayScrollTracking();
|
|
6543
6630
|
}
|
|
6544
6631
|
else {
|
|
6545
|
-
this.
|
|
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" },
|
|
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
|
-
/**
|
|
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
|
|
8719
|
-
//
|
|
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
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
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
|
|
8741
|
-
//
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
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
|
-
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
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
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
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
|
-
|
|
8770
|
-
|
|
8946
|
+
else {
|
|
8947
|
+
this.controlWrapper?.nativeElement?.focus({ preventScroll: true });
|
|
8948
|
+
}
|
|
8949
|
+
});
|
|
8950
|
+
}
|
|
8771
8951
|
/**
|
|
8772
|
-
*
|
|
8773
|
-
*
|
|
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
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
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
|
-
|
|
8962
|
+
const selectedIdx = list.findIndex((node) => this.isSelected(node));
|
|
8963
|
+
this.markedIndex.set(selectedIdx >= 0 ? selectedIdx : 0);
|
|
8794
8964
|
}
|
|
8795
8965
|
/**
|
|
8796
|
-
*
|
|
8797
|
-
*
|
|
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
|
-
|
|
8800
|
-
|
|
8801
|
-
|
|
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
|
-
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
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
|
-
/**
|
|
8809
|
-
|
|
8810
|
-
const
|
|
8811
|
-
|
|
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
|
-
|
|
8814
|
-
|
|
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
|
-
/**
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
this.
|
|
9042
|
+
/** Defer a scroll to the marked option (after a keyboard move re-lays the row). */
|
|
9043
|
+
scrollToMarked() {
|
|
9044
|
+
setTimeout(() => this.scrollMarkedIntoView());
|
|
9045
|
+
}
|
|
9046
|
+
/** Navigate into a node's children and reset the highlight for the new level. */
|
|
9047
|
+
enterNode(node) {
|
|
9048
|
+
this.breadcrumb.update((stack) => [...stack, node]);
|
|
9049
|
+
this.resetMarked();
|
|
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
|
-
|
|
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.
|
|
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
|
-
*
|
|
9060
|
-
*
|
|
9061
|
-
* the
|
|
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
|
-
|
|
9065
|
-
const
|
|
9066
|
-
|
|
9067
|
-
|
|
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
|
-
}
|
|
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];
|
|
9101
9290
|
}
|
|
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;
|
|
9107
|
-
}
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
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" },
|
|
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,9 +9444,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9268
9444
|
}], dropdownPanel: [{
|
|
9269
9445
|
type: ViewChild,
|
|
9270
9446
|
args: ['dropdownPanel']
|
|
9271
|
-
}],
|
|
9272
|
-
type:
|
|
9273
|
-
args: ['
|
|
9447
|
+
}], optionsListContainer: [{
|
|
9448
|
+
type: ViewChild,
|
|
9449
|
+
args: ['optionsListContainer']
|
|
9450
|
+
}], optionEls: [{
|
|
9451
|
+
type: ViewChildren,
|
|
9452
|
+
args: ['optionRef']
|
|
9453
|
+
}], hierarchicalOverlay: [{
|
|
9454
|
+
type: ViewChild,
|
|
9455
|
+
args: ['hierarchicalOverlay']
|
|
9274
9456
|
}] } });
|
|
9275
9457
|
|
|
9276
9458
|
// ─── Service ─────────────────────────────────────────────────────────────────
|
|
@@ -10070,7 +10252,7 @@ class BkPagination {
|
|
|
10070
10252
|
return this.getPageCount();
|
|
10071
10253
|
}
|
|
10072
10254
|
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"] }] });
|
|
10255
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPagination, isStandalone: true, selector: "bk-pagination", inputs: { pageSize: "pageSize", total: "total", activePage: "activePage", showPageSize: "showPageSize", showRecordsText: "showRecordsText", showPageCount: "showPageCount", customClass: "customClass" }, outputs: { changePageSize: "changePageSize", pageChanged: "pageChanged", activePageChange: "activePageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"md:px-4 px-2 md:py-3 py-2 border-t border-[#EBEDF3] rounded-b-xl\">\r\n <div class=\"flex flex-row items-center justify-between md:gap-3 gap-1 {{ customClass }}\">\r\n\r\n <!-- Page size dropdown -->\r\n\r\n @if (!pageSizeHidden) {\r\n <div class=\"flex gap-3 items-center pagination\">\r\n @if (showPageSizeLabel) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">Rows per page</p>\r\n }\r\n @if (showPageSizeInput) {\r\n <bk-select\r\n [items]=\"pageSizesList\"\r\n [searchable]=\"false\"\r\n bindLabel=\"key\"\r\n bindValue=\"value\"\r\n [clearable]=\"false\"\r\n [(ngModel)]=\"pageSize\"\r\n [dropdownPosition]=\"'top'\"\r\n (change)=\"changeSize($event)\"\r\n [variation]=\"'sm'\"\r\n [isResponsive]=\"false\"\r\n class=\"!min-w-[90px] lg:!min-w-[131px]\"\r\n >\r\n </bk-select>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- showing entries -->\r\n @if (showRecordsText) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n Showing <span>{{ startIndex }}</span> to\r\n <span>{{ endIndex > totalItems ? totalItems : endIndex }}</span> of\r\n <span>{{ totalItems }}</span> Records\r\n </p>\r\n }\r\n\r\n <!-- Pagination main -->\r\n <!-- With 2+ top-level blocks visible, the parent row's justify-between already\r\n pins this to the end on its own; customClass on the row (e.g. \"justify-end\")\r\n controls arrangement among those blocks.\r\n Hidden down to just this one, there's nothing left for the row to distribute\r\n against, so it grows to fill the row (flex-1) instead \u2014 letting customClass\r\n act here on its own two children (page count text vs. the page-number list)\r\n via e.g. \"justify-between\" or \"justify-around\". -->\r\n <nav\r\n class=\"flex gap-1.5 items-center {{ customClass }}\"\r\n [class.flex-1]=\"pageSizeHidden && !showRecordsText\"\r\n >\r\n\r\n @if (showPageCount) {\r\n <!-- Page count -->\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n\r\n\r\n <!-- Page count mobile version -->\r\n <p class=\"text-xs text-[#141414] font-medium md:hidden block\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n }\r\n\r\n <ul class=\"flex items-center space-x-1 text-[13px] text-[#B9BBC6]\">\r\n\r\n <!-- Previous -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- Previous -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage - 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n\r\n <!-- Page Numbers -->\r\n <li *ngFor=\"let item of paginate()\">\r\n <a\r\n (click)=\"onClickPage(item)\"\r\n href=\"javascript:void(0)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 leading-6 rounded-lg\"\r\n [ngClass]=\"item === activePage\r\n ? 'text-[#15191E] bg-[#F8F8FA] hover:bg-[#F8F8FA]'\r\n : 'hover:bg-[#F8F8FA] hover:text-[#15191E]'\">\r\n {{ item }}\r\n </a>\r\n </li>\r\n\r\n <!-- Next -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage + 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- next double arrow -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(getTotalPages())\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkSelect, selector: "bk-select", inputs: ["items", "bindLabel", "bindValue", "bindIcon", "isResponsive", "placeholder", "notFoundText", "loadingText", "clearAllText", "groupBy", "colorKey", "dropdownView", "gridColumns", "gridVariation", "gridSelectionActions", "gridMinWidth", "gridMaxHeight", "gridSelectedLabelKeys", "gridSelectedLabelSeparator", "gridApplyText", "gridClearText", "showDots", "showAvatar", "avatarKey", "iconAlt", "label", "required", "variation", "iconSrc", "multiple", "maxLabels", "searchable", "allSelect", "clearable", "readonly", "disabled", "loading", "closeOnSelect", "openOnFocus", "dropdownPosition", "hasError", "errorMessage", "appendToBody", "compareWith"], outputs: ["disabledChange", "open", "close", "focus", "blur", "search", "clear", "change", "scrollToEnd"] }] });
|
|
10074
10256
|
}
|
|
10075
10257
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, decorators: [{
|
|
10076
10258
|
type: Component,
|
|
@@ -10354,6 +10536,8 @@ class BkMenu {
|
|
|
10354
10536
|
* already sets it apart from the page.
|
|
10355
10537
|
*/
|
|
10356
10538
|
submenuBackground = false;
|
|
10539
|
+
/** Emit parent clicks as selections as well as toggling their inline submenu. */
|
|
10540
|
+
emitParentClick = false;
|
|
10357
10541
|
/** Id of the currently selected leaf item. Two-way bindable. */
|
|
10358
10542
|
activeItemId = '';
|
|
10359
10543
|
/** Tint item icons: dark by default, white on the active (dark) row. */
|
|
@@ -10552,6 +10736,11 @@ class BkMenu {
|
|
|
10552
10736
|
if (this.hasChildren(item)) {
|
|
10553
10737
|
if (!this.isPopup) {
|
|
10554
10738
|
this.toggle(item, siblings);
|
|
10739
|
+
if (this.emitParentClick) {
|
|
10740
|
+
this.activeItemId = item.id;
|
|
10741
|
+
this.activeItemIdChange.emit(item.id);
|
|
10742
|
+
this.itemClick.emit(item);
|
|
10743
|
+
}
|
|
10555
10744
|
return;
|
|
10556
10745
|
}
|
|
10557
10746
|
if (this.trigger !== 'click')
|
|
@@ -10575,13 +10764,10 @@ class BkMenu {
|
|
|
10575
10764
|
}
|
|
10576
10765
|
// Pop-up mode: open a parent's fly-out on hover (and close its siblings).
|
|
10577
10766
|
onItemEnter(item, siblings, event, level, parent) {
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
//
|
|
10581
|
-
|
|
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)))
|
|
10767
|
+
// Hover only opens/switches fly-outs in hover mode. In click mode every
|
|
10768
|
+
// open and switch must come from a real click, so hover does nothing —
|
|
10769
|
+
// even while a sibling's panel is already open.
|
|
10770
|
+
if (!this.isHoverTrigger || item.disabled || !this.hasChildren(item))
|
|
10585
10771
|
return;
|
|
10586
10772
|
// Re-entering after crossing the gap: keep what's already up rather than
|
|
10587
10773
|
// tearing it down and re-placing it.
|
|
@@ -10734,7 +10920,7 @@ class BkMenu {
|
|
|
10734
10920
|
this.closeAll();
|
|
10735
10921
|
}
|
|
10736
10922
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
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"] }] });
|
|
10923
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkMenu, isStandalone: true, selector: "bk-menu", inputs: { items: "items", orientation: "orientation", submenuMode: "submenuMode", trigger: "trigger", size: "size", hoverCloseDelay: "hoverCloseDelay", singleOpen: "singleOpen", submenuBackground: "submenuBackground", emitParentClick: "emitParentClick", activeItemId: "activeItemId", tintIcons: "tintIcons", maxHeight: "maxHeight" }, outputs: { activeItemIdChange: "activeItemIdChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)", "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, usesOnChanges: true, ngImport: i0, template: "<nav\r\n class=\"bk-menu\"\r\n [class.bk-menu--vertical]=\"isVertical\"\r\n [class.bk-menu--horizontal]=\"!isVertical\"\r\n [class.bk-menu--popup]=\"isPopup\"\r\n [class.bk-menu--compact]=\"isCompact\"\r\n [class.bk-menu--tint]=\"tintIcons\"\r\n role=\"menubar\"\r\n [attr.aria-orientation]=\"orientation\">\r\n <ul\r\n class=\"bk-menu__list\"\r\n [class.bk-menu__list--scroll]=\"maxHeightStyle\"\r\n [style.maxHeight]=\"maxHeightStyle\">\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl; context: { $implicit: items, level: 0, parent: null }\">\r\n </ng-container>\r\n </ul>\r\n</nav>\r\n\r\n<!-- Recursive item renderer. Context: $implicit = items at this level,\r\n level = depth, parent = the item they hang off (null at the top). -->\r\n<ng-template #itemTpl let-items let-level=\"level\" let-parent=\"parent\">\r\n @for (item of items; track item.id; let i = $index) {\r\n @if (isGroupStart(items, i)) {\r\n <li\r\n class=\"bk-menu__group-title bk-menu__group-title--section\"\r\n [class.bk-menu__group-title--divider]=\"i > 0\"\r\n [style.paddingLeft.px]=\"groupTitleIndent(level)\"\r\n role=\"presentation\">\r\n {{ item.groupLabel }}\r\n </li>\r\n }\r\n <li\r\n class=\"bk-menu__item\"\r\n [class.bk-menu__item--has-children]=\"hasChildren(item)\"\r\n [class.bk-menu__item--open]=\"isOpen(item)\"\r\n (mouseenter)=\"onItemEnter(item, items, $event, level, parent)\"\r\n (mouseleave)=\"onItemLeave(item)\"\r\n role=\"none\">\r\n <button\r\n type=\"button\"\r\n class=\"bk-menu__button\"\r\n [class.bk-menu__button--active]=\"isHighlighted(item)\"\r\n [class.bk-menu__button--disabled]=\"item.disabled\"\r\n [class.bk-menu__button--parent]=\"hasChildren(item)\"\r\n [style.paddingLeft.px]=\"inlineIndent(level)\"\r\n [disabled]=\"item.disabled\"\r\n [attr.aria-haspopup]=\"hasChildren(item) ? 'true' : null\"\r\n [attr.aria-expanded]=\"hasChildren(item) ? isOpen(item) : null\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item, items, $event, level, parent)\">\r\n @if (item.icon) {\r\n <img class=\"bk-menu__icon\" [attr.src]=\"item.icon\" [alt]=\"item.iconAlt || item.label\" />\r\n }\r\n <span class=\"bk-menu__label\" (mouseenter)=\"onLabelEnter($event)\">{{ item.label }}</span>\r\n @if (hasChildren(item)) {\r\n <svg\r\n class=\"bk-menu__chevron\"\r\n [class.bk-menu__chevron--open]=\"!isPopup && isOpen(item)\"\r\n [class.bk-menu__chevron--right]=\"chevronDir(item, level) === 'right'\"\r\n [class.bk-menu__chevron--left]=\"chevronDir(item, level) === 'left'\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\">\r\n <path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n }\r\n </button>\r\n\r\n @if (hasChildren(item)) {\r\n <ul\r\n class=\"bk-menu__submenu\"\r\n [class.bk-menu__submenu--inline]=\"!isPopup\"\r\n [class.bk-menu__submenu--bg]=\"submenuBackground && !isPopup\"\r\n [class.bk-menu__submenu--popup]=\"isPopup\"\r\n [class.bk-menu__submenu--open]=\"isOpen(item)\"\r\n [class.bk-menu__submenu--placing]=\"isPlacing(item)\"\r\n [class.bk-menu__submenu--side-right]=\"submenuSide(item) === 'right'\"\r\n [class.bk-menu__submenu--side-left]=\"submenuSide(item) === 'left'\"\r\n [class.bk-menu__submenu--side-down]=\"submenuSide(item) === 'down'\"\r\n [class.bk-menu__submenu--side-up]=\"submenuSide(item) === 'up'\"\r\n [style.top.px]=\"popupTop(item)\"\r\n [style.left.px]=\"popupLeft(item)\"\r\n [style.maxWidth]=\"popupMaxWidth(item)\"\r\n [style.maxHeight]=\"popupMaxHeight(item)\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"item.childrenLabel || item.label\">\r\n @if (item.childrenLabel) {\r\n <li\r\n class=\"bk-menu__group-title\"\r\n [style.paddingLeft.px]=\"groupTitleIndent(level)\"\r\n (mouseenter)=\"onLabelEnter($event)\"\r\n role=\"presentation\">\r\n {{ item.childrenLabel }}\r\n </li>\r\n }\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl;\r\n context: { $implicit: item.children, level: level + 1, parent: item }\">\r\n </ng-container>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n", styles: [".bk-menu{--menu-bg: #ffffff;--menu-submenu-bg: #f8f8f8;--menu-text: #141414;--menu-subtext: #6b7080;--menu-hover-bg: #edeef0;--menu-hover-text: #141414;--menu-active-bg: #141414;--menu-active-text: #ffffff;--menu-border: #efeff1;--menu-shadow: 0 7px 18px 0 rgba(0, 0, 0, .09);--menu-radius: 8px;--menu-disabled: .5;--menu-font-size: 14px;--menu-tracking: -.28px;--menu-pad-y: 10px;--menu-submenu-pad-y: 8px;--menu-pad-x: 12px;--menu-gap: 8px;--menu-icon-size: 16px;--menu-chevron-size: 16px;--menu-group-font-size: 11px;--menu-title-outdent: 8px;--menu-popup-pad: 4px;--menu-popup-pad-y: 8px;--menu-popup-item-pad-x: 16px;--menu-popup-min-w: 200px;--menu-popup-max-w: 280px;@apply block w-full max-w-full font-medium bg-[var(--menu-bg)] text-[color:var(--menu-text)] border border-[var(--menu-border)] rounded-[var(--menu-radius)] overflow-hidden;font-size:var(--menu-font-size);letter-spacing:var(--menu-tracking)}.bk-menu--compact{--menu-radius: 6px;--menu-font-size: 12px;--menu-tracking: -.24px;--menu-pad-y: 6px;--menu-submenu-pad-y: 4px;--menu-pad-x: 8px;--menu-gap: 6px;--menu-icon-size: 14px;--menu-chevron-size: 14px;--menu-group-font-size: 10px;--menu-title-outdent: 6px;--menu-popup-pad: 3px;--menu-popup-pad-y: 6px;--menu-popup-item-pad-x: 14px;--menu-popup-min-w: 160px;--menu-popup-max-w: 240px}.bk-menu__list,.bk-menu__submenu{@apply list-none m-0 p-0;}.bk-menu__list--scroll{@apply overflow-auto;}.bk-menu--horizontal>.bk-menu__list{@apply flex flex-row items-stretch overflow-x-auto;}.bk-menu__item{@apply relative;}.bk-menu__button{@apply flex items-center w-full m-0 border-0 bg-transparent text-inherit text-left cursor-pointer whitespace-nowrap transition-colors duration-100;font:inherit;letter-spacing:inherit;gap:var(--menu-gap);padding:var(--menu-pad-y) var(--menu-pad-x)}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{@apply w-auto;}.bk-menu--vertical>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{@apply rounded-t-[var(--menu-radius)];}.bk-menu--vertical>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{@apply rounded-b-[var(--menu-radius)];}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{@apply rounded-l-[var(--menu-radius)];}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{@apply rounded-r-[var(--menu-radius)];}.bk-menu__button:hover:not(:disabled):not(.bk-menu__button--active){@apply bg-[var(--menu-hover-bg)] text-[color:var(--menu-hover-text)];}.bk-menu__button--active{@apply bg-[var(--menu-active-bg)] text-[color:var(--menu-active-text)];}.bk-menu__button--disabled,.bk-menu__button:disabled{@apply opacity-[var(--menu-disabled)] cursor-not-allowed;}.bk-menu__submenu .bk-menu__button{@apply text-[color:var(--menu-subtext)] font-normal;padding-top:var(--menu-submenu-pad-y);padding-bottom:var(--menu-submenu-pad-y)}.bk-menu__submenu--popup .bk-menu__button{padding-left:var(--menu-popup-item-pad-x);padding-right:var(--menu-popup-item-pad-x)}.bk-menu__submenu .bk-menu__button--active{@apply text-[color:var(--menu-active-text)];}.bk-menu__group-title{@apply font-semibold uppercase tracking-wider text-[color:var(--menu-subtext)] whitespace-nowrap overflow-hidden text-ellipsis select-none;font-size:var(--menu-group-font-size);padding:var(--menu-pad-y) var(--menu-pad-x) calc(var(--menu-pad-y) / 2);padding-left:calc(var(--menu-pad-x) - var(--menu-title-outdent))}.bk-menu__submenu--popup>.bk-menu__group-title{margin-left:calc(var(--menu-popup-pad) * -1);margin-right:calc(var(--menu-popup-pad) * -1);padding-left:calc(var(--menu-popup-item-pad-x) - var(--menu-title-outdent) + var(--menu-popup-pad) + 2px);padding-right:calc(var(--menu-popup-item-pad-x) + var(--menu-popup-pad) + 2px)}.bk-menu__group-title--section{@apply mb-0 tracking-wide;padding-top:calc(var(--menu-pad-y) * 1.25)}.bk-menu__group-title--divider{@apply border-t border-[var(--menu-border)];margin-top:calc(var(--menu-pad-y) / 2)}.bk-menu__icon{@apply shrink-0 object-contain;width:var(--menu-icon-size);height:var(--menu-icon-size)}.bk-menu--tint .bk-menu__icon{@apply [filter:brightness(0)_saturate(0)];}.bk-menu--tint .bk-menu__button--active .bk-menu__icon{@apply [filter:brightness(0)_invert(1)];}.bk-menu__label{@apply flex-auto min-w-0 overflow-hidden text-ellipsis;}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button>.bk-menu__label{@apply flex-none overflow-visible;}.bk-menu__chevron{@apply shrink-0 opacity-80 transition-transform duration-[.18s];width:var(--menu-chevron-size);height:var(--menu-chevron-size)}.bk-menu__chevron--open{@apply rotate-180;}.bk-menu__chevron--right{@apply -rotate-90;}.bk-menu__chevron--left{@apply rotate-90;}.bk-menu__submenu--inline{@apply overflow-hidden max-h-0 transition-[max-height] duration-200;}.bk-menu__submenu--inline.bk-menu__submenu--open{@apply max-h-[1000px];}.bk-menu__submenu--inline.bk-menu__submenu--bg{background-color:var(--menu-submenu-bg)}.bk-menu__submenu--popup{@apply fixed z-[1000] max-h-[100vh-16px] overflow-y-auto overflow-x-hidden bg-[var(--menu-bg)] border border-[var(--menu-border)] rounded-xl shadow-[var(--menu-shadow)] hidden;padding:var(--menu-popup-pad-y) var(--menu-popup-pad);min-width:var(--menu-popup-min-w);max-width:var(--menu-popup-max-w)}.bk-menu__submenu--popup.bk-menu__submenu--open{@apply block;}.bk-menu__submenu--placing{@apply opacity-0 pointer-events-none;}@media (max-width: 640px){.bk-menu--horizontal>.bk-menu__list{@apply overflow-x-auto;-webkit-overflow-scrolling:touch}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
10738
10924
|
}
|
|
10739
10925
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, decorators: [{
|
|
10740
10926
|
type: Component,
|
|
@@ -10755,6 +10941,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10755
10941
|
type: Input
|
|
10756
10942
|
}], submenuBackground: [{
|
|
10757
10943
|
type: Input
|
|
10944
|
+
}], emitParentClick: [{
|
|
10945
|
+
type: Input
|
|
10758
10946
|
}], activeItemId: [{
|
|
10759
10947
|
type: Input
|
|
10760
10948
|
}], tintIcons: [{
|
|
@@ -10777,11 +10965,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10777
10965
|
}] } });
|
|
10778
10966
|
|
|
10779
10967
|
/* =========================================================================
|
|
10780
|
-
Placement
|
|
10781
|
-
|
|
10968
|
+
Placement vocabulary for bk-popover, plus the one piece of maths CDK's
|
|
10969
|
+
connected-overlay strategy doesn't do for us: keeping the arrow centred on
|
|
10970
|
+
the *trigger* rather than the panel.
|
|
10782
10971
|
|
|
10783
|
-
|
|
10784
|
-
|
|
10972
|
+
Flip/push/viewport-clamping used to live here by hand (see git history for
|
|
10973
|
+
computePopoverPosition) — Angular CDK Overlay owns all of that now. What's
|
|
10974
|
+
left is DOM-free by design, so the rules stay readable and testable.
|
|
10785
10975
|
========================================================================= */
|
|
10786
10976
|
/** Every placement, in the order a placement picker should show them. */
|
|
10787
10977
|
const POPOVER_PLACEMENTS = [
|
|
@@ -10790,7 +10980,9 @@ const POPOVER_PLACEMENTS = [
|
|
|
10790
10980
|
'bottom-left', 'bottom', 'bottom-right',
|
|
10791
10981
|
'left-top', 'left', 'left-bottom'
|
|
10792
10982
|
];
|
|
10793
|
-
|
|
10983
|
+
/** The side CDK should try when the requested one doesn't fit — only ever the direct
|
|
10984
|
+
* opposite, never a diagonal, so the alignment word stays meaningful after a flip. */
|
|
10985
|
+
const OPPOSITE_SIDE = {
|
|
10794
10986
|
top: 'bottom',
|
|
10795
10987
|
bottom: 'top',
|
|
10796
10988
|
left: 'right',
|
|
@@ -10829,81 +11021,12 @@ function joinPlacement(side, align) {
|
|
|
10829
11021
|
return side;
|
|
10830
11022
|
return `${side}-${ALIGN_EDGES[side][align]}`;
|
|
10831
11023
|
}
|
|
11024
|
+
/** min wins when the range is inverted (arrow limit wider than the panel itself on a very
|
|
11025
|
+
* narrow/maxWidth-constrained panel), which keeps the arrow at the panel's leading edge
|
|
11026
|
+
* rather than pushing it past the trailing one. */
|
|
10832
11027
|
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
11028
|
return Math.max(min, Math.min(value, max));
|
|
10836
11029
|
}
|
|
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
11030
|
|
|
10908
11031
|
/** Edge length of the arrow square. Mirrored by --bk-popover-arrow in popover.css. */
|
|
10909
11032
|
const ARROW_SIZE = 10;
|
|
@@ -10939,11 +11062,36 @@ class BkPopover {
|
|
|
10939
11062
|
openDelay = input(80, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
|
|
10940
11063
|
closeDelay = input(150, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
|
|
10941
11064
|
maxWidth = input('280px', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
|
|
11065
|
+
/**
|
|
11066
|
+
* Fixed panel width, e.g. `'320px'`. Unset by default, so the panel sizes to its content
|
|
11067
|
+
* (capped by `maxWidth`) as before. Set this when the content's natural width shouldn't drive
|
|
11068
|
+
* layout — a form, a fixed-column list — so the panel doesn't reflow between opens as content
|
|
11069
|
+
* changes.
|
|
11070
|
+
*
|
|
11071
|
+
* Overrides `maxWidth` entirely while set — a plain CSS `max-width` would otherwise silently
|
|
11072
|
+
* cap a `width` larger than it (280px default), which is never what setting an exact width was
|
|
11073
|
+
* asking for. Raise `maxWidth` too only if you want *both* a starting width and a cap it can
|
|
11074
|
+
* still grow past for some other reason (e.g. a responsive breakpoint override elsewhere).
|
|
11075
|
+
*/
|
|
11076
|
+
width = input(null, ...(ngDevMode ? [{ debugName: "width" }] : []));
|
|
10942
11077
|
panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : []));
|
|
10943
11078
|
/**
|
|
10944
|
-
*
|
|
10945
|
-
*
|
|
10946
|
-
*
|
|
11079
|
+
* The max-width actually applied to the panel: whichever of `width`/`maxWidth` is in effect,
|
|
11080
|
+
* additionally capped to the viewport so the panel can never extend past the screen edge — an
|
|
11081
|
+
* oversized `width` (or a placement CDK could only push so far before running out of room)
|
|
11082
|
+
* shrinks to fit instead of overflowing. Mirrors the old hand-rolled positioner's clamp(), which
|
|
11083
|
+
* guaranteed the panel stayed fully on-screen; a bare CSS `max-width` alone doesn't provide that
|
|
11084
|
+
* once the requested size is close to (or exceeds) the viewport itself.
|
|
11085
|
+
*/
|
|
11086
|
+
effectiveMaxWidth = computed(() => {
|
|
11087
|
+
const requested = this.width() ?? this.maxWidth();
|
|
11088
|
+
return `min(${requested}, calc(100vw - 16px))`;
|
|
11089
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveMaxWidth" }] : []));
|
|
11090
|
+
/**
|
|
11091
|
+
* @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break.
|
|
11092
|
+
* The panel now always positions via Angular CDK Overlay, which portals into the shared
|
|
11093
|
+
* `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
|
|
11094
|
+
* to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
|
|
10947
11095
|
*/
|
|
10948
11096
|
appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
|
|
10949
11097
|
opened = output();
|
|
@@ -10951,50 +11099,73 @@ class BkPopover {
|
|
|
10951
11099
|
openChange = output();
|
|
10952
11100
|
anchorRef;
|
|
10953
11101
|
panelRef;
|
|
11102
|
+
popoverOverlay;
|
|
10954
11103
|
static activeInstance = null;
|
|
10955
|
-
host = inject(ElementRef);
|
|
10956
11104
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
10957
|
-
/**
|
|
10958
|
-
*
|
|
10959
|
-
*
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
11105
|
+
/** True once CDK has positioned the panel at least once since open() — the template keeps
|
|
11106
|
+
* the panel hidden until then, so the first frame (only there to be measured) never flashes
|
|
11107
|
+
* in the corner. */
|
|
11108
|
+
panelReady = signal(false, ...(ngDevMode ? [{ debugName: "panelReady" }] : []));
|
|
11109
|
+
/** Placement actually applied, once known — null before the first (positionChange) fires
|
|
11110
|
+
* (or once closed), in which case activePlacement()/side() fall back to the requested one. */
|
|
11111
|
+
resolvedPlacement = signal(null, ...(ngDevMode ? [{ debugName: "resolvedPlacement" }] : []));
|
|
10963
11112
|
/** Where the panel actually is, once positioned — may differ from `placement`. */
|
|
10964
|
-
activePlacement = computed(() => this.
|
|
11113
|
+
activePlacement = computed(() => this.resolvedPlacement() ?? this.placement(), ...(ngDevMode ? [{ debugName: "activePlacement" }] : []));
|
|
10965
11114
|
/** Side the panel sits on. Drives which edge the arrow hangs off (see CSS). */
|
|
10966
|
-
side = computed(() =>
|
|
11115
|
+
side = computed(() => splitPlacement(this.activePlacement()).side, ...(ngDevMode ? [{ debugName: "side" }] : []));
|
|
11116
|
+
/** Distance from the panel's leading edge to the arrow's centre, along the panel's cross
|
|
11117
|
+
* axis — null until measured. Recomputed from the *actual rendered rects*, not derived from
|
|
11118
|
+
* CDK's position strategy, so it's correct however CDK had to push/clamp the panel. */
|
|
11119
|
+
arrowOffsetPx = signal(null, ...(ngDevMode ? [{ debugName: "arrowOffsetPx" }] : []));
|
|
11120
|
+
/** Arrow offset along the panel's cross axis — x on top/bottom, y on left/right. */
|
|
11121
|
+
arrowLeft = computed(() => {
|
|
11122
|
+
const px = this.arrowOffsetPx();
|
|
11123
|
+
if (px == null)
|
|
11124
|
+
return null;
|
|
11125
|
+
const s = this.side();
|
|
11126
|
+
return s === 'top' || s === 'bottom' ? px : null;
|
|
11127
|
+
}, ...(ngDevMode ? [{ debugName: "arrowLeft" }] : []));
|
|
11128
|
+
arrowTop = computed(() => {
|
|
11129
|
+
const px = this.arrowOffsetPx();
|
|
11130
|
+
if (px == null)
|
|
11131
|
+
return null;
|
|
11132
|
+
const s = this.side();
|
|
11133
|
+
return s === 'left' || s === 'right' ? px : null;
|
|
11134
|
+
}, ...(ngDevMode ? [{ debugName: "arrowTop" }] : []));
|
|
11135
|
+
/**
|
|
11136
|
+
* Requested position first, its opposite side as a fallback when `flip` allows it — CDK tries
|
|
11137
|
+
* these in order and only falls to the second when the first genuinely doesn't fit. Push (on
|
|
11138
|
+
* by default) then keeps whichever one it lands on inside the viewport, matching the old
|
|
11139
|
+
* hand-rolled shift-along-the-edge behaviour. Each entry is tagged with the side/align it came
|
|
11140
|
+
* from (see positionMeta) so onPositionChange can read back which one CDK actually used.
|
|
11141
|
+
*
|
|
11142
|
+
* A stable field, computed once per open() — not a template-bound getter. A getter re-runs on
|
|
11143
|
+
* every change-detection pass (several times before CDK ever reads it), reassigning
|
|
11144
|
+
* `positionMeta` with fresh object references each time; onPositionChange would then be matching
|
|
11145
|
+
* against an array CDK was never actually given.
|
|
11146
|
+
*/
|
|
11147
|
+
popoverPositions = [];
|
|
11148
|
+
positionMeta = [];
|
|
11149
|
+
computePositions() {
|
|
11150
|
+
const { side, align } = splitPlacement(this.placement());
|
|
11151
|
+
const entries = [
|
|
11152
|
+
{ pos: toConnectedPosition(side, align, this.offset()), side, align }
|
|
11153
|
+
];
|
|
11154
|
+
if (this.flip()) {
|
|
11155
|
+
const oppositeSide = OPPOSITE_SIDE[side];
|
|
11156
|
+
entries.push({ pos: toConnectedPosition(oppositeSide, align, this.offset()), side: oppositeSide, align });
|
|
11157
|
+
}
|
|
11158
|
+
this.positionMeta = entries;
|
|
11159
|
+
this.popoverPositions = entries.map(e => e.pos);
|
|
11160
|
+
}
|
|
10967
11161
|
openTimer = null;
|
|
10968
11162
|
closeTimer = null;
|
|
10969
11163
|
pointerInPanel = false;
|
|
10970
11164
|
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
11165
|
ngOnDestroy() {
|
|
10988
11166
|
this.clearTimers();
|
|
10989
11167
|
this.resizeObserver?.disconnect();
|
|
10990
|
-
|
|
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
|
-
}
|
|
11168
|
+
this.detachOverlayScrollTracking();
|
|
10998
11169
|
if (BkPopover.activeInstance === this)
|
|
10999
11170
|
BkPopover.activeInstance = null;
|
|
11000
11171
|
}
|
|
@@ -11008,36 +11179,28 @@ class BkPopover {
|
|
|
11008
11179
|
}
|
|
11009
11180
|
BkPopover.activeInstance = this;
|
|
11010
11181
|
this.clearTimers();
|
|
11011
|
-
this.
|
|
11182
|
+
this.panelReady.set(false);
|
|
11183
|
+
this.resolvedPlacement.set(null);
|
|
11184
|
+
this.arrowOffsetPx.set(null);
|
|
11185
|
+
this.computePositions();
|
|
11012
11186
|
this.isOpen.set(true);
|
|
11013
11187
|
this.opened.emit();
|
|
11014
11188
|
this.openChange.emit(true);
|
|
11015
|
-
|
|
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
|
-
});
|
|
11189
|
+
this.attachOverlayScrollTracking();
|
|
11031
11190
|
}
|
|
11032
11191
|
close() {
|
|
11033
11192
|
if (!this.isOpen())
|
|
11034
11193
|
return;
|
|
11035
11194
|
this.clearTimers();
|
|
11195
|
+
this.detachOverlayScrollTracking();
|
|
11196
|
+
// Disconnect rather than leave it observing a panel CDK is about to detach — a fresh
|
|
11197
|
+
// observer is (re)created lazily in onPositionChange on the next open.
|
|
11036
11198
|
this.resizeObserver?.disconnect();
|
|
11037
|
-
|
|
11038
|
-
this.restorePanel();
|
|
11199
|
+
this.resizeObserver = undefined;
|
|
11039
11200
|
this.isOpen.set(false);
|
|
11040
|
-
this.
|
|
11201
|
+
this.panelReady.set(false);
|
|
11202
|
+
this.resolvedPlacement.set(null);
|
|
11203
|
+
this.arrowOffsetPx.set(null);
|
|
11041
11204
|
this.pointerInPanel = false;
|
|
11042
11205
|
this.closed.emit();
|
|
11043
11206
|
this.openChange.emit(false);
|
|
@@ -11077,78 +11240,107 @@ class BkPopover {
|
|
|
11077
11240
|
this.pointerInPanel = false;
|
|
11078
11241
|
this.scheduleClose();
|
|
11079
11242
|
}
|
|
11080
|
-
/**
|
|
11081
|
-
|
|
11243
|
+
/**
|
|
11244
|
+
* Click-outside-to-close, driven by CDK's document-level outside-pointer-event dispatcher —
|
|
11245
|
+
* it already excludes clicks on the cdkOverlayOrigin (the anchor) by design, so onAnchorClick()
|
|
11246
|
+
* stays the sole opener/toggler. No backdrop involved, so it doesn't block page/nested-scroll-
|
|
11247
|
+
* container scroll the way a modal's would (see the phone-dropdown writeup for why that matters).
|
|
11248
|
+
*/
|
|
11249
|
+
onOverlayOutsideClick() {
|
|
11082
11250
|
if (this.trigger() !== 'click' || !this.closeOnClickOutside())
|
|
11083
11251
|
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
11252
|
this.close();
|
|
11092
|
-
}
|
|
11253
|
+
}
|
|
11093
11254
|
onEscape() {
|
|
11094
11255
|
if (this.isOpen() && this.closeOnEscape())
|
|
11095
11256
|
this.close();
|
|
11096
11257
|
}
|
|
11097
11258
|
// --- Positioning ---
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11259
|
+
/**
|
|
11260
|
+
* CDK's default `reposition` scroll strategy only reacts to real `document`/`window` scroll —
|
|
11261
|
+
* it has no way to know an app shell might scroll a nested container instead (this one
|
|
11262
|
+
* commonly does — dashboard layouts with a fixed header/sidebar and a scrollable content pane).
|
|
11263
|
+
* A capture-phase listener on `document` still sees scroll events fired on any descendant
|
|
11264
|
+
* scrollable element (scroll doesn't bubble, but capture does) — same trick `bk-select` and the
|
|
11265
|
+
* `bk-input` phone dropdown already use. Also recomputes the arrow, since `updatePosition()`
|
|
11266
|
+
* sliding the panel along the same side doesn't necessarily fire (positionChange) — that only
|
|
11267
|
+
* fires when the *side* changes, not every pixel of a push/slide. rAF-throttled so a fast
|
|
11268
|
+
* scroll doesn't force layout on every tick.
|
|
11269
|
+
*/
|
|
11270
|
+
overlayScrollRafId = null;
|
|
11271
|
+
onOverlayScroll = () => {
|
|
11272
|
+
if (this.overlayScrollRafId != null)
|
|
11273
|
+
return;
|
|
11274
|
+
this.overlayScrollRafId = requestAnimationFrame(() => {
|
|
11275
|
+
this.overlayScrollRafId = null;
|
|
11276
|
+
this.popoverOverlay?.overlayRef?.updatePosition();
|
|
11277
|
+
if (this.panelReady())
|
|
11278
|
+
this.arrowOffsetPx.set(this.computeArrowOffset(this.side()));
|
|
11279
|
+
});
|
|
11101
11280
|
};
|
|
11102
|
-
|
|
11103
|
-
|
|
11281
|
+
attachOverlayScrollTracking() {
|
|
11282
|
+
document.addEventListener('scroll', this.onOverlayScroll, true);
|
|
11283
|
+
window.addEventListener('resize', this.onOverlayScroll);
|
|
11284
|
+
}
|
|
11285
|
+
detachOverlayScrollTracking() {
|
|
11286
|
+
document.removeEventListener('scroll', this.onOverlayScroll, true);
|
|
11287
|
+
window.removeEventListener('resize', this.onOverlayScroll);
|
|
11288
|
+
if (this.overlayScrollRafId != null) {
|
|
11289
|
+
cancelAnimationFrame(this.overlayScrollRafId);
|
|
11290
|
+
this.overlayScrollRafId = null;
|
|
11291
|
+
}
|
|
11292
|
+
}
|
|
11293
|
+
/**
|
|
11294
|
+
* Fires whenever CDK (re)applies a position, including the first one after open. Reads back
|
|
11295
|
+
* which of `popoverPositions`' tagged entries CDK actually used — matched by field value
|
|
11296
|
+
* (positionsEqual), not object reference: CDK's position strategy reconstructs its own
|
|
11297
|
+
* ConnectedPosition objects internally, so `event.connectionPair` is never `===` to the object
|
|
11298
|
+
* we handed it even when it's the exact same logical position. Recomputes the arrow from the
|
|
11299
|
+
* real rendered rects, and — on the very first call — starts observing the panel for
|
|
11300
|
+
* content-size changes and reveals it.
|
|
11301
|
+
*/
|
|
11302
|
+
onPositionChange(event) {
|
|
11303
|
+
const match = this.positionMeta.find(e => positionsEqual(e.pos, event.connectionPair));
|
|
11304
|
+
const side = match?.side ?? splitPlacement(this.placement()).side;
|
|
11305
|
+
const align = match?.align ?? splitPlacement(this.placement()).align;
|
|
11306
|
+
this.resolvedPlacement.set(joinPlacement(side, align));
|
|
11307
|
+
this.arrowOffsetPx.set(this.computeArrowOffset(side));
|
|
11308
|
+
this.panelReady.set(true);
|
|
11309
|
+
// Content can change size while open (async data, an expanding section), which moves every
|
|
11310
|
+
// edge the panel is aligned against — re-run CDK's own positioning, then ours, when it does.
|
|
11311
|
+
// observe() on an already-observed target is a harmless no-op, so no "have we done this
|
|
11312
|
+
// already" guard is needed here.
|
|
11313
|
+
if (typeof ResizeObserver !== 'undefined' && this.panelRef) {
|
|
11314
|
+
if (!this.resizeObserver) {
|
|
11315
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
11316
|
+
this.popoverOverlay?.overlayRef?.updatePosition();
|
|
11317
|
+
if (this.panelReady())
|
|
11318
|
+
this.arrowOffsetPx.set(this.computeArrowOffset(this.side()));
|
|
11319
|
+
});
|
|
11320
|
+
}
|
|
11321
|
+
this.resizeObserver.observe(this.panelRef.nativeElement);
|
|
11322
|
+
}
|
|
11323
|
+
}
|
|
11324
|
+
/**
|
|
11325
|
+
* Arrow offset along the panel's cross axis, measured from the actual rendered anchor/panel
|
|
11326
|
+
* rects rather than reverse-engineered from CDK's position strategy — correct however far CDK
|
|
11327
|
+
* had to push/clamp the panel to stay on screen.
|
|
11328
|
+
*/
|
|
11329
|
+
computeArrowOffset(side) {
|
|
11104
11330
|
const anchor = this.anchorRef?.nativeElement;
|
|
11105
11331
|
const panel = this.panelRef?.nativeElement;
|
|
11106
11332
|
if (!anchor || !panel)
|
|
11107
|
-
return;
|
|
11333
|
+
return 0;
|
|
11108
11334
|
const anchorRect = anchor.getBoundingClientRect();
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
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;
|
|
11335
|
+
const panelRect = panel.getBoundingClientRect();
|
|
11336
|
+
const vertical = side === 'top' || side === 'bottom';
|
|
11337
|
+
const anchorCentre = vertical
|
|
11338
|
+
? anchorRect.left + anchorRect.width / 2
|
|
11339
|
+
: anchorRect.top + anchorRect.height / 2;
|
|
11340
|
+
const panelStart = vertical ? panelRect.left : panelRect.top;
|
|
11341
|
+
const panelSize = vertical ? panelRect.width : panelRect.height;
|
|
11342
|
+
const arrowLimit = ARROW_SIZE / 2 + ARROW_CORNER_GAP;
|
|
11343
|
+
return clamp(anchorCentre - panelStart, arrowLimit, panelSize - arrowLimit);
|
|
11152
11344
|
}
|
|
11153
11345
|
// --- Timers ---
|
|
11154
11346
|
scheduleClose() {
|
|
@@ -11175,27 +11367,65 @@ class BkPopover {
|
|
|
11175
11367
|
this.cancelClose();
|
|
11176
11368
|
}
|
|
11177
11369
|
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@
|
|
11370
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPopover, isStandalone: true, selector: "bk-popover", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "flip", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed", openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "attr.title": "null" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchor"], descendants: true }, { propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true }, { propertyName: "popoverOverlay", first: true, predicate: ["popoverOverlay"], descendants: true }], exportAs: ["bkPopover"], ngImport: i0, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n cdkOverlayOrigin\r\n #popoverOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n<!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of an\r\n inline `position:fixed` div, so it escapes clipping inside dialogs/scroll containers and\r\n stacks correctly above other CDK-overlay content, regardless of the old appendToBody flag (see\r\n its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n-->\r\n<ng-template\r\n cdkConnectedOverlay\r\n #popoverOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"popoverOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"popoverPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\"\r\n>\r\n <!-- Hidden until panelReady(): the first frame exists only so CDK/we can measure it, and\r\n painting it at its initial position first flashes it in the corner. -->\r\n <div\r\n #panel\r\n class=\"bk-popover-panel\"\r\n [ngClass]=\"panelClass()\"\r\n role=\"dialog\"\r\n [attr.data-side]=\"side()\"\r\n [style.width]=\"width()\"\r\n [style.maxWidth]=\"effectiveMaxWidth()\"\r\n [class.bk-popover-ready]=\"panelReady()\"\r\n (mouseenter)=\"onPanelEnter()\"\r\n (mouseleave)=\"onPanelLeave()\"\r\n >\r\n @if (showArrow()) {\r\n <!-- A rotated square, not a border triangle: it inherits the panel's\r\n background and border, so the tip matches the panel on every side.\r\n Sits above the panel's own border, hiding the segment it crosses. -->\r\n <span\r\n class=\"bk-popover-arrow\"\r\n [style.left.px]=\"arrowLeft()\"\r\n [style.top.px]=\"arrowTop()\"\r\n ></span>\r\n }\r\n\r\n @if (title()) {\r\n <div class=\"bk-popover-header\">\r\n <span class=\"bk-popover-title\">{{ title() }}</span>\r\n @if (closable()) {\r\n <button type=\"button\" class=\"bk-popover-close\" aria-label=\"Close\" (click)=\"close()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"bk-popover-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply static z-[10000] bg-white border border-[#E3E3E7] rounded-lg p-3 cursor-default;box-shadow:0 12px 24px -6px #1018281f,0 4px 8px -4px #1018280f;visibility:hidden;opacity:0}.bk-popover-panel.bk-popover-ready{visibility:visible;opacity:1;transition:opacity .12s ease-out}.bk-popover-arrow{@apply absolute block w-2.5 h-2.5 bg-white border border-[#E3E3E7];}.bk-popover-panel[data-side=top] .bk-popover-arrow{bottom:-5px;border-top:none;border-left:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=bottom] .bk-popover-arrow{top:-5px;border-bottom:none;border-right:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=left] .bk-popover-arrow{right:-5px;border-bottom:none;border-left:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-panel[data-side=right] .bk-popover-arrow{left:-5px;border-top:none;border-right:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-header{@apply flex items-start justify-between gap-3 mb-1;}.bk-popover-title{@apply text-sm font-semibold text-[#141414];}.bk-popover-close{@apply shrink-0 text-gray-400 hover:text-[#141414] cursor-pointer -me-1 -mt-0.5;}.bk-popover-body{@apply text-sm font-normal text-[#6B7080];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
|
|
11179
11371
|
}
|
|
11180
11372
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, decorators: [{
|
|
11181
11373
|
type: Component,
|
|
11182
|
-
args: [{ selector: 'bk-popover', standalone: true, exportAs: 'bkPopover', imports: [CommonModule], host: {
|
|
11374
|
+
args: [{ selector: 'bk-popover', standalone: true, exportAs: 'bkPopover', imports: [CommonModule, OverlayModule], host: {
|
|
11183
11375
|
// A static `title="…"` lands on the input *and* stays on the host as a real
|
|
11184
11376
|
// HTML attribute, which the browser would render as its own native tooltip
|
|
11185
11377
|
// over the trigger. Stripping it here means the input can keep the obvious
|
|
11186
11378
|
// name without consumers having to remember to bind it.
|
|
11187
11379
|
'[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@
|
|
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: [{
|
|
11380
|
+
}, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n cdkOverlayOrigin\r\n #popoverOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n<!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of an\r\n inline `position:fixed` div, so it escapes clipping inside dialogs/scroll containers and\r\n stacks correctly above other CDK-overlay content, regardless of the old appendToBody flag (see\r\n its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n-->\r\n<ng-template\r\n cdkConnectedOverlay\r\n #popoverOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"popoverOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"popoverPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\"\r\n>\r\n <!-- Hidden until panelReady(): the first frame exists only so CDK/we can measure it, and\r\n painting it at its initial position first flashes it in the corner. -->\r\n <div\r\n #panel\r\n class=\"bk-popover-panel\"\r\n [ngClass]=\"panelClass()\"\r\n role=\"dialog\"\r\n [attr.data-side]=\"side()\"\r\n [style.width]=\"width()\"\r\n [style.maxWidth]=\"effectiveMaxWidth()\"\r\n [class.bk-popover-ready]=\"panelReady()\"\r\n (mouseenter)=\"onPanelEnter()\"\r\n (mouseleave)=\"onPanelLeave()\"\r\n >\r\n @if (showArrow()) {\r\n <!-- A rotated square, not a border triangle: it inherits the panel's\r\n background and border, so the tip matches the panel on every side.\r\n Sits above the panel's own border, hiding the segment it crosses. -->\r\n <span\r\n class=\"bk-popover-arrow\"\r\n [style.left.px]=\"arrowLeft()\"\r\n [style.top.px]=\"arrowTop()\"\r\n ></span>\r\n }\r\n\r\n @if (title()) {\r\n <div class=\"bk-popover-header\">\r\n <span class=\"bk-popover-title\">{{ title() }}</span>\r\n @if (closable()) {\r\n <button type=\"button\" class=\"bk-popover-close\" aria-label=\"Close\" (click)=\"close()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"bk-popover-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply static z-[10000] bg-white border border-[#E3E3E7] rounded-lg p-3 cursor-default;box-shadow:0 12px 24px -6px #1018281f,0 4px 8px -4px #1018280f;visibility:hidden;opacity:0}.bk-popover-panel.bk-popover-ready{visibility:visible;opacity:1;transition:opacity .12s ease-out}.bk-popover-arrow{@apply absolute block w-2.5 h-2.5 bg-white border border-[#E3E3E7];}.bk-popover-panel[data-side=top] .bk-popover-arrow{bottom:-5px;border-top:none;border-left:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=bottom] .bk-popover-arrow{top:-5px;border-bottom:none;border-right:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=left] .bk-popover-arrow{right:-5px;border-bottom:none;border-left:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-panel[data-side=right] .bk-popover-arrow{left:-5px;border-top:none;border-right:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-header{@apply flex items-start justify-between gap-3 mb-1;}.bk-popover-title{@apply text-sm font-semibold text-[#141414];}.bk-popover-close{@apply shrink-0 text-gray-400 hover:text-[#141414] cursor-pointer -me-1 -mt-0.5;}.bk-popover-body{@apply text-sm font-normal text-[#6B7080];}\n"] }]
|
|
11381
|
+
}], propDecorators: { placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], flip: [{ type: i0.Input, args: [{ isSignal: true, alias: "flip", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], openChange: [{ type: i0.Output, args: ["openChange"] }], anchorRef: [{
|
|
11190
11382
|
type: ViewChild,
|
|
11191
11383
|
args: ['anchor']
|
|
11192
11384
|
}], panelRef: [{
|
|
11193
11385
|
type: ViewChild,
|
|
11194
11386
|
args: ['panel']
|
|
11387
|
+
}], popoverOverlay: [{
|
|
11388
|
+
type: ViewChild,
|
|
11389
|
+
args: ['popoverOverlay']
|
|
11195
11390
|
}], onEscape: [{
|
|
11196
11391
|
type: HostListener,
|
|
11197
11392
|
args: ['document:keydown.escape']
|
|
11198
11393
|
}] } });
|
|
11394
|
+
/** CDK's vertical axis speaks `top`/`bottom`/`center`, not `start`/`end` — unlike the
|
|
11395
|
+
* horizontal axis, it isn't RTL-mirrored, so there's no `start`/`end` to flip. */
|
|
11396
|
+
function alignToVertical(align) {
|
|
11397
|
+
if (align === 'start')
|
|
11398
|
+
return 'top';
|
|
11399
|
+
if (align === 'end')
|
|
11400
|
+
return 'bottom';
|
|
11401
|
+
return 'center';
|
|
11402
|
+
}
|
|
11403
|
+
/** One side+align combination, translated into CDK's connected-position language. */
|
|
11404
|
+
function toConnectedPosition(side, align, offsetPx) {
|
|
11405
|
+
if (side === 'top' || side === 'bottom') {
|
|
11406
|
+
return {
|
|
11407
|
+
originX: align, overlayX: align,
|
|
11408
|
+
originY: side === 'top' ? 'top' : 'bottom',
|
|
11409
|
+
overlayY: side === 'top' ? 'bottom' : 'top',
|
|
11410
|
+
offsetY: side === 'top' ? -offsetPx : offsetPx
|
|
11411
|
+
};
|
|
11412
|
+
}
|
|
11413
|
+
const vertical = alignToVertical(align);
|
|
11414
|
+
return {
|
|
11415
|
+
originY: vertical, overlayY: vertical,
|
|
11416
|
+
originX: side === 'left' ? 'start' : 'end',
|
|
11417
|
+
overlayX: side === 'left' ? 'end' : 'start',
|
|
11418
|
+
offsetX: side === 'left' ? -offsetPx : offsetPx
|
|
11419
|
+
};
|
|
11420
|
+
}
|
|
11421
|
+
/** Field-by-field equality for ConnectedPosition — CDK does not preserve object identity for
|
|
11422
|
+
* positions passed via cdkConnectedOverlayPositions, so `event.connectionPair` must be matched
|
|
11423
|
+
* by value against the entries we handed it, never by `===`. */
|
|
11424
|
+
function positionsEqual(a, b) {
|
|
11425
|
+
return a.originX === b.originX && a.originY === b.originY &&
|
|
11426
|
+
a.overlayX === b.overlayX && a.overlayY === b.overlayY &&
|
|
11427
|
+
(a.offsetX ?? 0) === (b.offsetX ?? 0) && (a.offsetY ?? 0) === (b.offsetY ?? 0);
|
|
11428
|
+
}
|
|
11199
11429
|
|
|
11200
11430
|
/**
|
|
11201
11431
|
* A stacked ("avatar list") group. Renders a set of overlapping `bk-avatar`s and
|
|
@@ -12187,7 +12417,7 @@ class BkTh extends BkCellBase {
|
|
|
12187
12417
|
popover?.close();
|
|
12188
12418
|
}
|
|
12189
12419
|
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 });
|
|
12420
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTh, isStandalone: true, selector: "th[bk-th]", inputs: { columnKeyInput: { classPropertyName: "columnKeyInput", publicName: "columnKey", isSignal: true, isRequired: false, transformFunction: null }, widthInput: { classPropertyName: "widthInput", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, sortOrder: { classPropertyName: "sortOrder", publicName: "sortOrder", isSignal: true, isRequired: false, transformFunction: null }, sortDirections: { classPropertyName: "sortDirections", publicName: "sortDirections", isSignal: true, isRequired: false, transformFunction: null }, sortPriorityInput: { classPropertyName: "sortPriorityInput", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, filterMultiple: { classPropertyName: "filterMultiple", publicName: "filterMultiple", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortOrder: "sortOrderChange", checked: "checkedChange" }, host: { properties: { "class.bk-th-sortable": "showSort()", "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "class.bk-th-align-right": "align() === 'right'", "class.bk-th-align-center": "align() === 'center'", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.width": "widthInput()", "style.text-align": "align()" }, classAttribute: "bk-th" }, usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <!-- Selection column: checkbox, plus a caret when custom selections exist. -->\r\n <div class=\"bk-th-selection\">\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n\r\n @if (selections().length) {\r\n <!-- appendToBody: see the filter popover below \u2014 same containment problem. -->\r\n <bk-popover\r\n #selectionPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-left\"\r\n [showArrow]=\"false\"\r\n [appendToBody]=\"true\"\r\n >\r\n <button type=\"button\" bkPopoverTrigger class=\"bk-th-selection-caret\" aria-label=\"Selection options\">\r\n <svg width=\"8\" height=\"5\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"#78829D\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <ul class=\"bk-table-menu\">\r\n @for (selection of selections(); track selection.text) {\r\n <li>\r\n <button type=\"button\" class=\"bk-table-menu-item\" (click)=\"runSelection(selection, selectionPop)\">\r\n {{ selection.text }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </bk-popover>\r\n }\r\n </div>\r\n} @else {\r\n <div class=\"bk-th-content\" [class.bk-th-clickable]=\"showSort()\">\r\n <!--\r\n Only the label triggers sorting. The filter icon sits outside this span so\r\n opening the menu doesn't also flip the sort order.\r\n -->\r\n <span class=\"bk-th-label\" (click)=\"onSortClick()\">\r\n <ng-content></ng-content>\r\n\r\n @if (showSort()) {\r\n <span\r\n class=\"bk-sort-icon\"\r\n [class.bk-sort-asc]=\"sortOrder() === 'ascend'\"\r\n [class.bk-sort-desc]=\"sortOrder() === 'descend'\"\r\n ></span>\r\n }\r\n\r\n @if (showSort() && sortPriority !== null && sortOrder() !== null) {\r\n <!-- Rank badge: without it, multi-sort gives no clue which column wins. -->\r\n <span class=\"bk-sort-priority\">{{ sortPriority }}</span>\r\n }\r\n </span>\r\n\r\n @if (showFilter()) {\r\n <!--\r\n appendToBody is not optional here. The panel is `position: fixed`, and a\r\n table puts two things in its way: the header cell is inside\r\n `.bk-table-container`, which scrolls, and any transformed ancestor would\r\n turn the panel's viewport coordinates into cell-relative ones. Relocating\r\n it to <body> is the only placement that survives both.\r\n -->\r\n <bk-popover\r\n #filterPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-right\"\r\n [showArrow]=\"false\"\r\n panelClass=\"bk-filter-popover\"\r\n [appendToBody]=\"true\"\r\n (opened)=\"onFilterMenuOpen()\"\r\n >\r\n <button\r\n type=\"button\"\r\n bkPopoverTrigger\r\n class=\"bk-filter-trigger\"\r\n [class.bk-filter-active]=\"isFiltered()\"\r\n aria-label=\"Filter column\"\r\n >\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M1.5 2.5h13L9.5 8.2v4.6l-3 1.7V8.2L1.5 2.5Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.3\"\r\n stroke-linejoin=\"round\"\r\n [attr.fill]=\"isFiltered() ? 'currentColor' : 'none'\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"bk-filter-menu\">\r\n <ul class=\"bk-filter-list\">\r\n @for (option of filters(); track option.value) {\r\n <li class=\"bk-filter-option\">\r\n @if (filterMultiple()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [label]=\"option.text\"\r\n [ngModel]=\"isPending(option.value)\"\r\n (ngModelChange)=\"toggleFilterOption(option.value, $event)\"\r\n ></bk-checkbox>\r\n } @else {\r\n <bk-radio-button\r\n [label]=\"option.text\"\r\n [value]=\"option.value\"\r\n [ngModel]=\"singleFilter\"\r\n (ngModelChange)=\"singleFilter = $event\"\r\n ></bk-radio-button>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <div class=\"bk-filter-actions\">\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-link\" (click)=\"resetFilter(filterPop)\">\r\n Reset\r\n </button>\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-primary\" (click)=\"applyFilter(filterPop)\">\r\n OK\r\n </button>\r\n </div>\r\n </div>\r\n </bk-popover>\r\n }\r\n </div>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkRadioButton, selector: "bk-radio-button", inputs: ["radioClass", "label", "labelClass", "value", "uncheckedValue", "allowDeselect", "disabled", "variant"], outputs: ["change"] }, { kind: "component", type: BkPopover, selector: "bk-popover", inputs: ["placement", "trigger", "title", "closable", "disabled", "showArrow", "offset", "flip", "closeOnClickOutside", "closeOnEscape", "openDelay", "closeDelay", "maxWidth", "width", "panelClass", "appendToBody"], outputs: ["opened", "closed", "openChange"], exportAs: ["bkPopover"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
12191
12421
|
}
|
|
12192
12422
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, decorators: [{
|
|
12193
12423
|
type: Component,
|
|
@@ -12840,5 +13070,5 @@ const BK_TABLE = [
|
|
|
12840
13070
|
* Generated bundle index. Do not edit.
|
|
12841
13071
|
*/
|
|
12842
13072
|
|
|
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,
|
|
13073
|
+
export { ARROW_CORNER_GAP, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, DEFAULT_COUNTRY_OPTIONS, NEUTRAL_APPEARANCE, OPPOSITE_SIDE, POPOVER_PLACEMENTS, clamp, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
|
|
12844
13074
|
//# sourceMappingURL=brickclay-org-ui.mjs.map
|