UNPKG

@ng-matero/extensions

Version:
1 lines 153 kB
{"version":3,"file":"mtxGrid.mjs","sources":["../../../projects/extensions/grid/column-resize/resize-strategy.ts","../../../projects/extensions/grid/column-resize/column-resize-directives/common.ts","../../../projects/extensions/grid/column-resize/column-resize-directives/column-resize.ts","../../../projects/extensions/grid/column-resize/column-resize-directives/column-resize-flex.ts","../../../projects/extensions/grid/column-resize/overlay-handle.ts","../../../projects/extensions/grid/column-resize/resizable-directives/common.ts","../../../projects/extensions/grid/column-resize/resizable-directives/resizable.ts","../../../projects/extensions/grid/column-resize/column-resize-module.ts","../../../projects/extensions/grid/grid-utils.ts","../../../projects/extensions/grid/grid-pipes.ts","../../../projects/extensions/grid/grid-menu.ts","../../../projects/extensions/grid/cell.ts","../../../projects/extensions/grid/cell.html","../../../projects/extensions/grid/column-menu.ts","../../../projects/extensions/grid/column-menu.html","../../../projects/extensions/grid/grid-expansion-toggle.ts","../../../projects/extensions/grid/grid-selectable-cell.ts","../../../projects/extensions/grid/grid.ts","../../../projects/extensions/grid/grid.html","../../../projects/extensions/grid/grid-module.ts","../../../projects/extensions/grid/mtxGrid.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport { Injectable, Provider } from '@angular/core';\n\nimport {\n CdkFlexTableResizeStrategy,\n ResizeStrategy,\n TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER,\n} from '@ng-matero/extensions/column-resize';\n\nexport { TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER };\n\n/**\n * Overrides CdkFlexTableResizeStrategy to match mat-column elements.\n */\n@Injectable()\nexport class MatFlexTableResizeStrategy extends CdkFlexTableResizeStrategy {\n protected override getColumnCssClass(cssFriendlyColumnName: string): string {\n return `mat-column-${cssFriendlyColumnName}`;\n }\n}\n\nexport const FLEX_RESIZE_STRATEGY_PROVIDER: Provider = {\n provide: ResizeStrategy,\n useClass: MatFlexTableResizeStrategy,\n};\n","import { Provider } from '@angular/core';\n\nimport {\n _COALESCED_STYLE_SCHEDULER,\n _CoalescedStyleScheduler,\n ColumnResize,\n ColumnResizeNotifier,\n ColumnResizeNotifierSource,\n HeaderRowEventDispatcher,\n} from '@ng-matero/extensions/column-resize';\n\nimport {\n TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER,\n FLEX_RESIZE_STRATEGY_PROVIDER,\n} from '../resize-strategy';\n\nconst PROVIDERS: Provider[] = [\n ColumnResizeNotifier,\n HeaderRowEventDispatcher,\n ColumnResizeNotifierSource,\n { provide: _COALESCED_STYLE_SCHEDULER, useClass: _CoalescedStyleScheduler },\n];\nexport const TABLE_PROVIDERS: Provider[] = [\n ...PROVIDERS,\n TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER,\n];\nexport const FLEX_PROVIDERS: Provider[] = [...PROVIDERS, FLEX_RESIZE_STRATEGY_PROVIDER];\n\nexport const TABLE_HOST_BINDINGS = {\n class: 'mat-column-resize-table',\n};\nexport const FLEX_HOST_BINDINGS = {\n class: 'mat-column-resize-flex',\n};\n\nexport abstract class AbstractMatColumnResize extends ColumnResize {\n getTableHeight() {\n const table = this.elementRef.nativeElement;\n const tableParent = table.parentNode as HTMLElement;\n const isTableContainer = tableParent.classList.contains('mat-table-container');\n return isTableContainer ? tableParent.offsetHeight : table.offsetHeight;\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport { Directive, ElementRef, NgZone, inject } from '@angular/core';\nimport {\n ColumnResize,\n ColumnResizeNotifier,\n ColumnResizeNotifierSource,\n HeaderRowEventDispatcher,\n} from '@ng-matero/extensions/column-resize';\n\nimport { AbstractMatColumnResize, TABLE_HOST_BINDINGS, TABLE_PROVIDERS } from './common';\n\n/**\n * Explicitly enables column resizing for a table-based mat-table.\n * Individual columns must be annotated specifically.\n */\n@Directive({\n selector: 'table[mat-table][columnResize]',\n host: TABLE_HOST_BINDINGS,\n providers: [...TABLE_PROVIDERS, { provide: ColumnResize, useExisting: MatColumnResize }],\n})\nexport class MatColumnResize extends AbstractMatColumnResize {\n readonly columnResizeNotifier = inject(ColumnResizeNotifier);\n readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n protected readonly eventDispatcher = inject(HeaderRowEventDispatcher);\n protected readonly ngZone = inject(NgZone);\n protected readonly notifier = inject(ColumnResizeNotifierSource);\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport { Directive, ElementRef, NgZone, inject } from '@angular/core';\nimport {\n ColumnResize,\n ColumnResizeNotifier,\n ColumnResizeNotifierSource,\n HeaderRowEventDispatcher,\n} from '@ng-matero/extensions/column-resize';\n\nimport { AbstractMatColumnResize, FLEX_HOST_BINDINGS, FLEX_PROVIDERS } from './common';\n\n/**\n * Explicitly enables column resizing for a flexbox-based mat-table.\n * Individual columns must be annotated specifically.\n */\n@Directive({\n selector: 'mat-table[columnResize]',\n host: FLEX_HOST_BINDINGS,\n providers: [...FLEX_PROVIDERS, { provide: ColumnResize, useExisting: MatColumnResizeFlex }],\n})\nexport class MatColumnResizeFlex extends AbstractMatColumnResize {\n readonly columnResizeNotifier = inject(ColumnResizeNotifier);\n readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n protected readonly eventDispatcher = inject(HeaderRowEventDispatcher);\n protected readonly ngZone = inject(NgZone);\n protected readonly notifier = inject(ColumnResizeNotifierSource);\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { CdkColumnDef } from '@angular/cdk/table';\nimport {\n ChangeDetectionStrategy,\n Component,\n DOCUMENT,\n ElementRef,\n NgZone,\n ViewChild,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\nimport {\n ColumnResize,\n ColumnResizeNotifierSource,\n HeaderRowEventDispatcher,\n ResizeOverlayHandle,\n ResizeRef,\n _COALESCED_STYLE_SCHEDULER,\n _CoalescedStyleScheduler,\n} from '@ng-matero/extensions/column-resize';\n\nimport { AbstractMatColumnResize } from './column-resize-directives/common';\n\n/**\n * Component shown over the edge of a resizable column that is responsible\n * for handling column resize mouse events and displaying a vertical line along the column edge.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mat-column-resize-overlay-thumb' },\n template: '<div #top class=\"mat-column-resize-overlay-thumb-top\"></div>',\n})\nexport class MatColumnResizeOverlayHandle extends ResizeOverlayHandle {\n protected readonly columnDef = inject(CdkColumnDef);\n protected readonly columnResize = inject(ColumnResize);\n protected readonly directionality = inject(Directionality);\n protected readonly elementRef = inject(ElementRef);\n protected readonly eventDispatcher = inject(HeaderRowEventDispatcher);\n protected readonly ngZone = inject(NgZone);\n protected readonly resizeNotifier = inject(ColumnResizeNotifierSource);\n protected readonly resizeRef = inject(ResizeRef);\n protected readonly styleScheduler = inject<_CoalescedStyleScheduler>(_COALESCED_STYLE_SCHEDULER);\n protected readonly document = inject(DOCUMENT);\n\n @ViewChild('top', { static: true }) topElement!: ElementRef<HTMLElement>;\n\n protected override updateResizeActive(active: boolean): void {\n super.updateResizeActive(active);\n\n const originHeight = this.resizeRef.origin.nativeElement.offsetHeight;\n this.topElement.nativeElement.style.height = `${originHeight}px`;\n this.resizeRef.overlayRef.updateSize({\n height: active\n ? (this.columnResize as AbstractMatColumnResize).getTableHeight()\n : originHeight,\n });\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport { Type } from '@angular/core';\nimport { Resizable } from '@ng-matero/extensions/column-resize';\nimport { MatColumnResizeOverlayHandle } from '../overlay-handle';\n\nexport abstract class AbstractMatResizable extends Resizable<MatColumnResizeOverlayHandle> {\n override minWidthPxInternal = 32;\n\n protected override getInlineHandleCssClassName(): string {\n return 'mat-resizable-handle';\n }\n\n protected override getOverlayHandleComponentType(): Type<MatColumnResizeOverlayHandle> {\n return MatColumnResizeOverlayHandle;\n }\n}\n\nexport const RESIZABLE_HOST_BINDINGS = {\n class: 'mat-resizable',\n};\n\nexport const RESIZABLE_INPUTS = [\n 'minWidthPx: matResizableMinWidthPx',\n 'maxWidthPx: matResizableMaxWidthPx',\n];\n","import { Directionality } from '@angular/cdk/bidi';\nimport { Overlay } from '@angular/cdk/overlay';\nimport { CdkColumnDef } from '@angular/cdk/table';\nimport {\n ChangeDetectorRef,\n DOCUMENT,\n Directive,\n ElementRef,\n Injector,\n Input,\n NgZone,\n ViewContainerRef,\n inject,\n} from '@angular/core';\nimport {\n ColumnResize,\n ColumnResizeNotifierSource,\n HeaderRowEventDispatcher,\n ResizeStrategy,\n _COALESCED_STYLE_SCHEDULER,\n _CoalescedStyleScheduler,\n} from '@ng-matero/extensions/column-resize';\n\nimport { AbstractMatResizable, RESIZABLE_HOST_BINDINGS, RESIZABLE_INPUTS } from './common';\n\n/**\n * Explicitly enables column resizing for a mat-header-cell.\n */\n@Directive({\n selector: 'mat-header-cell[resizable], th[mat-header-cell][resizable]',\n host: {\n '[class]': 'resizableClass',\n },\n inputs: RESIZABLE_INPUTS,\n})\nexport class MatResizable extends AbstractMatResizable {\n protected readonly columnDef = inject(CdkColumnDef);\n protected readonly columnResize = inject(ColumnResize);\n protected readonly directionality = inject(Directionality);\n protected readonly elementRef = inject(ElementRef);\n protected readonly eventDispatcher = inject(HeaderRowEventDispatcher);\n protected readonly injector = inject(Injector);\n protected readonly ngZone = inject(NgZone);\n protected readonly overlay = inject(Overlay);\n protected readonly resizeNotifier = inject(ColumnResizeNotifierSource);\n protected readonly resizeStrategy = inject(ResizeStrategy);\n protected readonly styleScheduler = inject<_CoalescedStyleScheduler>(_COALESCED_STYLE_SCHEDULER);\n protected readonly viewContainerRef = inject(ViewContainerRef);\n protected readonly changeDetectorRef = inject(ChangeDetectorRef);\n protected readonly document = inject(DOCUMENT);\n\n isResizable = true;\n\n get resizableClass() {\n return this.isResizable ? RESIZABLE_HOST_BINDINGS.class : '';\n }\n\n @Input()\n get resizable() {\n return this.isResizable;\n }\n set resizable(newValue: any) {\n this.isResizable = newValue == null || newValue === '' || newValue;\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport { NgModule } from '@angular/core';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\nimport { MatColumnResize } from './column-resize-directives/column-resize';\nimport { MatColumnResizeFlex } from './column-resize-directives/column-resize-flex';\nimport { MatColumnResizeOverlayHandle } from './overlay-handle';\nimport { MatResizable } from './resizable-directives/resizable';\n\nconst ENTRY_COMMON_COMPONENTS = [MatColumnResizeOverlayHandle];\n\n@NgModule({\n imports: ENTRY_COMMON_COMPONENTS,\n exports: ENTRY_COMMON_COMPONENTS,\n})\nexport class MatColumnResizeCommonModule {}\n\nconst IMPORTS = [OverlayModule, MatColumnResizeCommonModule];\n\n@NgModule({\n imports: [...IMPORTS, MatColumnResize, MatColumnResizeFlex, MatResizable],\n exports: [MatColumnResize, MatColumnResizeFlex, MatResizable],\n})\nexport class MatColumnResizeModule {}\n","import { Injectable } from '@angular/core';\nimport { MtxGridColumn } from './interfaces';\n\n@Injectable({ providedIn: 'root' })\nexport class MtxGridUtils {\n constructor() {}\n\n /**\n * Get cell's value based on the data and column's field (e.g. `a.b.c`)\n * @param rowData Row data\n * @param colDef Column definition\n * @returns\n */\n getCellValue(rowData: Record<string, any>, colDef: MtxGridColumn): string {\n const keyArr = colDef.field ? colDef.field.split('.') : [];\n let tmp: any = '';\n keyArr.forEach((key: string, i: number) => {\n if (i === 0) {\n tmp = rowData[key];\n } else {\n tmp = tmp && tmp[key];\n }\n });\n return tmp;\n }\n\n /**\n * Get all data of a col\n * @param data All data\n * @param colDef Column definition\n * @returns\n */\n getColData(data: any[], colDef: MtxGridColumn): any[] {\n return data.map(rowData => this.getCellValue(rowData, colDef));\n }\n\n /**\n * Whether the value is empty (`null`, `undefined`, `''`, `[]`)\n * @param value\n * @returns\n */\n isEmpty(value: any) {\n return value == null || value.toString() === '';\n }\n\n /**\n * Whether the value contain HTML\n * @param value\n * @returns\n */\n isContainHTML(value: string) {\n return /<\\/?[a-z][\\s\\S]*>/i.test(value);\n }\n}\n","import { KeyValueChangeRecord, Pipe, PipeTransform, inject } from '@angular/core';\nimport { isObservable } from 'rxjs';\nimport { MtxGridUtils } from './grid-utils';\nimport { MtxGridColumn, MtxGridColumnButton, MtxGridRowClassFormatter } from './interfaces';\n\n@Pipe({ name: 'colClass' })\nexport class MtxGridColClassPipe implements PipeTransform {\n transform(\n colDef: MtxGridColumn,\n rowData?: Record<string, any>,\n rowChangeRecord?: KeyValueChangeRecord<string, any>,\n currentValue?: any\n ) {\n if (typeof colDef.class === 'string') {\n return colDef.class;\n } else if (typeof colDef.class === 'function') {\n return colDef.class(rowData, colDef);\n }\n return '';\n }\n}\n\n@Pipe({ name: 'rowClass' })\nexport class MtxGridRowClassPipe implements PipeTransform {\n transform(\n rowData: Record<string, any>,\n index: number | undefined,\n dataIndex: number,\n rowClassFormatter?: MtxGridRowClassFormatter\n ) {\n const rowIndex = index === undefined ? dataIndex : index;\n const classList: string[] = rowIndex % 2 === 1 ? ['mat-row-odd'] : [];\n if (rowClassFormatter) {\n for (const key of Object.keys(rowClassFormatter)) {\n if (rowClassFormatter[key](rowData, rowIndex)) {\n classList.push(key);\n }\n }\n }\n return classList.join(' ');\n }\n}\n\n@Pipe({ name: 'cellActions' })\nexport class MtxGridCellActionsPipe implements PipeTransform {\n transform(\n btns?: MtxGridColumnButton[] | ((rowData: any) => MtxGridColumnButton[]),\n rowData?: Record<string, any>,\n rowChangeRecord?: KeyValueChangeRecord<string, any>,\n currentValue?: any\n ) {\n if (typeof btns === 'function') {\n return btns(rowData);\n } else if (Array.isArray(btns)) {\n return btns;\n }\n return [];\n }\n}\n\n@Pipe({ name: 'cellActionTooltip' })\nexport class MtxGridCellActionTooltipPipe implements PipeTransform {\n transform(btn: MtxGridColumnButton) {\n if (typeof btn.tooltip === 'string' || isObservable(btn.tooltip)) {\n return { message: btn.tooltip };\n } else {\n return btn.tooltip || { message: '' };\n }\n }\n}\n\n@Pipe({ name: 'cellActionBadge' })\nexport class MtxGridCellActionBadgePipe implements PipeTransform {\n transform(btn: MtxGridColumnButton) {\n if (typeof btn.badge === 'number' || typeof btn.badge === 'string' || isObservable(btn.badge)) {\n return { content: btn.badge };\n } else {\n return btn.badge || { content: '' };\n }\n }\n}\n\n@Pipe({ name: 'cellActionDisable' })\nexport class MtxGridCellActionDisablePipe implements PipeTransform {\n transform(\n btn: MtxGridColumnButton,\n rowData: Record<string, any>,\n rowChangeRecord?: KeyValueChangeRecord<string, any>,\n currentValue?: any\n ) {\n if (typeof btn.disabled === 'boolean') {\n return btn.disabled;\n } else if (typeof btn.disabled === 'function') {\n return btn.disabled(rowData);\n } else {\n return false;\n }\n }\n}\n\n@Pipe({ name: 'cellSummary' })\nexport class MtxGridCellSummaryPipe implements PipeTransform {\n private utils = inject(MtxGridUtils);\n\n transform(data: any[], colDef: MtxGridColumn) {\n if (typeof colDef.summary === 'string') {\n return colDef.summary;\n } else if (typeof colDef.summary === 'function') {\n return (colDef.summary as (data: any[], colDef?: MtxGridColumn) => any)(\n this.utils.getColData(data, colDef),\n colDef\n );\n }\n }\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n Input,\n ViewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { MatIcon } from '@angular/material/icon';\nimport { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';\nimport { MtxGridCellActionDisablePipe } from './grid-pipes';\nimport { MtxGridMenuItem } from './interfaces';\n\n@Component({\n selector: 'mtx-grid-menu',\n exportAs: 'mtxGridMenu',\n template: `\n <mat-menu class=\"mtx-grid-menu\">\n @for (item of items; track $index) {\n @if (!item.iif || item.iif(data)) {\n @if (item.children && item.children.length > 0) {\n <button\n mat-menu-item\n [matMenuTriggerFor]=\"gridMenu.menu\"\n [disabled]=\"item | cellActionDisable: data\"\n [class]=\"item.class\"\n (click)=\"item.click?.(data)\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl; context: { $implicit: item }\" />\n <span>{{ item.text }}</span>\n </button>\n\n <mtx-grid-menu #gridMenu [items]=\"item.children\" [data]=\"data\" />\n } @else {\n <button\n mat-menu-item\n [disabled]=\"item | cellActionDisable: data\"\n [class]=\"item.class\"\n (click)=\"item.click?.(data)\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl; context: { $implicit: item }\" />\n <span>{{ item.text }}</span>\n </button>\n }\n }\n }\n </mat-menu>\n\n <ng-template #iconTpl let-item>\n @if (item.icon) {\n <mat-icon class=\"mtx-grid-icon\">{{ item.icon }}</mat-icon>\n } @else if (item.fontIcon) {\n <mat-icon class=\"mtx-grid-icon\" [fontIcon]=\"item.fontIcon\"></mat-icon>\n } @else if (item.svgIcon) {\n <mat-icon class=\"mtx-grid-icon\" [svgIcon]=\"item.svgIcon\"></mat-icon>\n }\n </ng-template>\n `,\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgTemplateOutlet,\n MatMenu,\n MatMenuItem,\n MatMenuTrigger,\n MatIcon,\n MtxGridMenu,\n MtxGridCellActionDisablePipe,\n ],\n})\nexport class MtxGridMenu {\n @ViewChild(MatMenu, { static: true }) menu!: MatMenu;\n\n @Input() items: MtxGridMenuItem[] = [];\n\n @Input() data: Record<string, any> = {};\n}\n","import {\n AsyncPipe,\n CurrencyPipe,\n DatePipe,\n DecimalPipe,\n NgTemplateOutlet,\n PercentPipe,\n} from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n DoCheck,\n EventEmitter,\n Input,\n KeyValueChangeRecord,\n KeyValueChanges,\n KeyValueDiffer,\n KeyValueDiffers,\n OnInit,\n Output,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\nimport { MatBadge } from '@angular/material/badge';\nimport { MatButton, MatIconButton } from '@angular/material/button';\nimport { MatChip, MatChipListbox } from '@angular/material/chips';\nimport { MatIcon } from '@angular/material/icon';\nimport { MatMenuTrigger } from '@angular/material/menu';\nimport { MatTooltip } from '@angular/material/tooltip';\nimport { isObservable } from 'rxjs';\n\nimport { MtxToObservablePipe } from '@ng-matero/extensions/core';\nimport { MtxDialog } from '@ng-matero/extensions/dialog';\nimport { MtxGridMenu } from './grid-menu';\nimport {\n MtxGridCellActionBadgePipe,\n MtxGridCellActionDisablePipe,\n MtxGridCellActionTooltipPipe,\n MtxGridCellActionsPipe,\n MtxGridCellSummaryPipe,\n} from './grid-pipes';\nimport { MtxGridUtils } from './grid-utils';\nimport { MtxGridColumn, MtxGridColumnButton } from './interfaces';\n\n@Component({\n selector: 'mtx-grid-cell',\n exportAs: 'mtxGridCell',\n templateUrl: './cell.html',\n styleUrl: './cell.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n AsyncPipe,\n CurrencyPipe,\n DatePipe,\n DecimalPipe,\n NgTemplateOutlet,\n PercentPipe,\n MatButton,\n MatIconButton,\n MatIcon,\n MatChipListbox,\n MatChip,\n MatTooltip,\n MatBadge,\n MatMenuTrigger,\n MtxToObservablePipe,\n MtxGridCellActionsPipe,\n MtxGridCellSummaryPipe,\n MtxGridCellActionDisablePipe,\n MtxGridCellActionTooltipPipe,\n MtxGridCellActionBadgePipe,\n MtxGridMenu,\n ],\n})\nexport class MtxGridCell implements OnInit, DoCheck {\n private _dialog = inject(MtxDialog);\n private _utils = inject(MtxGridUtils);\n private _differs = inject(KeyValueDiffers);\n private _changeDetectorRef = inject(ChangeDetectorRef);\n\n /** Row data */\n @Input() rowData: Record<string, any> = {};\n\n /** Column definition */\n @Input() colDef!: MtxGridColumn;\n\n /** Table data */\n @Input() data: any[] = [];\n\n /** Whether show summary */\n @Input() summary = false;\n\n /** Placeholder for the empty value (`null`, `''`, `[]`) */\n @Input() placeholder: string = '--';\n\n @Output() rowDataChange = new EventEmitter<KeyValueChangeRecord<string, any>>();\n\n private rowDataDiffer?: KeyValueDiffer<string, any>;\n\n rowChangeRecord?: KeyValueChangeRecord<string, any>;\n\n get _value() {\n return this._utils.getCellValue(this.rowData, this.colDef);\n }\n\n ngOnInit(): void {\n this.rowDataDiffer = this._differs.find(this.rowData).create();\n }\n\n ngDoCheck(): void {\n const changes = this.rowDataDiffer?.diff(this.rowData);\n if (changes) {\n this._applyChanges(changes);\n }\n }\n\n private _applyChanges(changes: KeyValueChanges<string, any>) {\n changes.forEachChangedItem(record => {\n this.rowChangeRecord = record;\n this.rowDataChange.emit(record);\n this._changeDetectorRef.markForCheck();\n });\n }\n\n _getText(value: any) {\n return value === undefined ? '' : this._utils.isEmpty(value) ? this.placeholder : value;\n }\n\n _getTooltip(value: any) {\n return this._utils.isEmpty(value) ? '' : value;\n }\n\n _getFormatterTooltip(value: any) {\n return this._utils.isContainHTML(value) || this._utils.isEmpty(value) ? '' : value;\n }\n\n _onActionClick(event: MouseEvent, btn: MtxGridColumnButton, rowData: Record<string, any>) {\n event.preventDefault();\n event.stopPropagation();\n\n if (typeof btn.pop === 'string' || isObservable(btn.pop)) {\n this._dialog.open({\n title: btn.pop,\n buttons: [\n { color: 'primary', text: 'OK', onClick: () => btn.click?.(rowData) || {} },\n { text: 'CLOSE' },\n ],\n });\n } else if (typeof btn.pop === 'object') {\n this._dialog.open({\n title: btn.pop?.title,\n description: btn.pop?.description,\n buttons: [\n {\n color: btn.pop?.okColor || 'primary',\n text: btn.pop?.okText || 'OK',\n onClick: () => btn.click?.(rowData) || {},\n },\n {\n color: btn.pop?.closeColor,\n text: btn.pop?.closeText || 'CLOSE',\n },\n ],\n });\n } else {\n btn.click?.(rowData);\n }\n }\n}\n","@if (summary) {\n <span\n [title]=\"_getFormatterTooltip((data | cellSummary: colDef))\"\n [innerHTML]=\"_getText((data | cellSummary: colDef))\">\n </span>\n} @else {\n <!-- Custom formatting -->\n @if (colDef.formatter) {\n <span\n [title]=\"_getFormatterTooltip(colDef.formatter(rowData, colDef))\"\n [innerHTML]=\"_getText(colDef.formatter(rowData, colDef))\">\n </span>\n } @else {\n <!-- Default formatting -->\n @switch (colDef.type) {\n <!-- Buttons -->\n @case ('button') {\n @for (btn of colDef.buttons | cellActions: rowData: rowChangeRecord: rowChangeRecord?.currentValue; track btn) {\n @if (!btn.iif || btn.iif(rowData)) {\n @if(btn.children && btn.children.length>0){\n @if (btn.type === 'icon') {\n <button\n matIconButton\n [color]=\"btn.color || 'primary'\"\n type=\"button\"\n class=\"mtx-grid-action-button\"\n [class]=\"btn.class\"\n [disabled]=\"btn | cellActionDisable: rowData : rowChangeRecord : rowChangeRecord?.currentValue\"\n [matTooltip]=\"(btn | cellActionTooltip).message | toObservable | async\"\n [matTooltipClass]=\"(btn | cellActionTooltip).class\"\n [matTooltipHideDelay]=\"(btn | cellActionTooltip).hideDelay\"\n [matTooltipShowDelay]=\"(btn | cellActionTooltip).showDelay\"\n [matTooltipPosition]=\"(btn | cellActionTooltip).position || 'below'\"\n [matTooltipPositionAtOrigin]=\"(btn | cellActionTooltip).positionAtOrigin\"\n [matTooltipTouchGestures]=\"(btn | cellActionTooltip).touchGestures || 'auto'\"\n [matTooltipDisabled]=\"(btn | cellActionTooltip).disabled\"\n [matBadge]=\"(btn | cellActionBadge).content | toObservable | async\"\n [matBadgeDescription]=\"(btn | cellActionBadge).description | toObservable | async\"\n [matBadgeColor]=\"(btn | cellActionBadge).color\"\n [matBadgePosition]=\"(btn | cellActionBadge).position || 'above after'\"\n [matBadgeSize]=\"(btn | cellActionBadge).size || 'medium'\"\n [matBadgeOverlap]=\"(btn | cellActionBadge).overlap\"\n [matBadgeDisabled]=\"(btn | cellActionBadge).disabled\"\n [matBadgeHidden]=\"(btn | cellActionBadge).hidden\"\n [matMenuTriggerFor]=\"btn.children && btn.children.length>0 ? gridMenu.menu : null\"\n (click)=\"$event.stopPropagation()\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl; context: { $implicit: btn }\"></mat-icon>\n </button>\n\n <mtx-grid-menu #gridMenu [items]=\"btn.children || []\" [data]=\"rowData\" />\n } @else {\n <button\n [matButton]=\"btn.type || 'text'\"\n [color]=\"btn.color || 'primary'\"\n type=\"button\"\n class=\"mtx-grid-action-button\"\n [class]=\"btn.class\"\n [disabled]=\"btn | cellActionDisable: rowData : rowChangeRecord : rowChangeRecord?.currentValue\"\n [matTooltip]=\"(btn | cellActionTooltip).message | toObservable | async\"\n [matTooltipClass]=\"(btn | cellActionTooltip).class\"\n [matTooltipHideDelay]=\"(btn | cellActionTooltip).hideDelay\"\n [matTooltipShowDelay]=\"(btn | cellActionTooltip).showDelay\"\n [matTooltipPosition]=\"(btn | cellActionTooltip).position || 'below'\"\n [matTooltipPositionAtOrigin]=\"(btn | cellActionTooltip).positionAtOrigin\"\n [matTooltipTouchGestures]=\"(btn | cellActionTooltip).touchGestures || 'auto'\"\n [matTooltipDisabled]=\"(btn | cellActionTooltip).disabled\"\n [matBadge]=\"(btn | cellActionBadge).content | toObservable | async\"\n [matBadgeDescription]=\"(btn | cellActionBadge).description | toObservable | async\"\n [matBadgeColor]=\"(btn | cellActionBadge).color\"\n [matBadgePosition]=\"(btn | cellActionBadge).position || 'above after'\"\n [matBadgeSize]=\"(btn | cellActionBadge).size || 'medium'\"\n [matBadgeOverlap]=\"(btn | cellActionBadge).overlap\"\n [matBadgeDisabled]=\"(btn | cellActionBadge).disabled\"\n [matBadgeHidden]=\"(btn | cellActionBadge).hidden\"\n [matMenuTriggerFor]=\"btn.children && btn.children.length>0 ? gridMenu.menu : null\"\n (click)=\"$event.stopPropagation()\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl; context: { $implicit: btn }\"></mat-icon>\n <span>{{ btn.text | toObservable | async }}</span>\n </button>\n\n <mtx-grid-menu #gridMenu [items]=\"btn.children || []\" [data]=\"rowData\" />\n }\n }@else {\n @if (btn.type === 'icon') {\n <button\n matIconButton\n [color]=\"btn.color || 'primary'\"\n type=\"button\"\n class=\"mtx-grid-action-button\"\n [class]=\"btn.class\"\n [disabled]=\"btn | cellActionDisable: rowData : rowChangeRecord : rowChangeRecord?.currentValue\"\n [matTooltip]=\"(btn | cellActionTooltip).message | toObservable | async\"\n [matTooltipClass]=\"(btn | cellActionTooltip).class\"\n [matTooltipHideDelay]=\"(btn | cellActionTooltip).hideDelay\"\n [matTooltipShowDelay]=\"(btn | cellActionTooltip).showDelay\"\n [matTooltipPosition]=\"(btn | cellActionTooltip).position || 'below'\"\n [matTooltipPositionAtOrigin]=\"(btn | cellActionTooltip).positionAtOrigin\"\n [matTooltipTouchGestures]=\"(btn | cellActionTooltip).touchGestures || 'auto'\"\n [matTooltipDisabled]=\"(btn | cellActionTooltip).disabled\"\n [matBadge]=\"(btn | cellActionBadge).content | toObservable | async\"\n [matBadgeDescription]=\"(btn | cellActionBadge).description | toObservable | async\"\n [matBadgeColor]=\"(btn | cellActionBadge).color\"\n [matBadgePosition]=\"(btn | cellActionBadge).position || 'above after'\"\n [matBadgeSize]=\"(btn | cellActionBadge).size || 'medium'\"\n [matBadgeOverlap]=\"(btn | cellActionBadge).overlap\"\n [matBadgeDisabled]=\"(btn | cellActionBadge).disabled\"\n [matBadgeHidden]=\"(btn | cellActionBadge).hidden\"\n (click)=\"_onActionClick($event, btn, rowData)\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl; context: { $implicit: btn }\"></mat-icon>\n </button>\n } @else {\n <button\n [matButton]=\"btn.type || 'text'\"\n [color]=\"btn.color || 'primary'\"\n type=\"button\"\n class=\"mtx-grid-action-button\"\n [class]=\"btn.class\"\n [disabled]=\"btn | cellActionDisable: rowData : rowChangeRecord : rowChangeRecord?.currentValue\"\n [matTooltip]=\"(btn | cellActionTooltip).message | toObservable | async\"\n [matTooltipClass]=\"(btn | cellActionTooltip).class\"\n [matTooltipHideDelay]=\"(btn | cellActionTooltip).hideDelay\"\n [matTooltipShowDelay]=\"(btn | cellActionTooltip).showDelay\"\n [matTooltipPosition]=\"(btn | cellActionTooltip).position || 'below'\"\n [matTooltipPositionAtOrigin]=\"(btn | cellActionTooltip).positionAtOrigin\"\n [matTooltipTouchGestures]=\"(btn | cellActionTooltip).touchGestures || 'auto'\"\n [matTooltipDisabled]=\"(btn | cellActionTooltip).disabled\"\n [matBadge]=\"(btn | cellActionBadge).content | toObservable | async\"\n [matBadgeDescription]=\"(btn | cellActionBadge).description | toObservable | async\"\n [matBadgeColor]=\"(btn | cellActionBadge).color\"\n [matBadgePosition]=\"(btn | cellActionBadge).position || 'above after'\"\n [matBadgeSize]=\"(btn | cellActionBadge).size || 'medium'\"\n [matBadgeOverlap]=\"(btn | cellActionBadge).overlap\"\n [matBadgeDisabled]=\"(btn | cellActionBadge).disabled\"\n [matBadgeHidden]=\"(btn | cellActionBadge).hidden\"\n (click)=\"_onActionClick($event, btn, rowData)\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl; context: { $implicit: btn }\"></mat-icon>\n <span>{{ btn.text | toObservable | async }}</span>\n </button>\n }\n }\n }\n }\n }\n <!-- Tag -->\n @case ('tag') {\n @if (colDef.tag && colDef.tag[_value]) {\n <mat-chip-listbox>\n <mat-chip color=\"primary\" [class]=\"'bg-' + colDef.tag[_value].color\">\n {{colDef.tag[_value].text}}\n </mat-chip>\n </mat-chip-listbox>\n } @else {\n {{_value}}\n }\n }\n <!-- Link -->\n @case ('link') {\n <a [href]=\"_value\" target=\"_blank\">{{_value}}</a>\n }\n <!-- Image -->\n @case ('image') {\n <img class=\"mtx-grid-img\" [src]=\"_value\" alt=\"\">\n }\n <!-- Boolean -->\n @case ('boolean') {\n <span [title]=\"_getTooltip(_value)\">{{_getText(_value)}}</span>\n }\n <!-- Number -->\n @case ('number') {\n <span [title]=\"_getTooltip(_value | number: colDef.typeParameter?.digitsInfo: colDef.typeParameter?.locale)\">\n {{_getText(_value | number: colDef.typeParameter?.digitsInfo: colDef.typeParameter?.locale)}}\n </span>\n }\n <!-- Currency -->\n @case ('currency') {\n <span [title]=\"_getTooltip(_value | currency: colDef.typeParameter?.currencyCode: colDef.typeParameter?.display: colDef.typeParameter?.digitsInfo: colDef.typeParameter?.locale)\">\n {{_getText(_value | currency: colDef.typeParameter?.currencyCode: colDef.typeParameter?.display: colDef.typeParameter?.digitsInfo: colDef.typeParameter?.locale)}}\n </span>\n }\n <!-- Percent -->\n @case ('percent') {\n <span [title]=\"_getTooltip(_value | percent: colDef.typeParameter?.digitsInfo: colDef.typeParameter?.locale)\">\n {{_getText(_value | percent: colDef.typeParameter?.digitsInfo: colDef.typeParameter?.locale)}}\n </span>\n }\n <!-- Date -->\n @case ('date') {\n <span [title]=\"_getTooltip(_value | date: colDef.typeParameter?.format: colDef.typeParameter?.timezone: colDef.typeParameter?.locale)\">\n {{_getText(_value | date: colDef.typeParameter?.format: colDef.typeParameter?.timezone: colDef.typeParameter?.locale)}}\n </span>\n }\n <!-- Default -->\n @default {\n <span [title]=\"_getTooltip(_value)\">{{_getText(_value)}}</span>\n }\n }\n }\n}\n\n<ng-template #iconTpl let-btn>\n @if (btn.icon) {\n <mat-icon class=\"mtx-grid-icon\">{{btn.icon}}</mat-icon>\n } @else if(btn.fontIcon) {\n <mat-icon class=\"mtx-grid-icon\" [fontIcon]=\"btn.fontIcon\"></mat-icon>\n } @else if(btn.svgIcon) {\n <mat-icon class=\"mtx-grid-icon\" [svgIcon]=\"btn.svgIcon\"></mat-icon>\n }\n</ng-template>\n","import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';\nimport { AsyncPipe, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n TemplateRef,\n ViewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { MatButton, MatIconButton } from '@angular/material/button';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { ThemePalette } from '@angular/material/core';\nimport { MatIcon } from '@angular/material/icon';\nimport { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';\n\nimport { MtxToObservablePipe } from '@ng-matero/extensions/core';\nimport {\n MtxGridButtonType,\n MtxGridColumn,\n MtxGridColumnPinOption,\n MtxGridColumnPinValue,\n} from './interfaces';\n\n@Component({\n selector: 'mtx-grid-column-menu',\n exportAs: 'mtxGridColumnMenu',\n templateUrl: './column-menu.html',\n styleUrl: './column-menu.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n AsyncPipe,\n NgTemplateOutlet,\n FormsModule,\n MatButton,\n MatIconButton,\n MatIcon,\n MatMenu,\n MatMenuTrigger,\n MatMenuItem,\n MatCheckbox,\n CdkDrag,\n CdkDropList,\n MtxToObservablePipe,\n ],\n})\nexport class MtxGridColumnMenu {\n @ViewChild(MatMenu, { static: true }) menuPanel!: MatMenu;\n @ViewChild(MatMenuTrigger) menuTrigger!: MatMenuTrigger;\n\n @Input() columns: MtxGridColumn[] = [];\n @Input() selectable = true;\n @Input() selectableChecked: 'show' | 'hide' = 'show';\n @Input() sortable = true;\n @Input() pinnable = true;\n\n @Input()\n get buttonText() {\n const defaultText = `Columns ${this.selectableChecked === 'show' ? 'Shown' : 'Hidden'}`;\n return this._buttonText ? this._buttonText : defaultText;\n }\n set buttonText(value: string) {\n this._buttonText = value;\n }\n private _buttonText = '';\n\n @Input() buttonType: MtxGridButtonType = 'outlined';\n @Input() buttonColor: ThemePalette;\n @Input() buttonClass = '';\n @Input() buttonIcon = '';\n @Input() buttonFontIcon = '';\n @Input() buttonSvgIcon = '';\n\n @Input() showHeader = false;\n @Input() headerText = 'Columns Header';\n @Input() headerTemplate!: TemplateRef<any>;\n @Input() showFooter = false;\n @Input() footerText = 'Columns Footer';\n @Input() footerTemplate!: TemplateRef<any>;\n\n @Output() columnChange = new EventEmitter<MtxGridColumn[]>();\n\n @Input()\n get pinOptions() {\n return this._pinOptions;\n }\n set pinOptions(value: MtxGridColumnPinOption[]) {\n if (value.length > 0) {\n this._pinOptions = value;\n }\n }\n private _pinOptions: MtxGridColumnPinOption[] = [\n { label: 'Pin Left', value: 'left' },\n { label: 'Pin Right', value: 'right' },\n { label: 'No Pin', value: null },\n ];\n\n _handleDroped(e: CdkDragDrop<string[]>) {\n moveItemInArray(this.columns, e.previousIndex, e.currentIndex);\n this.columnChange.emit(this.columns);\n }\n\n _handleChecked(col: MtxGridColumn) {\n if (this.selectableChecked === 'show') {\n col.hide = !col.show;\n } else {\n col.show = !col.hide;\n }\n this.columnChange.emit(this.columns);\n }\n\n _handlePinSelect(col: MtxGridColumn, val: MtxGridColumnPinValue) {\n if (col.pinned != val) {\n col.pinned = val;\n this.columnChange.emit(this.columns);\n }\n }\n}\n","@if (buttonType === 'icon') {\n <button\n [class]=\"buttonClass\"\n matIconButton\n type=\"button\"\n [color]=\"buttonColor\"\n [matMenuTriggerFor]=\"menu\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl\"></mat-icon>\n </button>\n} @else {\n <button\n [class]=\"buttonClass\"\n [matButton]=\"buttonType\"\n type=\"button\"\n [color]=\"buttonColor\"\n [matMenuTriggerFor]=\"menu\"\n >\n <mat-icon *ngTemplateOutlet=\"iconTpl\"></mat-icon>\n {{ buttonText }}\n </button>\n}\n\n<ng-template #iconTpl>\n @if (buttonIcon) {\n <mat-icon>{{buttonIcon}}</mat-icon>\n } @else if(buttonFontIcon) {\n <mat-icon [fontIcon]=\"buttonFontIcon\"></mat-icon>\n } @else if(buttonSvgIcon) {\n <mat-icon [svgIcon]=\"buttonSvgIcon\"></mat-icon>\n }\n</ng-template>\n\n<mat-menu #menu=\"matMenu\" class=\"mtx-grid-column-menu\">\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div class=\"mtx-grid-column-menu-content\"\n (click)=\"$event.stopPropagation()\" (keydown)=\"$event.stopPropagation()\">\n @if (showHeader) {\n <div class=\"mtx-grid-column-menu-header\">\n @if (headerTemplate) {\n <ng-template [ngTemplateOutlet]=\"headerTemplate\"></ng-template>\n } @else {\n {{headerText}}\n }\n </div>\n }\n\n <div class=\"mtx-grid-column-menu-body\">\n @if (sortable) {\n <div class=\"mtx-grid-column-menu-list\"\n cdkDropList (cdkDropListDropped)=\"_handleDroped($event)\">\n @for (col of columns; track col.field) {\n <div class=\"mtx-grid-column-menu-item\"\n cdkDrag [cdkDragDisabled]=\"selectableChecked === 'show'? !col.show : col.hide\">\n <svg class=\"mtx-grid-icon mtx-grid-column-drag-handle-icon\" viewBox=\"0 0 24 24\"\n width=\"24px\" height=\"24px\" fill=\"currentColor\" focusable=\"false\">\n <path d=\"M7,19V17H9V19H7M11,19V17H13V19H11M15,19V17H17V19H15M7,15V13H9V15H7M11,15V13H13V15H11M15,15V13H17V15H15M7,11V9H9V11H7M11,11V9H13V11H11M15,11V9H17V11H15M7,7V5H9V7H7M11,7V5H13V7H11M15,7V5H17V7H15Z\" />\n </svg>\n <ng-template [ngTemplateOutlet]=\"checkboxList\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\">\n </ng-template>\n </div>\n }\n </div>\n }\n\n @if (!sortable) {\n <div class=\"mtx-grid-column-menu-list\">\n @for (col of columns; track col.field) {\n <div class=\"mtx-grid-column-menu-item\">\n <ng-template [ngTemplateOutlet]=\"checkboxList\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\">\n </ng-template>\n </div>\n }\n </div>\n }\n </div>\n\n @if (showFooter) {\n <div class=\"mtx-grid-column-menu-footer\">\n @if (footerTemplate) {\n <ng-template [ngTemplateOutlet]=\"footerTemplate\"></ng-template>\n } @else {\n {{footerText}}\n }\n </div>\n }\n </div>\n</mat-menu>\n\n<ng-template #checkboxList let-col>\n @if (pinnable) {\n <button class=\"mtx-grid-column-pin-button\" matIconButton type=\"button\"\n [matMenuTriggerFor]=\"pinList\">\n @if (col.pinned) {\n <svg class=\"mtx-grid-icon mtx-grid-column-pin-icon\"\n viewBox=\"0 0 24 24\" width=\"24px\" height=\"24px\" fill=\"currentColor\" focusable=\"false\">\n <path d=\"M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z\" />\n </svg>\n }\n @if (!col.pinned) {\n <svg class=\"mtx-grid-icon mtx-grid-column-pin-off-icon\"\n viewBox=\"0 0 24 24\" width=\"24px\" height=\"24px\" fill=\"currentColor\" focusable=\"false\">\n <path d=\"M2,5.27L3.28,4L20,20.72L18.73,22L12.8,16.07V22H11.2V16H6V14L8,12V11.27L2,5.27M16,12L18,14V16H17.82L8,6.18V4H7V2H17V4H16V12Z\" />\n </svg>\n }\n </button>\n <mat-menu #pinList=\"matMenu\" class=\"mtx-grid-column-pin-list\">\n @for (item of pinOptions; track item) {\n <button class=\"mtx-grid-column-pin-option\" type=\"button\"\n mat-menu-item\n (click)=\"_handlePinSelect(col, item.value)\">\n <span class=\"mtx-grid-column-pin-option-placeholder\">\n <!-- eslint-disable-next-line @angular-eslint/template/eqeqeq -->\n @if (col.pinned==item.value) {\n <svg class=\"mtx-grid-icon mtx-grid-column-pin-check-icon\"\n viewBox=\"0 0 24 24\" width=\"24px\" height=\"24px\" fill=\"currentColor\" focusable=\"false\">\n <path d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\" />\n </svg>\n }\n </span>\n <span class=\"mtx-grid-column-pin-option-text\">{{item.label | toObservable | async}}</span>\n </button>\n }\n </mat-menu>\n }\n\n @if (selectable) {\n <mat-checkbox class=\"mtx-grid-column-menu-item-label\"\n [(ngModel)]=\"col[selectableChecked]\" [disabled]=\"col.disabled\"\n (change)=\"_handleChecked(col)\">{{col.header | toObservable | async}}</mat-checkbox>\n } @else {\n <span class=\"mtx-grid-column-menu-item-label\">{{col.header | toObservable | async}}</span>\n }\n</ng-template>\n","import { Directive, EventEmitter, Input, Output, TemplateRef } from '@angular/core';\n\n@Directive({\n selector: '[mtx-grid-expansion-toggle]',\n host: {\n '[class.expanded]': 'opened',\n '(click)': 'onClick($event)',\n },\n})\nexport class MtxGridExpansionToggle {\n private _opened = false;\n private _row: any;\n private _tplRef!: TemplateRef<any>;\n\n @Input()\n get opened() {\n return this._opened;\n }\n set opened(newValue: boolean) {\n this._opened = newValue;\n this.openedChange.emit(newValue);\n }\n @Output() openedChange = new EventEmitter<boolean>();\n\n @Input()\n set expandableRow(value: any) {\n if (value !== this._row) {\n this._row = value;\n }\n }\n\n @Input('expansionRowTpl')\n set template(value: TemplateRef<any>) {\n if (value !== this._tplRef) {\n this._tplRef = value;\n }\n }\n\n @Output() toggleChange = new EventEmitter<MtxGridExpansionToggle>();\n\n onClick(event: MouseEvent) {\n event.preventDefault();\n event.stopPropagation();\n this.toggle();\n }\n\n toggle() {\n this.opened = !this.opened;\n this.toggleChange.emit(this);\n }\n}\n","import { Directive, EventEmitter, Input, Output } from '@angular/core';\n\n@Directive({\n selector: '[mtx-grid-selectable-cell]',\n host: {\n '[class.selected]': 'selected',\n '(click)': 'onClick($event)',\n },\n})\nexport class MtxGridSelectableCell {\n ctrlKeyPressed = false;\n shiftKeyPressed = false;\n\n get selected() {\n return this._selected;\n }\n private _selected = false;\n\n @Input() cellSelectable = true;\n\n @Output() cellSelectedChange = new EventEmitter<MtxGridSelectableCell>();\n\n onClick(event: MouseEvent) {\n this.ctrlKeyPressed = event.ctrlKey;\n this.shiftKeyPressed = event.shiftKey;\n\n if (this.cellSelectable) {\n this.select();\n }\n }\n\n select() {\n this._selected = true;\n this.cellSelectedChange.emit(this);\n }\n\n deselect() {\n this._selected = false;\n this.cellSelectedChange.emit(this);\n }\n\n toggle() {\n this._selected = !this._selected;\n this.cellSelectedChange.emit(this);\n }\n}\n","import { SelectionModel } from '@angular/cdk/collections';\nimport { AsyncPipe, NgTemplateOutlet } from '@angular/common';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ContentChildren,\n ElementRef,\n EventEmitter,\n InjectionToken,\n Input,\n KeyValueChangeRecord,\n OnChanges,\n OnDestroy,\n Output,\n QueryList,\n SimpleChanges,\n TemplateRef,\n TrackByFunction,\n ViewChild,\n ViewEncapsulation,\n booleanAttribute,\n inject,\n} from '@angular/core';\nimport { MatIconButton } from '@angular/material/button';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { ThemePalette, _animationsDisabled } from '@angular/material/core';\nimport { MatPaginator, PageEvent } from '@angular/material/paginator';\nimport { MatProgressBar } from '@angular/material/progress-bar';\nimport { MatSort, MatSortHeader, Sort, SortDirection } from '@angular/material/sort';\nimport {\n MatCell,\n MatCellDef,\n MatColumnDef,\n MatFooterCell,\n MatFooterCellDef,\n MatFooterRow,\n MatFooterRowDef,\n MatHeaderCell,\n MatHeaderCellDef,\n MatHeaderRow,\n MatHeaderRowDef,\n MatRow,\n MatRowDef,\n MatTable,\n MatTableDataSource,\n} from '@angular/material/table';\n\nimport { ColumnResize } from '@ng-matero/extensions/column-resize';\nimport { MtxIsTemplateRefPipe, MtxToObservablePipe } from '@ng-matero/extensions/core';\nimport { MtxGridCell } from './cell';\nimport { MtxGridColumnMenu } from './column-menu';\nimport { MatColumnResize, MatResizable } from './column-resize';\nimport { MtxGridExpansionToggle } from './grid-expansion-toggle';\nimport { MtxGridColClassPipe, MtxGridRowClassPipe } from './grid-pipes';\nimport { MtxGridSelectableCell } from './grid-selectable-cell';\nimport { MtxGridUtils } from './grid-utils';\nimport {\n MtxGridButtonType,\n MtxGridCellTemplate,\n MtxGridColumn,\n MtxGridColumnPinOption,\n MtxGridDefaultOptions,\n MtxGridRowClassFormatter,\n MtxGridRowSelectionFormatter,\n} from './interfaces';\n\n/** Injection token that can be used to specify default grid options. */\nexport const MTX_GRID_DEFAULT_OPTIONS = new InjectionToken<MtxGridDefaultOptions>(\n 'mtx-grid-default-options'\n);\n\n@Component({\n selector: 'mtx-grid',\n exportAs: 'mtxGrid',\n templ