@brickclay-org/ui 0.1.91 → 0.1.92
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 +396 -6
- package/fesm2022/brickclay-org-ui.mjs.map +1 -1
- package/index.d.ts +405 -8
- package/package.json +1 -1
- package/src/styles.css +1 -0
|
@@ -8,9 +8,9 @@ import * as i2 from '@angular/cdk/overlay';
|
|
|
8
8
|
import { OverlayModule, Overlay } from '@angular/cdk/overlay';
|
|
9
9
|
import { Subject, filter } from 'rxjs';
|
|
10
10
|
import moment from 'moment';
|
|
11
|
-
import * as
|
|
11
|
+
import * as i1$1 from '@angular/cdk/drag-drop';
|
|
12
12
|
import { moveItemInArray, DragDropModule, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
13
|
-
import * as i1$
|
|
13
|
+
import * as i1$2 from '@angular/cdk/scrolling';
|
|
14
14
|
import { ScrollingModule, CdkScrollable, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
|
15
15
|
import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
|
|
16
16
|
import { DIALOG_DATA, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
|
|
@@ -5955,7 +5955,7 @@ class BkGrid {
|
|
|
5955
5955
|
return this.noRecordImgUrl || './assets/icons/no-data-found.jpg';
|
|
5956
5956
|
}
|
|
5957
5957
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5958
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkGrid, isStandalone: true, selector: "bk-grid", inputs: { draggable: "draggable", columns: "columns", result: "result", actions: "actions", customClass: "customClass", actionIconClass: "actionIconClass", actionClass: "actionClass", showNoRecords: "showNoRecords", noRecordFoundHeight: "noRecordFoundHeight", noRecordImgUrl: "noRecordImgUrl", showNoRecordImg: "showNoRecordImg", noRecordMessage: "noRecordMessage", rows: "rows" }, outputs: { change: "change", actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header; let i = $index) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\r\n >\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20 {{actionClass}}\">Action</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\"\r\n >\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\"\r\n [ngClass]=\"{ 'cursor-move ': draggable }\"\r\n >\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n @if (showNoRecordImg) {\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n }\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i3.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: i3.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: i3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
5958
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkGrid, isStandalone: true, selector: "bk-grid", inputs: { draggable: "draggable", columns: "columns", result: "result", actions: "actions", customClass: "customClass", actionIconClass: "actionIconClass", actionClass: "actionClass", showNoRecords: "showNoRecords", noRecordFoundHeight: "noRecordFoundHeight", noRecordImgUrl: "noRecordImgUrl", showNoRecordImg: "showNoRecordImg", noRecordMessage: "noRecordMessage", rows: "rows" }, outputs: { change: "change", actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header; let i = $index) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\r\n >\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20 {{actionClass}}\">Action</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\"\r\n >\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\"\r\n [ngClass]=\"{ 'cursor-move ': draggable }\"\r\n >\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n @if (showNoRecordImg) {\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n }\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i1$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: i1$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: i1$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
5959
5959
|
}
|
|
5960
5960
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, decorators: [{
|
|
5961
5961
|
type: Component,
|
|
@@ -9193,7 +9193,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9193
9193
|
*/
|
|
9194
9194
|
class BkDialogContent {
|
|
9195
9195
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9196
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive: i1$
|
|
9196
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive: i1$2.CdkScrollable }], ngImport: i0 });
|
|
9197
9197
|
}
|
|
9198
9198
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, decorators: [{
|
|
9199
9199
|
type: Directive,
|
|
@@ -13776,7 +13776,7 @@ class BkDragHandle {
|
|
|
13776
13776
|
icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
13777
13777
|
ariaLabel = input('Reorder row', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
13778
13778
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDragHandle, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13779
|
-
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:
|
|
13779
|
+
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: i1$1.CdkDragHandle }], ngImport: i0, template: `
|
|
13780
13780
|
<ng-container [ngTemplateOutlet]="icon() ?? defaultIcon"></ng-container>
|
|
13781
13781
|
<ng-template #defaultIcon>
|
|
13782
13782
|
<svg width="10" height="16" viewBox="0 0 10 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -14077,6 +14077,396 @@ const BK_TABLE = [
|
|
|
14077
14077
|
BkTreeDrag
|
|
14078
14078
|
];
|
|
14079
14079
|
|
|
14080
|
+
/**
|
|
14081
|
+
* Content-agnostic kanban board: column layout, card positioning and
|
|
14082
|
+
* drag-and-drop, and nothing about what a card contains or what a click on
|
|
14083
|
+
* one should do.
|
|
14084
|
+
*
|
|
14085
|
+
* The board never renders a card's insides itself — `cardTemplate` does that,
|
|
14086
|
+
* receiving the card and its column as context:
|
|
14087
|
+
*
|
|
14088
|
+
* <bk-kanban
|
|
14089
|
+
* [columns]="columns"
|
|
14090
|
+
* [cards]="cards()"
|
|
14091
|
+
* [cardTemplate]="card"
|
|
14092
|
+
* (cardMoved)="onCardMoved($event)"
|
|
14093
|
+
* (cardClicked)="onCardClicked($event)"
|
|
14094
|
+
* ></bk-kanban>
|
|
14095
|
+
*
|
|
14096
|
+
* <ng-template #card let-card let-column="column">
|
|
14097
|
+
* <div [bkKanbanClickTarget]="'hours'">{{ card.hours }}h</div>
|
|
14098
|
+
* {{ card.title }}
|
|
14099
|
+
* </ng-template>
|
|
14100
|
+
*
|
|
14101
|
+
* That is deliberate, not an oversight — see the package spec's Design
|
|
14102
|
+
* Principles. Three consequences fall out of it directly:
|
|
14103
|
+
*
|
|
14104
|
+
* - **Data ownership stays with the caller.** A move is reported through
|
|
14105
|
+
* `cardMoved`, not applied to some copy of `cards` this component keeps to
|
|
14106
|
+
* itself. Internally it *does* mutate the card objects it was handed
|
|
14107
|
+
* (`columnIdField`'s field, and an `order` field used to remember position
|
|
14108
|
+
* within a column) so the board redraws in the right place immediately,
|
|
14109
|
+
* exactly the way `bk-grid`'s own row-drag mutates `result` in place and
|
|
14110
|
+
* renumbers `sortOrder` — but persistence, and reverting the view if a
|
|
14111
|
+
* save fails, are the host's job. Reverting is just handing back a
|
|
14112
|
+
* `cards` array (or updated objects) that reflect the pre-move state; nothing
|
|
14113
|
+
* further to undo on this end.
|
|
14114
|
+
* - **Clicks are reported, never acted on.** `cardClicked` says which card and
|
|
14115
|
+
* which named region (see `[bkKanbanClickTarget]`); opening a popup or
|
|
14116
|
+
* doing nothing at all is entirely up to whoever is listening.
|
|
14117
|
+
* - **A card's own shape is never inspected**, beyond the two fields above.
|
|
14118
|
+
* Tags, hours, avatars, due dates — the board doesn't know they exist.
|
|
14119
|
+
*/
|
|
14120
|
+
class BkKanban {
|
|
14121
|
+
/* ================= Inputs ================= */
|
|
14122
|
+
/** Column/status definitions. Unlimited — the board renders whatever it's given. */
|
|
14123
|
+
columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
14124
|
+
/** Flat card list. Grouped into columns via `columnIdField`, ordered within
|
|
14125
|
+
* a column by an `order` field when the cards carry one, otherwise left in
|
|
14126
|
+
* the sequence they appear here. */
|
|
14127
|
+
cards = input.required(...(ngDevMode ? [{ debugName: "cards" }] : []));
|
|
14128
|
+
/** Renders a card's body. Receives `{ $implicit: card, card, column, index }`. */
|
|
14129
|
+
cardTemplate = input.required(...(ngDevMode ? [{ debugName: "cardTemplate" }] : []));
|
|
14130
|
+
/** Field name, or a resolver function, that gives a card's column id.
|
|
14131
|
+
*
|
|
14132
|
+
* A field name can be both read and written, so a cross-column drop
|
|
14133
|
+
* updates it directly. A resolver function is read-only — the board still
|
|
14134
|
+
* reports the move via `cardMoved`, but leaves updating the source data to
|
|
14135
|
+
* the host, since there's nowhere on a function to write the new value. */
|
|
14136
|
+
columnIdField = input('columnId', ...(ngDevMode ? [{ debugName: "columnIdField" }] : []));
|
|
14137
|
+
dragEnabled = input(true, ...(ngDevMode ? [{ debugName: "dragEnabled" }] : []));
|
|
14138
|
+
dragScope = input('both', ...(ngDevMode ? [{ debugName: "dragScope" }] : []));
|
|
14139
|
+
wipLimitBehavior = input('warn', ...(ngDevMode ? [{ debugName: "wipLimitBehavior" }] : []));
|
|
14140
|
+
/** Lets columns themselves be dragged into a new order, via their header
|
|
14141
|
+
* (`.bk-kanban-column-header` is the drag handle — a card's own drag
|
|
14142
|
+
* keeps working independently, since it's a separate, unconnected drop
|
|
14143
|
+
* list one level down). Off by default: reordering the board's own
|
|
14144
|
+
* columns is a bigger commitment than reordering cards within it, and not
|
|
14145
|
+
* every consumer wants a "To do / In progress / Done" pipeline to be
|
|
14146
|
+
* rearrangeable. `columns` is mutated in place the same way `cards` is
|
|
14147
|
+
* (see the component doc) — persisting the new order, if it needs to be,
|
|
14148
|
+
* is the host's job, done from `columnMoved`. */
|
|
14149
|
+
columnDragEnabled = input(false, ...(ngDevMode ? [{ debugName: "columnDragEnabled" }] : []));
|
|
14150
|
+
/** See `BkKanbanColumnScrollMode`. */
|
|
14151
|
+
columnScrollMode = input('body', ...(ngDevMode ? [{ debugName: "columnScrollMode" }] : []));
|
|
14152
|
+
/** Extra class(es) appended to the board's own wrapper — `.bk-kanban-board`
|
|
14153
|
+
* in `kanban.html`, the element that directly contains the scrollable
|
|
14154
|
+
* region holding every column. Same idea as `columnClass`/`colHeaderClass`
|
|
14155
|
+
* one level down: it only adds classes, nothing here replaces bk-kanban's
|
|
14156
|
+
* own layout.
|
|
14157
|
+
*
|
|
14158
|
+
* Deliberately kept off the *scrolling* element itself
|
|
14159
|
+
* (`.bk-kanban`, one level further in): a `padding` or `border` in here
|
|
14160
|
+
* would otherwise become part of what has to be scrolled past, and change
|
|
14161
|
+
* where the scrollbar itself ends up sitting relative to the columns —
|
|
14162
|
+
* this wrapper exists specifically so `boardClass` can decorate (a
|
|
14163
|
+
* background, a border, padding around the whole board) without ever
|
|
14164
|
+
* touching the box CDK and `columnScrollMode` are actually scrolling. */
|
|
14165
|
+
boardClass = input('', ...(ngDevMode ? [{ debugName: "boardClass" }] : []));
|
|
14166
|
+
/** Identity for `@for`'s `track`. Defaults to position in the rendered column. */
|
|
14167
|
+
trackBy = input(null, ...(ngDevMode ? [{ debugName: "trackBy" }] : []));
|
|
14168
|
+
/** Rendered in a fixed slot in every column's header — e.g. an "add card"
|
|
14169
|
+
* button. Receives `BkKanbanColumnActionsContext`. The board owns where it
|
|
14170
|
+
* sits; the consumer owns what it does. */
|
|
14171
|
+
columnHeaderActionsTemplate = input(null, ...(ngDevMode ? [{ debugName: "columnHeaderActionsTemplate" }] : []));
|
|
14172
|
+
/** Overrides the built-in "No cards" placeholder for an empty column.
|
|
14173
|
+
* Receives `BkKanbanEmptyStateContext`. Takes priority over both
|
|
14174
|
+
* `noDataText` and a column's own `noDataText` — see `emptyStateText`. */
|
|
14175
|
+
emptyStateTemplate = input(null, ...(ngDevMode ? [{ debugName: "emptyStateTemplate" }] : []));
|
|
14176
|
+
/** Board-wide placeholder text for an empty column, used whenever a column
|
|
14177
|
+
* doesn't set its own `noDataText`. Only read when `emptyStateTemplate`
|
|
14178
|
+
* isn't supplied — see `emptyStateText`. */
|
|
14179
|
+
noDataText = input('No cards', ...(ngDevMode ? [{ debugName: "noDataText" }] : []));
|
|
14180
|
+
/** Whether a column flags an over-limit drop while still dragging (`'live'`)
|
|
14181
|
+
* or only once the drop is attempted (`'on-drop'`). See the doc block on
|
|
14182
|
+
* `isLiveOverLimit` for how the two relate to `wipLimitBehavior`. */
|
|
14183
|
+
dragPreviewMode = input('live', ...(ngDevMode ? [{ debugName: "dragPreviewMode" }] : []));
|
|
14184
|
+
/* ================= Outputs ================= */
|
|
14185
|
+
cardMoved = output();
|
|
14186
|
+
cardClicked = output();
|
|
14187
|
+
columnLimitExceeded = output();
|
|
14188
|
+
/** A column reorder completed — see `columnDragEnabled`. */
|
|
14189
|
+
columnMoved = output();
|
|
14190
|
+
/** Reserved — see `BkKanbanColumnActionsContext.trigger`. Most consumers
|
|
14191
|
+
* bind a click handler directly on their own header-actions template and
|
|
14192
|
+
* never reach for this. */
|
|
14193
|
+
columnActionTriggered = output();
|
|
14194
|
+
/* ================= Grouping ================= */
|
|
14195
|
+
/**
|
|
14196
|
+
* Bumped after every in-place mutation (`setColumnId`, `renumber`) so
|
|
14197
|
+
* `grouped` re-runs even though neither `cards()`'s array identity nor any
|
|
14198
|
+
* card's object identity changed — the same trick as the table demo's
|
|
14199
|
+
* `pgSelectionTick`, needed for exactly the same reason: signals only
|
|
14200
|
+
* notice a new reference, and mutating fields in place is what lets a drop
|
|
14201
|
+
* redraw in the right place without waiting on the host to hand back a
|
|
14202
|
+
* whole new array.
|
|
14203
|
+
*/
|
|
14204
|
+
structureTick = signal(0, ...(ngDevMode ? [{ debugName: "structureTick" }] : []));
|
|
14205
|
+
/** Cards grouped by column id, each group in `order` order when present
|
|
14206
|
+
* (falling back to their sequence in `cards()` otherwise). Cards whose
|
|
14207
|
+
* resolved column id matches no known column are dropped silently rather
|
|
14208
|
+
* than rendered nowhere. */
|
|
14209
|
+
grouped = computed(() => {
|
|
14210
|
+
this.structureTick();
|
|
14211
|
+
const map = new Map();
|
|
14212
|
+
for (const column of this.columns())
|
|
14213
|
+
map.set(column.id, []);
|
|
14214
|
+
for (const card of this.cards()) {
|
|
14215
|
+
const list = map.get(this.resolveColumnId(card));
|
|
14216
|
+
list?.push(card);
|
|
14217
|
+
}
|
|
14218
|
+
for (const list of map.values()) {
|
|
14219
|
+
if (list.some((c) => this.cardOrder(c) !== null)) {
|
|
14220
|
+
list.sort((a, b) => (this.cardOrder(a) ?? 0) - (this.cardOrder(b) ?? 0));
|
|
14221
|
+
}
|
|
14222
|
+
}
|
|
14223
|
+
return map;
|
|
14224
|
+
}, ...(ngDevMode ? [{ debugName: "grouped" }] : []));
|
|
14225
|
+
/** The cards to render for one column, in display order. */
|
|
14226
|
+
cardsFor(columnId) {
|
|
14227
|
+
return this.grouped().get(columnId) ?? [];
|
|
14228
|
+
}
|
|
14229
|
+
resolveColumnId(card) {
|
|
14230
|
+
const field = this.columnIdField();
|
|
14231
|
+
return typeof field === 'function' ? field(card) : card[field];
|
|
14232
|
+
}
|
|
14233
|
+
cardOrder(card) {
|
|
14234
|
+
const value = card['order'];
|
|
14235
|
+
return typeof value === 'number' ? value : null;
|
|
14236
|
+
}
|
|
14237
|
+
resolveTrackBy(card, index) {
|
|
14238
|
+
const fn = this.trackBy();
|
|
14239
|
+
return fn ? fn(card) : index;
|
|
14240
|
+
}
|
|
14241
|
+
/* ================= Column-level view state ================= */
|
|
14242
|
+
/** Column-header count badge, flagged once the column is over its limit —
|
|
14243
|
+
* only while `wipLimitBehavior` is `'warn'`; `'block'` should never let a
|
|
14244
|
+
* column get there and `'none'` treats the number as pure information. */
|
|
14245
|
+
isColumnOverLimit(column) {
|
|
14246
|
+
return (this.wipLimitBehavior() === 'warn' &&
|
|
14247
|
+
column.wipLimit != null &&
|
|
14248
|
+
this.cardsFor(column.id).length > column.wipLimit);
|
|
14249
|
+
}
|
|
14250
|
+
/** "3" with no limit, "3 / 5" with one — the header count badge's label. */
|
|
14251
|
+
columnCountLabel(column) {
|
|
14252
|
+
const count = this.cardsFor(column.id).length;
|
|
14253
|
+
return column.wipLimit != null ? `${count} / ${column.wipLimit}` : `${count}`;
|
|
14254
|
+
}
|
|
14255
|
+
columnActionsContext(column) {
|
|
14256
|
+
return {
|
|
14257
|
+
$implicit: column,
|
|
14258
|
+
column,
|
|
14259
|
+
trigger: () => this.columnActionTriggered.emit({ columnId: column.id })
|
|
14260
|
+
};
|
|
14261
|
+
}
|
|
14262
|
+
emptyStateContext(column) {
|
|
14263
|
+
return { $implicit: column, column };
|
|
14264
|
+
}
|
|
14265
|
+
/** Text for the built-in empty-column placeholder: a column's own
|
|
14266
|
+
* `noDataText` when it sets one, else the board-wide `noDataText` input.
|
|
14267
|
+
* Only consulted when `emptyStateTemplate` isn't supplied — the template
|
|
14268
|
+
* wins outright once given, exactly like `emptyStateContext` itself. */
|
|
14269
|
+
emptyStateText(column) {
|
|
14270
|
+
return column.noDataText ?? this.noDataText();
|
|
14271
|
+
}
|
|
14272
|
+
cardContext(card, column, index) {
|
|
14273
|
+
return { $implicit: card, card, column, index };
|
|
14274
|
+
}
|
|
14275
|
+
/** Which columns a column's drop list connects to, per `dragScope`. */
|
|
14276
|
+
connectedListIds(columnId) {
|
|
14277
|
+
if (!this.dragEnabled() || this.dragScope() === 'same')
|
|
14278
|
+
return [];
|
|
14279
|
+
return this.columns()
|
|
14280
|
+
.filter((c) => c.id !== columnId)
|
|
14281
|
+
.map((c) => c.id);
|
|
14282
|
+
}
|
|
14283
|
+
/** `'cross'` means *only* moves between columns — reordering within one has
|
|
14284
|
+
* to be switched off at the list level, since a scoped-out `connectedTo`
|
|
14285
|
+
* alone still leaves the list free to sort itself. */
|
|
14286
|
+
sortingDisabled = computed(() => this.dragScope() === 'cross', ...(ngDevMode ? [{ debugName: "sortingDisabled" }] : []));
|
|
14287
|
+
/* ================= Column-level drag (reordering columns) ================= */
|
|
14288
|
+
/**
|
|
14289
|
+
* `columns` is reordered in place — same trick as `cards` (see the
|
|
14290
|
+
* component doc): the array reference the host handed in is mutated
|
|
14291
|
+
* directly (`moveItemInArray`) rather than swapped for a new one, so the
|
|
14292
|
+
* next render just reflects the new order. There's no `structureTick`-style
|
|
14293
|
+
* signal to bump here the way card moves need one — nothing derives
|
|
14294
|
+
* columns through a `computed()` the way `cardsFor` derives through
|
|
14295
|
+
* `grouped`; the template reads `columns()` directly in its `@for`, so the
|
|
14296
|
+
* drop event's own change detection pass is enough.
|
|
14297
|
+
*/
|
|
14298
|
+
onColumnDrop(event) {
|
|
14299
|
+
if (!this.columnDragEnabled() || event.previousIndex === event.currentIndex)
|
|
14300
|
+
return;
|
|
14301
|
+
const columns = this.columns();
|
|
14302
|
+
const moved = columns[event.previousIndex];
|
|
14303
|
+
moveItemInArray(columns, event.previousIndex, event.currentIndex);
|
|
14304
|
+
this.columnMoved.emit({
|
|
14305
|
+
columnId: moved.id,
|
|
14306
|
+
fromIndex: event.previousIndex,
|
|
14307
|
+
toIndex: event.currentIndex
|
|
14308
|
+
});
|
|
14309
|
+
}
|
|
14310
|
+
/* ================= Drag state (for the live WIP preview) ================= */
|
|
14311
|
+
dragSourceColumnId = signal(null, ...(ngDevMode ? [{ debugName: "dragSourceColumnId" }] : []));
|
|
14312
|
+
hoveredOverLimitColumnId = signal(null, ...(ngDevMode ? [{ debugName: "hoveredOverLimitColumnId" }] : []));
|
|
14313
|
+
onDragStarted(column) {
|
|
14314
|
+
this.dragSourceColumnId.set(column.id);
|
|
14315
|
+
}
|
|
14316
|
+
onDragEnded() {
|
|
14317
|
+
this.dragSourceColumnId.set(null);
|
|
14318
|
+
this.hoveredOverLimitColumnId.set(null);
|
|
14319
|
+
}
|
|
14320
|
+
/**
|
|
14321
|
+
* Live WIP-limit preview (§12 of the spec): as the dragged card enters a
|
|
14322
|
+
* column, work out whether *landing* here would exceed its `wipLimit` and
|
|
14323
|
+
* flag it immediately — before release, and independent of
|
|
14324
|
+
* `wipLimitBehavior`, which only governs what happens once the card is
|
|
14325
|
+
* actually dropped. A card re-entering its own source column doesn't grow
|
|
14326
|
+
* that column's count, so only a genuine cross-column entry counts as +1.
|
|
14327
|
+
*/
|
|
14328
|
+
onListEntered(event, column) {
|
|
14329
|
+
if (this.dragPreviewMode() !== 'live' || column.wipLimit == null)
|
|
14330
|
+
return;
|
|
14331
|
+
const enteringFromElsewhere = this.dragSourceColumnId() !== column.id;
|
|
14332
|
+
const wouldBeCount = event.container.data.length + (enteringFromElsewhere ? 1 : 0);
|
|
14333
|
+
this.hoveredOverLimitColumnId.set(wouldBeCount > column.wipLimit ? column.id : null);
|
|
14334
|
+
}
|
|
14335
|
+
onListExited(column) {
|
|
14336
|
+
if (this.hoveredOverLimitColumnId() === column.id)
|
|
14337
|
+
this.hoveredOverLimitColumnId.set(null);
|
|
14338
|
+
}
|
|
14339
|
+
isLiveOverLimit(column) {
|
|
14340
|
+
return this.hoveredOverLimitColumnId() === column.id;
|
|
14341
|
+
}
|
|
14342
|
+
/* ================= Drop handling ================= */
|
|
14343
|
+
onDrop(event, column) {
|
|
14344
|
+
this.dragSourceColumnId.set(null);
|
|
14345
|
+
this.hoveredOverLimitColumnId.set(null);
|
|
14346
|
+
if (!this.dragEnabled())
|
|
14347
|
+
return;
|
|
14348
|
+
const fromColumnId = event.previousContainer.id;
|
|
14349
|
+
const toColumnId = event.container.id;
|
|
14350
|
+
const card = event.item.data;
|
|
14351
|
+
if (fromColumnId === toColumnId) {
|
|
14352
|
+
if (event.previousIndex === event.currentIndex)
|
|
14353
|
+
return;
|
|
14354
|
+
const list = this.cardsFor(toColumnId);
|
|
14355
|
+
moveItemInArray(list, event.previousIndex, event.currentIndex);
|
|
14356
|
+
this.renumber(list);
|
|
14357
|
+
this.structureTick.update((n) => n + 1);
|
|
14358
|
+
this.cardMoved.emit({ card, fromColumnId, toColumnId, newIndex: event.currentIndex });
|
|
14359
|
+
return;
|
|
14360
|
+
}
|
|
14361
|
+
const targetList = this.cardsFor(toColumnId);
|
|
14362
|
+
const attemptedCount = targetList.length + 1;
|
|
14363
|
+
const wipLimit = column.wipLimit;
|
|
14364
|
+
const wouldExceed = wipLimit != null && attemptedCount > wipLimit;
|
|
14365
|
+
if (wouldExceed) {
|
|
14366
|
+
this.columnLimitExceeded.emit({ columnId: toColumnId, wipLimit: wipLimit, attemptedCount });
|
|
14367
|
+
}
|
|
14368
|
+
if (wouldExceed && this.wipLimitBehavior() === 'block') {
|
|
14369
|
+
// Rejected: nothing below is mutated, so the next render finds the card
|
|
14370
|
+
// still exactly where `cards()` says it is — the same "snap back" any
|
|
14371
|
+
// cancelled CDK drag shows, not a bespoke undo.
|
|
14372
|
+
return;
|
|
14373
|
+
}
|
|
14374
|
+
const sourceList = this.cardsFor(fromColumnId);
|
|
14375
|
+
const fromIndex = sourceList.indexOf(card);
|
|
14376
|
+
if (fromIndex < 0)
|
|
14377
|
+
return; // Column and card disagree about where it lives; leave state alone.
|
|
14378
|
+
sourceList.splice(fromIndex, 1);
|
|
14379
|
+
targetList.splice(event.currentIndex, 0, card);
|
|
14380
|
+
this.setColumnId(card, toColumnId);
|
|
14381
|
+
this.renumber(sourceList);
|
|
14382
|
+
this.renumber(targetList);
|
|
14383
|
+
this.structureTick.update((n) => n + 1);
|
|
14384
|
+
this.cardMoved.emit({ card, fromColumnId, toColumnId, newIndex: event.currentIndex });
|
|
14385
|
+
}
|
|
14386
|
+
setColumnId(card, columnId) {
|
|
14387
|
+
const field = this.columnIdField();
|
|
14388
|
+
// A resolver function has nowhere to write back to — the host owns that
|
|
14389
|
+
// mapping and is expected to apply the move from `cardMoved` itself.
|
|
14390
|
+
if (typeof field === 'string')
|
|
14391
|
+
card[field] = columnId;
|
|
14392
|
+
}
|
|
14393
|
+
renumber(list) {
|
|
14394
|
+
list.forEach((card, index) => {
|
|
14395
|
+
card['order'] = index;
|
|
14396
|
+
});
|
|
14397
|
+
}
|
|
14398
|
+
/* ================= Click handling (§5) ================= */
|
|
14399
|
+
/**
|
|
14400
|
+
* One listener per card resolves both the whole-card click and every
|
|
14401
|
+
* `[bkKanbanClickTarget]` region: `closest()` from the actual event target
|
|
14402
|
+
* finds the nearest marked ancestor within this card, or there isn't one
|
|
14403
|
+
* and it's a plain card click. Either way this fires exactly once — never
|
|
14404
|
+
* once for the region and again for the card underneath it.
|
|
14405
|
+
*/
|
|
14406
|
+
onCardClick(event, card) {
|
|
14407
|
+
const wrapper = event.currentTarget;
|
|
14408
|
+
const marked = event.target?.closest('[data-bk-kanban-click-target]');
|
|
14409
|
+
const target = marked && wrapper.contains(marked)
|
|
14410
|
+
? (marked.dataset['bkKanbanClickTarget'] ?? 'card')
|
|
14411
|
+
: 'card';
|
|
14412
|
+
this.cardClicked.emit({ card, target });
|
|
14413
|
+
}
|
|
14414
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkKanban, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14415
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkKanban, isStandalone: true, selector: "bk-kanban", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: true, transformFunction: null }, cardTemplate: { classPropertyName: "cardTemplate", publicName: "cardTemplate", isSignal: true, isRequired: true, transformFunction: null }, columnIdField: { classPropertyName: "columnIdField", publicName: "columnIdField", isSignal: true, isRequired: false, transformFunction: null }, dragEnabled: { classPropertyName: "dragEnabled", publicName: "dragEnabled", isSignal: true, isRequired: false, transformFunction: null }, dragScope: { classPropertyName: "dragScope", publicName: "dragScope", isSignal: true, isRequired: false, transformFunction: null }, wipLimitBehavior: { classPropertyName: "wipLimitBehavior", publicName: "wipLimitBehavior", isSignal: true, isRequired: false, transformFunction: null }, columnDragEnabled: { classPropertyName: "columnDragEnabled", publicName: "columnDragEnabled", isSignal: true, isRequired: false, transformFunction: null }, columnScrollMode: { classPropertyName: "columnScrollMode", publicName: "columnScrollMode", isSignal: true, isRequired: false, transformFunction: null }, boardClass: { classPropertyName: "boardClass", publicName: "boardClass", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, columnHeaderActionsTemplate: { classPropertyName: "columnHeaderActionsTemplate", publicName: "columnHeaderActionsTemplate", isSignal: true, isRequired: false, transformFunction: null }, emptyStateTemplate: { classPropertyName: "emptyStateTemplate", publicName: "emptyStateTemplate", isSignal: true, isRequired: false, transformFunction: null }, noDataText: { classPropertyName: "noDataText", publicName: "noDataText", isSignal: true, isRequired: false, transformFunction: null }, dragPreviewMode: { classPropertyName: "dragPreviewMode", publicName: "dragPreviewMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardMoved: "cardMoved", cardClicked: "cardClicked", columnLimitExceeded: "columnLimitExceeded", columnMoved: "columnMoved", columnActionTriggered: "columnActionTriggered" }, host: { classAttribute: "bk-kanban-host" }, exportAs: ["bkKanban"], ngImport: i0, template: "<div class=\"bk-kanban-board\" [class]=\"boardClass()\">\r\n <div\r\n class=\"bk-kanban\"\r\n [class.bk-kanban--scroll-wrapper]=\"columnScrollMode() === 'wrapper'\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n [cdkDropListData]=\"columns()\"\r\n [cdkDropListDisabled]=\"!columnDragEnabled()\"\r\n (cdkDropListDropped)=\"onColumnDrop($event)\"\r\n >\r\n @for (column of columns(); track column.id) {\r\n <div\r\n class=\"bk-kanban-column\"\r\n cdkDrag\r\n [cdkDragData]=\"column\"\r\n [cdkDragDisabled]=\"!columnDragEnabled()\"\r\n [class]=\"column.columnClass\"\r\n [class.bk-kanban-column-warn]=\"isColumnOverLimit(column)\"\r\n [class.bk-kanban-column-live-over]=\"isLiveOverLimit(column)\"\r\n >\r\n <div class=\"bk-kanban-column-header\" cdkDragHandle [class]=\"column.colHeaderClass\">\r\n <span class=\"bk-kanban-column-title\">{{ column.label }}</span>\r\n <bk-badge\r\n class=\"bk-kanban-column-count\"\r\n [label]=\"columnCountLabel(column)\"\r\n size=\"sm\"\r\n [color]=\"isColumnOverLimit(column) || isLiveOverLimit(column) ? 'Warning' : 'Gray'\"\r\n ></bk-badge>\r\n\r\n @if (columnHeaderActionsTemplate(); as actionsTpl) {\r\n <div class=\"bk-kanban-column-actions\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"actionsTpl\"\r\n [ngTemplateOutletContext]=\"columnActionsContext(column)\"\r\n ></ng-container>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"bk-kanban-column-body\"\r\n cdkDropList\r\n [id]=\"column.id\"\r\n [cdkDropListData]=\"cardsFor(column.id)\"\r\n [cdkDropListConnectedTo]=\"connectedListIds(column.id)\"\r\n [cdkDropListSortingDisabled]=\"sortingDisabled()\"\r\n [cdkDropListDisabled]=\"!dragEnabled()\"\r\n (cdkDropListDropped)=\"onDrop($event, column)\"\r\n (cdkDropListEntered)=\"onListEntered($event, column)\"\r\n (cdkDropListExited)=\"onListExited(column)\"\r\n >\r\n @if (cardsFor(column.id).length === 0) {\r\n <div class=\"bk-kanban-empty\">\r\n @if (emptyStateTemplate(); as emptyTpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"emptyTpl\"\r\n [ngTemplateOutletContext]=\"emptyStateContext(column)\"\r\n ></ng-container>\r\n } @else {\r\n <span class=\"bk-kanban-empty-text\">{{ emptyStateText(column) }}</span>\r\n }\r\n </div>\r\n }\r\n\r\n @for (card of cardsFor(column.id); track resolveTrackBy(card, $index); let i = $index) {\r\n <div\r\n class=\"bk-kanban-card\"\r\n cdkDrag\r\n [cdkDragData]=\"card\"\r\n [cdkDragDisabled]=\"!dragEnabled()\"\r\n (cdkDragStarted)=\"onDragStarted(column)\"\r\n (cdkDragEnded)=\"onDragEnded()\"\r\n (click)=\"onCardClick($event, card)\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"cardTemplate()\"\r\n [ngTemplateOutletContext]=\"cardContext(card, column, i)\"\r\n ></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".bk-kanban-host,.bk-kanban-board{display:block;height:100%}.bk-kanban{@apply flex items-stretch gap-4 w-full h-full overflow-x-auto;scroll-snap-type:x proximity}.bk-kanban--scroll-wrapper{align-items:flex-start;overflow-y:auto}.bk-kanban--scroll-wrapper .bk-kanban-column-body{overflow-y:visible}.bk-kanban-column{@apply flex flex-col shrink-0 w-[300px] max-w-[85vw] rounded-xl border border-[#EBEDF3] overflow-hidden;background:var(--bk-kanban-column-bg, #f9fafa);scroll-snap-align:start}.bk-kanban-column-header{@apply flex items-center justify-between gap-2 px-3 py-2.5;background:var(--bk-kanban-header-bg, #f9fafa);border-bottom:1px solid #ebedf3}.bk-kanban-column:not(.cdk-drag-disabled)>.bk-kanban-column-header{cursor:grab}.bk-kanban-column.cdk-drag-dragging>.bk-kanban-column-header{cursor:grabbing}.bk-kanban-column-title{@apply text-[13px] font-semibold text-[#15191E] truncate;}.bk-kanban-column-count{@apply shrink-0;}.bk-kanban-column-actions{@apply shrink-0 flex items-center;}.bk-kanban-column-body{@apply flex-1 flex flex-col gap-2 p-2.5 overflow-y-auto;min-height:96px}.bk-kanban-empty{@apply flex flex-1 flex-col items-center justify-center py-6 text-center;}.bk-kanban-empty-text{@apply text-xs font-medium text-[#78829D];}.bk-kanban-card{@apply bg-white rounded-lg border border-[#EBEDF3] p-3 cursor-pointer;box-shadow:0 1px 2px #1018280a;transition:box-shadow .15s ease,border-color .15s ease}.bk-kanban-card:hover{@apply border-[#C4CADA];box-shadow:0 2px 6px #10182814}.bk-kanban-card.cdk-drag-dragging{transition:none}.bk-kanban-column-warn{@apply border-amber-300 bg-amber-50;}.bk-kanban-column-warn .bk-kanban-column-header{@apply bg-amber-50 border-amber-200;}.bk-kanban-column-live-over{@apply border-amber-400 bg-amber-50;outline:2px dashed theme(\"colors.amber.400\");outline-offset:-2px}.bk-kanban-column-live-over .bk-kanban-column-header{@apply bg-amber-50 border-amber-200;}.bk-kanban-card.cdk-drag-preview{@apply rounded-lg;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;cursor:grabbing}.bk-kanban-card.cdk-drag-placeholder{@apply border-dashed border-[#C4CADA] bg-[#F1F2F4];box-shadow:none;opacity:.6}.bk-kanban-column-body.cdk-drop-list-dragging .bk-kanban-card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.bk-kanban-column.cdk-drag-preview{box-shadow:0 8px 10px -6px #0003,0 20px 25px -5px #00000024}.bk-kanban-column.cdk-drag-placeholder{@apply border-dashed border-[#C4CADA] bg-[#F1F2F4];box-shadow:none;opacity:.5}.bk-kanban-column.cdk-drag-placeholder .bk-kanban-column-header,.bk-kanban-column.cdk-drag-placeholder .bk-kanban-column-body{visibility:hidden}.bk-kanban.cdk-drop-list-dragging .bk-kanban-column:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@media (max-width: 640px){.bk-kanban-column{width:86vw}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$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: i1$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: i1$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
14416
|
+
}
|
|
14417
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkKanban, decorators: [{
|
|
14418
|
+
type: Component,
|
|
14419
|
+
args: [{ selector: 'bk-kanban', standalone: true, exportAs: 'bkKanban', imports: [NgTemplateOutlet, DragDropModule, BkBadge], encapsulation: ViewEncapsulation.None, host: {
|
|
14420
|
+
class: 'bk-kanban-host'
|
|
14421
|
+
}, template: "<div class=\"bk-kanban-board\" [class]=\"boardClass()\">\r\n <div\r\n class=\"bk-kanban\"\r\n [class.bk-kanban--scroll-wrapper]=\"columnScrollMode() === 'wrapper'\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n [cdkDropListData]=\"columns()\"\r\n [cdkDropListDisabled]=\"!columnDragEnabled()\"\r\n (cdkDropListDropped)=\"onColumnDrop($event)\"\r\n >\r\n @for (column of columns(); track column.id) {\r\n <div\r\n class=\"bk-kanban-column\"\r\n cdkDrag\r\n [cdkDragData]=\"column\"\r\n [cdkDragDisabled]=\"!columnDragEnabled()\"\r\n [class]=\"column.columnClass\"\r\n [class.bk-kanban-column-warn]=\"isColumnOverLimit(column)\"\r\n [class.bk-kanban-column-live-over]=\"isLiveOverLimit(column)\"\r\n >\r\n <div class=\"bk-kanban-column-header\" cdkDragHandle [class]=\"column.colHeaderClass\">\r\n <span class=\"bk-kanban-column-title\">{{ column.label }}</span>\r\n <bk-badge\r\n class=\"bk-kanban-column-count\"\r\n [label]=\"columnCountLabel(column)\"\r\n size=\"sm\"\r\n [color]=\"isColumnOverLimit(column) || isLiveOverLimit(column) ? 'Warning' : 'Gray'\"\r\n ></bk-badge>\r\n\r\n @if (columnHeaderActionsTemplate(); as actionsTpl) {\r\n <div class=\"bk-kanban-column-actions\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"actionsTpl\"\r\n [ngTemplateOutletContext]=\"columnActionsContext(column)\"\r\n ></ng-container>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"bk-kanban-column-body\"\r\n cdkDropList\r\n [id]=\"column.id\"\r\n [cdkDropListData]=\"cardsFor(column.id)\"\r\n [cdkDropListConnectedTo]=\"connectedListIds(column.id)\"\r\n [cdkDropListSortingDisabled]=\"sortingDisabled()\"\r\n [cdkDropListDisabled]=\"!dragEnabled()\"\r\n (cdkDropListDropped)=\"onDrop($event, column)\"\r\n (cdkDropListEntered)=\"onListEntered($event, column)\"\r\n (cdkDropListExited)=\"onListExited(column)\"\r\n >\r\n @if (cardsFor(column.id).length === 0) {\r\n <div class=\"bk-kanban-empty\">\r\n @if (emptyStateTemplate(); as emptyTpl) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"emptyTpl\"\r\n [ngTemplateOutletContext]=\"emptyStateContext(column)\"\r\n ></ng-container>\r\n } @else {\r\n <span class=\"bk-kanban-empty-text\">{{ emptyStateText(column) }}</span>\r\n }\r\n </div>\r\n }\r\n\r\n @for (card of cardsFor(column.id); track resolveTrackBy(card, $index); let i = $index) {\r\n <div\r\n class=\"bk-kanban-card\"\r\n cdkDrag\r\n [cdkDragData]=\"card\"\r\n [cdkDragDisabled]=\"!dragEnabled()\"\r\n (cdkDragStarted)=\"onDragStarted(column)\"\r\n (cdkDragEnded)=\"onDragEnded()\"\r\n (click)=\"onCardClick($event, card)\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"cardTemplate()\"\r\n [ngTemplateOutletContext]=\"cardContext(card, column, i)\"\r\n ></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".bk-kanban-host,.bk-kanban-board{display:block;height:100%}.bk-kanban{@apply flex items-stretch gap-4 w-full h-full overflow-x-auto;scroll-snap-type:x proximity}.bk-kanban--scroll-wrapper{align-items:flex-start;overflow-y:auto}.bk-kanban--scroll-wrapper .bk-kanban-column-body{overflow-y:visible}.bk-kanban-column{@apply flex flex-col shrink-0 w-[300px] max-w-[85vw] rounded-xl border border-[#EBEDF3] overflow-hidden;background:var(--bk-kanban-column-bg, #f9fafa);scroll-snap-align:start}.bk-kanban-column-header{@apply flex items-center justify-between gap-2 px-3 py-2.5;background:var(--bk-kanban-header-bg, #f9fafa);border-bottom:1px solid #ebedf3}.bk-kanban-column:not(.cdk-drag-disabled)>.bk-kanban-column-header{cursor:grab}.bk-kanban-column.cdk-drag-dragging>.bk-kanban-column-header{cursor:grabbing}.bk-kanban-column-title{@apply text-[13px] font-semibold text-[#15191E] truncate;}.bk-kanban-column-count{@apply shrink-0;}.bk-kanban-column-actions{@apply shrink-0 flex items-center;}.bk-kanban-column-body{@apply flex-1 flex flex-col gap-2 p-2.5 overflow-y-auto;min-height:96px}.bk-kanban-empty{@apply flex flex-1 flex-col items-center justify-center py-6 text-center;}.bk-kanban-empty-text{@apply text-xs font-medium text-[#78829D];}.bk-kanban-card{@apply bg-white rounded-lg border border-[#EBEDF3] p-3 cursor-pointer;box-shadow:0 1px 2px #1018280a;transition:box-shadow .15s ease,border-color .15s ease}.bk-kanban-card:hover{@apply border-[#C4CADA];box-shadow:0 2px 6px #10182814}.bk-kanban-card.cdk-drag-dragging{transition:none}.bk-kanban-column-warn{@apply border-amber-300 bg-amber-50;}.bk-kanban-column-warn .bk-kanban-column-header{@apply bg-amber-50 border-amber-200;}.bk-kanban-column-live-over{@apply border-amber-400 bg-amber-50;outline:2px dashed theme(\"colors.amber.400\");outline-offset:-2px}.bk-kanban-column-live-over .bk-kanban-column-header{@apply bg-amber-50 border-amber-200;}.bk-kanban-card.cdk-drag-preview{@apply rounded-lg;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;cursor:grabbing}.bk-kanban-card.cdk-drag-placeholder{@apply border-dashed border-[#C4CADA] bg-[#F1F2F4];box-shadow:none;opacity:.6}.bk-kanban-column-body.cdk-drop-list-dragging .bk-kanban-card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.bk-kanban-column.cdk-drag-preview{box-shadow:0 8px 10px -6px #0003,0 20px 25px -5px #00000024}.bk-kanban-column.cdk-drag-placeholder{@apply border-dashed border-[#C4CADA] bg-[#F1F2F4];box-shadow:none;opacity:.5}.bk-kanban-column.cdk-drag-placeholder .bk-kanban-column-header,.bk-kanban-column.cdk-drag-placeholder .bk-kanban-column-body{visibility:hidden}.bk-kanban.cdk-drop-list-dragging .bk-kanban-column:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@media (max-width: 640px){.bk-kanban-column{width:86vw}}\n"] }]
|
|
14422
|
+
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], cards: [{ type: i0.Input, args: [{ isSignal: true, alias: "cards", required: true }] }], cardTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "cardTemplate", required: true }] }], columnIdField: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnIdField", required: false }] }], dragEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragEnabled", required: false }] }], dragScope: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragScope", required: false }] }], wipLimitBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "wipLimitBehavior", required: false }] }], columnDragEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnDragEnabled", required: false }] }], columnScrollMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnScrollMode", required: false }] }], boardClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "boardClass", required: false }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], columnHeaderActionsTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnHeaderActionsTemplate", required: false }] }], emptyStateTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyStateTemplate", required: false }] }], noDataText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noDataText", required: false }] }], dragPreviewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragPreviewMode", required: false }] }], cardMoved: [{ type: i0.Output, args: ["cardMoved"] }], cardClicked: [{ type: i0.Output, args: ["cardClicked"] }], columnLimitExceeded: [{ type: i0.Output, args: ["columnLimitExceeded"] }], columnMoved: [{ type: i0.Output, args: ["columnMoved"] }], columnActionTriggered: [{ type: i0.Output, args: ["columnActionTriggered"] }] } });
|
|
14423
|
+
|
|
14424
|
+
/**
|
|
14425
|
+
* Marks an element inside a `cardTemplate` as its own click region.
|
|
14426
|
+
*
|
|
14427
|
+
* `bk-kanban` never attaches a listener to this element directly — it puts
|
|
14428
|
+
* one listener on the whole card and, on click, walks up from
|
|
14429
|
+
* `event.target` (`Element.closest`) looking for the nearest marked
|
|
14430
|
+
* ancestor. That single-listener design is what makes a click on a marked
|
|
14431
|
+
* region resolve to *just* that region's name, instead of firing once for
|
|
14432
|
+
* the region and once more, as a duplicate, for the card underneath it.
|
|
14433
|
+
* This directive's only job is to leave something that walk can find: a
|
|
14434
|
+
* `data-bk-kanban-click-target` attribute carrying the name you gave it.
|
|
14435
|
+
*
|
|
14436
|
+
* <div [bkKanbanClickTarget]="'hours'">{{ card.hours }}h</div>
|
|
14437
|
+
* <div [bkKanbanClickTarget]="'assignee'">
|
|
14438
|
+
* <bk-ui-avatar [name]="card.assignee"></bk-ui-avatar>
|
|
14439
|
+
* </div>
|
|
14440
|
+
*
|
|
14441
|
+
* A click on either fires `cardClicked` with `target: 'hours'` /
|
|
14442
|
+
* `'assignee'`; a click anywhere else on the card falls back to the default
|
|
14443
|
+
* `target: 'card'`. See `BkKanbanCardClickedEvent`.
|
|
14444
|
+
*/
|
|
14445
|
+
class BkKanbanClickTarget {
|
|
14446
|
+
target = input.required(...(ngDevMode ? [{ debugName: "target", alias: 'bkKanbanClickTarget' }] : [{ alias: 'bkKanbanClickTarget' }]));
|
|
14447
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkKanbanClickTarget, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
14448
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: BkKanbanClickTarget, isStandalone: true, selector: "[bkKanbanClickTarget]", inputs: { target: { classPropertyName: "target", publicName: "bkKanbanClickTarget", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-bk-kanban-click-target": "target()" } }, ngImport: i0 });
|
|
14449
|
+
}
|
|
14450
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkKanbanClickTarget, decorators: [{
|
|
14451
|
+
type: Directive,
|
|
14452
|
+
args: [{
|
|
14453
|
+
selector: '[bkKanbanClickTarget]',
|
|
14454
|
+
standalone: true,
|
|
14455
|
+
host: {
|
|
14456
|
+
'[attr.data-bk-kanban-click-target]': 'target()'
|
|
14457
|
+
}
|
|
14458
|
+
}]
|
|
14459
|
+
}], propDecorators: { target: [{ type: i0.Input, args: [{ isSignal: true, alias: "bkKanbanClickTarget", required: true }] }] } });
|
|
14460
|
+
|
|
14461
|
+
/**
|
|
14462
|
+
* Types for bk-kanban.
|
|
14463
|
+
*
|
|
14464
|
+
* The board is content-agnostic by design (see the component's own doc
|
|
14465
|
+
* comment): it only ever moves opaque `T` values between columns and reports
|
|
14466
|
+
* what happened. Every type here describes either a column, or one of the
|
|
14467
|
+
* events the board reports — never anything about what a card renders as.
|
|
14468
|
+
*/
|
|
14469
|
+
|
|
14080
14470
|
/*
|
|
14081
14471
|
* Public API Surface of brickclay-lib
|
|
14082
14472
|
*/
|
|
@@ -14086,5 +14476,5 @@ const BK_TABLE = [
|
|
|
14086
14476
|
* Generated bundle index. Do not edit.
|
|
14087
14477
|
*/
|
|
14088
14478
|
|
|
14089
|
-
export { ARROW_CORNER_GAP, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarMonth, CalendarSelection, CalendarWeekday, ColumnFilterOption, DEFAULT_COUNTRY_OPTIONS, NEUTRAL_APPEARANCE, OPPOSITE_SIDE, POPOVER_PLACEMENTS, clamp, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
|
|
14479
|
+
export { ARROW_CORNER_GAP, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkKanban, BkKanbanClickTarget, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarMonth, CalendarSelection, CalendarWeekday, ColumnFilterOption, DEFAULT_COUNTRY_OPTIONS, NEUTRAL_APPEARANCE, OPPOSITE_SIDE, POPOVER_PLACEMENTS, clamp, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
|
|
14090
14480
|
//# sourceMappingURL=brickclay-org-ui.mjs.map
|