@brickclay-org/ui 0.1.77 → 0.1.78
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 +1822 -48
- package/fesm2022/brickclay-org-ui.mjs.map +1 -1
- package/index.d.ts +1053 -17
- package/package.json +1 -1
- package/src/assets/icons/no-data-found.jpg +0 -0
- package/src/lib/column-select/components/column-select/column-select.css +3 -2
- package/src/lib/input/input.css +88 -0
- package/src/lib/menu/menu.css +65 -13
- package/src/lib/table/table.css +646 -0
- package/src/styles.css +1 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, EventEmitter, forwardRef, HostListener, ViewChild, Input, Output, Injectable, NgModule, ViewEncapsulation, Optional, Self, Directive, ChangeDetectionStrategy, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, createComponent } from '@angular/core';
|
|
2
|
+
import { Component, EventEmitter, forwardRef, HostListener, ViewChild, Input, Output, Injectable, NgModule, ViewEncapsulation, Optional, Self, Directive, ChangeDetectionStrategy, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, createComponent, NgZone, ContentChild } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
|
-
import { CommonModule, NgClass } from '@angular/common';
|
|
4
|
+
import { CommonModule, NgClass, NgTemplateOutlet } from '@angular/common';
|
|
5
5
|
import * as i2 from '@angular/forms';
|
|
6
6
|
import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
|
|
7
7
|
import moment from 'moment';
|
|
8
8
|
import { Subject, filter } from 'rxjs';
|
|
9
9
|
import * as i2$1 from '@angular/cdk/drag-drop';
|
|
10
|
-
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
11
|
-
import * as
|
|
12
|
-
import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
|
|
10
|
+
import { moveItemInArray, DragDropModule, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
11
|
+
import * as i2$2 from '@angular/cdk/scrolling';
|
|
12
|
+
import { ScrollingModule, CdkScrollable, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
|
13
13
|
import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
|
|
14
14
|
import { DIALOG_DATA, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
|
|
15
15
|
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
@@ -4276,10 +4276,18 @@ class BKTooltipDirective {
|
|
|
4276
4276
|
// this.renderer.removeStyle(document.body, 'overflow-x');
|
|
4277
4277
|
// }
|
|
4278
4278
|
// }
|
|
4279
|
-
// Hide tooltip
|
|
4280
|
-
//
|
|
4279
|
+
// Hide tooltip the instant *any* mousedown happens, not just on this host:
|
|
4280
|
+
// otherwise a tooltip shown by hovering one element (e.g. a "+N" badge)
|
|
4281
|
+
// can still be mid-fade — mouseleave's hide is debounced 100ms and the
|
|
4282
|
+
// fade itself takes 300ms — when a click elsewhere opens something else
|
|
4283
|
+
// (a dropdown panel, another tooltip's host), so the two stack visibly.
|
|
4284
|
+
// Also covers CDK drag-drop, which steals the element before mouseleave fires.
|
|
4281
4285
|
onInteract() {
|
|
4282
|
-
this.
|
|
4286
|
+
if (this.hideTimeout) {
|
|
4287
|
+
clearTimeout(this.hideTimeout);
|
|
4288
|
+
this.hideTimeout = null;
|
|
4289
|
+
}
|
|
4290
|
+
this.hideTooltipInstant();
|
|
4283
4291
|
}
|
|
4284
4292
|
onWindowChange() {
|
|
4285
4293
|
if (this.tooltipElement?.style.visibility === 'visible') {
|
|
@@ -4295,6 +4303,19 @@ class BKTooltipDirective {
|
|
|
4295
4303
|
}
|
|
4296
4304
|
return true;
|
|
4297
4305
|
}
|
|
4306
|
+
/** Snap-hide with no fade: used when something else (a dropdown panel, another
|
|
4307
|
+
* tooltip) is opening right now, so the two never visibly overlap mid-fade. */
|
|
4308
|
+
hideTooltipInstant() {
|
|
4309
|
+
if (this.tooltipElement) {
|
|
4310
|
+
this.renderer.setStyle(this.tooltipElement, 'transition', 'none');
|
|
4311
|
+
this.hideTooltip();
|
|
4312
|
+
requestAnimationFrame(() => {
|
|
4313
|
+
if (this.tooltipElement)
|
|
4314
|
+
this.renderer.removeStyle(this.tooltipElement, 'transition');
|
|
4315
|
+
});
|
|
4316
|
+
}
|
|
4317
|
+
this.isHoveringTooltip = false;
|
|
4318
|
+
}
|
|
4298
4319
|
hideTooltip() {
|
|
4299
4320
|
if (this.tooltipElement) {
|
|
4300
4321
|
this.setStyle(this.tooltipElement, {
|
|
@@ -4608,7 +4629,7 @@ class BKTooltipDirective {
|
|
|
4608
4629
|
});
|
|
4609
4630
|
}
|
|
4610
4631
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
4611
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BKTooltipDirective, isStandalone: true, selector: "[bkTooltip]", inputs: { tooltipContent: ["bkTooltip", "tooltipContent"], tooltipPosition: ["bkTooltipPosition", "tooltipPosition"], scrollable: ["bkTooltipScrollable", "scrollable"], maxHeight: ["bkTooltipMaxHeight", "maxHeight"], tooltipSize: ["bkTooltipSize", "tooltipSize"], autoHeight: ["bkTooltipAutoHeight", "autoHeight"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "mousedown": "onInteract()", "touchstart": "onInteract()", "window:scroll": "onWindowChange()", "window:resize": "onWindowChange()" } }, usesOnChanges: true, ngImport: i0 });
|
|
4632
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BKTooltipDirective, isStandalone: true, selector: "[bkTooltip]", inputs: { tooltipContent: ["bkTooltip", "tooltipContent"], tooltipPosition: ["bkTooltipPosition", "tooltipPosition"], scrollable: ["bkTooltipScrollable", "scrollable"], maxHeight: ["bkTooltipMaxHeight", "maxHeight"], tooltipSize: ["bkTooltipSize", "tooltipSize"], autoHeight: ["bkTooltipAutoHeight", "autoHeight"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "document:mousedown": "onInteract()", "touchstart": "onInteract()", "window:scroll": "onWindowChange()", "window:resize": "onWindowChange()" } }, usesOnChanges: true, ngImport: i0 });
|
|
4612
4633
|
}
|
|
4613
4634
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BKTooltipDirective, decorators: [{
|
|
4614
4635
|
type: Directive,
|
|
@@ -4642,7 +4663,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4642
4663
|
args: ['mouseleave']
|
|
4643
4664
|
}], onInteract: [{
|
|
4644
4665
|
type: HostListener,
|
|
4645
|
-
args: ['mousedown']
|
|
4666
|
+
args: ['document:mousedown']
|
|
4646
4667
|
}, {
|
|
4647
4668
|
type: HostListener,
|
|
4648
4669
|
args: ['touchstart']
|
|
@@ -4665,6 +4686,9 @@ class BkGrid {
|
|
|
4665
4686
|
actionClass = '';
|
|
4666
4687
|
showNoRecords = false;
|
|
4667
4688
|
noRecordFoundHeight = '';
|
|
4689
|
+
/** Custom illustration for the empty state. Falls back to a built-in SVG when omitted. */
|
|
4690
|
+
noRecordImgUrl;
|
|
4691
|
+
noRecordMessage = 'Data may be empty, or try adjusting your filter.';
|
|
4668
4692
|
change = new EventEmitter();
|
|
4669
4693
|
/* ================= Outputs ================= */
|
|
4670
4694
|
actionClick = new EventEmitter();
|
|
@@ -4818,12 +4842,15 @@ class BkGrid {
|
|
|
4818
4842
|
});
|
|
4819
4843
|
});
|
|
4820
4844
|
}
|
|
4845
|
+
get noRecordImagePath() {
|
|
4846
|
+
return this.noRecordImgUrl || '../../../../assets/icons/no-data-found.jpg';
|
|
4847
|
+
}
|
|
4821
4848
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4822
|
-
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" }, 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 <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=\"./assets/media/logos/no-data-found.jpg\"\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 >Data may be empty, or try adjusting your filter.</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"], 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"] }] });
|
|
4849
|
+
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" }, 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\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"], 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"] }] });
|
|
4823
4850
|
}
|
|
4824
4851
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, decorators: [{
|
|
4825
4852
|
type: Component,
|
|
4826
|
-
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 <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=\"./assets/media/logos/no-data-found.jpg\"\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 >Data may be empty, or try adjusting your filter.</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"] }]
|
|
4853
|
+
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\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"] }]
|
|
4827
4854
|
}], propDecorators: { draggable: [{
|
|
4828
4855
|
type: Input
|
|
4829
4856
|
}], columns: [{
|
|
@@ -4842,6 +4869,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4842
4869
|
type: Input
|
|
4843
4870
|
}], noRecordFoundHeight: [{
|
|
4844
4871
|
type: Input
|
|
4872
|
+
}], noRecordImgUrl: [{
|
|
4873
|
+
type: Input
|
|
4874
|
+
}], noRecordMessage: [{
|
|
4875
|
+
type: Input
|
|
4845
4876
|
}], change: [{
|
|
4846
4877
|
type: Output
|
|
4847
4878
|
}], actionClick: [{
|
|
@@ -5957,7 +5988,7 @@ class BkSelect {
|
|
|
5957
5988
|
useExisting: forwardRef(() => BkSelect),
|
|
5958
5989
|
multi: true
|
|
5959
5990
|
}
|
|
5960
|
-
], 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\">\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 >+{{ 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 [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 >\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 <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 </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-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-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: "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"] }] });
|
|
5991
|
+
], 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\">\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 [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 >\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 <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 </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-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-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: "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"] }] });
|
|
5961
5992
|
}
|
|
5962
5993
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
|
|
5963
5994
|
type: Component,
|
|
@@ -5967,7 +5998,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5967
5998
|
useExisting: forwardRef(() => BkSelect),
|
|
5968
5999
|
multi: true
|
|
5969
6000
|
}
|
|
5970
|
-
], template: "<div class=\"bk-select-container\" [ngClass]=\"variation\">\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 >+{{ 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 [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 >\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 <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 </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-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-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"] }]
|
|
6001
|
+
], template: "<div class=\"bk-select-container\" [ngClass]=\"variation\">\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 [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 >\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 <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 </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-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-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"] }]
|
|
5971
6002
|
}], 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 }] }], 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: [{
|
|
5972
6003
|
type: Input
|
|
5973
6004
|
}], label: [{
|
|
@@ -6023,6 +6054,8 @@ class BkInput {
|
|
|
6023
6054
|
hint = '';
|
|
6024
6055
|
required = false;
|
|
6025
6056
|
type = 'text';
|
|
6057
|
+
/** 'sm' shrinks height, padding, font size and icon sizing for compact contexts (e.g. dropdown search boxes). */
|
|
6058
|
+
size = 'default';
|
|
6026
6059
|
value = '';
|
|
6027
6060
|
hasError = false;
|
|
6028
6061
|
showErrorIcon = false;
|
|
@@ -6311,14 +6344,14 @@ class BkInput {
|
|
|
6311
6344
|
this.pendingMaskedValue = null;
|
|
6312
6345
|
}
|
|
6313
6346
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6314
|
-
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", 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", countryCode: "countryCode", countryOptions: "countryOptions", iconOrientation: "iconOrientation", password: "password", showPassword: "showPassword", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
|
|
6347
|
+
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", countryCode: "countryCode", countryOptions: "countryOptions", iconOrientation: "iconOrientation", password: "password", showPassword: "showPassword", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
|
|
6315
6348
|
provideNgxMask(),
|
|
6316
6349
|
{
|
|
6317
6350
|
provide: NG_VALUE_ACCESSOR,
|
|
6318
6351
|
useExisting: forwardRef(() => BkInput),
|
|
6319
6352
|
multi: true
|
|
6320
6353
|
}
|
|
6321
|
-
], 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\">\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 (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--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--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(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--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-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}\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 }] });
|
|
6354
|
+
], 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 (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--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--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(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--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-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--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 }] });
|
|
6322
6355
|
}
|
|
6323
6356
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, decorators: [{
|
|
6324
6357
|
type: Component,
|
|
@@ -6329,7 +6362,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6329
6362
|
useExisting: forwardRef(() => BkInput),
|
|
6330
6363
|
multi: true
|
|
6331
6364
|
}
|
|
6332
|
-
], template: "<div class=\"input-container\">\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 (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--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--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(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--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-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}\n"] }]
|
|
6365
|
+
], 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 (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--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--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(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--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-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--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"] }]
|
|
6333
6366
|
}], propDecorators: { id: [{
|
|
6334
6367
|
type: Input
|
|
6335
6368
|
}], name: [{
|
|
@@ -6350,6 +6383,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6350
6383
|
type: Input
|
|
6351
6384
|
}], type: [{
|
|
6352
6385
|
type: Input
|
|
6386
|
+
}], size: [{
|
|
6387
|
+
type: Input
|
|
6353
6388
|
}], value: [{
|
|
6354
6389
|
type: Input
|
|
6355
6390
|
}], hasError: [{
|
|
@@ -7763,7 +7798,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7763
7798
|
*/
|
|
7764
7799
|
class BkDialogContent {
|
|
7765
7800
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7766
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive:
|
|
7801
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive: i2$2.CdkScrollable }], ngImport: i0 });
|
|
7767
7802
|
}
|
|
7768
7803
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, decorators: [{
|
|
7769
7804
|
type: Directive,
|
|
@@ -9131,6 +9166,9 @@ class BkColumnFilterService {
|
|
|
9131
9166
|
localStorage.setItem(key, JSON.stringify(list));
|
|
9132
9167
|
}
|
|
9133
9168
|
showColumn(field, columnsFilterList) {
|
|
9169
|
+
if (!Array.isArray(columnsFilterList)) {
|
|
9170
|
+
return false;
|
|
9171
|
+
}
|
|
9134
9172
|
return columnsFilterList.find((i) => i.columnName === field)?.selected || false;
|
|
9135
9173
|
}
|
|
9136
9174
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkColumnFilterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -9143,6 +9181,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9143
9181
|
}]
|
|
9144
9182
|
}], ctorParameters: () => [] });
|
|
9145
9183
|
|
|
9184
|
+
/** Rough panel footprint used for auto-flip space checks (search input + option rows + padding). */
|
|
9185
|
+
const PANEL_ESTIMATED_WIDTH = 190;
|
|
9186
|
+
const PANEL_ESTIMATED_HEIGHT = 260;
|
|
9146
9187
|
class BkColumnSelect {
|
|
9147
9188
|
columnFilterService;
|
|
9148
9189
|
searchable = false;
|
|
@@ -9151,9 +9192,16 @@ class BkColumnSelect {
|
|
|
9151
9192
|
columns = [];
|
|
9152
9193
|
isOpened = false;
|
|
9153
9194
|
label = 'Columns';
|
|
9154
|
-
lefticon = '../../../../assets/icons/
|
|
9195
|
+
lefticon = '../../../../assets/icons/columns-black.svg';
|
|
9196
|
+
/** Corner the dropdown opens from, relative to the trigger button. */
|
|
9197
|
+
position = 'bottom-right';
|
|
9198
|
+
/** When true, flips each axis independently if there isn't enough viewport room for `position`. */
|
|
9199
|
+
autoFlip = true;
|
|
9155
9200
|
isOpenedChange = new EventEmitter();
|
|
9156
9201
|
formBoxRef;
|
|
9202
|
+
triggerRef;
|
|
9203
|
+
/** Corner actually rendered on — starts from `position`, auto-flipped on open when needed. */
|
|
9204
|
+
resolvedPosition = 'bottom-right';
|
|
9157
9205
|
/** Value bound via ngModel – only updated when user ticks/unticks a checkbox, never on search. */
|
|
9158
9206
|
columnsFilterList = [];
|
|
9159
9207
|
search = '';
|
|
@@ -9177,6 +9225,41 @@ class BkColumnSelect {
|
|
|
9177
9225
|
if ((columnsChanged || cacheKeyChanged) && this.columnsFilterList.length === 0 && this.shouldLoadFromService()) {
|
|
9178
9226
|
this.loadColumnsFilterListFromService();
|
|
9179
9227
|
}
|
|
9228
|
+
if (changes['isOpened']?.currentValue) {
|
|
9229
|
+
this.resolvedPosition = this.computePlacement();
|
|
9230
|
+
}
|
|
9231
|
+
}
|
|
9232
|
+
/** Picks `position`, flipping each axis independently if the trigger doesn't have room for it. */
|
|
9233
|
+
computePlacement() {
|
|
9234
|
+
const triggerEl = this.triggerRef?.nativeElement;
|
|
9235
|
+
const [vertical, horizontal] = this.position.split('-');
|
|
9236
|
+
if (!this.autoFlip || !triggerEl) {
|
|
9237
|
+
return this.position;
|
|
9238
|
+
}
|
|
9239
|
+
const rect = triggerEl.getBoundingClientRect();
|
|
9240
|
+
const spaceBelow = window.innerHeight - rect.bottom;
|
|
9241
|
+
const spaceAbove = rect.top;
|
|
9242
|
+
const resolvedVertical = this.flipIfShort(vertical, 'top', 'bottom', vertical === 'bottom' ? spaceBelow : spaceAbove, vertical === 'bottom' ? spaceAbove : spaceBelow, PANEL_ESTIMATED_HEIGHT);
|
|
9243
|
+
// 'right' hangs the panel leftward from the trigger's right edge (room = rect.right);
|
|
9244
|
+
// 'left' hangs it rightward from the trigger's left edge (room = viewport width - rect.left).
|
|
9245
|
+
const spaceHangingLeft = rect.right;
|
|
9246
|
+
const spaceHangingRight = window.innerWidth - rect.left;
|
|
9247
|
+
const resolvedHorizontal = this.flipIfShort(horizontal, 'right', 'left', horizontal === 'right' ? spaceHangingLeft : spaceHangingRight, horizontal === 'right' ? spaceHangingRight : spaceHangingLeft, PANEL_ESTIMATED_WIDTH);
|
|
9248
|
+
return `${resolvedVertical}-${resolvedHorizontal}`;
|
|
9249
|
+
}
|
|
9250
|
+
/** Flips `current` to its opposite when it doesn't have `needed` space and the opposite has more room. */
|
|
9251
|
+
flipIfShort(current, a, b, spaceCurrent, spaceOpposite, needed) {
|
|
9252
|
+
if (spaceCurrent < needed && spaceOpposite > spaceCurrent) {
|
|
9253
|
+
return current === a ? b : a;
|
|
9254
|
+
}
|
|
9255
|
+
return current;
|
|
9256
|
+
}
|
|
9257
|
+
/** Tailwind classes placing the panel on `resolvedPosition`'s corner of the trigger. */
|
|
9258
|
+
get panelPositionClass() {
|
|
9259
|
+
const [vertical, horizontal] = this.resolvedPosition.split('-');
|
|
9260
|
+
const verticalClass = vertical === 'top' ? 'bottom-full mb-2' : 'top-full mt-2';
|
|
9261
|
+
const horizontalClass = horizontal === 'left' ? 'left-0' : 'right-0';
|
|
9262
|
+
return `${verticalClass} ${horizontalClass}`;
|
|
9180
9263
|
}
|
|
9181
9264
|
shouldLoadFromService() {
|
|
9182
9265
|
return !!this.cacheKey && !!this.columns?.length;
|
|
@@ -9240,13 +9323,13 @@ class BkColumnSelect {
|
|
|
9240
9323
|
return this.columnsFilterList.filter((x) => x.columnName.toLowerCase().includes(this.search.toLowerCase()));
|
|
9241
9324
|
}
|
|
9242
9325
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkColumnSelect, deps: [{ token: BkColumnFilterService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9243
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkColumnSelect, isStandalone: true, selector: "bk-column-select", inputs: { searchable: "searchable", buttonClass: "buttonClass", cacheKey: "cacheKey", columns: "columns", isOpened: "isOpened", label: "label", lefticon: "lefticon" }, outputs: { isOpenedChange: "isOpenedChange" }, host: { listeners: { "document:click": "onClick($event)" } }, providers: [
|
|
9326
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkColumnSelect, isStandalone: true, selector: "bk-column-select", inputs: { searchable: "searchable", buttonClass: "buttonClass", cacheKey: "cacheKey", columns: "columns", isOpened: "isOpened", label: "label", lefticon: "lefticon", position: "position", autoFlip: "autoFlip" }, outputs: { isOpenedChange: "isOpenedChange" }, host: { listeners: { "document:click": "onClick($event)" } }, providers: [
|
|
9244
9327
|
{
|
|
9245
9328
|
provide: NG_VALUE_ACCESSOR,
|
|
9246
9329
|
useExisting: forwardRef(() => BkColumnSelect),
|
|
9247
9330
|
multi: true,
|
|
9248
9331
|
},
|
|
9249
|
-
], viewQueries: [{ propertyName: "formBoxRef", first: true, predicate: ["formBox"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n\r\n <bk-button [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"lefticon\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"label\" [buttonClass]=\"`text-black ${buttonClass}`\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute
|
|
9332
|
+
], viewQueries: [{ propertyName: "formBoxRef", first: true, predicate: ["formBox"], descendants: true }, { propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n\r\n <bk-button #trigger [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"lefticon\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"label\" [buttonClass]=\"`text-black ${buttonClass}`\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute {{ panelPositionClass }} w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl z-[9999]\">\r\n @if(searchable){\r\n <div class=\"px-3 py-1\">\r\n <bk-input [id]=\"'search-input-1'\" [name]=\"'search-input-1'\" [size]=\"'sm'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n </div>\r\n }\r\n <div class=\"column-select-options-list\">\r\n @for (column of list; track column.columnName; let i = $index) {\r\n <div class=\"flex items-center gap-2 px-3 py-1 hover:bg-gray-100 cursor-pointer\">\r\n <bk-checkbox [label]=\"column.columnName\" id=\"columnsFilterList-{{column.columnName}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\" labelClass=\"!text-left\"\r\n (change)=\"onChangeColumnFilter()\">\r\n\r\n </bk-checkbox>\r\n\r\n <!-- <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{column.columnName}}\">\r\n {{column.columnName}}\r\n </label> -->\r\n\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"column-select-option-empty\">No records found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".column-select-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.column-select-options-list{display:flex;flex-direction:column;overflow-y:auto;max-height:225px}\n"], dependencies: [{ 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: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkInput, selector: "bk-input", inputs: ["id", "name", "mask", "dropSpecialCharacters", "autoComplete", "label", "placeholder", "hint", "required", "type", "size", "value", "hasError", "showErrorIcon", "errorMessage", "disabled", "tabIndex", "readOnly", "autoCapitalize", "inputMode", "iconSrc", "iconAlt", "showIcon", "phone", "countryCode", "countryOptions", "iconOrientation", "password", "showPassword", "pattern", "max", "min", "step", "maxlength", "minlength"], outputs: ["input", "change", "focus", "blur", "clicked"] }] });
|
|
9250
9333
|
}
|
|
9251
9334
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkColumnSelect, decorators: [{
|
|
9252
9335
|
type: Component,
|
|
@@ -9256,7 +9339,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9256
9339
|
useExisting: forwardRef(() => BkColumnSelect),
|
|
9257
9340
|
multi: true,
|
|
9258
9341
|
},
|
|
9259
|
-
], template: "<div class=\"relative\">\r\n\r\n <bk-button [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"lefticon\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"label\" [buttonClass]=\"`text-black ${buttonClass}`\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute
|
|
9342
|
+
], template: "<div class=\"relative\">\r\n\r\n <bk-button #trigger [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"lefticon\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"label\" [buttonClass]=\"`text-black ${buttonClass}`\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute {{ panelPositionClass }} w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl z-[9999]\">\r\n @if(searchable){\r\n <div class=\"px-3 py-1\">\r\n <bk-input [id]=\"'search-input-1'\" [name]=\"'search-input-1'\" [size]=\"'sm'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n </div>\r\n }\r\n <div class=\"column-select-options-list\">\r\n @for (column of list; track column.columnName; let i = $index) {\r\n <div class=\"flex items-center gap-2 px-3 py-1 hover:bg-gray-100 cursor-pointer\">\r\n <bk-checkbox [label]=\"column.columnName\" id=\"columnsFilterList-{{column.columnName}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\" labelClass=\"!text-left\"\r\n (change)=\"onChangeColumnFilter()\">\r\n\r\n </bk-checkbox>\r\n\r\n <!-- <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{column.columnName}}\">\r\n {{column.columnName}}\r\n </label> -->\r\n\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"column-select-option-empty\">No records found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".column-select-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.column-select-options-list{display:flex;flex-direction:column;overflow-y:auto;max-height:225px}\n"] }]
|
|
9260
9343
|
}], ctorParameters: () => [{ type: BkColumnFilterService }], propDecorators: { searchable: [{
|
|
9261
9344
|
type: Input
|
|
9262
9345
|
}], buttonClass: [{
|
|
@@ -9271,11 +9354,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9271
9354
|
type: Input
|
|
9272
9355
|
}], lefticon: [{
|
|
9273
9356
|
type: Input
|
|
9357
|
+
}], position: [{
|
|
9358
|
+
type: Input
|
|
9359
|
+
}], autoFlip: [{
|
|
9360
|
+
type: Input
|
|
9274
9361
|
}], isOpenedChange: [{
|
|
9275
9362
|
type: Output
|
|
9276
9363
|
}], formBoxRef: [{
|
|
9277
9364
|
type: ViewChild,
|
|
9278
9365
|
args: ['formBox']
|
|
9366
|
+
}], triggerRef: [{
|
|
9367
|
+
type: ViewChild,
|
|
9368
|
+
args: ['trigger', { read: ElementRef }]
|
|
9279
9369
|
}], onClick: [{
|
|
9280
9370
|
type: HostListener,
|
|
9281
9371
|
args: ['document:click', ['$event']]
|
|
@@ -9893,8 +9983,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9893
9983
|
* open/closed.
|
|
9894
9984
|
* - Submenus render inline (accordion) or as pop-ups, opened by hover or click.
|
|
9895
9985
|
* Pop-ups adapt to the orientation: they drop *below* a horizontal top-level
|
|
9896
|
-
* item and fly out to the side for vertical menus / deeper levels
|
|
9897
|
-
*
|
|
9986
|
+
* item and fly out to the side for vertical menus / deeper levels. Side
|
|
9987
|
+
* fly-outs flip when the preferred side has no room; menubar drop-downs never
|
|
9988
|
+
* flip — they stay under their trigger and scroll instead.
|
|
9898
9989
|
*/
|
|
9899
9990
|
class BkMenu {
|
|
9900
9991
|
host;
|
|
@@ -9909,12 +10000,27 @@ class BkMenu {
|
|
|
9909
10000
|
trigger = 'hover';
|
|
9910
10001
|
/** `compact` shrinks the type, padding and icons for dense layouts. */
|
|
9911
10002
|
size = 'default';
|
|
10003
|
+
/** Fallback grace period for the pointer to cross the gap into a fly-out. */
|
|
10004
|
+
static HOVER_CLOSE_DELAY_MS = 400;
|
|
10005
|
+
/**
|
|
10006
|
+
* Hover mode only: how long (ms) a fly-out survives after the pointer leaves,
|
|
10007
|
+
* giving it time to cross the gap into the panel. Raise it for menus whose
|
|
10008
|
+
* fly-outs sit further from their trigger, or for touch-ish pointers.
|
|
10009
|
+
*/
|
|
10010
|
+
hoverCloseDelay = BkMenu.HOVER_CLOSE_DELAY_MS;
|
|
9912
10011
|
/**
|
|
9913
10012
|
* Keep only one submenu open per level: opening a parent collapses its
|
|
9914
10013
|
* siblings (and their descendants) so the menu stays compact. Pop-up mode
|
|
9915
10014
|
* always behaves this way; this input adds it to inline (accordion) mode.
|
|
9916
10015
|
*/
|
|
9917
10016
|
singleOpen = false;
|
|
10017
|
+
/**
|
|
10018
|
+
* Tints an inline (accordion) submenu's whole block — title + rows — with
|
|
10019
|
+
* the lightest gray token. Off by default. Pop-up submenus don't offer
|
|
10020
|
+
* this: their padding/insets are different, and the panel's own border
|
|
10021
|
+
* already sets it apart from the page.
|
|
10022
|
+
*/
|
|
10023
|
+
submenuBackground = false;
|
|
9918
10024
|
/** Id of the currently selected leaf item. Two-way bindable. */
|
|
9919
10025
|
activeItemId = '';
|
|
9920
10026
|
/** Tint item icons: dark by default, white on the active (dark) row. */
|
|
@@ -9929,7 +10035,7 @@ class BkMenu {
|
|
|
9929
10035
|
itemClick = new EventEmitter();
|
|
9930
10036
|
/** Ids of currently expanded/opened parent nodes. */
|
|
9931
10037
|
openIds = new Set();
|
|
9932
|
-
/** Viewport
|
|
10038
|
+
/** Viewport box for each open fixed-position fly-out, keyed by id. */
|
|
9933
10039
|
popupPos = new Map();
|
|
9934
10040
|
/** Side each open fly-out resolved to — drives the chevron and hover bridge. */
|
|
9935
10041
|
popupSide = new Map();
|
|
@@ -9939,12 +10045,73 @@ class BkMenu {
|
|
|
9939
10045
|
* position never flashes on the wrong side.
|
|
9940
10046
|
*/
|
|
9941
10047
|
measuredIds = new Set();
|
|
9942
|
-
/**
|
|
9943
|
-
|
|
10048
|
+
/** Floor for a fly-out's height cap, so a trigger near the bottom edge still
|
|
10049
|
+
* gets a usable (scrollable) panel rather than a sliver. */
|
|
10050
|
+
static MIN_POPUP_H = 120;
|
|
10051
|
+
/**
|
|
10052
|
+
* Ceiling for a fly-out's height — automatic, not a consumer input. Without
|
|
10053
|
+
* one, a popup with many items grows to fill nearly the whole viewport just
|
|
10054
|
+
* because the room is there. Same three-tier breakpoints bk-select uses for
|
|
10055
|
+
* its options list, so a "large" panel reads the same across the design
|
|
10056
|
+
* system regardless of which component renders it.
|
|
10057
|
+
*/
|
|
10058
|
+
static popupHeightCeiling() {
|
|
10059
|
+
const vh = window.innerHeight;
|
|
10060
|
+
if (vh <= 700)
|
|
10061
|
+
return 125;
|
|
10062
|
+
if (vh <= 900)
|
|
10063
|
+
return 166;
|
|
10064
|
+
return 210;
|
|
10065
|
+
}
|
|
9944
10066
|
closeTimer = null;
|
|
9945
10067
|
constructor(host) {
|
|
9946
10068
|
this.host = host;
|
|
9947
10069
|
}
|
|
10070
|
+
/**
|
|
10071
|
+
* Inline mode: whenever the active leaf is (re)set — including the very
|
|
10072
|
+
* first binding, so a deep link or a page refresh lands with the section
|
|
10073
|
+
* already open — expand every ancestor on its path. Pop-up fly-outs are
|
|
10074
|
+
* driven by hover/click, not by which leaf is active, so this is skipped
|
|
10075
|
+
* in `popup` mode.
|
|
10076
|
+
*/
|
|
10077
|
+
ngOnChanges(changes) {
|
|
10078
|
+
if (this.isPopup)
|
|
10079
|
+
return;
|
|
10080
|
+
if (changes['activeItemId'] || changes['items']) {
|
|
10081
|
+
this.expandAncestorsOfActive();
|
|
10082
|
+
}
|
|
10083
|
+
}
|
|
10084
|
+
expandAncestorsOfActive() {
|
|
10085
|
+
if (!this.activeItemId)
|
|
10086
|
+
return;
|
|
10087
|
+
const chain = this.findAncestorChain(this.items, this.activeItemId);
|
|
10088
|
+
if (!chain)
|
|
10089
|
+
return;
|
|
10090
|
+
let siblings = this.items;
|
|
10091
|
+
for (const id of chain) {
|
|
10092
|
+
if (this.singleOpen) {
|
|
10093
|
+
for (const sibling of siblings) {
|
|
10094
|
+
if (sibling.id !== id)
|
|
10095
|
+
this.closeBranch(sibling);
|
|
10096
|
+
}
|
|
10097
|
+
}
|
|
10098
|
+
this.openIds.add(id);
|
|
10099
|
+
siblings = siblings.find(item => item.id === id)?.children ?? [];
|
|
10100
|
+
}
|
|
10101
|
+
}
|
|
10102
|
+
/** Ids of every ancestor leading to `targetId` (root-first), `[]` if it's top-level, or `null` if not found. */
|
|
10103
|
+
findAncestorChain(items, targetId) {
|
|
10104
|
+
for (const item of items) {
|
|
10105
|
+
if (item.id === targetId)
|
|
10106
|
+
return [];
|
|
10107
|
+
if (item.children?.length) {
|
|
10108
|
+
const nested = this.findAncestorChain(item.children, targetId);
|
|
10109
|
+
if (nested)
|
|
10110
|
+
return [item.id, ...nested];
|
|
10111
|
+
}
|
|
10112
|
+
}
|
|
10113
|
+
return null;
|
|
10114
|
+
}
|
|
9948
10115
|
get isVertical() { return this.orientation === 'vertical'; }
|
|
9949
10116
|
get isPopup() { return this.submenuMode === 'popup'; }
|
|
9950
10117
|
get isCompact() { return this.size === 'compact'; }
|
|
@@ -9962,6 +10129,27 @@ class BkMenu {
|
|
|
9962
10129
|
popupLeft(item) {
|
|
9963
10130
|
return this.isPopup ? (this.popupPos.get(item.id)?.left ?? null) : null;
|
|
9964
10131
|
}
|
|
10132
|
+
// Size caps for an open fly-out. Width keeps the CSS cap as the upper bound and
|
|
10133
|
+
// only tightens it when the viewport is narrower; height is whatever room is
|
|
10134
|
+
// left below/beside the trigger, past which the panel scrolls.
|
|
10135
|
+
popupMaxWidth(item) {
|
|
10136
|
+
const box = this.isPopup ? this.popupPos.get(item.id) : null;
|
|
10137
|
+
return box ? `min(var(--menu-popup-max-w), ${box.maxW}px)` : null;
|
|
10138
|
+
}
|
|
10139
|
+
popupMaxHeight(item) {
|
|
10140
|
+
const box = this.isPopup ? this.popupPos.get(item.id) : null;
|
|
10141
|
+
return box ? `${box.maxH}px` : null;
|
|
10142
|
+
}
|
|
10143
|
+
// Labels are capped by the panel width and ellipsised; a tooltip would be noise
|
|
10144
|
+
// on the ones that fit, so it is attached on hover, only when actually clipped.
|
|
10145
|
+
onLabelEnter(event) {
|
|
10146
|
+
const el = event.currentTarget;
|
|
10147
|
+
const text = (el.textContent ?? '').trim();
|
|
10148
|
+
if (el.scrollWidth > el.clientWidth + 1)
|
|
10149
|
+
el.setAttribute('title', text);
|
|
10150
|
+
else
|
|
10151
|
+
el.removeAttribute('title');
|
|
10152
|
+
}
|
|
9965
10153
|
/** Resolved side of an open fly-out, or null before it has been placed. */
|
|
9966
10154
|
submenuSide(item) {
|
|
9967
10155
|
return this.isPopup ? (this.popupSide.get(item.id) ?? null) : null;
|
|
@@ -9981,6 +10169,15 @@ class BkMenu {
|
|
|
9981
10169
|
hasChildren(item) {
|
|
9982
10170
|
return !!item.children && item.children.length > 0;
|
|
9983
10171
|
}
|
|
10172
|
+
// Whether the item at `index` opens a new `groupLabel` section: it has one,
|
|
10173
|
+
// and it differs from the sibling right before it (the first item always
|
|
10174
|
+
// starts a section, so the very first group gets a heading but no divider).
|
|
10175
|
+
isGroupStart(items, index) {
|
|
10176
|
+
const item = items[index];
|
|
10177
|
+
if (!item.groupLabel)
|
|
10178
|
+
return false;
|
|
10179
|
+
return index === 0 || items[index - 1].groupLabel !== item.groupLabel;
|
|
10180
|
+
}
|
|
9984
10181
|
isOpen(item) {
|
|
9985
10182
|
return this.openIds.has(item.id);
|
|
9986
10183
|
}
|
|
@@ -10076,7 +10273,7 @@ class BkMenu {
|
|
|
10076
10273
|
this.closeTimer = setTimeout(() => {
|
|
10077
10274
|
this.closeTimer = null;
|
|
10078
10275
|
this.closeBranch(item);
|
|
10079
|
-
},
|
|
10276
|
+
}, Math.max(0, this.hoverCloseDelay));
|
|
10080
10277
|
}
|
|
10081
10278
|
cancelPendingClose() {
|
|
10082
10279
|
if (this.closeTimer === null)
|
|
@@ -10127,24 +10324,20 @@ class BkMenu {
|
|
|
10127
10324
|
const pad = 8;
|
|
10128
10325
|
const vw = window.innerWidth;
|
|
10129
10326
|
const vh = window.innerHeight;
|
|
10130
|
-
const
|
|
10327
|
+
const maxW = vw - pad * 2;
|
|
10328
|
+
const w = Math.min(size?.w ?? 220, maxW);
|
|
10131
10329
|
const h = size?.h ?? 0;
|
|
10132
10330
|
if (prefer === 'down' || prefer === 'up') {
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
}
|
|
10144
|
-
let left = rect.left;
|
|
10145
|
-
if (left + w > vw - pad)
|
|
10146
|
-
left = rect.right - w; // right-align under the trigger
|
|
10147
|
-
return { pos: { top, left: this.clamp(left, pad, vw - pad - w) }, side };
|
|
10331
|
+
// Menubar drop-down: it always drops *down*, left-aligned to its trigger.
|
|
10332
|
+
// No flipping here — a top-level item is at the top of the page, so both
|
|
10333
|
+
// flips (up, and right-aligning) only ever tore the panel away from the
|
|
10334
|
+
// button it belongs to. Overflow is absorbed by clamping into the viewport
|
|
10335
|
+
// and scrolling inside the panel instead.
|
|
10336
|
+
const top = rect.bottom + gap;
|
|
10337
|
+
const left = this.clamp(rect.left, pad, vw - pad - w);
|
|
10338
|
+
const room = Math.max(BkMenu.MIN_POPUP_H, vh - pad - top);
|
|
10339
|
+
const maxH = Math.min(room, BkMenu.popupHeightCeiling());
|
|
10340
|
+
return { pos: { top, left, maxW, maxH }, side: 'down' };
|
|
10148
10341
|
}
|
|
10149
10342
|
// Sideways: take the preferred side if the panel fits, else the other one —
|
|
10150
10343
|
// and if it fits on neither, the side with more room to be clamped into.
|
|
@@ -10161,7 +10354,9 @@ class BkMenu {
|
|
|
10161
10354
|
let top = rect.top;
|
|
10162
10355
|
if (h && top + h > vh - pad)
|
|
10163
10356
|
top = Math.max(pad, vh - pad - h);
|
|
10164
|
-
|
|
10357
|
+
const room = Math.max(BkMenu.MIN_POPUP_H, vh - pad - top);
|
|
10358
|
+
const maxH = Math.min(room, BkMenu.popupHeightCeiling());
|
|
10359
|
+
return { pos: { top, left: this.clamp(left, pad, vw - pad - w), maxW, maxH }, side };
|
|
10165
10360
|
}
|
|
10166
10361
|
clamp(value, min, max) {
|
|
10167
10362
|
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
@@ -10206,11 +10401,11 @@ class BkMenu {
|
|
|
10206
10401
|
this.closeAll();
|
|
10207
10402
|
}
|
|
10208
10403
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
10209
|
-
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", singleOpen: "singleOpen", activeItemId: "activeItemId", tintIcons: "tintIcons", maxHeight: "maxHeight" }, outputs: { activeItemIdChange: "activeItemIdChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)", "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, 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) {\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\">{{ 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--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 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 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-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-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-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-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-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;}.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 border-b border-[var(--menu-border)] mb-1;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-pad-x) - var(--menu-title-outdent) + var(--menu-popup-pad));padding-right:calc(var(--menu-pad-x) + var(--menu-popup-pad))}.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--popup{@apply fixed z-[1000] max-h-[100vh-16px] overflow-y-auto bg-[var(--menu-bg)] border border-[var(--menu-border)] rounded-xl shadow-[var(--menu-shadow)] hidden;padding: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"] }] });
|
|
10404
|
+
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"] }] });
|
|
10210
10405
|
}
|
|
10211
10406
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, decorators: [{
|
|
10212
10407
|
type: Component,
|
|
10213
|
-
args: [{ selector: 'bk-menu', standalone: true, imports: [CommonModule], 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) {\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\">{{ 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--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 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 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-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-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-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-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-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;}.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 border-b border-[var(--menu-border)] mb-1;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-pad-x) - var(--menu-title-outdent) + var(--menu-popup-pad));padding-right:calc(var(--menu-pad-x) + var(--menu-popup-pad))}.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--popup{@apply fixed z-[1000] max-h-[100vh-16px] overflow-y-auto bg-[var(--menu-bg)] border border-[var(--menu-border)] rounded-xl shadow-[var(--menu-shadow)] hidden;padding: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"] }]
|
|
10408
|
+
args: [{ selector: 'bk-menu', standalone: true, imports: [CommonModule], 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"] }]
|
|
10214
10409
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { items: [{
|
|
10215
10410
|
type: Input
|
|
10216
10411
|
}], orientation: [{
|
|
@@ -10221,8 +10416,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10221
10416
|
type: Input
|
|
10222
10417
|
}], size: [{
|
|
10223
10418
|
type: Input
|
|
10419
|
+
}], hoverCloseDelay: [{
|
|
10420
|
+
type: Input
|
|
10224
10421
|
}], singleOpen: [{
|
|
10225
10422
|
type: Input
|
|
10423
|
+
}], submenuBackground: [{
|
|
10424
|
+
type: Input
|
|
10226
10425
|
}], activeItemId: [{
|
|
10227
10426
|
type: Input
|
|
10228
10427
|
}], tintIcons: [{
|
|
@@ -10720,6 +10919,1581 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10720
10919
|
type: Input
|
|
10721
10920
|
}] } });
|
|
10722
10921
|
|
|
10922
|
+
/**
|
|
10923
|
+
* Types for bk-table.
|
|
10924
|
+
*
|
|
10925
|
+
* The control is template-driven: consumers write their own <thead>/<tbody>
|
|
10926
|
+
* markup and the component supplies behaviour. These types describe the
|
|
10927
|
+
* contracts passed *into* that markup — sorting, filtering and query state.
|
|
10928
|
+
*/
|
|
10929
|
+
function normalizeBkTableSize(size) {
|
|
10930
|
+
if (size === 'middle')
|
|
10931
|
+
return 'md';
|
|
10932
|
+
if (size === 'small')
|
|
10933
|
+
return 'sm';
|
|
10934
|
+
return size;
|
|
10935
|
+
}
|
|
10936
|
+
function flattenBkTreeData(root, childrenKey = 'children', isExpanded = (n) => !!n['expand']) {
|
|
10937
|
+
const out = [];
|
|
10938
|
+
const walk = (nodes, level, parent) => {
|
|
10939
|
+
for (const node of nodes) {
|
|
10940
|
+
out.push({ data: node, level, parent });
|
|
10941
|
+
const children = node[childrenKey];
|
|
10942
|
+
if (children?.length && isExpanded(node)) {
|
|
10943
|
+
walk(children, level + 1, node);
|
|
10944
|
+
}
|
|
10945
|
+
}
|
|
10946
|
+
};
|
|
10947
|
+
walk(root, 0);
|
|
10948
|
+
return out;
|
|
10949
|
+
}
|
|
10950
|
+
/**
|
|
10951
|
+
* Whether `node` sits anywhere inside `ancestor`'s subtree.
|
|
10952
|
+
*
|
|
10953
|
+
* The guard a tree drag cannot do without: dropping a node into its own
|
|
10954
|
+
* descendant detaches that whole branch from the tree, and nothing afterwards
|
|
10955
|
+
* can find it again.
|
|
10956
|
+
*/
|
|
10957
|
+
function containsBkTreeNode(ancestor, node, childrenKey = 'children') {
|
|
10958
|
+
const children = ancestor[childrenKey] ?? [];
|
|
10959
|
+
for (const child of children) {
|
|
10960
|
+
if (child === node || containsBkTreeNode(child, node, childrenKey))
|
|
10961
|
+
return true;
|
|
10962
|
+
}
|
|
10963
|
+
return false;
|
|
10964
|
+
}
|
|
10965
|
+
/**
|
|
10966
|
+
* Applies a resolved tree drop to the tree behind the rows.
|
|
10967
|
+
*
|
|
10968
|
+
* `before` / `after` insert into the target's sibling list; `inside` makes the
|
|
10969
|
+
* dragged node the target's **first** child — first, not last, so the row
|
|
10970
|
+
* appears directly beneath the row it was dropped on rather than teleporting
|
|
10971
|
+
* to the bottom of a long branch.
|
|
10972
|
+
*
|
|
10973
|
+
* A node's subtree travels with it, because it is nested inside it. Dropping a
|
|
10974
|
+
* node into its own descendant is refused: that move would detach the branch
|
|
10975
|
+
* from the tree with nothing left pointing at it.
|
|
10976
|
+
*
|
|
10977
|
+
* Mutates `root` in place and reports whether anything moved; re-emit your
|
|
10978
|
+
* signal with a fresh array identity when it returns true.
|
|
10979
|
+
*/
|
|
10980
|
+
function moveBkTreeNode(root, dragged, target, position, childrenKey = 'children') {
|
|
10981
|
+
if (!dragged || !target || dragged.data === target.data)
|
|
10982
|
+
return false;
|
|
10983
|
+
if (containsBkTreeNode(dragged.data, target.data, childrenKey))
|
|
10984
|
+
return false;
|
|
10985
|
+
const fromList = dragged.parent ? (dragged.parent[childrenKey] ?? []) : root;
|
|
10986
|
+
const fromIndex = fromList.indexOf(dragged.data);
|
|
10987
|
+
if (fromIndex < 0)
|
|
10988
|
+
return false;
|
|
10989
|
+
fromList.splice(fromIndex, 1);
|
|
10990
|
+
if (position === 'inside') {
|
|
10991
|
+
const children = target.data[childrenKey] ?? [];
|
|
10992
|
+
children.unshift(dragged.data);
|
|
10993
|
+
target.data[childrenKey] = children;
|
|
10994
|
+
return true;
|
|
10995
|
+
}
|
|
10996
|
+
const toList = target.parent ? (target.parent[childrenKey] ?? []) : root;
|
|
10997
|
+
// Located after the removal, so an index in the same list already accounts
|
|
10998
|
+
// for the gap the dragged node left behind.
|
|
10999
|
+
const toIndex = toList.indexOf(target.data);
|
|
11000
|
+
if (toIndex < 0) {
|
|
11001
|
+
fromList.splice(fromIndex, 0, dragged.data);
|
|
11002
|
+
return false;
|
|
11003
|
+
}
|
|
11004
|
+
toList.splice(position === 'after' ? toIndex + 1 : toIndex, 0, dragged.data);
|
|
11005
|
+
return true;
|
|
11006
|
+
}
|
|
11007
|
+
|
|
11008
|
+
/** Marks projected content as the table's title bar. */
|
|
11009
|
+
class BkTableTitle {
|
|
11010
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11011
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkTableTitle, isStandalone: true, selector: "[bkTableTitle]", ngImport: i0 });
|
|
11012
|
+
}
|
|
11013
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableTitle, decorators: [{
|
|
11014
|
+
type: Directive,
|
|
11015
|
+
args: [{ selector: '[bkTableTitle]', standalone: true }]
|
|
11016
|
+
}] });
|
|
11017
|
+
/** Marks projected content as the table's footer bar. */
|
|
11018
|
+
class BkTableFooter {
|
|
11019
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableFooter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11020
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkTableFooter, isStandalone: true, selector: "[bkTableFooter]", ngImport: i0 });
|
|
11021
|
+
}
|
|
11022
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableFooter, decorators: [{
|
|
11023
|
+
type: Directive,
|
|
11024
|
+
args: [{ selector: '[bkTableFooter]', standalone: true }]
|
|
11025
|
+
}] });
|
|
11026
|
+
/**
|
|
11027
|
+
* Row template for virtual scroll mode.
|
|
11028
|
+
*
|
|
11029
|
+
* Virtual scrolling can't use a projected <tbody> — the rows have to be created
|
|
11030
|
+
* and destroyed by the viewport as it scrolls, so they must come from a
|
|
11031
|
+
* template the table instantiates itself:
|
|
11032
|
+
*
|
|
11033
|
+
* <tbody>
|
|
11034
|
+
* <ng-template bkVirtualScroll let-row let-i="index">
|
|
11035
|
+
* <tr>…</tr>
|
|
11036
|
+
* </ng-template>
|
|
11037
|
+
* </tbody>
|
|
11038
|
+
*/
|
|
11039
|
+
class BkVirtualScroll {
|
|
11040
|
+
templateRef;
|
|
11041
|
+
constructor(templateRef) {
|
|
11042
|
+
this.templateRef = templateRef;
|
|
11043
|
+
}
|
|
11044
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkVirtualScroll, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
11045
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkVirtualScroll, isStandalone: true, selector: "[bkVirtualScroll]", ngImport: i0 });
|
|
11046
|
+
}
|
|
11047
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkVirtualScroll, decorators: [{
|
|
11048
|
+
type: Directive,
|
|
11049
|
+
args: [{ selector: '[bkVirtualScroll]', standalone: true }]
|
|
11050
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
11051
|
+
/**
|
|
11052
|
+
* Template-driven table.
|
|
11053
|
+
*
|
|
11054
|
+
* Unlike `bk-grid`, this component renders none of your cells — you write the
|
|
11055
|
+
* `<thead>`/`<tbody>` markup and it supplies behaviour: sort and filter state,
|
|
11056
|
+
* pagination, sticky header and columns, virtual scrolling. That's what makes
|
|
11057
|
+
* colspan, nested tables, editable cells and grouped headers possible at all;
|
|
11058
|
+
* none of them can be expressed as a column config object.
|
|
11059
|
+
*
|
|
11060
|
+
* <bk-table #t [data]="rows" [bordered]="true" size="middle">
|
|
11061
|
+
* <thead>
|
|
11062
|
+
* <tr><th bk-th [sortFn]="byName">Name</th></tr>
|
|
11063
|
+
* </thead>
|
|
11064
|
+
* <tbody>
|
|
11065
|
+
* @for (row of t.renderData(); track row.id) {
|
|
11066
|
+
* <tr><td bk-td>{{ row.name }}</td></tr>
|
|
11067
|
+
* }
|
|
11068
|
+
* </tbody>
|
|
11069
|
+
* </bk-table>
|
|
11070
|
+
*
|
|
11071
|
+
* Client vs server work is decided per column, exactly like ng-zorro: pass a
|
|
11072
|
+
* comparator to `sortFn` and the table sorts; pass `true` and it only reports
|
|
11073
|
+
* the change through `queryParams` for you to handle.
|
|
11074
|
+
*/
|
|
11075
|
+
class BkTable {
|
|
11076
|
+
host = inject((ElementRef));
|
|
11077
|
+
zone = inject(NgZone);
|
|
11078
|
+
constructor() {
|
|
11079
|
+
// renderData is a computed, so the only way to push it out as an event is
|
|
11080
|
+
// to watch it. Consumers use this to keep a select-all checkbox or a
|
|
11081
|
+
// summary row in step with the rows actually on screen.
|
|
11082
|
+
effect(() => this.currentPageDataChange.emit(this.renderData()));
|
|
11083
|
+
// A path that failed shouldn't stay hidden forever if the consumer swaps
|
|
11084
|
+
// it for a different one — only the path that actually 404'd should be
|
|
11085
|
+
// treated as broken.
|
|
11086
|
+
effect(() => {
|
|
11087
|
+
this.noResultImage();
|
|
11088
|
+
this.emptyImageFailed.set(false);
|
|
11089
|
+
});
|
|
11090
|
+
// Freeze the column proportions once there are real rows to measure. Rows
|
|
11091
|
+
// arriving asynchronously are the common case, and widths measured against
|
|
11092
|
+
// an empty table would be frozen wrong forever.
|
|
11093
|
+
effect(() => {
|
|
11094
|
+
const columnCount = this.columns().length;
|
|
11095
|
+
// A column appearing or disappearing invalidates the frozen widths: they
|
|
11096
|
+
// no longer sum to the table, and the newcomer takes whatever is left
|
|
11097
|
+
// over. Drop them and let the next run measure the new set.
|
|
11098
|
+
if (this.layoutFixed() && columnCount !== this.frozenColumnCount) {
|
|
11099
|
+
this.remeasureColumns();
|
|
11100
|
+
return;
|
|
11101
|
+
}
|
|
11102
|
+
if (this.layoutFixed() || this.freezeScheduled)
|
|
11103
|
+
return;
|
|
11104
|
+
if (!this.stableColumnWidth() || this.isVirtual())
|
|
11105
|
+
return;
|
|
11106
|
+
if (this.renderData().length === 0)
|
|
11107
|
+
return;
|
|
11108
|
+
// Measuring inside the effect would read a layout that hasn't happened
|
|
11109
|
+
// yet — these rows are only being rendered as a result of it. Columns
|
|
11110
|
+
// also register one at a time, so this run is rarely the last one.
|
|
11111
|
+
this.freezeScheduled = true;
|
|
11112
|
+
setTimeout(() => {
|
|
11113
|
+
this.freezeScheduled = false;
|
|
11114
|
+
this.freezeColumnWidths();
|
|
11115
|
+
});
|
|
11116
|
+
});
|
|
11117
|
+
}
|
|
11118
|
+
/* ================= Data ================= */
|
|
11119
|
+
/** Full row set. In server mode, only the current page's rows. */
|
|
11120
|
+
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
11121
|
+
/* ================= Appearance ================= */
|
|
11122
|
+
/** Roomiest first: `lg`, `default`, `md`, `sm`. `sm` suits modals. */
|
|
11123
|
+
size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
11124
|
+
/** One class rather than a binding per size, and it resolves the aliases. */
|
|
11125
|
+
sizeClass = computed(() => `bk-table-${normalizeBkTableSize(this.size())}`, ...(ngDevMode ? [{ debugName: "sizeClass" }] : []));
|
|
11126
|
+
bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : []));
|
|
11127
|
+
/** Convenience alternative to projecting `[bkTableTitle]`. */
|
|
11128
|
+
title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
11129
|
+
/** Convenience alternative to projecting `[bkTableFooter]`. */
|
|
11130
|
+
footer = input('', ...(ngDevMode ? [{ debugName: "footer" }] : []));
|
|
11131
|
+
/**
|
|
11132
|
+
* `x` is a min-width that forces horizontal scrolling instead of column
|
|
11133
|
+
* collapse; `y` caps the body height and pins the header. Fixed columns
|
|
11134
|
+
* (`th[bk-th][left]`) need `x` set to have anything to scroll over.
|
|
11135
|
+
*/
|
|
11136
|
+
scroll = input({}, ...(ngDevMode ? [{ debugName: "scroll" }] : []));
|
|
11137
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
11138
|
+
/**
|
|
11139
|
+
* `loading` always suppresses the empty state — a fetch in flight isn't
|
|
11140
|
+
* "no data," and shouldn't flash that message just because the previous
|
|
11141
|
+
* page's rows haven't arrived yet. This is only about the *spinner*
|
|
11142
|
+
* overlay `loading` draws on top of the table. Turn it off when a
|
|
11143
|
+
* consumer already shows its own loading indicator elsewhere and doesn't
|
|
11144
|
+
* want a second one competing with it — `loading` keeps doing its other
|
|
11145
|
+
* job either way.
|
|
11146
|
+
*/
|
|
11147
|
+
showLoadingOverlay = input(true, ...(ngDevMode ? [{ debugName: "showLoadingOverlay" }] : []));
|
|
11148
|
+
/** Shown when there are no rows to render. */
|
|
11149
|
+
noResultText = input('Data may be empty, or try adjusting your filter.', ...(ngDevMode ? [{ debugName: "noResultText" }] : []));
|
|
11150
|
+
noResultImage = input('./assets/media/logos/no-data-found.jpg', ...(ngDevMode ? [{ debugName: "noResultImage" }] : []));
|
|
11151
|
+
/**
|
|
11152
|
+
* Set once `noResultImage()` fails to load, so the template can drop the
|
|
11153
|
+
* `<img>` instead of leaving the browser's broken-image glyph sitting next
|
|
11154
|
+
* to the empty-state text — bk-grid's empty state does exactly that on any
|
|
11155
|
+
* deployment where the asset path doesn't resolve. The text alone still
|
|
11156
|
+
* communicates "no data"; a broken icon just looks like the component is
|
|
11157
|
+
* broken.
|
|
11158
|
+
*/
|
|
11159
|
+
emptyImageFailed = signal(false, ...(ngDevMode ? [{ debugName: "emptyImageFailed" }] : []));
|
|
11160
|
+
onEmptyImageError() {
|
|
11161
|
+
this.emptyImageFailed.set(true);
|
|
11162
|
+
}
|
|
11163
|
+
/* ================= Pagination ================= */
|
|
11164
|
+
showPagination = input(true, ...(ngDevMode ? [{ debugName: "showPagination" }] : []));
|
|
11165
|
+
/**
|
|
11166
|
+
* When true the table slices `data` itself. Turn it off for server-side
|
|
11167
|
+
* paging and feed `total` instead.
|
|
11168
|
+
*/
|
|
11169
|
+
frontPagination = input(true, ...(ngDevMode ? [{ debugName: "frontPagination" }] : []));
|
|
11170
|
+
pageIndex = model(1, ...(ngDevMode ? [{ debugName: "pageIndex" }] : []));
|
|
11171
|
+
/**
|
|
11172
|
+
* Defaults to 25 because that is the smallest size `bk-pagination` offers
|
|
11173
|
+
* (25/50/75/100). A value outside that list matches no option and leaves its
|
|
11174
|
+
* "rows per page" select rendering blank.
|
|
11175
|
+
*/
|
|
11176
|
+
pageSize = model(25, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
11177
|
+
/** Row count for server mode. Ignored when `frontPagination` is on. */
|
|
11178
|
+
total = input(0, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
11179
|
+
/* ================= Virtual scroll ================= */
|
|
11180
|
+
/**
|
|
11181
|
+
* Row height in px. Required for virtual scroll — the viewport can't measure
|
|
11182
|
+
* rows it hasn't created. Rows must be uniform height, which is why virtual
|
|
11183
|
+
* scroll does not combine with rowspan, tree data or expandable rows.
|
|
11184
|
+
*/
|
|
11185
|
+
virtualItemSize = input(0, ...(ngDevMode ? [{ debugName: "virtualItemSize" }] : []));
|
|
11186
|
+
virtualTrackBy = input((index) => index, ...(ngDevMode ? [{ debugName: "virtualTrackBy" }] : []));
|
|
11187
|
+
viewport;
|
|
11188
|
+
/**
|
|
11189
|
+
* Scrolls the virtual viewport so the row at `index` (into `renderData()`)
|
|
11190
|
+
* lands at the top.
|
|
11191
|
+
*
|
|
11192
|
+
* Indexes are 0-based against the rendered rows, not the raw `data` input —
|
|
11193
|
+
* sorting/filtering already reduced it to what's actually on screen, and
|
|
11194
|
+
* jumping against the raw array would land on the wrong row the moment
|
|
11195
|
+
* either is active.
|
|
11196
|
+
*/
|
|
11197
|
+
scrollToIndex(index, behavior = 'smooth') {
|
|
11198
|
+
if (!this.isVirtual() || !this.viewport)
|
|
11199
|
+
return;
|
|
11200
|
+
if (index < 0 || index >= this.renderData().length)
|
|
11201
|
+
return;
|
|
11202
|
+
this.viewport.scrollToIndex(index, behavior);
|
|
11203
|
+
}
|
|
11204
|
+
/* ================= Column sizing ================= */
|
|
11205
|
+
/**
|
|
11206
|
+
* Hold the columns still once they have been measured.
|
|
11207
|
+
*
|
|
11208
|
+
* A table left on `table-layout: auto` sizes its columns from whatever
|
|
11209
|
+
* content is currently on screen, so sorting, filtering or paging — none of
|
|
11210
|
+
* which change the columns — visibly resizes them. Freezing the proportions
|
|
11211
|
+
* after the first real layout keeps the header from jumping under the
|
|
11212
|
+
* pointer that just clicked it.
|
|
11213
|
+
*
|
|
11214
|
+
* Turn it off if the content genuinely should drive the widths on every
|
|
11215
|
+
* change. Columns with an explicit `width` are never overwritten either way.
|
|
11216
|
+
*/
|
|
11217
|
+
stableColumnWidth = input(true, ...(ngDevMode ? [{ debugName: "stableColumnWidth" }] : []));
|
|
11218
|
+
/* ================= Outputs ================= */
|
|
11219
|
+
/** Everything the server needs to reproduce the current view. */
|
|
11220
|
+
queryParams = output();
|
|
11221
|
+
/** The rows actually rendered, after filter/sort/paging. */
|
|
11222
|
+
currentPageDataChange = output();
|
|
11223
|
+
/* ================= Projected slots ================= */
|
|
11224
|
+
titleContent;
|
|
11225
|
+
footerContent;
|
|
11226
|
+
virtualScroll;
|
|
11227
|
+
/* ================= Column registry ================= */
|
|
11228
|
+
/**
|
|
11229
|
+
* Registered `th[bk-th]` instances. Sorting and filtering are driven by
|
|
11230
|
+
* column state, so the pipeline below reads through this signal — replacing
|
|
11231
|
+
* the array (rather than mutating it) is what makes the computeds re-run.
|
|
11232
|
+
*/
|
|
11233
|
+
columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
11234
|
+
registerColumn(column) {
|
|
11235
|
+
this.columns.update((list) => [...list, column]);
|
|
11236
|
+
}
|
|
11237
|
+
unregisterColumn(column) {
|
|
11238
|
+
this.columns.update((list) => list.filter((c) => c !== column));
|
|
11239
|
+
}
|
|
11240
|
+
/**
|
|
11241
|
+
* Re-emits query params. Columns call this when their sort or filter
|
|
11242
|
+
* changes; the data pipeline reacts on its own through signals, so this
|
|
11243
|
+
* exists purely to notify the consumer.
|
|
11244
|
+
*/
|
|
11245
|
+
onColumnStateChange() {
|
|
11246
|
+
// A filter narrowing the row set can strand the user past the last page.
|
|
11247
|
+
if (this.frontPagination() && this.pageIndex() !== 1) {
|
|
11248
|
+
this.pageIndex.set(1);
|
|
11249
|
+
}
|
|
11250
|
+
this.emitQueryParams();
|
|
11251
|
+
}
|
|
11252
|
+
/* ================= Data pipeline ================= */
|
|
11253
|
+
/**
|
|
11254
|
+
* Rows surviving every column's client-side filter. Columns whose filter is
|
|
11255
|
+
* handled server-side contribute nothing here.
|
|
11256
|
+
*/
|
|
11257
|
+
filtered = computed(() => {
|
|
11258
|
+
const active = this.columns().filter((c) => c.clientFilterFn && c.filterValue().length > 0);
|
|
11259
|
+
if (!active.length)
|
|
11260
|
+
return this.data();
|
|
11261
|
+
return this.data().filter((row) => active.every((c) => c.clientFilterFn(c.filterValue(), row)));
|
|
11262
|
+
}, ...(ngDevMode ? [{ debugName: "filtered" }] : []));
|
|
11263
|
+
/**
|
|
11264
|
+
* Filtered rows in sort order.
|
|
11265
|
+
*
|
|
11266
|
+
* Multi-sort runs columns by descending `sortPriority`, and comparators are
|
|
11267
|
+
* applied in that order until one breaks the tie — so a priority-2 column
|
|
11268
|
+
* only orders rows a priority-3 column considers equal.
|
|
11269
|
+
*/
|
|
11270
|
+
sorted = computed(() => {
|
|
11271
|
+
const active = this.columns()
|
|
11272
|
+
.filter((c) => c.clientSortFn && c.sortOrder() !== null)
|
|
11273
|
+
.sort((a, b) => (b.sortPriority ?? 0) - (a.sortPriority ?? 0));
|
|
11274
|
+
if (!active.length)
|
|
11275
|
+
return this.filtered();
|
|
11276
|
+
// Copy first: sort mutates, and the input array belongs to the consumer.
|
|
11277
|
+
return [...this.filtered()].sort((rowA, rowB) => {
|
|
11278
|
+
for (const column of active) {
|
|
11279
|
+
const order = column.sortOrder();
|
|
11280
|
+
const result = column.clientSortFn(rowA, rowB, order);
|
|
11281
|
+
if (result !== 0)
|
|
11282
|
+
return order === 'descend' ? -result : result;
|
|
11283
|
+
}
|
|
11284
|
+
return 0;
|
|
11285
|
+
});
|
|
11286
|
+
}, ...(ngDevMode ? [{ debugName: "sorted" }] : []));
|
|
11287
|
+
/** Row count before paging — what the pager needs to size itself. */
|
|
11288
|
+
totalCount = computed(() => this.frontPagination() ? this.sorted().length : this.total(), ...(ngDevMode ? [{ debugName: "totalCount" }] : []));
|
|
11289
|
+
/**
|
|
11290
|
+
* The rows to render. Iterate this in your `<tbody>`, not the raw input:
|
|
11291
|
+
* it is the input after filtering, sorting and paging.
|
|
11292
|
+
*/
|
|
11293
|
+
renderData = computed(() => {
|
|
11294
|
+
// Virtual scroll windows the DOM itself — slicing to a page on top of that
|
|
11295
|
+
// would cap the viewport at `pageSize` rows and defeat the point of it.
|
|
11296
|
+
if (!this.frontPagination() || this.isVirtual())
|
|
11297
|
+
return this.sorted();
|
|
11298
|
+
const size = this.pageSize();
|
|
11299
|
+
const start = (this.pageIndex() - 1) * size;
|
|
11300
|
+
return this.sorted().slice(start, start + size);
|
|
11301
|
+
}, ...(ngDevMode ? [{ debugName: "renderData" }] : []));
|
|
11302
|
+
isVirtual = computed(() => this.virtualItemSize() > 0, ...(ngDevMode ? [{ debugName: "isVirtual" }] : []));
|
|
11303
|
+
/**
|
|
11304
|
+
* Column widths for the virtual-scroll `<colgroup>`.
|
|
11305
|
+
*
|
|
11306
|
+
* Virtual scroll splits the header and body into two tables, so they can no
|
|
11307
|
+
* longer size each other — a shared colgroup is what keeps their columns
|
|
11308
|
+
* lined up, and it needs a declared width per column to do it.
|
|
11309
|
+
*/
|
|
11310
|
+
colWidths = computed(() => this.columns().map((c) => c.width), ...(ngDevMode ? [{ debugName: "colWidths" }] : []));
|
|
11311
|
+
/* ================= Derived view state ================= */
|
|
11312
|
+
hasTitle = computed(() => !!this.title() || !!this.titleContent, ...(ngDevMode ? [{ debugName: "hasTitle" }] : []));
|
|
11313
|
+
hasFooter = computed(() => !!this.footer() || !!this.footerContent, ...(ngDevMode ? [{ debugName: "hasFooter" }] : []));
|
|
11314
|
+
isEmpty = computed(() => !this.loading() && this.renderData().length === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
11315
|
+
/** Floor for the empty state's home: `.bk-table-empty` is absolutely
|
|
11316
|
+
* positioned against this container (see table.css), so without either
|
|
11317
|
+
* `scroll.y` or this fallback it'd have a ~0px-tall box to center in
|
|
11318
|
+
* (just the header row, since an empty `<tbody>` contributes nothing)
|
|
11319
|
+
* and get clipped by `overflow-auto`. */
|
|
11320
|
+
static EMPTY_STATE_MIN_HEIGHT = '350px';
|
|
11321
|
+
containerStyle = computed(() => {
|
|
11322
|
+
const { y, fill } = this.scroll();
|
|
11323
|
+
if (!y) {
|
|
11324
|
+
return this.isEmpty() ? { 'min-height': BkTable.EMPTY_STATE_MIN_HEIGHT } : {};
|
|
11325
|
+
}
|
|
11326
|
+
return { [fill ? 'height' : 'max-height']: y, 'overflow-y': 'auto' };
|
|
11327
|
+
}, ...(ngDevMode ? [{ debugName: "containerStyle" }] : []));
|
|
11328
|
+
/** Set once the columns have been measured and pinned. */
|
|
11329
|
+
layoutFixed = signal(false, ...(ngDevMode ? [{ debugName: "layoutFixed" }] : []));
|
|
11330
|
+
tableStyle = computed(() => {
|
|
11331
|
+
const { x } = this.scroll();
|
|
11332
|
+
const style = {};
|
|
11333
|
+
// `min-width` alone regresses the table's floor from "100% of container"
|
|
11334
|
+
// (the `.bk-table` class's `min-w-full`) down to just `x`, because an
|
|
11335
|
+
// inline style always wins over a class rule for the same property — so
|
|
11336
|
+
// without an explicit `width` here too, a container wider than `x` left
|
|
11337
|
+
// the table (and every column sized off it) narrower than its own frame.
|
|
11338
|
+
if (x) {
|
|
11339
|
+
style['width'] = '100%';
|
|
11340
|
+
style['min-width'] = x;
|
|
11341
|
+
}
|
|
11342
|
+
// `fixed` is what actually stops content from resizing columns; a declared
|
|
11343
|
+
// scroll width implies it too, since the point of one is a stable grid.
|
|
11344
|
+
if (x || this.layoutFixed())
|
|
11345
|
+
style['table-layout'] = 'fixed';
|
|
11346
|
+
return style;
|
|
11347
|
+
}, ...(ngDevMode ? [{ debugName: "tableStyle" }] : []));
|
|
11348
|
+
/* ================= Layout measurement ================= */
|
|
11349
|
+
virtualHead;
|
|
11350
|
+
headResizeObserver;
|
|
11351
|
+
layoutResizeObserver;
|
|
11352
|
+
ngAfterViewInit() {
|
|
11353
|
+
this.observeHeaderHeight();
|
|
11354
|
+
this.observeTableVisibility();
|
|
11355
|
+
}
|
|
11356
|
+
ngOnDestroy() {
|
|
11357
|
+
this.headResizeObserver?.disconnect();
|
|
11358
|
+
this.layoutResizeObserver?.disconnect();
|
|
11359
|
+
}
|
|
11360
|
+
/**
|
|
11361
|
+
* Publishes the first header row's height as `--bk-thead-row-1`.
|
|
11362
|
+
*
|
|
11363
|
+
* A grouped header's second row has to stick *below* the first, which means
|
|
11364
|
+
* knowing how tall the first is — and that changes with density, with font
|
|
11365
|
+
* loading, and with any header that wraps. Measuring it is the only offset
|
|
11366
|
+
* that stays correct; a constant is right for exactly one configuration.
|
|
11367
|
+
*/
|
|
11368
|
+
observeHeaderHeight() {
|
|
11369
|
+
const thead = this.host.nativeElement.querySelector('thead');
|
|
11370
|
+
if (!thead)
|
|
11371
|
+
return;
|
|
11372
|
+
const apply = () => {
|
|
11373
|
+
const firstRow = thead.querySelector('tr');
|
|
11374
|
+
if (!firstRow)
|
|
11375
|
+
return;
|
|
11376
|
+
this.host.nativeElement.style.setProperty('--bk-thead-row-1', `${firstRow.offsetHeight}px`);
|
|
11377
|
+
};
|
|
11378
|
+
apply();
|
|
11379
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
11380
|
+
this.zone.runOutsideAngular(() => {
|
|
11381
|
+
this.headResizeObserver = new ResizeObserver(apply);
|
|
11382
|
+
this.headResizeObserver.observe(thead);
|
|
11383
|
+
});
|
|
11384
|
+
}
|
|
11385
|
+
}
|
|
11386
|
+
/**
|
|
11387
|
+
* Two unrelated jobs that both boil down to "re-check this whenever the
|
|
11388
|
+
* table's or the container's box size changes," so one `ResizeObserver`
|
|
11389
|
+
* watching both elements does them together.
|
|
11390
|
+
*
|
|
11391
|
+
* **Retries the column freeze.** A table that mounts inside a `[hidden]`
|
|
11392
|
+
* ancestor — a collapsed `tr[bkExpand]` holding a nested `bk-table`, most
|
|
11393
|
+
* commonly — measures 0 on its first freeze attempt, so
|
|
11394
|
+
* `freezeColumnWidths()` correctly declines to pin widths it can't see
|
|
11395
|
+
* (`if (!tableWidth) return;`). Nothing else ever asks it to try again: the
|
|
11396
|
+
* constructor effect only reruns when one of its own signals changes, and
|
|
11397
|
+
* none of them do just because the table became visible. Left alone, that
|
|
11398
|
+
* table stays on `table-layout: auto` forever — and an auto-layout cell
|
|
11399
|
+
* can't give a nested table's `min-width: 100%` a real number to resolve
|
|
11400
|
+
* against, which is what leaves a nested `bk-table` stuck at its own
|
|
11401
|
+
* shrink-to-fit width even after the row expands. Once `layoutFixed` is
|
|
11402
|
+
* true the call is a no-op, so this can just stay connected for the
|
|
11403
|
+
* table's life rather than tracking whether it still needs to be.
|
|
11404
|
+
*
|
|
11405
|
+
* **Tracks whether the rows fall short of the container.** See
|
|
11406
|
+
* `updateUnderfilled`.
|
|
11407
|
+
*/
|
|
11408
|
+
observeTableVisibility() {
|
|
11409
|
+
if (typeof ResizeObserver === 'undefined')
|
|
11410
|
+
return;
|
|
11411
|
+
const table = this.host.nativeElement.querySelector('table.bk-table');
|
|
11412
|
+
const container = this.host.nativeElement.querySelector('.bk-table-container');
|
|
11413
|
+
if (!table)
|
|
11414
|
+
return;
|
|
11415
|
+
this.zone.runOutsideAngular(() => {
|
|
11416
|
+
this.layoutResizeObserver = new ResizeObserver(() => {
|
|
11417
|
+
if (!this.layoutFixed() &&
|
|
11418
|
+
this.stableColumnWidth() &&
|
|
11419
|
+
!this.isVirtual() &&
|
|
11420
|
+
this.renderData().length > 0) {
|
|
11421
|
+
this.freezeColumnWidths();
|
|
11422
|
+
}
|
|
11423
|
+
this.updateUnderfilled(table, container);
|
|
11424
|
+
});
|
|
11425
|
+
this.layoutResizeObserver.observe(table);
|
|
11426
|
+
if (container)
|
|
11427
|
+
this.layoutResizeObserver.observe(container);
|
|
11428
|
+
});
|
|
11429
|
+
}
|
|
11430
|
+
/**
|
|
11431
|
+
* Marks the host when rows end well short of a reserved `scroll.y`
|
|
11432
|
+
* (`fill`, most commonly) height, so `.bk-table-underfilled` in the
|
|
11433
|
+
* stylesheet can close the real data off with a border instead of letting
|
|
11434
|
+
* it trail into blank reserved space with nothing marking where it
|
|
11435
|
+
* stopped. Left off whenever rows fill or overflow the container — the
|
|
11436
|
+
* frame's own border (or the scroll cutoff) already closes those cases,
|
|
11437
|
+
* and adding another border would double up against it.
|
|
11438
|
+
*/
|
|
11439
|
+
updateUnderfilled(table, container) {
|
|
11440
|
+
if (!container)
|
|
11441
|
+
return;
|
|
11442
|
+
const underfilled = table.offsetHeight < container.clientHeight;
|
|
11443
|
+
this.host.nativeElement.classList.toggle('bk-table-underfilled', underfilled);
|
|
11444
|
+
}
|
|
11445
|
+
/**
|
|
11446
|
+
* Pins the columns at the proportions auto layout arrived at.
|
|
11447
|
+
*
|
|
11448
|
+
* Widths are stored as percentages, not pixels: under `table-layout: fixed`
|
|
11449
|
+
* a percentage resolves against the table, so the columns keep their
|
|
11450
|
+
* relationship when the container resizes. Pixels would freeze the table at
|
|
11451
|
+
* whatever width it happened to have when the rows first arrived.
|
|
11452
|
+
*
|
|
11453
|
+
* Only the first header row is written to — that is the row `table-layout:
|
|
11454
|
+
* fixed` reads widths from. A grouped header's second row inherits its share
|
|
11455
|
+
* of whatever the group above it was given.
|
|
11456
|
+
*/
|
|
11457
|
+
freezeColumnWidths() {
|
|
11458
|
+
const table = this.host.nativeElement.querySelector('table.bk-table');
|
|
11459
|
+
const row = table?.tHead?.rows[0];
|
|
11460
|
+
if (!table || !row?.cells.length)
|
|
11461
|
+
return;
|
|
11462
|
+
const tableWidth = table.offsetWidth;
|
|
11463
|
+
if (!tableWidth)
|
|
11464
|
+
return;
|
|
11465
|
+
const cells = Array.from(row.cells);
|
|
11466
|
+
// Read every width before writing any: the first write invalidates layout,
|
|
11467
|
+
// so measuring and assigning in one pass would size each column against
|
|
11468
|
+
// the columns already changed ahead of it.
|
|
11469
|
+
const widths = cells.map((cell) => cell.offsetWidth);
|
|
11470
|
+
cells.forEach((cell, index) => {
|
|
11471
|
+
// A declared `width` is an instruction, not a measurement. Leave it.
|
|
11472
|
+
if (cell.style.width)
|
|
11473
|
+
return;
|
|
11474
|
+
cell.style.width = `${((widths[index] / tableWidth) * 100).toFixed(4)}%`;
|
|
11475
|
+
this.frozenCells.push(cell);
|
|
11476
|
+
});
|
|
11477
|
+
this.frozenColumnCount = this.columns().length;
|
|
11478
|
+
this.layoutFixed.set(true);
|
|
11479
|
+
}
|
|
11480
|
+
/** The cells this component wrote a width to, so it can undo exactly those. */
|
|
11481
|
+
frozenCells = [];
|
|
11482
|
+
/** Column count the frozen widths were measured against. */
|
|
11483
|
+
frozenColumnCount = -1;
|
|
11484
|
+
/** Guards against stacking timeouts while columns are still registering. */
|
|
11485
|
+
freezeScheduled = false;
|
|
11486
|
+
/**
|
|
11487
|
+
* Drops the frozen widths so the columns are measured again. Call it after
|
|
11488
|
+
* replacing the dataset with one whose shape is different enough that the
|
|
11489
|
+
* old proportions no longer suit it.
|
|
11490
|
+
*/
|
|
11491
|
+
remeasureColumns() {
|
|
11492
|
+
this.frozenCells.forEach((cell) => (cell.style.width = ''));
|
|
11493
|
+
this.frozenCells = [];
|
|
11494
|
+
this.frozenColumnCount = -1;
|
|
11495
|
+
this.layoutFixed.set(false);
|
|
11496
|
+
}
|
|
11497
|
+
/**
|
|
11498
|
+
* Keeps the detached virtual-scroll header aligned with the body it no
|
|
11499
|
+
* longer shares a table with.
|
|
11500
|
+
*/
|
|
11501
|
+
onViewportScroll(event) {
|
|
11502
|
+
const head = this.virtualHead?.nativeElement;
|
|
11503
|
+
if (!head)
|
|
11504
|
+
return;
|
|
11505
|
+
head.scrollLeft = event.target.scrollLeft;
|
|
11506
|
+
}
|
|
11507
|
+
/* ================= Pagination ================= */
|
|
11508
|
+
onPageIndexChange(index) {
|
|
11509
|
+
if (index === this.pageIndex())
|
|
11510
|
+
return;
|
|
11511
|
+
this.pageIndex.set(index);
|
|
11512
|
+
this.emitQueryParams();
|
|
11513
|
+
}
|
|
11514
|
+
onPageSizeChange(size) {
|
|
11515
|
+
if (size === this.pageSize())
|
|
11516
|
+
return;
|
|
11517
|
+
this.pageSize.set(size);
|
|
11518
|
+
// Row 1 of the old page size is rarely row 1 of the new one; restarting is
|
|
11519
|
+
// the only landing spot that is meaningful at any size.
|
|
11520
|
+
this.pageIndex.set(1);
|
|
11521
|
+
this.emitQueryParams();
|
|
11522
|
+
}
|
|
11523
|
+
/* ================= Reset ================= */
|
|
11524
|
+
/** Clears every column's sort. Backs "reset sorters" in the demo. */
|
|
11525
|
+
clearSort() {
|
|
11526
|
+
this.columns().forEach((c) => c.clearSort());
|
|
11527
|
+
this.emitQueryParams();
|
|
11528
|
+
}
|
|
11529
|
+
/** Clears every column's filter selection. */
|
|
11530
|
+
clearFilter() {
|
|
11531
|
+
this.columns().forEach((c) => c.clearFilter());
|
|
11532
|
+
this.emitQueryParams();
|
|
11533
|
+
}
|
|
11534
|
+
/** Clears sorts and filters together and returns to the first page. */
|
|
11535
|
+
reset() {
|
|
11536
|
+
this.columns().forEach((c) => {
|
|
11537
|
+
c.clearSort();
|
|
11538
|
+
c.clearFilter();
|
|
11539
|
+
});
|
|
11540
|
+
this.pageIndex.set(1);
|
|
11541
|
+
this.emitQueryParams();
|
|
11542
|
+
}
|
|
11543
|
+
/* ================= Query params ================= */
|
|
11544
|
+
emitQueryParams() {
|
|
11545
|
+
const columns = this.columns();
|
|
11546
|
+
this.queryParams.emit({
|
|
11547
|
+
pageIndex: this.pageIndex(),
|
|
11548
|
+
pageSize: this.pageSize(),
|
|
11549
|
+
sort: columns
|
|
11550
|
+
.filter((c) => c.columnKey)
|
|
11551
|
+
.map((c) => ({ key: c.columnKey, value: c.sortOrder() })),
|
|
11552
|
+
filter: columns
|
|
11553
|
+
.filter((c) => c.columnKey && c.filterValue().length)
|
|
11554
|
+
.map((c) => ({ key: c.columnKey, value: c.filterValue() }))
|
|
11555
|
+
});
|
|
11556
|
+
}
|
|
11557
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11558
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTable, isStandalone: true, selector: "bk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null }, scroll: { classPropertyName: "scroll", publicName: "scroll", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showLoadingOverlay: { classPropertyName: "showLoadingOverlay", publicName: "showLoadingOverlay", isSignal: true, isRequired: false, transformFunction: null }, noResultText: { classPropertyName: "noResultText", publicName: "noResultText", isSignal: true, isRequired: false, transformFunction: null }, noResultImage: { classPropertyName: "noResultImage", publicName: "noResultImage", isSignal: true, isRequired: false, transformFunction: null }, showPagination: { classPropertyName: "showPagination", publicName: "showPagination", isSignal: true, isRequired: false, transformFunction: null }, frontPagination: { classPropertyName: "frontPagination", publicName: "frontPagination", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, virtualItemSize: { classPropertyName: "virtualItemSize", publicName: "virtualItemSize", isSignal: true, isRequired: false, transformFunction: null }, virtualTrackBy: { classPropertyName: "virtualTrackBy", publicName: "virtualTrackBy", isSignal: true, isRequired: false, transformFunction: null }, stableColumnWidth: { classPropertyName: "stableColumnWidth", publicName: "stableColumnWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageIndex: "pageIndexChange", pageSize: "pageSizeChange", queryParams: "queryParams", currentPageDataChange: "currentPageDataChange" }, host: { classAttribute: "bk-table-host" }, queries: [{ propertyName: "titleContent", first: true, predicate: BkTableTitle, descendants: true }, { propertyName: "footerContent", first: true, predicate: BkTableFooter, descendants: true }, { propertyName: "virtualScroll", first: true, predicate: BkVirtualScroll, descendants: true }], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "virtualHead", first: true, predicate: ["virtualHead"], descendants: true }], exportAs: ["bkTable"], ngImport: i0, template: "<!--\r\n Projection slots live inside <ng-template> rather than directly in the\r\n branches below. A given <ng-content> can only be declared once \u00E2\u20AC\u201D repeating\r\n the same selector in both the virtual and normal branches would leave one of\r\n them permanently empty. Wrapping each slot in a template declares it once and\r\n lets an outlet place it wherever it is needed.\r\n-->\r\n<ng-template #headSlot><ng-content select=\"thead\"></ng-content></ng-template>\r\n<ng-template #bodySlot><ng-content select=\"tbody\"></ng-content></ng-template>\r\n<ng-template #footSlot><ng-content select=\"tfoot\"></ng-content></ng-template>\r\n\r\n<div\r\n class=\"bk-table-wrapper\"\r\n [class.bk-table-bordered]=\"bordered()\"\r\n [ngClass]=\"sizeClass()\"\r\n>\r\n <!--\r\n The frame is one box, and it is the only box that draws an outline or a\r\n corner. Radius on the header cells and border on the table (or on the title\r\n bar) means two boxes describing the same corner from different places, and\r\n they disagree the moment a title bar appears above the header. Everything\r\n inside here draws separators only; `overflow: hidden` clips them to the curve.\r\n -->\r\n <div class=\"bk-table-frame\">\r\n @if (hasTitle()) {\r\n <div class=\"bk-table-title-bar\">\r\n @if (title()) {\r\n {{ title() }}\r\n }\r\n <ng-content select=\"[bkTableTitle]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <div class=\"bk-table-container\" [ngStyle]=\"containerStyle()\">\r\n @if (isVirtual() && virtualScroll) {\r\n <!--\r\n Header and body are two separate tables here, which they are not in any\r\n other mode. The CDK viewport scrolls by translating its content wrapper,\r\n and a transformed ancestor takes over as the containing block for\r\n sticky descendants \u00E2\u20AC\u201D so a header inside the viewport gets dragged along\r\n by the very transform it is supposed to stay still against. Lifting it\r\n out is the only way it stays put.\r\n\r\n The cost is that the two tables can no longer size each other, so a\r\n shared <colgroup> holds their columns in alignment and the body's\r\n horizontal scroll is mirrored onto the header by hand.\r\n -->\r\n <div #virtualHead class=\"bk-table-virtual-head\">\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n </table>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport\r\n class=\"bk-table-viewport\"\r\n [itemSize]=\"virtualItemSize()\"\r\n [style.height]=\"scroll().y || '400px'\"\r\n (scroll)=\"onViewportScroll($event)\"\r\n >\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <tbody>\r\n <ng-container\r\n *cdkVirtualFor=\"\r\n let row of renderData();\r\n let i = index;\r\n trackBy: virtualTrackBy()\r\n \"\r\n [ngTemplateOutlet]=\"virtualScroll.templateRef\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\r\n ></ng-container>\r\n </tbody>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n </cdk-virtual-scroll-viewport>\r\n } @else {\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"bodySlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n }\r\n\r\n @if (loading() && showLoadingOverlay()) {\r\n <div class=\"bk-table-loading\">\r\n <span class=\"bk-table-spinner\"></span>\r\n </div>\r\n }\r\n\r\n @if (isEmpty()) {\r\n <div class=\"bk-table-empty\">\r\n @if (!emptyImageFailed()) {\r\n <img\r\n [src]=\"noResultImage()\"\r\n class=\"bk-table-empty-img\"\r\n alt=\"No data found\"\r\n (error)=\"onEmptyImageError()\"\r\n />\r\n }\r\n <span class=\"bk-table-empty-text\">{{ noResultText() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (hasFooter()) {\r\n <div class=\"bk-table-footer-bar\">\r\n @if (footer()) {\r\n {{ footer() }}\r\n }\r\n <ng-content select=\"[bkTableFooter]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <!-- Inside the frame: the pager belongs to the table it drives, and the\r\n frame's bottom edge is what closes the card around both.\r\n\r\n `!isEmpty()`, not `totalCount() > 0`: in server mode `totalCount()`\r\n is just the `total` input, which can say more rows exist than are\r\n actually on screen right now (a search with no matches but a stale\r\n total, a page past the end) \u2014 the pager has nothing to page through\r\n either way, so it goes by what's actually rendered. -->\r\n @if (showPagination() && !isEmpty()) {\r\n <div class=\"bk-table-pagination\">\r\n <bk-pagination\r\n [total]=\"totalCount()\"\r\n [pageSize]=\"pageSize()\"\r\n [activePage]=\"pageIndex()\"\r\n (pageChanged)=\"onPageIndexChange($event)\"\r\n (changePageSize)=\"onPageSizeChange($event)\"\r\n ></bk-pagination>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".bk-table-host{display:block}.bk-table-wrapper{@apply w-full;}.bk-table-frame{border:1px solid #ebedf3;border-radius:.75rem;overflow:hidden}.bk-table-title-bar,.bk-table-footer-bar{@apply text-[13px] font-semibold text-[#15191E] bg-[#F9FAFA] px-4 py-2.5;}.bk-table-title-bar{border-bottom:1px solid #ebedf3}.bk-table-footer-bar{border-top:1px solid #ebedf3}.bk-table-container{@apply relative overflow-auto;}.bk-table{@apply min-w-full text-left;border-collapse:separate;border-spacing:0}.bk-th{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap align-middle;border-bottom:1px solid #ebedf3;position:sticky;top:0;z-index:2}.bk-table thead tr:nth-child(2) .bk-th{top:var(--bk-thead-row-1, 38px);z-index:1}.bk-th-content{@apply flex items-center justify-between gap-1;}.bk-th-align-right .bk-th-content{@apply justify-end;}.bk-th-align-center .bk-th-content{@apply justify-center;}.bk-th-label{@apply inline-flex items-center gap-1;}.bk-th-sortable .bk-th-label{@apply cursor-pointer select-none;}.bk-th-selection{@apply flex items-center gap-1;}.bk-cell-selection{@apply px-3;}.bk-th-selection-caret{@apply inline-flex items-center justify-center size-4 rounded hover:bg-[#EFF1F4];}.bk-td{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 align-middle bg-white;border-bottom:1px solid #ebedf3}.bk-td-content{@apply inline-flex items-center gap-1 align-middle;}.bk-td-content-block{@apply block w-full;}.bk-table tbody tr:hover .bk-td{@apply bg-[#FBFBFC];}.bk-table-lg .bk-th{@apply px-5 py-3.5 text-[13px];}.bk-table-lg .bk-td{@apply px-5 py-3.5 text-sm leading-5;}.bk-table-md .bk-th{@apply px-3 py-2;}.bk-table-md .bk-td{@apply px-3 py-1.5;}.bk-table-sm .bk-th{@apply px-2 py-1.5 text-[11px];}.bk-table-sm .bk-td{@apply px-2 py-1 text-xs;}.bk-table-lg .bk-cell-selection{@apply px-4;}.bk-table-md .bk-cell-selection{@apply px-2.5;}.bk-table-sm .bk-cell-selection{@apply px-2;}.bk-table-bordered .bk-th,.bk-table-bordered .bk-td{border-right:1px solid #ebedf3}.bk-table-bordered .bk-th:last-child,.bk-table-bordered .bk-td:last-child{border-right:0}.bk-table tbody tr:last-child>.bk-td{border-bottom:0}.bk-table-underfilled .bk-table tbody tr:last-child>.bk-td{border-bottom:1px solid #ebedf3}.bk-cell-sticky{position:sticky;z-index:1}.bk-th.bk-cell-sticky{z-index:3}.bk-cell-sticky-left:after,.bk-cell-sticky-right:before{content:\"\";@apply absolute top-0 bottom-0 w-2 pointer-events-none;}.bk-cell-sticky-left:after{right:-8px;background-image:linear-gradient(to right,rgba(0,0,0,.05),transparent)}.bk-cell-sticky-right:before{left:-8px;background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.bk-cell-ellipsis{@apply overflow-hidden text-ellipsis whitespace-nowrap;max-width:0}.bk-td-content-ellipsis{@apply flex w-full;}.bk-td-ellipsis-text{@apply overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1;}.bk-cell-break-word{@apply whitespace-normal;word-break:break-all}.bk-td-indent{@apply inline-block;}.bk-td-expand,.bk-td-expand-spacer{@apply inline-flex items-center justify-center size-4 shrink-0;}.bk-td-expand{@apply rounded text-[#78829D] hover:bg-[#EFF1F4] transition-transform duration-200;transform:rotate(-90deg)}.bk-td-expand-open{transform:rotate(0)}.bk-expanded-row>.bk-td,.bk-expanded-row>td{@apply bg-[#FBFBFC];}.bk-td-flush{@apply p-3;}.bk-table-flush .bk-table-frame{border:0;border-radius:0}.bk-table-summary .bk-td{@apply bg-[#F9FAFA] font-semibold;border-top:1px solid #ebedf3;border-bottom:0}.bk-table-summary-fixed .bk-td{position:sticky;bottom:0;z-index:2}.bk-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.bk-sort-icon:before,.bk-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-sort-asc: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\")}.bk-sort-asc: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\")}.bk-sort-desc: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\")}.bk-sort-desc: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\")}.bk-sort-priority{@apply inline-flex items-center justify-center min-w-4 h-4 px-1 rounded bg-[#EFF1F4] text-[10px] font-semibold text-[#4B5675];}.bk-filter-trigger{@apply inline-flex items-center justify-center size-5 rounded text-[#78829D] hover:bg-[#EFF1F4];}.bk-filter-active{@apply text-black;}.bk-filter-menu{@apply min-w-[180px];}.bk-filter-list{@apply flex flex-col gap-2 max-h-60 overflow-y-auto py-1;}.bk-filter-option{@apply text-[13px] text-[#15191E];}.bk-filter-actions{@apply flex items-center justify-between gap-2 pt-2 mt-2;border-top:1px solid #ebedf3}.bk-filter-btn{@apply text-xs font-semibold px-2.5 py-1 rounded;}.bk-filter-btn-link{@apply text-[#60646C] hover:bg-[#F1F2F4];}.bk-filter-btn-primary{@apply bg-black text-white hover:bg-[#2A2E36];}.bk-table-menu{@apply min-w-[160px] flex flex-col;}.bk-table-menu-item{@apply w-full text-left text-[13px] text-[#15191E] px-2 py-1.5 rounded hover:bg-[#F1F2F4];}.bk-table-loading{@apply absolute inset-0 flex items-center justify-center bg-white/60 z-10;}.bk-table-spinner{@apply block size-8 rounded-full border-2 border-[#EBEDF3] border-t-black;animation:bk-table-spin .8s linear infinite}@keyframes bk-table-spin{to{transform:rotate(360deg)}}.bk-table-empty{@apply absolute inset-x-0 bottom-0 flex flex-col justify-center items-center py-10;top:var(--bk-thead-row-1, 38px)}.bk-table-empty-img{@apply mb-3 w-96 max-w-full;}.bk-table-empty-text{@apply block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2;}.bk-table-pagination{@apply contents;}.bk-table-viewport{@apply w-full;}.bk-table-virtual-head{@apply w-full overflow-hidden;}.bk-table-virtual-head .bk-th{position:static}.bk-checkbox-indeterminate .checkbox{@apply bg-black border-black;}.bk-checkbox-indeterminate .checkbox:after{content:\"\";@apply absolute w-2 h-0.5 bg-white rounded-sm;}.cdk-drag-preview{display:table;table-layout:fixed;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)}.bk-drag-handle{@apply cursor-move inline-flex items-center justify-center text-[#C4CADA] hover:text-[#78829D] mr-2 align-middle;}.bk-tree-drop-line{@apply absolute pointer-events-none rounded-full;height:2px;background:#15191e;z-index:5}.bk-table tbody tr.bk-tree-drop-inside .bk-td{background:#f1f2f4;box-shadow:inset 0 0 0 1px #15191e59}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: BkPagination, selector: "bk-pagination", inputs: ["pageSize", "total", "activePage"], outputs: ["changePageSize", "pageChanged", "activePageChange"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
11559
|
+
}
|
|
11560
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTable, decorators: [{
|
|
11561
|
+
type: Component,
|
|
11562
|
+
args: [{ selector: 'bk-table', standalone: true, exportAs: 'bkTable', imports: [CommonModule, ScrollingModule, BkPagination], encapsulation: ViewEncapsulation.None, host: {
|
|
11563
|
+
class: 'bk-table-host'
|
|
11564
|
+
}, template: "<!--\r\n Projection slots live inside <ng-template> rather than directly in the\r\n branches below. A given <ng-content> can only be declared once \u00E2\u20AC\u201D repeating\r\n the same selector in both the virtual and normal branches would leave one of\r\n them permanently empty. Wrapping each slot in a template declares it once and\r\n lets an outlet place it wherever it is needed.\r\n-->\r\n<ng-template #headSlot><ng-content select=\"thead\"></ng-content></ng-template>\r\n<ng-template #bodySlot><ng-content select=\"tbody\"></ng-content></ng-template>\r\n<ng-template #footSlot><ng-content select=\"tfoot\"></ng-content></ng-template>\r\n\r\n<div\r\n class=\"bk-table-wrapper\"\r\n [class.bk-table-bordered]=\"bordered()\"\r\n [ngClass]=\"sizeClass()\"\r\n>\r\n <!--\r\n The frame is one box, and it is the only box that draws an outline or a\r\n corner. Radius on the header cells and border on the table (or on the title\r\n bar) means two boxes describing the same corner from different places, and\r\n they disagree the moment a title bar appears above the header. Everything\r\n inside here draws separators only; `overflow: hidden` clips them to the curve.\r\n -->\r\n <div class=\"bk-table-frame\">\r\n @if (hasTitle()) {\r\n <div class=\"bk-table-title-bar\">\r\n @if (title()) {\r\n {{ title() }}\r\n }\r\n <ng-content select=\"[bkTableTitle]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <div class=\"bk-table-container\" [ngStyle]=\"containerStyle()\">\r\n @if (isVirtual() && virtualScroll) {\r\n <!--\r\n Header and body are two separate tables here, which they are not in any\r\n other mode. The CDK viewport scrolls by translating its content wrapper,\r\n and a transformed ancestor takes over as the containing block for\r\n sticky descendants \u00E2\u20AC\u201D so a header inside the viewport gets dragged along\r\n by the very transform it is supposed to stay still against. Lifting it\r\n out is the only way it stays put.\r\n\r\n The cost is that the two tables can no longer size each other, so a\r\n shared <colgroup> holds their columns in alignment and the body's\r\n horizontal scroll is mirrored onto the header by hand.\r\n -->\r\n <div #virtualHead class=\"bk-table-virtual-head\">\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n </table>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport\r\n class=\"bk-table-viewport\"\r\n [itemSize]=\"virtualItemSize()\"\r\n [style.height]=\"scroll().y || '400px'\"\r\n (scroll)=\"onViewportScroll($event)\"\r\n >\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <tbody>\r\n <ng-container\r\n *cdkVirtualFor=\"\r\n let row of renderData();\r\n let i = index;\r\n trackBy: virtualTrackBy()\r\n \"\r\n [ngTemplateOutlet]=\"virtualScroll.templateRef\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\r\n ></ng-container>\r\n </tbody>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n </cdk-virtual-scroll-viewport>\r\n } @else {\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"bodySlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n }\r\n\r\n @if (loading() && showLoadingOverlay()) {\r\n <div class=\"bk-table-loading\">\r\n <span class=\"bk-table-spinner\"></span>\r\n </div>\r\n }\r\n\r\n @if (isEmpty()) {\r\n <div class=\"bk-table-empty\">\r\n @if (!emptyImageFailed()) {\r\n <img\r\n [src]=\"noResultImage()\"\r\n class=\"bk-table-empty-img\"\r\n alt=\"No data found\"\r\n (error)=\"onEmptyImageError()\"\r\n />\r\n }\r\n <span class=\"bk-table-empty-text\">{{ noResultText() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (hasFooter()) {\r\n <div class=\"bk-table-footer-bar\">\r\n @if (footer()) {\r\n {{ footer() }}\r\n }\r\n <ng-content select=\"[bkTableFooter]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <!-- Inside the frame: the pager belongs to the table it drives, and the\r\n frame's bottom edge is what closes the card around both.\r\n\r\n `!isEmpty()`, not `totalCount() > 0`: in server mode `totalCount()`\r\n is just the `total` input, which can say more rows exist than are\r\n actually on screen right now (a search with no matches but a stale\r\n total, a page past the end) \u2014 the pager has nothing to page through\r\n either way, so it goes by what's actually rendered. -->\r\n @if (showPagination() && !isEmpty()) {\r\n <div class=\"bk-table-pagination\">\r\n <bk-pagination\r\n [total]=\"totalCount()\"\r\n [pageSize]=\"pageSize()\"\r\n [activePage]=\"pageIndex()\"\r\n (pageChanged)=\"onPageIndexChange($event)\"\r\n (changePageSize)=\"onPageSizeChange($event)\"\r\n ></bk-pagination>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".bk-table-host{display:block}.bk-table-wrapper{@apply w-full;}.bk-table-frame{border:1px solid #ebedf3;border-radius:.75rem;overflow:hidden}.bk-table-title-bar,.bk-table-footer-bar{@apply text-[13px] font-semibold text-[#15191E] bg-[#F9FAFA] px-4 py-2.5;}.bk-table-title-bar{border-bottom:1px solid #ebedf3}.bk-table-footer-bar{border-top:1px solid #ebedf3}.bk-table-container{@apply relative overflow-auto;}.bk-table{@apply min-w-full text-left;border-collapse:separate;border-spacing:0}.bk-th{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap align-middle;border-bottom:1px solid #ebedf3;position:sticky;top:0;z-index:2}.bk-table thead tr:nth-child(2) .bk-th{top:var(--bk-thead-row-1, 38px);z-index:1}.bk-th-content{@apply flex items-center justify-between gap-1;}.bk-th-align-right .bk-th-content{@apply justify-end;}.bk-th-align-center .bk-th-content{@apply justify-center;}.bk-th-label{@apply inline-flex items-center gap-1;}.bk-th-sortable .bk-th-label{@apply cursor-pointer select-none;}.bk-th-selection{@apply flex items-center gap-1;}.bk-cell-selection{@apply px-3;}.bk-th-selection-caret{@apply inline-flex items-center justify-center size-4 rounded hover:bg-[#EFF1F4];}.bk-td{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 align-middle bg-white;border-bottom:1px solid #ebedf3}.bk-td-content{@apply inline-flex items-center gap-1 align-middle;}.bk-td-content-block{@apply block w-full;}.bk-table tbody tr:hover .bk-td{@apply bg-[#FBFBFC];}.bk-table-lg .bk-th{@apply px-5 py-3.5 text-[13px];}.bk-table-lg .bk-td{@apply px-5 py-3.5 text-sm leading-5;}.bk-table-md .bk-th{@apply px-3 py-2;}.bk-table-md .bk-td{@apply px-3 py-1.5;}.bk-table-sm .bk-th{@apply px-2 py-1.5 text-[11px];}.bk-table-sm .bk-td{@apply px-2 py-1 text-xs;}.bk-table-lg .bk-cell-selection{@apply px-4;}.bk-table-md .bk-cell-selection{@apply px-2.5;}.bk-table-sm .bk-cell-selection{@apply px-2;}.bk-table-bordered .bk-th,.bk-table-bordered .bk-td{border-right:1px solid #ebedf3}.bk-table-bordered .bk-th:last-child,.bk-table-bordered .bk-td:last-child{border-right:0}.bk-table tbody tr:last-child>.bk-td{border-bottom:0}.bk-table-underfilled .bk-table tbody tr:last-child>.bk-td{border-bottom:1px solid #ebedf3}.bk-cell-sticky{position:sticky;z-index:1}.bk-th.bk-cell-sticky{z-index:3}.bk-cell-sticky-left:after,.bk-cell-sticky-right:before{content:\"\";@apply absolute top-0 bottom-0 w-2 pointer-events-none;}.bk-cell-sticky-left:after{right:-8px;background-image:linear-gradient(to right,rgba(0,0,0,.05),transparent)}.bk-cell-sticky-right:before{left:-8px;background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.bk-cell-ellipsis{@apply overflow-hidden text-ellipsis whitespace-nowrap;max-width:0}.bk-td-content-ellipsis{@apply flex w-full;}.bk-td-ellipsis-text{@apply overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1;}.bk-cell-break-word{@apply whitespace-normal;word-break:break-all}.bk-td-indent{@apply inline-block;}.bk-td-expand,.bk-td-expand-spacer{@apply inline-flex items-center justify-center size-4 shrink-0;}.bk-td-expand{@apply rounded text-[#78829D] hover:bg-[#EFF1F4] transition-transform duration-200;transform:rotate(-90deg)}.bk-td-expand-open{transform:rotate(0)}.bk-expanded-row>.bk-td,.bk-expanded-row>td{@apply bg-[#FBFBFC];}.bk-td-flush{@apply p-3;}.bk-table-flush .bk-table-frame{border:0;border-radius:0}.bk-table-summary .bk-td{@apply bg-[#F9FAFA] font-semibold;border-top:1px solid #ebedf3;border-bottom:0}.bk-table-summary-fixed .bk-td{position:sticky;bottom:0;z-index:2}.bk-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.bk-sort-icon:before,.bk-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-sort-asc: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\")}.bk-sort-asc: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\")}.bk-sort-desc: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\")}.bk-sort-desc: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\")}.bk-sort-priority{@apply inline-flex items-center justify-center min-w-4 h-4 px-1 rounded bg-[#EFF1F4] text-[10px] font-semibold text-[#4B5675];}.bk-filter-trigger{@apply inline-flex items-center justify-center size-5 rounded text-[#78829D] hover:bg-[#EFF1F4];}.bk-filter-active{@apply text-black;}.bk-filter-menu{@apply min-w-[180px];}.bk-filter-list{@apply flex flex-col gap-2 max-h-60 overflow-y-auto py-1;}.bk-filter-option{@apply text-[13px] text-[#15191E];}.bk-filter-actions{@apply flex items-center justify-between gap-2 pt-2 mt-2;border-top:1px solid #ebedf3}.bk-filter-btn{@apply text-xs font-semibold px-2.5 py-1 rounded;}.bk-filter-btn-link{@apply text-[#60646C] hover:bg-[#F1F2F4];}.bk-filter-btn-primary{@apply bg-black text-white hover:bg-[#2A2E36];}.bk-table-menu{@apply min-w-[160px] flex flex-col;}.bk-table-menu-item{@apply w-full text-left text-[13px] text-[#15191E] px-2 py-1.5 rounded hover:bg-[#F1F2F4];}.bk-table-loading{@apply absolute inset-0 flex items-center justify-center bg-white/60 z-10;}.bk-table-spinner{@apply block size-8 rounded-full border-2 border-[#EBEDF3] border-t-black;animation:bk-table-spin .8s linear infinite}@keyframes bk-table-spin{to{transform:rotate(360deg)}}.bk-table-empty{@apply absolute inset-x-0 bottom-0 flex flex-col justify-center items-center py-10;top:var(--bk-thead-row-1, 38px)}.bk-table-empty-img{@apply mb-3 w-96 max-w-full;}.bk-table-empty-text{@apply block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2;}.bk-table-pagination{@apply contents;}.bk-table-viewport{@apply w-full;}.bk-table-virtual-head{@apply w-full overflow-hidden;}.bk-table-virtual-head .bk-th{position:static}.bk-checkbox-indeterminate .checkbox{@apply bg-black border-black;}.bk-checkbox-indeterminate .checkbox:after{content:\"\";@apply absolute w-2 h-0.5 bg-white rounded-sm;}.cdk-drag-preview{display:table;table-layout:fixed;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)}.bk-drag-handle{@apply cursor-move inline-flex items-center justify-center text-[#C4CADA] hover:text-[#78829D] mr-2 align-middle;}.bk-tree-drop-line{@apply absolute pointer-events-none rounded-full;height:2px;background:#15191e;z-index:5}.bk-table tbody tr.bk-tree-drop-inside .bk-td{background:#f1f2f4;box-shadow:inset 0 0 0 1px #15191e59}\n"] }]
|
|
11565
|
+
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "footer", required: false }] }], scroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "scroll", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showLoadingOverlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLoadingOverlay", required: false }] }], noResultText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultText", required: false }] }], noResultImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultImage", required: false }] }], showPagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPagination", required: false }] }], frontPagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "frontPagination", required: false }] }], pageIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageIndex", required: false }] }, { type: i0.Output, args: ["pageIndexChange"] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], virtualItemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualItemSize", required: false }] }], virtualTrackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualTrackBy", required: false }] }], viewport: [{
|
|
11566
|
+
type: ViewChild,
|
|
11567
|
+
args: [CdkVirtualScrollViewport]
|
|
11568
|
+
}], stableColumnWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "stableColumnWidth", required: false }] }], queryParams: [{ type: i0.Output, args: ["queryParams"] }], currentPageDataChange: [{ type: i0.Output, args: ["currentPageDataChange"] }], titleContent: [{
|
|
11569
|
+
type: ContentChild,
|
|
11570
|
+
args: [BkTableTitle]
|
|
11571
|
+
}], footerContent: [{
|
|
11572
|
+
type: ContentChild,
|
|
11573
|
+
args: [BkTableFooter]
|
|
11574
|
+
}], virtualScroll: [{
|
|
11575
|
+
type: ContentChild,
|
|
11576
|
+
args: [BkVirtualScroll]
|
|
11577
|
+
}], virtualHead: [{
|
|
11578
|
+
type: ViewChild,
|
|
11579
|
+
args: ['virtualHead']
|
|
11580
|
+
}] } });
|
|
11581
|
+
|
|
11582
|
+
/**
|
|
11583
|
+
* Behaviour shared by `th[bk-th]` and `td[bk-td]`: fixed columns, text
|
|
11584
|
+
* overflow handling and alignment.
|
|
11585
|
+
*
|
|
11586
|
+
* Fixed columns are `position: sticky`, which needs a pixel offset — and the
|
|
11587
|
+
* correct offset is the cell's distance from the edge of the table, which is
|
|
11588
|
+
* only knowable after layout. Subclasses get that measurement for free.
|
|
11589
|
+
*/
|
|
11590
|
+
class BkCellBase {
|
|
11591
|
+
el = inject((ElementRef));
|
|
11592
|
+
zone = inject(NgZone);
|
|
11593
|
+
/**
|
|
11594
|
+
* Pin this column to the left edge while the table scrolls horizontally.
|
|
11595
|
+
* `true` measures the offset; a string sets it explicitly.
|
|
11596
|
+
*
|
|
11597
|
+
* Pinned columns must be contiguous from the edge — a gap leaves the columns
|
|
11598
|
+
* beyond it overlapping as they scroll underneath.
|
|
11599
|
+
*/
|
|
11600
|
+
left = input(false, ...(ngDevMode ? [{ debugName: "left" }] : []));
|
|
11601
|
+
/** Pin to the right edge. Same rules as `left`. */
|
|
11602
|
+
right = input(false, ...(ngDevMode ? [{ debugName: "right" }] : []));
|
|
11603
|
+
/**
|
|
11604
|
+
* Truncate overflow with an ellipsis instead of wrapping.
|
|
11605
|
+
*
|
|
11606
|
+
* Put it on the `td`, not the `th`. It works by setting `max-width: 0` on
|
|
11607
|
+
* whichever cell carries it, and `table-layout: fixed` sizes a column from
|
|
11608
|
+
* its header cell alone — a `max-width` on the header collapses the whole
|
|
11609
|
+
* column toward zero regardless of any declared `width`. A `td`'s own width
|
|
11610
|
+
* is never consulted by `fixed` layout, so the same rule there only clips
|
|
11611
|
+
* the content, which is the point.
|
|
11612
|
+
*/
|
|
11613
|
+
ellipsis = input(false, ...(ngDevMode ? [{ debugName: "ellipsis" }] : []));
|
|
11614
|
+
/**
|
|
11615
|
+
* Allow breaks *inside* words. Without it a long unbroken string (a URL, an
|
|
11616
|
+
* ID) pushes past the cell instead of wrapping.
|
|
11617
|
+
*/
|
|
11618
|
+
breakWord = input(false, ...(ngDevMode ? [{ debugName: "breakWord" }] : []));
|
|
11619
|
+
align = input(null, ...(ngDevMode ? [{ debugName: "align" }] : []));
|
|
11620
|
+
/** Resolved sticky offsets, written after measurement. */
|
|
11621
|
+
stickyLeft = signal(null, ...(ngDevMode ? [{ debugName: "stickyLeft" }] : []));
|
|
11622
|
+
stickyRight = signal(null, ...(ngDevMode ? [{ debugName: "stickyRight" }] : []));
|
|
11623
|
+
resizeObserver;
|
|
11624
|
+
get isSticky() {
|
|
11625
|
+
return this.left() !== false || this.right() !== false;
|
|
11626
|
+
}
|
|
11627
|
+
ngAfterViewInit() {
|
|
11628
|
+
if (!this.isSticky)
|
|
11629
|
+
return;
|
|
11630
|
+
// Measuring synchronously here reads a layout that hasn't happened yet.
|
|
11631
|
+
// A table with many rows registers hundreds of these cells in one
|
|
11632
|
+
// synchronous pass, before the browser has laid out any of them — an
|
|
11633
|
+
// immediate `offsetWidth` read comes back 0, not "not yet available",
|
|
11634
|
+
// so nothing downstream can tell the difference from a genuinely
|
|
11635
|
+
// zero-width column. Deferring past the current task is what
|
|
11636
|
+
// `BkTable.freezeColumnWidths()` already does for the identical
|
|
11637
|
+
// problem; a plain event listener wouldn't fire without a real resize
|
|
11638
|
+
// to trigger it, so it can't stand in for this first measurement.
|
|
11639
|
+
this.zone.runOutsideAngular(() => {
|
|
11640
|
+
setTimeout(() => this.measure());
|
|
11641
|
+
});
|
|
11642
|
+
// Column widths move with the table, not with Angular's change detection,
|
|
11643
|
+
// so the offsets have to be recomputed from a layout signal. Watching the
|
|
11644
|
+
// table (not the cell) catches sibling columns resizing too.
|
|
11645
|
+
const table = this.el.nativeElement.closest('table');
|
|
11646
|
+
if (table && typeof ResizeObserver !== 'undefined') {
|
|
11647
|
+
this.zone.runOutsideAngular(() => {
|
|
11648
|
+
this.resizeObserver = new ResizeObserver(() => this.measure());
|
|
11649
|
+
this.resizeObserver.observe(table);
|
|
11650
|
+
});
|
|
11651
|
+
}
|
|
11652
|
+
}
|
|
11653
|
+
ngOnDestroy() {
|
|
11654
|
+
this.resizeObserver?.disconnect();
|
|
11655
|
+
}
|
|
11656
|
+
/**
|
|
11657
|
+
* Resolves the sticky offsets.
|
|
11658
|
+
*
|
|
11659
|
+
* Offsets are summed from sibling `offsetWidth`s rather than read from
|
|
11660
|
+
* `getBoundingClientRect()`: once a cell is sticky its rect reflects where it
|
|
11661
|
+
* has been *held*, not where the column sits, so measuring a scrolled table
|
|
11662
|
+
* that way feeds each cell its own displacement back. `offsetWidth` is
|
|
11663
|
+
* unaffected by the sticky shift.
|
|
11664
|
+
*/
|
|
11665
|
+
measure() {
|
|
11666
|
+
const cell = this.el.nativeElement;
|
|
11667
|
+
const leftInput = this.left();
|
|
11668
|
+
if (leftInput !== false) {
|
|
11669
|
+
this.stickyLeft.set(typeof leftInput === 'string' ? leftInput : `${this.sumWidths(cell, 'previous')}px`);
|
|
11670
|
+
}
|
|
11671
|
+
const rightInput = this.right();
|
|
11672
|
+
if (rightInput !== false) {
|
|
11673
|
+
this.stickyRight.set(typeof rightInput === 'string' ? rightInput : `${this.sumWidths(cell, 'next')}px`);
|
|
11674
|
+
}
|
|
11675
|
+
}
|
|
11676
|
+
sumWidths(cell, direction) {
|
|
11677
|
+
let total = 0;
|
|
11678
|
+
let sibling = direction === 'previous' ? cell.previousElementSibling : cell.nextElementSibling;
|
|
11679
|
+
while (sibling) {
|
|
11680
|
+
total += sibling.offsetWidth;
|
|
11681
|
+
sibling =
|
|
11682
|
+
direction === 'previous' ? sibling.previousElementSibling : sibling.nextElementSibling;
|
|
11683
|
+
}
|
|
11684
|
+
return total;
|
|
11685
|
+
}
|
|
11686
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCellBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11687
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: BkCellBase, isStandalone: true, inputs: { left: { classPropertyName: "left", publicName: "left", isSignal: true, isRequired: false, transformFunction: null }, right: { classPropertyName: "right", publicName: "right", isSignal: true, isRequired: false, transformFunction: null }, ellipsis: { classPropertyName: "ellipsis", publicName: "ellipsis", isSignal: true, isRequired: false, transformFunction: null }, breakWord: { classPropertyName: "breakWord", publicName: "breakWord", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
11688
|
+
}
|
|
11689
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCellBase, decorators: [{
|
|
11690
|
+
type: Directive
|
|
11691
|
+
}], propDecorators: { left: [{ type: i0.Input, args: [{ isSignal: true, alias: "left", required: false }] }], right: [{ type: i0.Input, args: [{ isSignal: true, alias: "right", required: false }] }], ellipsis: [{ type: i0.Input, args: [{ isSignal: true, alias: "ellipsis", required: false }] }], breakWord: [{ type: i0.Input, args: [{ isSignal: true, alias: "breakWord", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }] } });
|
|
11692
|
+
|
|
11693
|
+
/**
|
|
11694
|
+
* Header cell.
|
|
11695
|
+
*
|
|
11696
|
+
* Carries a column's sort state, filter menu and select-all checkbox, and
|
|
11697
|
+
* registers itself with the parent `bk-table` so the table's data pipeline can
|
|
11698
|
+
* read them. It renders whatever you project as the label:
|
|
11699
|
+
*
|
|
11700
|
+
* <th bk-th [sortFn]="byName" [filters]="statuses" [filterFn]="byStatus">
|
|
11701
|
+
* Name
|
|
11702
|
+
* </th>
|
|
11703
|
+
*
|
|
11704
|
+
* Use the native `colspan` / `rowspan` attributes for grouped headers — they
|
|
11705
|
+
* need no wrapper input.
|
|
11706
|
+
*/
|
|
11707
|
+
class BkTh extends BkCellBase {
|
|
11708
|
+
/** Optional: the parent table only exists when the th is inside one. */
|
|
11709
|
+
table = inject(BkTable, { optional: true, host: false });
|
|
11710
|
+
/** Identifies the column in `queryParams`. Required for server-side work. */
|
|
11711
|
+
columnKeyInput = input(null, ...(ngDevMode ? [{ debugName: "columnKeyInput", alias: 'columnKey' }] : [{ alias: 'columnKey' }]));
|
|
11712
|
+
/**
|
|
11713
|
+
* Column width. Required in virtual-scroll mode, where the header is a
|
|
11714
|
+
* separate table and has no body cells to size itself against.
|
|
11715
|
+
*/
|
|
11716
|
+
widthInput = input(null, ...(ngDevMode ? [{ debugName: "widthInput", alias: 'width' }] : [{ alias: 'width' }]));
|
|
11717
|
+
/** Plain-value views of the inputs, so the table can read them off BkColumnRef. */
|
|
11718
|
+
get columnKey() {
|
|
11719
|
+
return this.columnKeyInput();
|
|
11720
|
+
}
|
|
11721
|
+
get width() {
|
|
11722
|
+
return this.widthInput();
|
|
11723
|
+
}
|
|
11724
|
+
/* ================= Sorting ================= */
|
|
11725
|
+
/**
|
|
11726
|
+
* A comparator sorts client-side; `true` marks the column sortable but
|
|
11727
|
+
* leaves the sorting to the server.
|
|
11728
|
+
*/
|
|
11729
|
+
sortFn = input(null, ...(ngDevMode ? [{ debugName: "sortFn" }] : []));
|
|
11730
|
+
sortOrder = model(null, ...(ngDevMode ? [{ debugName: "sortOrder" }] : []));
|
|
11731
|
+
/** The cycle the header steps through on each click. */
|
|
11732
|
+
sortDirections = input(['ascend', 'descend', null], ...(ngDevMode ? [{ debugName: "sortDirections" }] : []));
|
|
11733
|
+
/**
|
|
11734
|
+
* Ranks this column against other sorted columns — higher wins. Columns
|
|
11735
|
+
* without a priority sort in registration order after those with one.
|
|
11736
|
+
*/
|
|
11737
|
+
sortPriorityInput = input(null, ...(ngDevMode ? [{ debugName: "sortPriorityInput", alias: 'sortPriority' }] : [{ alias: 'sortPriority' }]));
|
|
11738
|
+
/* ================= Filtering ================= */
|
|
11739
|
+
/** Options for the filter menu. An empty list hides the funnel icon. */
|
|
11740
|
+
filters = input([], ...(ngDevMode ? [{ debugName: "filters" }] : []));
|
|
11741
|
+
/** Predicate for client-side filtering, or `true` to defer to the server. */
|
|
11742
|
+
filterFn = input(null, ...(ngDevMode ? [{ debugName: "filterFn" }] : []));
|
|
11743
|
+
/** Multiple shows checkboxes; single shows radios and closes on pick. */
|
|
11744
|
+
filterMultiple = input(true, ...(ngDevMode ? [{ debugName: "filterMultiple" }] : []));
|
|
11745
|
+
/* ================= Selection ================= */
|
|
11746
|
+
checkbox = input(false, ...(ngDevMode ? [{ debugName: "checkbox" }] : []));
|
|
11747
|
+
checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
|
|
11748
|
+
indeterminate = input(false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : []));
|
|
11749
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
11750
|
+
/**
|
|
11751
|
+
* Extra entries in the select-all dropdown ("Select odd rows", …). Providing
|
|
11752
|
+
* any adds a caret beside the checkbox.
|
|
11753
|
+
*/
|
|
11754
|
+
selections = input([], ...(ngDevMode ? [{ debugName: "selections" }] : []));
|
|
11755
|
+
/* ================= Expand column ================= */
|
|
11756
|
+
/** Reserves the narrow width used by the expand-icon column. */
|
|
11757
|
+
showExpand = input(false, ...(ngDevMode ? [{ debugName: "showExpand" }] : []));
|
|
11758
|
+
/* ================= Internal state ================= */
|
|
11759
|
+
filterValue = signal([], ...(ngDevMode ? [{ debugName: "filterValue" }] : []));
|
|
11760
|
+
/** Menu selection while the popover is open, before OK is pressed. */
|
|
11761
|
+
pendingFilter = signal([], ...(ngDevMode ? [{ debugName: "pendingFilter" }] : []));
|
|
11762
|
+
showSort = computed(() => this.sortFn() !== null, ...(ngDevMode ? [{ debugName: "showSort" }] : []));
|
|
11763
|
+
showFilter = computed(() => this.filters().length > 0, ...(ngDevMode ? [{ debugName: "showFilter" }] : []));
|
|
11764
|
+
isFiltered = computed(() => this.filterValue().length > 0, ...(ngDevMode ? [{ debugName: "isFiltered" }] : []));
|
|
11765
|
+
/** Only comparators run in-process; `true` means the server sorts. */
|
|
11766
|
+
get clientSortFn() {
|
|
11767
|
+
const fn = this.sortFn();
|
|
11768
|
+
return typeof fn === 'function' ? fn : null;
|
|
11769
|
+
}
|
|
11770
|
+
get clientFilterFn() {
|
|
11771
|
+
const fn = this.filterFn();
|
|
11772
|
+
return typeof fn === 'function' ? fn : null;
|
|
11773
|
+
}
|
|
11774
|
+
get sortPriority() {
|
|
11775
|
+
return this.sortPriorityInput();
|
|
11776
|
+
}
|
|
11777
|
+
ngOnInit() {
|
|
11778
|
+
// Options marked byDefault are active before the menu is ever opened.
|
|
11779
|
+
const defaults = this.filters().filter((f) => f.byDefault).map((f) => f.value);
|
|
11780
|
+
if (defaults.length) {
|
|
11781
|
+
this.filterValue.set(defaults);
|
|
11782
|
+
this.pendingFilter.set(defaults);
|
|
11783
|
+
}
|
|
11784
|
+
this.table?.registerColumn(this);
|
|
11785
|
+
}
|
|
11786
|
+
ngOnDestroy() {
|
|
11787
|
+
super.ngOnDestroy();
|
|
11788
|
+
this.table?.unregisterColumn(this);
|
|
11789
|
+
}
|
|
11790
|
+
/* ================= Sort interaction ================= */
|
|
11791
|
+
/** Advances to the next order in `sortDirections`, wrapping at the end. */
|
|
11792
|
+
onSortClick() {
|
|
11793
|
+
if (!this.showSort())
|
|
11794
|
+
return;
|
|
11795
|
+
const cycle = this.sortDirections();
|
|
11796
|
+
const next = cycle[(cycle.indexOf(this.sortOrder()) + 1) % cycle.length];
|
|
11797
|
+
this.sortOrder.set(next);
|
|
11798
|
+
this.table?.onColumnStateChange();
|
|
11799
|
+
}
|
|
11800
|
+
clearSort() {
|
|
11801
|
+
this.sortOrder.set(null);
|
|
11802
|
+
}
|
|
11803
|
+
/* ================= Filter interaction ================= */
|
|
11804
|
+
isPending(value) {
|
|
11805
|
+
return this.pendingFilter().includes(value);
|
|
11806
|
+
}
|
|
11807
|
+
/**
|
|
11808
|
+
* Single-select view of the pending selection, for the radio list. The
|
|
11809
|
+
* underlying state stays an array in both modes so the filter predicate has
|
|
11810
|
+
* one shape to handle.
|
|
11811
|
+
*/
|
|
11812
|
+
get singleFilter() {
|
|
11813
|
+
return this.pendingFilter()[0] ?? null;
|
|
11814
|
+
}
|
|
11815
|
+
set singleFilter(value) {
|
|
11816
|
+
this.pendingFilter.set(value === null || value === undefined ? [] : [value]);
|
|
11817
|
+
}
|
|
11818
|
+
toggleFilterOption(value, selected) {
|
|
11819
|
+
if (!this.filterMultiple()) {
|
|
11820
|
+
this.pendingFilter.set(selected ? [value] : []);
|
|
11821
|
+
return;
|
|
11822
|
+
}
|
|
11823
|
+
this.pendingFilter.update((list) => selected ? [...list, value] : list.filter((v) => v !== value));
|
|
11824
|
+
}
|
|
11825
|
+
applyFilter(popover) {
|
|
11826
|
+
this.filterValue.set([...this.pendingFilter()]);
|
|
11827
|
+
this.table?.onColumnStateChange();
|
|
11828
|
+
popover?.close();
|
|
11829
|
+
}
|
|
11830
|
+
resetFilter(popover) {
|
|
11831
|
+
this.pendingFilter.set([]);
|
|
11832
|
+
this.filterValue.set([]);
|
|
11833
|
+
this.table?.onColumnStateChange();
|
|
11834
|
+
popover?.close();
|
|
11835
|
+
}
|
|
11836
|
+
clearFilter() {
|
|
11837
|
+
this.filterValue.set([]);
|
|
11838
|
+
this.pendingFilter.set([]);
|
|
11839
|
+
}
|
|
11840
|
+
/** Re-syncs the menu to the applied state so a cancelled edit doesn't stick. */
|
|
11841
|
+
onFilterMenuOpen() {
|
|
11842
|
+
this.pendingFilter.set([...this.filterValue()]);
|
|
11843
|
+
}
|
|
11844
|
+
/* ================= Selection interaction ================= */
|
|
11845
|
+
onCheckedChange(value) {
|
|
11846
|
+
this.checked.set(value);
|
|
11847
|
+
}
|
|
11848
|
+
runSelection(selection, popover) {
|
|
11849
|
+
selection.onSelect();
|
|
11850
|
+
popover?.close();
|
|
11851
|
+
}
|
|
11852
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
11853
|
+
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 });
|
|
11854
|
+
}
|
|
11855
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, decorators: [{
|
|
11856
|
+
type: Component,
|
|
11857
|
+
args: [{ selector: 'th[bk-th]', standalone: true, imports: [CommonModule, FormsModule, BkCheckbox, BkRadioButton, BkPopover], encapsulation: ViewEncapsulation.None, host: {
|
|
11858
|
+
class: 'bk-th',
|
|
11859
|
+
'[class.bk-th-sortable]': 'showSort()',
|
|
11860
|
+
'[class.bk-cell-selection]': 'checkbox()',
|
|
11861
|
+
'[class.bk-cell-sticky]': 'isSticky',
|
|
11862
|
+
'[class.bk-cell-sticky-left]': 'left() !== false',
|
|
11863
|
+
'[class.bk-cell-sticky-right]': 'right() !== false',
|
|
11864
|
+
'[class.bk-cell-ellipsis]': 'ellipsis()',
|
|
11865
|
+
'[class.bk-cell-break-word]': 'breakWord()',
|
|
11866
|
+
'[class.bk-th-align-right]': "align() === 'right'",
|
|
11867
|
+
'[class.bk-th-align-center]': "align() === 'center'",
|
|
11868
|
+
'[style.left]': 'stickyLeft()',
|
|
11869
|
+
'[style.right]': 'stickyRight()',
|
|
11870
|
+
'[style.width]': 'widthInput()',
|
|
11871
|
+
'[style.text-align]': 'align()'
|
|
11872
|
+
}, 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" }]
|
|
11873
|
+
}], propDecorators: { columnKeyInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnKey", required: false }] }], widthInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], sortFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortFn", required: false }] }], sortOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortOrder", required: false }] }, { type: i0.Output, args: ["sortOrderChange"] }], sortDirections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDirections", required: false }] }], sortPriorityInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortPriority", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], filterFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterFn", required: false }] }], filterMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterMultiple", required: false }] }], checkbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkbox", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], selections: [{ type: i0.Input, args: [{ isSignal: true, alias: "selections", required: false }] }], showExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExpand", required: false }] }] } });
|
|
11874
|
+
|
|
11875
|
+
/**
|
|
11876
|
+
* Body cell.
|
|
11877
|
+
*
|
|
11878
|
+
* Handles the parts of a cell the consumer shouldn't have to rebuild each
|
|
11879
|
+
* time — row checkbox, expand toggle, tree indentation, sticky positioning —
|
|
11880
|
+
* and projects everything else through untouched:
|
|
11881
|
+
*
|
|
11882
|
+
* <td bk-td [(checked)]="row.checked"></td>
|
|
11883
|
+
* <td bk-td [showExpand]="row.hasChildren" [(expand)]="row.expand"
|
|
11884
|
+
* [indentLevel]="row.level" [indentSize]="20">{{ row.name }}</td>
|
|
11885
|
+
*
|
|
11886
|
+
* Use the native `colspan` / `rowspan` attributes for spanning cells.
|
|
11887
|
+
*/
|
|
11888
|
+
class BkTd extends BkCellBase {
|
|
11889
|
+
ngZone = inject(NgZone);
|
|
11890
|
+
ellipsisResizeObserver;
|
|
11891
|
+
/**
|
|
11892
|
+
* The tooltip's content, and the switch for whether it shows at all — see
|
|
11893
|
+
* `observeEllipsisTruncation()`. Bound in the template onto the innermost
|
|
11894
|
+
* `.bk-td-ellipsis-text` span wrapping the projected content, not the `td`
|
|
11895
|
+
* or `.bk-td-content`: both of those are wider than the actual (possibly
|
|
11896
|
+
* truncated) text, and the tooltip should point at what's actually there.
|
|
11897
|
+
*/
|
|
11898
|
+
truncatedTooltip = signal('', ...(ngDevMode ? [{ debugName: "truncatedTooltip" }] : []));
|
|
11899
|
+
/** Forwarded to the content wrapper's `bkTooltip`. Override on a column whose default 'right' would run into its neighbour. */
|
|
11900
|
+
tooltipPosition = input('right', ...(ngDevMode ? [{ debugName: "tooltipPosition" }] : []));
|
|
11901
|
+
/** Only present when `ellipsis()` is true — see the `@else` branch in the template. */
|
|
11902
|
+
ellipsisTextRef;
|
|
11903
|
+
/* ================= Selection ================= */
|
|
11904
|
+
checkbox = input(false, ...(ngDevMode ? [{ debugName: "checkbox" }] : []));
|
|
11905
|
+
checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
|
|
11906
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
11907
|
+
indeterminate = input(false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : []));
|
|
11908
|
+
/* ================= Expansion ================= */
|
|
11909
|
+
/**
|
|
11910
|
+
* Renders the expand toggle. Set it false on leaf rows in a tree — the cell
|
|
11911
|
+
* still reserves the icon's width so labels stay aligned down the column.
|
|
11912
|
+
*/
|
|
11913
|
+
showExpand = input(false, ...(ngDevMode ? [{ debugName: "showExpand" }] : []));
|
|
11914
|
+
expand = model(false, ...(ngDevMode ? [{ debugName: "expand" }] : []));
|
|
11915
|
+
/**
|
|
11916
|
+
* Custom expand icon. The template receives the open state as `$implicit`:
|
|
11917
|
+
*
|
|
11918
|
+
* <ng-template #icon let-expanded>{{ expanded ? '−' : '+' }}</ng-template>
|
|
11919
|
+
*/
|
|
11920
|
+
expandIcon = input(null, ...(ngDevMode ? [{ debugName: "expandIcon" }] : []));
|
|
11921
|
+
/* ================= Tree indentation ================= */
|
|
11922
|
+
/** Depth of this row in the tree. Multiplied by `indentSize`. */
|
|
11923
|
+
indentLevel = input(0, ...(ngDevMode ? [{ debugName: "indentLevel" }] : []));
|
|
11924
|
+
/** Pixels of indent per level. */
|
|
11925
|
+
indentSize = input(20, ...(ngDevMode ? [{ debugName: "indentSize" }] : []));
|
|
11926
|
+
/**
|
|
11927
|
+
* Marks the column that carries the tree. Leaf rows in such a column get a
|
|
11928
|
+
* blank spacer where the toggle would be, so their labels line up with the
|
|
11929
|
+
* labels of siblings that do have children — including at depth 0, where
|
|
11930
|
+
* indentation alone gives nothing to align against.
|
|
11931
|
+
*/
|
|
11932
|
+
treeCell = input(false, ...(ngDevMode ? [{ debugName: "treeCell" }] : []));
|
|
11933
|
+
/**
|
|
11934
|
+
* The projected content is block-level and should fill the cell — a nested
|
|
11935
|
+
* `bk-table`, most commonly — rather than the default shrink-to-fit inline
|
|
11936
|
+
* box that lets ordinary text/icon content size to itself and still honour
|
|
11937
|
+
* `align` via `text-align`. Turning this on trades that `align` behaviour
|
|
11938
|
+
* away for whatever the block content does with the full width itself.
|
|
11939
|
+
*/
|
|
11940
|
+
block = input(false, ...(ngDevMode ? [{ debugName: "block" }] : []));
|
|
11941
|
+
indentPx = computed(() => this.indentLevel() * this.indentSize(), ...(ngDevMode ? [{ debugName: "indentPx" }] : []));
|
|
11942
|
+
/** A tree cell with no toggle of its own still reserves the toggle's width. */
|
|
11943
|
+
isLeafSpacer = computed(() => this.treeCell() && !this.showExpand(), ...(ngDevMode ? [{ debugName: "isLeafSpacer" }] : []));
|
|
11944
|
+
onExpandClick() {
|
|
11945
|
+
this.expand.set(!this.expand());
|
|
11946
|
+
}
|
|
11947
|
+
onCheckedChange(value) {
|
|
11948
|
+
this.checked.set(value);
|
|
11949
|
+
}
|
|
11950
|
+
ngAfterViewInit() {
|
|
11951
|
+
super.ngAfterViewInit();
|
|
11952
|
+
this.observeEllipsisTruncation();
|
|
11953
|
+
}
|
|
11954
|
+
ngOnDestroy() {
|
|
11955
|
+
super.ngOnDestroy();
|
|
11956
|
+
this.ellipsisResizeObserver?.disconnect();
|
|
11957
|
+
}
|
|
11958
|
+
/**
|
|
11959
|
+
* Drives `truncatedTooltip` from measured truncation rather than the
|
|
11960
|
+
* content being present unconditionally: `bkTooltip`'s own emptiness check
|
|
11961
|
+
* already suppresses the tooltip when there's nothing to show, so setting
|
|
11962
|
+
* it only when the cell is genuinely clipped (`scrollWidth > clientWidth`)
|
|
11963
|
+
* is what makes it show "for the truncated item only" — an `ellipsis` cell
|
|
11964
|
+
* whose text happens to fit never gets a tooltip at all.
|
|
11965
|
+
*
|
|
11966
|
+
* Measures the inner `.bk-td-ellipsis-text` span, not the `td` — that span
|
|
11967
|
+
* is now the element that actually owns `overflow: hidden` (see
|
|
11968
|
+
* `.bk-td-ellipsis-text` in table.css, and why: the ellipsis marker needs
|
|
11969
|
+
* a plain, non-flex element to render on at all). Because it clips its own
|
|
11970
|
+
* overflow, that overflow never reaches the `td`'s own `scrollWidth`
|
|
11971
|
+
* anymore — measuring the `td` here would read `scrollWidth ===
|
|
11972
|
+
* clientWidth` even when the text is visibly cut off, since the span
|
|
11973
|
+
* absorbs it first.
|
|
11974
|
+
*
|
|
11975
|
+
* Measured on resize, not on hover: `bkTooltip`'s own `mouseenter` listener
|
|
11976
|
+
* fires independently of this, so content has to already be correct
|
|
11977
|
+
* *before* any hover — computing it reactively to the hover would risk
|
|
11978
|
+
* showing whatever was last set instead of what's true at that moment.
|
|
11979
|
+
*/
|
|
11980
|
+
observeEllipsisTruncation() {
|
|
11981
|
+
if (!this.ellipsis() || typeof ResizeObserver === 'undefined')
|
|
11982
|
+
return;
|
|
11983
|
+
const textEl = this.ellipsisTextRef?.nativeElement;
|
|
11984
|
+
if (!textEl)
|
|
11985
|
+
return;
|
|
11986
|
+
const update = () => {
|
|
11987
|
+
const truncated = textEl.scrollWidth > textEl.clientWidth;
|
|
11988
|
+
this.truncatedTooltip.set(truncated ? (textEl.textContent ?? '').trim() : '');
|
|
11989
|
+
};
|
|
11990
|
+
this.ngZone.runOutsideAngular(() => {
|
|
11991
|
+
this.ellipsisResizeObserver = new ResizeObserver(update);
|
|
11992
|
+
this.ellipsisResizeObserver.observe(textEl);
|
|
11993
|
+
});
|
|
11994
|
+
}
|
|
11995
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTd, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
11996
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTd, isStandalone: true, selector: "td[bk-td]", inputs: { tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null }, expand: { classPropertyName: "expand", publicName: "expand", isSignal: true, isRequired: false, transformFunction: null }, expandIcon: { classPropertyName: "expandIcon", publicName: "expandIcon", isSignal: true, isRequired: false, transformFunction: null }, indentLevel: { classPropertyName: "indentLevel", publicName: "indentLevel", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, treeCell: { classPropertyName: "treeCell", publicName: "treeCell", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", expand: "expandChange" }, host: { properties: { "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()", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.text-align": "align()" }, classAttribute: "bk-td" }, viewQueries: [{ propertyName: "ellipsisTextRef", first: true, predicate: ["ellipsisText"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\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} @else {\r\n <span\r\n class=\"bk-td-content\"\r\n [class.bk-td-content-block]=\"block()\"\r\n [class.bk-td-content-ellipsis]=\"ellipsis()\"\r\n >\r\n @if (indentPx() > 0) {\r\n <!-- Depth is expressed as blank width, so the cell keeps one text flow\r\n and long labels still wrap under themselves rather than under the\r\n indent. -->\r\n <span class=\"bk-td-indent\" [style.padding-left.px]=\"indentPx()\"></span>\r\n }\r\n\r\n @if (showExpand()) {\r\n <button\r\n type=\"button\"\r\n class=\"bk-td-expand\"\r\n [class.bk-td-expand-open]=\"expand()\"\r\n [attr.aria-expanded]=\"expand()\"\r\n aria-label=\"Toggle row\"\r\n (click)=\"onExpandClick()\"\r\n >\r\n @if (expandIcon()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandIcon()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: expand() }\"\r\n ></ng-container>\r\n } @else {\r\n <svg width=\"8\" height=\"8\" 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=\"currentColor\"\r\n />\r\n </svg>\r\n }\r\n </button>\r\n } @else if (isLeafSpacer()) {\r\n <span class=\"bk-td-expand-spacer\"></span>\r\n }\r\n\r\n <span\r\n #ellipsisText\r\n [class.bk-td-ellipsis-text]=\"ellipsis()\"\r\n [bkTooltip]=\"truncatedTooltip()\"\r\n [bkTooltipPosition]=\"tooltipPosition()\"\r\n >\r\n <ng-content></ng-content>\r\n </span>\r\n </span>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
11997
|
+
}
|
|
11998
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTd, decorators: [{
|
|
11999
|
+
type: Component,
|
|
12000
|
+
args: [{ selector: 'td[bk-td]', standalone: true, imports: [CommonModule, FormsModule, BkCheckbox, BKTooltipDirective], encapsulation: ViewEncapsulation.None, host: {
|
|
12001
|
+
class: 'bk-td',
|
|
12002
|
+
'[class.bk-cell-selection]': 'checkbox()',
|
|
12003
|
+
'[class.bk-cell-sticky]': 'isSticky',
|
|
12004
|
+
'[class.bk-cell-sticky-left]': 'left() !== false',
|
|
12005
|
+
'[class.bk-cell-sticky-right]': 'right() !== false',
|
|
12006
|
+
'[class.bk-cell-ellipsis]': 'ellipsis()',
|
|
12007
|
+
'[class.bk-cell-break-word]': 'breakWord()',
|
|
12008
|
+
'[style.left]': 'stickyLeft()',
|
|
12009
|
+
'[style.right]': 'stickyRight()',
|
|
12010
|
+
'[style.text-align]': 'align()'
|
|
12011
|
+
}, template: "@if (checkbox()) {\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} @else {\r\n <span\r\n class=\"bk-td-content\"\r\n [class.bk-td-content-block]=\"block()\"\r\n [class.bk-td-content-ellipsis]=\"ellipsis()\"\r\n >\r\n @if (indentPx() > 0) {\r\n <!-- Depth is expressed as blank width, so the cell keeps one text flow\r\n and long labels still wrap under themselves rather than under the\r\n indent. -->\r\n <span class=\"bk-td-indent\" [style.padding-left.px]=\"indentPx()\"></span>\r\n }\r\n\r\n @if (showExpand()) {\r\n <button\r\n type=\"button\"\r\n class=\"bk-td-expand\"\r\n [class.bk-td-expand-open]=\"expand()\"\r\n [attr.aria-expanded]=\"expand()\"\r\n aria-label=\"Toggle row\"\r\n (click)=\"onExpandClick()\"\r\n >\r\n @if (expandIcon()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandIcon()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: expand() }\"\r\n ></ng-container>\r\n } @else {\r\n <svg width=\"8\" height=\"8\" 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=\"currentColor\"\r\n />\r\n </svg>\r\n }\r\n </button>\r\n } @else if (isLeafSpacer()) {\r\n <span class=\"bk-td-expand-spacer\"></span>\r\n }\r\n\r\n <span\r\n #ellipsisText\r\n [class.bk-td-ellipsis-text]=\"ellipsis()\"\r\n [bkTooltip]=\"truncatedTooltip()\"\r\n [bkTooltipPosition]=\"tooltipPosition()\"\r\n >\r\n <ng-content></ng-content>\r\n </span>\r\n </span>\r\n}\r\n" }]
|
|
12012
|
+
}], propDecorators: { tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], ellipsisTextRef: [{
|
|
12013
|
+
type: ViewChild,
|
|
12014
|
+
args: ['ellipsisText']
|
|
12015
|
+
}], checkbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkbox", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], showExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExpand", required: false }] }], expand: [{ type: i0.Input, args: [{ isSignal: true, alias: "expand", required: false }] }, { type: i0.Output, args: ["expandChange"] }], expandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandIcon", required: false }] }], indentLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentLevel", required: false }] }], indentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentSize", required: false }] }], treeCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeCell", required: false }] }], block: [{ type: i0.Input, args: [{ isSignal: true, alias: "block", required: false }] }] } });
|
|
12016
|
+
|
|
12017
|
+
/**
|
|
12018
|
+
* A detail row that appears beneath its parent when expanded.
|
|
12019
|
+
*
|
|
12020
|
+
* <tr [bkExpand]="row.expand">
|
|
12021
|
+
* <td colspan="5">…anything…</td>
|
|
12022
|
+
* </tr>
|
|
12023
|
+
*
|
|
12024
|
+
* The row is hidden rather than destroyed, so state inside it (a scrolled
|
|
12025
|
+
* nested table, a half-filled form) survives being collapsed and reopened.
|
|
12026
|
+
* Wrap it in `@if` instead when the content is expensive enough that keeping
|
|
12027
|
+
* it alive costs more than rebuilding it.
|
|
12028
|
+
*/
|
|
12029
|
+
class BkTrExpand {
|
|
12030
|
+
bkExpand = input(false, ...(ngDevMode ? [{ debugName: "bkExpand" }] : []));
|
|
12031
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTrExpand, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
12032
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: BkTrExpand, isStandalone: true, selector: "tr[bkExpand]", inputs: { bkExpand: { classPropertyName: "bkExpand", publicName: "bkExpand", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!bkExpand()" }, classAttribute: "bk-expanded-row" }, ngImport: i0 });
|
|
12033
|
+
}
|
|
12034
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTrExpand, decorators: [{
|
|
12035
|
+
type: Directive,
|
|
12036
|
+
args: [{
|
|
12037
|
+
selector: 'tr[bkExpand]',
|
|
12038
|
+
standalone: true,
|
|
12039
|
+
host: {
|
|
12040
|
+
class: 'bk-expanded-row',
|
|
12041
|
+
'[hidden]': '!bkExpand()'
|
|
12042
|
+
}
|
|
12043
|
+
}]
|
|
12044
|
+
}], propDecorators: { bkExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "bkExpand", required: false }] }] } });
|
|
12045
|
+
/**
|
|
12046
|
+
* Summary / totals rows, placed in a `<tfoot>`.
|
|
12047
|
+
*
|
|
12048
|
+
* <tfoot bkTableSummary [fixed]="true">
|
|
12049
|
+
* <tr><td bk-td>Total</td><td bk-td>{{ total }}</td></tr>
|
|
12050
|
+
* </tfoot>
|
|
12051
|
+
*
|
|
12052
|
+
* `fixed` pins the footer to the bottom of the scroll container so totals stay
|
|
12053
|
+
* visible while the body scrolls — the counterpart to the fixed header.
|
|
12054
|
+
*/
|
|
12055
|
+
class BkTableSummary {
|
|
12056
|
+
fixed = input(false, ...(ngDevMode ? [{ debugName: "fixed" }] : []));
|
|
12057
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableSummary, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
12058
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: BkTableSummary, isStandalone: true, selector: "tfoot[bkTableSummary]", inputs: { fixed: { classPropertyName: "fixed", publicName: "fixed", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.bk-table-summary-fixed": "fixed()" }, classAttribute: "bk-table-summary" }, ngImport: i0 });
|
|
12059
|
+
}
|
|
12060
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableSummary, decorators: [{
|
|
12061
|
+
type: Directive,
|
|
12062
|
+
args: [{
|
|
12063
|
+
selector: 'tfoot[bkTableSummary]',
|
|
12064
|
+
standalone: true,
|
|
12065
|
+
host: {
|
|
12066
|
+
class: 'bk-table-summary',
|
|
12067
|
+
'[class.bk-table-summary-fixed]': 'fixed()'
|
|
12068
|
+
}
|
|
12069
|
+
}]
|
|
12070
|
+
}], propDecorators: { fixed: [{ type: i0.Input, args: [{ isSignal: true, alias: "fixed", required: false }] }] } });
|
|
12071
|
+
|
|
12072
|
+
/**
|
|
12073
|
+
* Makes CDK row dragging behave inside a `<table>`.
|
|
12074
|
+
*
|
|
12075
|
+
* Two problems the CDK doesn't solve on its own, both carried over from
|
|
12076
|
+
* `bk-grid` where they were already working:
|
|
12077
|
+
*
|
|
12078
|
+
* 1. The drag preview is a detached copy of the `<tr>`, so it loses the column
|
|
12079
|
+
* widths the table gave it and collapses to its content. Widths are copied
|
|
12080
|
+
* across at drag start — from the *placeholder*, not the dragged row: by
|
|
12081
|
+
* the time `cdkDragStarted` fires, the CDK has already swapped the row out
|
|
12082
|
+
* for the placeholder and moved the row itself out to `<body>`, so the row
|
|
12083
|
+
* is no longer sitting inside the table and no longer reports the table's
|
|
12084
|
+
* widths. The placeholder is a clone left in the row's place, still inside
|
|
12085
|
+
* the table, so it's the one still telling the truth.
|
|
12086
|
+
* 2. Dragging to the edge of a scrolling table doesn't scroll it, so rows below
|
|
12087
|
+
* the fold are unreachable. Nearing an edge scrolls proportionally to how
|
|
12088
|
+
* close the pointer is.
|
|
12089
|
+
*
|
|
12090
|
+
* <div class="wrap" #d="bkTableDrag" bkTableDrag>
|
|
12091
|
+
* <bk-table>
|
|
12092
|
+
* <tbody cdkDropList (cdkDropListDropped)="drop($event)">
|
|
12093
|
+
* @for (row of rows; track row.id) {
|
|
12094
|
+
* <tr cdkDrag cdkDragLockAxis="y"
|
|
12095
|
+
* (cdkDragStarted)="d.onStart($event)"
|
|
12096
|
+
* (cdkDragMoved)="d.onMove($event)">
|
|
12097
|
+
*
|
|
12098
|
+
* The scroll container is resolved from the host, so put this on the element
|
|
12099
|
+
* that actually scrolls (or any ancestor of it).
|
|
12100
|
+
*/
|
|
12101
|
+
class BkTableDrag {
|
|
12102
|
+
el = inject((ElementRef));
|
|
12103
|
+
/** Distance from an edge, in px, at which auto-scroll kicks in. */
|
|
12104
|
+
edgeThreshold = 80;
|
|
12105
|
+
/** Fastest scroll step per move event, in px. */
|
|
12106
|
+
maxScrollSpeed = 25;
|
|
12107
|
+
onStart(event) {
|
|
12108
|
+
// Both the placeholder and the preview already exist by the time this
|
|
12109
|
+
// fires — the CDK creates and inserts them, in that order, before it
|
|
12110
|
+
// emits `started`. No need to defer the read; doing it synchronously
|
|
12111
|
+
// also means the preview is sized correctly on its very first frame
|
|
12112
|
+
// instead of visibly snapping to the right widths a tick later.
|
|
12113
|
+
const placeholder = document.querySelector('.cdk-drag-placeholder');
|
|
12114
|
+
const preview = document.querySelector('.cdk-drag-preview');
|
|
12115
|
+
if (!placeholder || !preview)
|
|
12116
|
+
return;
|
|
12117
|
+
const placeholderCells = placeholder.querySelectorAll('td');
|
|
12118
|
+
const previewCells = preview.querySelectorAll('td');
|
|
12119
|
+
placeholderCells.forEach((cell, index) => {
|
|
12120
|
+
const width = `${cell.getBoundingClientRect().width}px`;
|
|
12121
|
+
const previewCell = previewCells[index];
|
|
12122
|
+
if (previewCell) {
|
|
12123
|
+
previewCell.style.width = width;
|
|
12124
|
+
previewCell.style.minWidth = width;
|
|
12125
|
+
previewCell.style.maxWidth = width;
|
|
12126
|
+
}
|
|
12127
|
+
});
|
|
12128
|
+
}
|
|
12129
|
+
onMove(event) {
|
|
12130
|
+
const container = this.scrollContainer();
|
|
12131
|
+
if (!container)
|
|
12132
|
+
return;
|
|
12133
|
+
const rect = container.getBoundingClientRect();
|
|
12134
|
+
const pointerY = event.pointerPosition.y - rect.top;
|
|
12135
|
+
if (pointerY < this.edgeThreshold) {
|
|
12136
|
+
const intensity = 1 - pointerY / this.edgeThreshold;
|
|
12137
|
+
container.scrollTop -= Math.min(this.maxScrollSpeed, intensity * this.maxScrollSpeed);
|
|
12138
|
+
}
|
|
12139
|
+
else if (pointerY > rect.height - this.edgeThreshold) {
|
|
12140
|
+
const intensity = 1 - (rect.height - pointerY) / this.edgeThreshold;
|
|
12141
|
+
container.scrollTop += Math.min(this.maxScrollSpeed, intensity * this.maxScrollSpeed);
|
|
12142
|
+
}
|
|
12143
|
+
}
|
|
12144
|
+
/**
|
|
12145
|
+
* The nearest descendant that actually scrolls. `bk-table` puts the overflow
|
|
12146
|
+
* on an inner container, so the host itself usually isn't the scroller.
|
|
12147
|
+
* Protected so `BkTreeDrag` can position its drop indicator inside it.
|
|
12148
|
+
*/
|
|
12149
|
+
scrollContainer() {
|
|
12150
|
+
const host = this.el.nativeElement;
|
|
12151
|
+
const inner = host.querySelector('.bk-table-container');
|
|
12152
|
+
return inner ?? host;
|
|
12153
|
+
}
|
|
12154
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableDrag, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
12155
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkTableDrag, isStandalone: true, selector: "[bkTableDrag]", exportAs: ["bkTableDrag"], ngImport: i0 });
|
|
12156
|
+
}
|
|
12157
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTableDrag, decorators: [{
|
|
12158
|
+
type: Directive,
|
|
12159
|
+
args: [{
|
|
12160
|
+
selector: '[bkTableDrag]',
|
|
12161
|
+
standalone: true,
|
|
12162
|
+
exportAs: 'bkTableDrag'
|
|
12163
|
+
}]
|
|
12164
|
+
}] });
|
|
12165
|
+
|
|
12166
|
+
/**
|
|
12167
|
+
* The grip a row is dragged by — a reusable handle instead of a glyph copied
|
|
12168
|
+
* into every drag-sort table.
|
|
12169
|
+
*
|
|
12170
|
+
* `hostDirectives: [CdkDragHandle]` puts `cdkDragHandle` on the component's
|
|
12171
|
+
* own host element, so it registers as the drag origin the moment it appears
|
|
12172
|
+
* anywhere inside a `cdkDrag` row — no need to add the CDK directive by hand,
|
|
12173
|
+
* and no requirement about *where* in the row it sits:
|
|
12174
|
+
*
|
|
12175
|
+
* <!-- its own column -->
|
|
12176
|
+
* <td bk-td><bk-drag-handle></bk-drag-handle></td>
|
|
12177
|
+
* <td bk-td>{{ row.name }}</td>
|
|
12178
|
+
*
|
|
12179
|
+
* <!-- inline with the first column, no dedicated column at all -->
|
|
12180
|
+
* <td bk-td><bk-drag-handle></bk-drag-handle> {{ row.name }}</td>
|
|
12181
|
+
*
|
|
12182
|
+
* The icon is a default grip — swap it per table by passing a template:
|
|
12183
|
+
*
|
|
12184
|
+
* <ng-template #bars><svg>…</svg></ng-template>
|
|
12185
|
+
* <bk-drag-handle [icon]="bars"></bk-drag-handle>
|
|
12186
|
+
*
|
|
12187
|
+
* Same shape as `expandIcon` on `td[bk-td]`: a `TemplateRef` input the
|
|
12188
|
+
* component falls back from when it's `null`, rather than a projected slot —
|
|
12189
|
+
* `<ng-content>` has no way to render a default only when nothing was
|
|
12190
|
+
* projected into it.
|
|
12191
|
+
*/
|
|
12192
|
+
class BkDragHandle {
|
|
12193
|
+
icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
12194
|
+
ariaLabel = input('Reorder row', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
12195
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDragHandle, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12196
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: BkDragHandle, isStandalone: true, selector: "bk-drag-handle", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "button" }, properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "bk-drag-handle" }, exportAs: ["bkDragHandle"], hostDirectives: [{ directive: i2$1.CdkDragHandle }], ngImport: i0, template: `
|
|
12197
|
+
<ng-container [ngTemplateOutlet]="icon() ?? defaultIcon"></ng-container>
|
|
12198
|
+
<ng-template #defaultIcon>
|
|
12199
|
+
<svg width="10" height="16" viewBox="0 0 10 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
12200
|
+
<circle cx="3" cy="2" r="1.3" />
|
|
12201
|
+
<circle cx="3" cy="8" r="1.3" />
|
|
12202
|
+
<circle cx="3" cy="14" r="1.3" />
|
|
12203
|
+
<circle cx="7" cy="2" r="1.3" />
|
|
12204
|
+
<circle cx="7" cy="8" r="1.3" />
|
|
12205
|
+
<circle cx="7" cy="14" r="1.3" />
|
|
12206
|
+
</svg>
|
|
12207
|
+
</ng-template>
|
|
12208
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
12209
|
+
}
|
|
12210
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDragHandle, decorators: [{
|
|
12211
|
+
type: Component,
|
|
12212
|
+
args: [{
|
|
12213
|
+
selector: 'bk-drag-handle',
|
|
12214
|
+
standalone: true,
|
|
12215
|
+
exportAs: 'bkDragHandle',
|
|
12216
|
+
imports: [NgTemplateOutlet],
|
|
12217
|
+
hostDirectives: [CdkDragHandle],
|
|
12218
|
+
host: {
|
|
12219
|
+
class: 'bk-drag-handle',
|
|
12220
|
+
role: 'button',
|
|
12221
|
+
'[attr.aria-label]': 'ariaLabel()'
|
|
12222
|
+
},
|
|
12223
|
+
template: `
|
|
12224
|
+
<ng-container [ngTemplateOutlet]="icon() ?? defaultIcon"></ng-container>
|
|
12225
|
+
<ng-template #defaultIcon>
|
|
12226
|
+
<svg width="10" height="16" viewBox="0 0 10 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
12227
|
+
<circle cx="3" cy="2" r="1.3" />
|
|
12228
|
+
<circle cx="3" cy="8" r="1.3" />
|
|
12229
|
+
<circle cx="3" cy="14" r="1.3" />
|
|
12230
|
+
<circle cx="7" cy="2" r="1.3" />
|
|
12231
|
+
<circle cx="7" cy="8" r="1.3" />
|
|
12232
|
+
<circle cx="7" cy="14" r="1.3" />
|
|
12233
|
+
</svg>
|
|
12234
|
+
</ng-template>
|
|
12235
|
+
`
|
|
12236
|
+
}]
|
|
12237
|
+
}], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
12238
|
+
|
|
12239
|
+
/**
|
|
12240
|
+
* Tree-aware row dragging: before / after / inside.
|
|
12241
|
+
*
|
|
12242
|
+
* A table flattens the tree into one list of `<tr>` — every row is a sibling
|
|
12243
|
+
* in the same `<tbody>` whatever its depth, so nested `cdkDropList`s have
|
|
12244
|
+
* nothing to nest on. Instead the CDK is kept for what it is good at (the
|
|
12245
|
+
* preview, the placeholder, returning the row on release) with its sorting
|
|
12246
|
+
* turned off, and this directive does the targeting: the pointer's position
|
|
12247
|
+
* within the row under it picks the relationship —
|
|
12248
|
+
*
|
|
12249
|
+
* top third insert BEFORE the target, as a sibling
|
|
12250
|
+
* middle third drop INSIDE the target, as its child
|
|
12251
|
+
* bottom third insert AFTER the target, as a sibling
|
|
12252
|
+
*
|
|
12253
|
+
* — drawn live as a line above, a line below, or a tinted row, so the drop
|
|
12254
|
+
* never lands somewhere the indicator didn't say it would. Illegal targets
|
|
12255
|
+
* (the dragged row itself, anything in its own subtree, anything the `canDrop`
|
|
12256
|
+
* predicate vetoes) simply show no indicator.
|
|
12257
|
+
*
|
|
12258
|
+
* Set `scope="siblings"` to restrict dragging to reordering among the node's
|
|
12259
|
+
* current siblings — no re-parenting, no nesting, and no `inside` zone at all
|
|
12260
|
+
* (see `BkTreeDragScope`). That is the right default whenever the tree's
|
|
12261
|
+
* levels mean something specific; `canDrop` covers anything more particular
|
|
12262
|
+
* than the two built-in scopes.
|
|
12263
|
+
*
|
|
12264
|
+
* The directive never touches the tree. It resolves the drag into one event —
|
|
12265
|
+
* `{ dragged, target, position }` — and the consumer applies it, usually with
|
|
12266
|
+
* `moveBkTreeNode`. Hovering the middle of a row for `expandDelay` emits
|
|
12267
|
+
* `treeExpand` so collapsed branches can be opened mid-drag; acting on it is
|
|
12268
|
+
* likewise the consumer's call.
|
|
12269
|
+
*
|
|
12270
|
+
* <div bkTreeDrag #td="bkTreeDrag" [treeRows]="t.renderData()"
|
|
12271
|
+
* (treeDrop)="onDrop($event)" (treeExpand)="open($event)">
|
|
12272
|
+
* <bk-table #t [data]="rows()">
|
|
12273
|
+
* <tbody cdkDropList [cdkDropListSortingDisabled]="true">
|
|
12274
|
+
* @for (row of t.renderData(); track row.data.id) {
|
|
12275
|
+
* <tr cdkDrag cdkDragLockAxis="y"
|
|
12276
|
+
* (cdkDragStarted)="td.onDragStart($event, row)"
|
|
12277
|
+
* (cdkDragMoved)="td.onDragMove($event)"
|
|
12278
|
+
* (cdkDragEnded)="td.onDragEnd()">
|
|
12279
|
+
*
|
|
12280
|
+
* Sorting stays disabled on the drop list deliberately: with rows shuffling
|
|
12281
|
+
* under the pointer, an open branch's children sit still while their parent
|
|
12282
|
+
* moves. With a static list and an indicator, nothing lies.
|
|
12283
|
+
*
|
|
12284
|
+
* Extends `BkTableDrag`, so the preview keeps its column widths and dragging
|
|
12285
|
+
* near an edge still scrolls the table.
|
|
12286
|
+
*/
|
|
12287
|
+
class BkTreeDrag extends BkTableDrag {
|
|
12288
|
+
/**
|
|
12289
|
+
* The flattened rows currently rendered, in render order — the same array
|
|
12290
|
+
* the `<tbody>` iterates. Row *i* of the tbody is entry *i* here; that
|
|
12291
|
+
* index mapping is the whole basis of the hit-testing.
|
|
12292
|
+
*/
|
|
12293
|
+
treeRows = input([], ...(ngDevMode ? [{ debugName: "treeRows" }] : []));
|
|
12294
|
+
/** See `BkTreeDragScope`. Defaults to full re-parenting. */
|
|
12295
|
+
scope = input('anywhere', ...(ngDevMode ? [{ debugName: "scope" }] : []));
|
|
12296
|
+
/**
|
|
12297
|
+
* Consumer veto over and above the built-in guards — e.g. "a person cannot
|
|
12298
|
+
* contain a team". Return false and the indicator never appears.
|
|
12299
|
+
*/
|
|
12300
|
+
canDrop = input(null, ...(ngDevMode ? [{ debugName: "canDrop" }] : []));
|
|
12301
|
+
/** How long the pointer rests on a row's middle before `treeExpand` fires. */
|
|
12302
|
+
expandDelay = input(700, ...(ngDevMode ? [{ debugName: "expandDelay" }] : []));
|
|
12303
|
+
treeDrop = output();
|
|
12304
|
+
treeExpand = output();
|
|
12305
|
+
dragged = null;
|
|
12306
|
+
target = null;
|
|
12307
|
+
position = null;
|
|
12308
|
+
line = null;
|
|
12309
|
+
insideRow = null;
|
|
12310
|
+
expandTimer = null;
|
|
12311
|
+
expandFor = null;
|
|
12312
|
+
onDragStart(event, row) {
|
|
12313
|
+
super.onStart(event); // preview column widths
|
|
12314
|
+
this.dragged = row;
|
|
12315
|
+
}
|
|
12316
|
+
onDragMove(event) {
|
|
12317
|
+
super.onMove(event); // edge auto-scroll
|
|
12318
|
+
if (!this.dragged)
|
|
12319
|
+
return;
|
|
12320
|
+
const container = this.scrollContainer();
|
|
12321
|
+
const tbody = container?.querySelector('tbody');
|
|
12322
|
+
if (!container || !tbody)
|
|
12323
|
+
return;
|
|
12324
|
+
const { y } = event.pointerPosition;
|
|
12325
|
+
const rows = Array.from(tbody.rows);
|
|
12326
|
+
// The dragged row stays in the DOM as the CDK's placeholder, so DOM order
|
|
12327
|
+
// still matches treeRows() one to one — including any rows a mid-drag
|
|
12328
|
+
// auto-expand has just added.
|
|
12329
|
+
const index = rows.findIndex((tr) => {
|
|
12330
|
+
const r = tr.getBoundingClientRect();
|
|
12331
|
+
return y >= r.top && y < r.bottom;
|
|
12332
|
+
});
|
|
12333
|
+
const target = index >= 0 ? this.treeRows()[index] ?? null : null;
|
|
12334
|
+
if (!target || !this.isLegal(target)) {
|
|
12335
|
+
this.setTarget(null, null, null, container);
|
|
12336
|
+
return;
|
|
12337
|
+
}
|
|
12338
|
+
const rect = rows[index].getBoundingClientRect();
|
|
12339
|
+
const fraction = (y - rect.top) / rect.height;
|
|
12340
|
+
// In 'siblings' scope there is no legal way to land inside a row — that
|
|
12341
|
+
// would make the dragged node a child of something it wasn't a child of
|
|
12342
|
+
// before, which is exactly what this scope rules out. The row splits in
|
|
12343
|
+
// half instead of thirds, so the whole target is reachable as before/after.
|
|
12344
|
+
const position = this.scope() === 'siblings'
|
|
12345
|
+
? fraction < 1 / 2
|
|
12346
|
+
? 'before'
|
|
12347
|
+
: 'after'
|
|
12348
|
+
: fraction < 1 / 3
|
|
12349
|
+
? 'before'
|
|
12350
|
+
: fraction > 2 / 3
|
|
12351
|
+
? 'after'
|
|
12352
|
+
: 'inside';
|
|
12353
|
+
if (position !== 'inside' || this.canDropAt(target, 'inside')) {
|
|
12354
|
+
this.setTarget(target, position, rows[index], container);
|
|
12355
|
+
}
|
|
12356
|
+
else {
|
|
12357
|
+
this.setTarget(null, null, null, container);
|
|
12358
|
+
}
|
|
12359
|
+
}
|
|
12360
|
+
onDragEnd() {
|
|
12361
|
+
if (this.dragged && this.target && this.position) {
|
|
12362
|
+
this.treeDrop.emit({ dragged: this.dragged, target: this.target, position: this.position });
|
|
12363
|
+
}
|
|
12364
|
+
this.clearIndicator();
|
|
12365
|
+
this.clearExpandTimer();
|
|
12366
|
+
this.dragged = null;
|
|
12367
|
+
this.target = null;
|
|
12368
|
+
this.position = null;
|
|
12369
|
+
}
|
|
12370
|
+
ngOnDestroy() {
|
|
12371
|
+
this.clearIndicator();
|
|
12372
|
+
this.clearExpandTimer();
|
|
12373
|
+
}
|
|
12374
|
+
/* ================= Guards ================= */
|
|
12375
|
+
/**
|
|
12376
|
+
* Structural legality, before the zone is even known. Dropping a node
|
|
12377
|
+
* anywhere inside its own subtree would detach that branch from the tree
|
|
12378
|
+
* with nothing left pointing at it — walking the parent chain is cheaper
|
|
12379
|
+
* than searching the subtree, and `flattenBkTreeData` already carries it.
|
|
12380
|
+
*
|
|
12381
|
+
* In `'siblings'` scope, the only legal targets are the dragged node's
|
|
12382
|
+
* current siblings — same `parent` reference, root-level nodes included
|
|
12383
|
+
* (`undefined === undefined`). That alone also rules out every cycle: a
|
|
12384
|
+
* node's siblings can never be its own ancestor.
|
|
12385
|
+
*/
|
|
12386
|
+
isLegal(target) {
|
|
12387
|
+
if (!this.dragged || target.data === this.dragged.data)
|
|
12388
|
+
return false;
|
|
12389
|
+
if (this.scope() === 'siblings') {
|
|
12390
|
+
return target.parent === this.dragged.parent;
|
|
12391
|
+
}
|
|
12392
|
+
for (let p = target.parent; p;) {
|
|
12393
|
+
if (p === this.dragged.data)
|
|
12394
|
+
return false;
|
|
12395
|
+
p = this.treeRows().find((r) => r.data === p)?.parent;
|
|
12396
|
+
}
|
|
12397
|
+
return true;
|
|
12398
|
+
}
|
|
12399
|
+
canDropAt(target, position) {
|
|
12400
|
+
const veto = this.canDrop();
|
|
12401
|
+
return !veto || veto(this.dragged, target, position);
|
|
12402
|
+
}
|
|
12403
|
+
/* ================= Indicator ================= */
|
|
12404
|
+
setTarget(target, position, rowEl, container) {
|
|
12405
|
+
const changed = target !== this.target || position !== this.position;
|
|
12406
|
+
this.target = target && position && this.canDropAt(target, position) ? target : null;
|
|
12407
|
+
this.position = this.target ? position : null;
|
|
12408
|
+
if (!changed)
|
|
12409
|
+
return;
|
|
12410
|
+
this.clearIndicator();
|
|
12411
|
+
if (!this.target || !rowEl) {
|
|
12412
|
+
this.clearExpandTimer();
|
|
12413
|
+
return;
|
|
12414
|
+
}
|
|
12415
|
+
if (this.position === 'inside') {
|
|
12416
|
+
rowEl.classList.add('bk-tree-drop-inside');
|
|
12417
|
+
this.insideRow = rowEl;
|
|
12418
|
+
this.armExpandTimer(this.target);
|
|
12419
|
+
}
|
|
12420
|
+
else {
|
|
12421
|
+
this.drawLine(rowEl, container, this.position === 'after');
|
|
12422
|
+
this.clearExpandTimer();
|
|
12423
|
+
}
|
|
12424
|
+
}
|
|
12425
|
+
drawLine(rowEl, container, below) {
|
|
12426
|
+
if (!this.line) {
|
|
12427
|
+
this.line = document.createElement('div');
|
|
12428
|
+
this.line.className = 'bk-tree-drop-line';
|
|
12429
|
+
container.appendChild(this.line);
|
|
12430
|
+
}
|
|
12431
|
+
const rowRect = rowEl.getBoundingClientRect();
|
|
12432
|
+
const containerRect = container.getBoundingClientRect();
|
|
12433
|
+
const edge = below ? rowRect.bottom : rowRect.top;
|
|
12434
|
+
this.line.style.top = `${edge - containerRect.top + container.scrollTop - 1}px`;
|
|
12435
|
+
this.line.style.left = `${rowRect.left - containerRect.left + container.scrollLeft}px`;
|
|
12436
|
+
this.line.style.width = `${rowRect.width}px`;
|
|
12437
|
+
}
|
|
12438
|
+
clearIndicator() {
|
|
12439
|
+
this.line?.remove();
|
|
12440
|
+
this.line = null;
|
|
12441
|
+
this.insideRow?.classList.remove('bk-tree-drop-inside');
|
|
12442
|
+
this.insideRow = null;
|
|
12443
|
+
}
|
|
12444
|
+
/* ================= Auto-expand ================= */
|
|
12445
|
+
/**
|
|
12446
|
+
* One timer per hovered node: moving within the same row keeps it running,
|
|
12447
|
+
* moving to another row restarts it. The directive only reports the dwell —
|
|
12448
|
+
* whether the node has children to show is the consumer's knowledge.
|
|
12449
|
+
*/
|
|
12450
|
+
armExpandTimer(target) {
|
|
12451
|
+
if (this.expandFor === target.data)
|
|
12452
|
+
return;
|
|
12453
|
+
this.clearExpandTimer();
|
|
12454
|
+
this.expandFor = target.data;
|
|
12455
|
+
this.expandTimer = setTimeout(() => this.treeExpand.emit(target), this.expandDelay());
|
|
12456
|
+
}
|
|
12457
|
+
clearExpandTimer() {
|
|
12458
|
+
if (this.expandTimer)
|
|
12459
|
+
clearTimeout(this.expandTimer);
|
|
12460
|
+
this.expandTimer = null;
|
|
12461
|
+
this.expandFor = null;
|
|
12462
|
+
}
|
|
12463
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTreeDrag, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
12464
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: BkTreeDrag, isStandalone: true, selector: "[bkTreeDrag]", inputs: { treeRows: { classPropertyName: "treeRows", publicName: "treeRows", isSignal: true, isRequired: false, transformFunction: null }, scope: { classPropertyName: "scope", publicName: "scope", isSignal: true, isRequired: false, transformFunction: null }, canDrop: { classPropertyName: "canDrop", publicName: "canDrop", isSignal: true, isRequired: false, transformFunction: null }, expandDelay: { classPropertyName: "expandDelay", publicName: "expandDelay", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { treeDrop: "treeDrop", treeExpand: "treeExpand" }, exportAs: ["bkTreeDrag"], usesInheritance: true, ngImport: i0 });
|
|
12465
|
+
}
|
|
12466
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTreeDrag, decorators: [{
|
|
12467
|
+
type: Directive,
|
|
12468
|
+
args: [{
|
|
12469
|
+
selector: '[bkTreeDrag]',
|
|
12470
|
+
standalone: true,
|
|
12471
|
+
exportAs: 'bkTreeDrag'
|
|
12472
|
+
}]
|
|
12473
|
+
}], propDecorators: { treeRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeRows", required: false }] }], scope: [{ type: i0.Input, args: [{ isSignal: true, alias: "scope", required: false }] }], canDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDrop", required: false }] }], expandDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandDelay", required: false }] }], treeDrop: [{ type: i0.Output, args: ["treeDrop"] }], treeExpand: [{ type: i0.Output, args: ["treeExpand"] }] } });
|
|
12474
|
+
|
|
12475
|
+
/**
|
|
12476
|
+
* bk-table public surface.
|
|
12477
|
+
*
|
|
12478
|
+
* `BK_TABLE` is the convenience bundle — spread it into a standalone
|
|
12479
|
+
* component's `imports` rather than listing eight symbols by hand:
|
|
12480
|
+
*
|
|
12481
|
+
* imports: [...BK_TABLE]
|
|
12482
|
+
*/
|
|
12483
|
+
const BK_TABLE = [
|
|
12484
|
+
BkTable,
|
|
12485
|
+
BkTableTitle,
|
|
12486
|
+
BkTableFooter,
|
|
12487
|
+
BkVirtualScroll,
|
|
12488
|
+
BkTh,
|
|
12489
|
+
BkTd,
|
|
12490
|
+
BkTrExpand,
|
|
12491
|
+
BkTableSummary,
|
|
12492
|
+
BkTableDrag,
|
|
12493
|
+
BkDragHandle,
|
|
12494
|
+
BkTreeDrag
|
|
12495
|
+
];
|
|
12496
|
+
|
|
10723
12497
|
/*
|
|
10724
12498
|
* Public API Surface of brickclay-lib
|
|
10725
12499
|
*/
|
|
@@ -10729,5 +12503,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10729
12503
|
* Generated bundle index. Do not edit.
|
|
10730
12504
|
*/
|
|
10731
12505
|
|
|
10732
|
-
export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, NEUTRAL_APPEARANCE, POPOVER_PLACEMENTS, computePopoverPosition, deriveAppearance, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, parseColor, splitPlacement };
|
|
12506
|
+
export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, NEUTRAL_APPEARANCE, POPOVER_PLACEMENTS, computePopoverPosition, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
|
|
10733
12507
|
//# sourceMappingURL=brickclay-org-ui.mjs.map
|