@dragonworks/ngx-dashboard 21.1.1 → 21.2.1

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.
@@ -23,7 +23,7 @@ import { isPlatformBrowser } from '@angular/common';
23
23
 
24
24
  // Auto-generated by scripts/generate-versions.js
25
25
  // Do not edit manually
26
- const NGX_DASHBOARD_VERSION = '21.1.1';
26
+ const NGX_DASHBOARD_VERSION = '21.2.1';
27
27
 
28
28
  /**
29
29
  * Maximum number of columns supported by the grid.
@@ -242,14 +242,14 @@ class UnknownWidgetComponent {
242
242
  dashboardGetState() {
243
243
  return this.state();
244
244
  }
245
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UnknownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
246
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: UnknownWidgetComponent, isStandalone: true, selector: "lib-unknown-widget", ngImport: i0, template: `
245
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnknownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
246
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: UnknownWidgetComponent, isStandalone: true, selector: "lib-unknown-widget", ngImport: i0, template: `
247
247
  <div class="unknown-widget-container" [matTooltip]="tooltipText()">
248
248
  <mat-icon class="unknown-widget-icon">error_outline</mat-icon>
249
249
  </div>
250
250
  `, isInline: true, styles: [".unknown-widget-container{display:flex;align-items:center;justify-content:center;width:100%;height:100%;background-color:var(--mat-sys-error);border-radius:8px;container-type:size}.unknown-widget-icon{color:var(--mat-sys-on-error);font-size:clamp(12px,75cqmin,68px);width:clamp(12px,75cqmin,68px);height:clamp(12px,75cqmin,68px)}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
251
251
  }
252
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UnknownWidgetComponent, decorators: [{
252
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: UnknownWidgetComponent, decorators: [{
253
253
  type: Component,
254
254
  args: [{ selector: 'lib-unknown-widget', imports: [MatIconModule, MatTooltipModule], template: `
255
255
  <div class="unknown-widget-container" [matTooltip]="tooltipText()">
@@ -362,10 +362,10 @@ class DashboardService {
362
362
  }
363
363
  }
364
364
  }
365
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
366
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardService, providedIn: 'root' });
365
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
366
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardService, providedIn: 'root' });
367
367
  }
368
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardService, decorators: [{
368
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardService, decorators: [{
369
369
  type: Injectable,
370
370
  args: [{
371
371
  providedIn: 'root',
@@ -1087,8 +1087,14 @@ withMethods((store) => ({
1087
1087
  };
1088
1088
  widgetsById[WidgetIdUtils.toString(widgetId)] = cell;
1089
1089
  });
1090
+ // Adopt the incoming dashboardId only on the initial load (when the
1091
+ // store's id is still empty). On subsequent imperative imports the
1092
+ // existing id is preserved so that bridge registration stays stable
1093
+ // and Export→Import across dashboards "just works" without requiring
1094
+ // consumers to rewrite the id in the file.
1095
+ const currentId = store.dashboardId();
1090
1096
  patchState(store, {
1091
- dashboardId: data.dashboardId,
1097
+ ...(currentId ? {} : { dashboardId: data.dashboardId }),
1092
1098
  rows: data.rows,
1093
1099
  columns: data.columns,
1094
1100
  gutterSize: data.gutterSize,
@@ -1137,8 +1143,8 @@ class CellSettingsDialogComponent {
1137
1143
  };
1138
1144
  this.dialogRef.close(newData);
1139
1145
  }
1140
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellSettingsDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1141
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: CellSettingsDialogComponent, isStandalone: true, selector: "lib-cell-settings-dialog", ngImport: i0, template: `
1146
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellSettingsDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1147
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: CellSettingsDialogComponent, isStandalone: true, selector: "lib-cell-settings-dialog", ngImport: i0, template: `
1142
1148
  <h2 mat-dialog-title i18n="@@ngx.dashboard.cell.settings.title">
1143
1149
  Cell Display Settings
1144
1150
  </h2>
@@ -1204,7 +1210,7 @@ class CellSettingsDialogComponent {
1204
1210
  </mat-dialog-actions>
1205
1211
  `, isInline: true, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden;padding-top:.5rem}.cell-info{margin:0 0 1.5rem;padding-bottom:1rem}.radio-group{width:100%}mat-radio-group{display:block}mat-radio-button{width:100%;display:block;margin-bottom:1rem}mat-radio-button:last-child{margin-bottom:0}.radio-option{margin-left:.75rem;padding:.25rem 0}.option-title{display:block;margin-bottom:.25rem}.option-description{display:block}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i4$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i4$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1206
1212
  }
1207
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellSettingsDialogComponent, decorators: [{
1213
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellSettingsDialogComponent, decorators: [{
1208
1214
  type: Component,
1209
1215
  args: [{ selector: 'lib-cell-settings-dialog', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1210
1216
  FormsModule,
@@ -1295,10 +1301,10 @@ class DefaultCellSettingsDialogProvider extends CellSettingsDialogProvider {
1295
1301
  const result = await firstValueFrom(dialogRef.afterClosed());
1296
1302
  return result;
1297
1303
  }
1298
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DefaultCellSettingsDialogProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1299
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DefaultCellSettingsDialogProvider, providedIn: 'root' });
1304
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DefaultCellSettingsDialogProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1305
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DefaultCellSettingsDialogProvider, providedIn: 'root' });
1300
1306
  }
1301
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DefaultCellSettingsDialogProvider, decorators: [{
1307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DefaultCellSettingsDialogProvider, decorators: [{
1302
1308
  type: Injectable,
1303
1309
  args: [{
1304
1310
  providedIn: 'root',
@@ -1330,10 +1336,10 @@ class CellContextMenuService {
1330
1336
  hide() {
1331
1337
  this.#activeMenu.set(null);
1332
1338
  }
1333
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1334
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellContextMenuService });
1339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1340
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellContextMenuService });
1335
1341
  }
1336
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellContextMenuService, decorators: [{
1342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellContextMenuService, decorators: [{
1337
1343
  type: Injectable
1338
1344
  }] });
1339
1345
 
@@ -1618,10 +1624,10 @@ class CellComponent {
1618
1624
  // Fall back to stored state if widget doesn't implement dashboardGetState
1619
1625
  return this.widgetState();
1620
1626
  }
1621
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1622
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: CellComponent, isStandalone: true, selector: "lib-cell", inputs: { widgetId: { classPropertyName: "widgetId", publicName: "widgetId", isSignal: true, isRequired: true, transformFunction: null }, cellId: { classPropertyName: "cellId", publicName: "cellId", isSignal: true, isRequired: true, transformFunction: null }, widgetFactory: { classPropertyName: "widgetFactory", publicName: "widgetFactory", isSignal: true, isRequired: false, transformFunction: null }, widgetState: { classPropertyName: "widgetState", publicName: "widgetState", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, rowSpan: { classPropertyName: "rowSpan", publicName: "rowSpan", isSignal: true, isRequired: false, transformFunction: null }, colSpan: { classPropertyName: "colSpan", publicName: "colSpan", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { row: "rowChange", column: "columnChange", dragStart: "dragStart", dragEnd: "dragEnd", edit: "edit", delete: "delete", settings: "settings", resizeStart: "resizeStart", resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { properties: { "style.grid-row": "gridRowStyle()", "style.grid-column": "gridColumnStyle()", "class.is-dragging": "isDragging()", "class.drag-active": "isDragActive()", "class.flat": "flat() === true" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":host{display:block;width:100%;height:100%;position:relative;z-index:1;container-type:inline-size}:host(.drag-active):not(.is-dragging){pointer-events:none}:host(.is-dragging){z-index:100;opacity:.5;pointer-events:none}:host(.is-dragging) .content-area{pointer-events:none}:host(:hover) .resize-handle{opacity:1}.cell{width:100%;height:100%;border-radius:4px;box-shadow:0 2px 6px #0000001a;padding:0;box-sizing:border-box;overflow:hidden;position:relative;container-type:inline-size}.cell:hover{box-shadow:0 4px 10px #00000026;transform:translateY(-2px)}.cell.flat{box-shadow:none;border:none}.cell.flat:hover{box-shadow:none;transform:none;border-color:#bdbdbd}.cell.resizing{-webkit-user-select:none;user-select:none}.content-area{width:100%;height:100%;overflow:auto;pointer-events:auto;position:relative;z-index:1}.content-area:hover{transform:initial}:host(:not(.is-dragging)) .cell.flat .content-area{pointer-events:auto}:host(:not(.is-dragging)) .cell.flat .content-area:hover{transform:initial}.resize-handle{position:absolute;z-index:20}.resize-handle--right{cursor:col-resize;width:16px;height:100%;right:-8px;top:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--right:hover{opacity:1}.resize-handle--right:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle--bottom{cursor:row-resize;width:100%;height:16px;bottom:-8px;left:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--bottom:hover{opacity:1}.resize-handle--bottom:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle-line{background-color:#0000001a}.resize-handle--right .resize-handle-line{width:8px;height:40px;border-radius:2px}.resize-handle--bottom .resize-handle-line{width:40px;height:8px;border-radius:2px}.resize-preview{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary);padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;z-index:30}.cell.is-resizing{opacity:.6}.cell.is-resizing .resize-handle{background-color:#2196f380}:root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1627
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1628
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CellComponent, isStandalone: true, selector: "lib-cell", inputs: { widgetId: { classPropertyName: "widgetId", publicName: "widgetId", isSignal: true, isRequired: true, transformFunction: null }, cellId: { classPropertyName: "cellId", publicName: "cellId", isSignal: true, isRequired: true, transformFunction: null }, widgetFactory: { classPropertyName: "widgetFactory", publicName: "widgetFactory", isSignal: true, isRequired: false, transformFunction: null }, widgetState: { classPropertyName: "widgetState", publicName: "widgetState", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, rowSpan: { classPropertyName: "rowSpan", publicName: "rowSpan", isSignal: true, isRequired: false, transformFunction: null }, colSpan: { classPropertyName: "colSpan", publicName: "colSpan", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { row: "rowChange", column: "columnChange", dragStart: "dragStart", dragEnd: "dragEnd", edit: "edit", delete: "delete", settings: "settings", resizeStart: "resizeStart", resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { properties: { "style.grid-row": "gridRowStyle()", "style.grid-column": "gridColumnStyle()", "class.is-dragging": "isDragging()", "class.drag-active": "isDragActive()", "class.flat": "flat() === true" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":host{display:block;width:100%;height:100%;position:relative;z-index:1;container-type:inline-size}:host(.drag-active):not(.is-dragging){pointer-events:none}:host(.is-dragging){z-index:100;opacity:.5;pointer-events:none}:host(.is-dragging) .content-area{pointer-events:none}:host(:hover) .resize-handle{opacity:1}.cell{width:100%;height:100%;border-radius:4px;box-shadow:0 2px 6px #0000001a;padding:0;box-sizing:border-box;overflow:hidden;position:relative;container-type:inline-size}.cell:hover{box-shadow:0 4px 10px #00000026;transform:translateY(-2px)}.cell.flat{box-shadow:none;border:none}.cell.flat:hover{box-shadow:none;transform:none;border-color:#bdbdbd}.cell.resizing{-webkit-user-select:none;user-select:none}.content-area{width:100%;height:100%;overflow:auto;pointer-events:auto;position:relative;z-index:1}.content-area:hover{transform:initial}:host(:not(.is-dragging)) .cell.flat .content-area{pointer-events:auto}:host(:not(.is-dragging)) .cell.flat .content-area:hover{transform:initial}.resize-handle{position:absolute;z-index:20}.resize-handle--right{cursor:col-resize;width:16px;height:100%;right:-8px;top:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--right:hover{opacity:1}.resize-handle--right:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle--bottom{cursor:row-resize;width:100%;height:16px;bottom:-8px;left:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--bottom:hover{opacity:1}.resize-handle--bottom:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle-line{background-color:#0000001a}.resize-handle--right .resize-handle-line{width:8px;height:40px;border-radius:2px}.resize-handle--bottom .resize-handle-line{width:40px;height:8px;border-radius:2px}.resize-preview{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary);padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;z-index:30}.cell.is-resizing{opacity:.6}.cell.is-resizing .resize-handle{background-color:#2196f380}:root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1623
1629
  }
1624
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellComponent, decorators: [{
1630
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellComponent, decorators: [{
1625
1631
  type: Component,
1626
1632
  args: [{ selector: 'lib-cell', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1627
1633
  '[style.grid-row]': 'gridRowStyle()',
@@ -1632,6 +1638,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1632
1638
  }, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":host{display:block;width:100%;height:100%;position:relative;z-index:1;container-type:inline-size}:host(.drag-active):not(.is-dragging){pointer-events:none}:host(.is-dragging){z-index:100;opacity:.5;pointer-events:none}:host(.is-dragging) .content-area{pointer-events:none}:host(:hover) .resize-handle{opacity:1}.cell{width:100%;height:100%;border-radius:4px;box-shadow:0 2px 6px #0000001a;padding:0;box-sizing:border-box;overflow:hidden;position:relative;container-type:inline-size}.cell:hover{box-shadow:0 4px 10px #00000026;transform:translateY(-2px)}.cell.flat{box-shadow:none;border:none}.cell.flat:hover{box-shadow:none;transform:none;border-color:#bdbdbd}.cell.resizing{-webkit-user-select:none;user-select:none}.content-area{width:100%;height:100%;overflow:auto;pointer-events:auto;position:relative;z-index:1}.content-area:hover{transform:initial}:host(:not(.is-dragging)) .cell.flat .content-area{pointer-events:auto}:host(:not(.is-dragging)) .cell.flat .content-area:hover{transform:initial}.resize-handle{position:absolute;z-index:20}.resize-handle--right{cursor:col-resize;width:16px;height:100%;right:-8px;top:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--right:hover{opacity:1}.resize-handle--right:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle--bottom{cursor:row-resize;width:100%;height:16px;bottom:-8px;left:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--bottom:hover{opacity:1}.resize-handle--bottom:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle-line{background-color:#0000001a}.resize-handle--right .resize-handle-line{width:8px;height:40px;border-radius:2px}.resize-handle--bottom .resize-handle-line{width:40px;height:8px;border-radius:2px}.resize-preview{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary);padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;z-index:30}.cell.is-resizing{opacity:.6}.cell.is-resizing .resize-handle{background-color:#2196f380}:root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}\n"] }]
1633
1639
  }], ctorParameters: () => [], propDecorators: { widgetId: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetId", required: true }] }], cellId: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellId", required: true }] }], widgetFactory: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetFactory", required: false }] }], widgetState: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetState", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: false }] }], flat: [{ type: i0.Input, args: [{ isSignal: true, alias: "flat", required: false }] }], row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }, { type: i0.Output, args: ["rowChange"] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }, { type: i0.Output, args: ["columnChange"] }], rowSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSpan", required: false }] }], colSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "colSpan", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], dragStart: [{ type: i0.Output, args: ["dragStart"] }], dragEnd: [{ type: i0.Output, args: ["dragEnd"] }], edit: [{ type: i0.Output, args: ["edit"] }], delete: [{ type: i0.Output, args: ["delete"] }], settings: [{ type: i0.Output, args: ["settings"] }], resizeStart: [{ type: i0.Output, args: ["resizeStart"] }], resizeMove: [{ type: i0.Output, args: ["resizeMove"] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], container: [{ type: i0.ViewChild, args: ['container', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
1634
1640
 
1641
+ /**
1642
+ * Map SelectionModifier values to KeyboardEvent.key values. Compared against
1643
+ * `event.key` directly (rather than the boolean `*Key` flags) so unrelated
1644
+ * keypresses while a modifier is held don't flip the modifier-held state.
1645
+ */
1646
+ const MODIFIER_KEY = {
1647
+ shift: 'Shift',
1648
+ ctrl: 'Control',
1649
+ alt: 'Alt',
1650
+ meta: 'Meta',
1651
+ };
1635
1652
  class DashboardViewerComponent {
1636
1653
  #store = inject(DashboardStore);
1637
1654
  #renderer = inject(Renderer2);
@@ -1644,6 +1661,16 @@ class DashboardViewerComponent {
1644
1661
  gutters = computed(() => this.columns() + 1, ...(ngDevMode ? [{ debugName: "gutters" }] : /* istanbul ignore next */ []));
1645
1662
  // Selection feature
1646
1663
  enableSelection = input(false, ...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
1664
+ selectionModifier = input(null, ...(ngDevMode ? [{ debugName: "selectionModifier" }] : /* istanbul ignore next */ []));
1665
+ /**
1666
+ * Minimum pointer movement (in CSS pixels) between pointerdown and
1667
+ * pointerup required to emit `selectionComplete`. Below the threshold,
1668
+ * the gesture is treated as a click and no event is emitted.
1669
+ *
1670
+ * Default 4 — matches OS-native click-vs-drag thresholds. Set to 0 to
1671
+ * preserve the legacy behavior where every pointerup emits.
1672
+ */
1673
+ dragThreshold = input(4, ...(ngDevMode ? [{ debugName: "dragThreshold" }] : /* istanbul ignore next */ []));
1647
1674
  selectionComplete = output();
1648
1675
  // store signals - read-only
1649
1676
  cells = this.#store.cells;
@@ -1651,6 +1678,23 @@ class DashboardViewerComponent {
1651
1678
  isSelecting = signal(false, ...(ngDevMode ? [{ debugName: "isSelecting" }] : /* istanbul ignore next */ []));
1652
1679
  selectionStart = signal(null, ...(ngDevMode ? [{ debugName: "selectionStart" }] : /* istanbul ignore next */ []));
1653
1680
  selectionCurrent = signal(null, ...(ngDevMode ? [{ debugName: "selectionCurrent" }] : /* istanbul ignore next */ []));
1681
+ // Modifier-key gating state for selectionModifier
1682
+ #modifierHeld = signal(false, ...(ngDevMode ? [{ debugName: "#modifierHeld" }] : /* istanbul ignore next */ []));
1683
+ /**
1684
+ * Whether the selection overlay is currently interactive (intercepts
1685
+ * pointer events). Always false when `enableSelection` is false.
1686
+ * When `selectionModifier` is null, true whenever selection is enabled
1687
+ * (legacy behavior). Otherwise, true only while the configured modifier
1688
+ * is held or a drag is in progress (which keeps the overlay armed
1689
+ * across mid-drag modifier release).
1690
+ */
1691
+ armed = computed(() => {
1692
+ if (!this.enableSelection())
1693
+ return false;
1694
+ if (this.selectionModifier() === null)
1695
+ return true;
1696
+ return this.#modifierHeld() || this.isSelecting();
1697
+ }, ...(ngDevMode ? [{ debugName: "armed" }] : /* istanbul ignore next */ []));
1654
1698
  // Computed selection bounds (normalized)
1655
1699
  selectionBounds = computed(() => {
1656
1700
  const start = this.selectionStart();
@@ -1667,9 +1711,11 @@ class DashboardViewerComponent {
1667
1711
  // Generate array for template iteration
1668
1712
  rowNumbers = computed(() => Array.from({ length: this.rows() }, (_, i) => i + 1), ...(ngDevMode ? [{ debugName: "rowNumbers" }] : /* istanbul ignore next */ []));
1669
1713
  colNumbers = computed(() => Array.from({ length: this.columns() }, (_, i) => i + 1), ...(ngDevMode ? [{ debugName: "colNumbers" }] : /* istanbul ignore next */ []));
1670
- // Document-level event listeners (cleanup needed)
1671
- #mouseMoveListener;
1672
- #mouseUpListener;
1714
+ // Document-level pointer listeners (cleanup needed)
1715
+ #pointerMoveListener;
1716
+ #pointerUpListener;
1717
+ // Pointer position at the start of a drag, for dragThreshold checks
1718
+ #pointerDownPos = signal(null, ...(ngDevMode ? [{ debugName: "#pointerDownPos" }] : /* istanbul ignore next */ []));
1673
1719
  constructor() {
1674
1720
  // Sync grid configuration with store when inputs change
1675
1721
  effect(() => {
@@ -1687,6 +1733,38 @@ class DashboardViewerComponent {
1687
1733
  this.isSelecting.set(false);
1688
1734
  }
1689
1735
  });
1736
+ // Modifier-key tracking. Only registers document/window listeners when a
1737
+ // modifier is configured, so dashboards using the default (null) pay no
1738
+ // global keystroke cost. Cleans up listeners and resets state on
1739
+ // modifier change or component teardown.
1740
+ effect((onCleanup) => {
1741
+ const modifier = this.selectionModifier();
1742
+ if (modifier === null) {
1743
+ this.#modifierHeld.set(false);
1744
+ return;
1745
+ }
1746
+ const keyName = MODIFIER_KEY[modifier];
1747
+ const offKeyDown = this.#renderer.listen('document', 'keydown', (event) => {
1748
+ if (event.key === keyName) {
1749
+ this.#modifierHeld.set(true);
1750
+ }
1751
+ });
1752
+ const offKeyUp = this.#renderer.listen('document', 'keyup', (event) => {
1753
+ if (event.key === keyName) {
1754
+ this.#modifierHeld.set(false);
1755
+ }
1756
+ });
1757
+ // Cover focus-loss cases where keyup may never fire (Alt-Tab, etc.)
1758
+ const offBlur = this.#renderer.listen('window', 'blur', () => {
1759
+ this.#modifierHeld.set(false);
1760
+ });
1761
+ onCleanup(() => {
1762
+ offKeyDown();
1763
+ offKeyUp();
1764
+ offBlur();
1765
+ this.#modifierHeld.set(false);
1766
+ });
1767
+ });
1690
1768
  }
1691
1769
  // Selection methods
1692
1770
  /**
@@ -1702,88 +1780,115 @@ class DashboardViewerComponent {
1702
1780
  col <= bounds.endCol);
1703
1781
  }
1704
1782
  /**
1705
- * Handle mouse down on ghost cell to start selection
1783
+ * Handle pointer down on a ghost cell to start a selection. Uses
1784
+ * PointerEvent so mouse / touch / pen all work uniformly.
1706
1785
  */
1707
- onGhostCellMouseDown(event, row, col) {
1708
- if (!this.enableSelection())
1786
+ onGhostCellPointerDown(event, row, col) {
1787
+ if (!this.armed())
1788
+ return;
1789
+ if (event.pointerType === 'mouse' && event.button !== 0)
1709
1790
  return;
1710
- if (event.button !== 0)
1711
- return; // Only left button
1712
1791
  event.preventDefault();
1713
1792
  event.stopPropagation();
1714
1793
  this.isSelecting.set(true);
1715
1794
  this.selectionStart.set({ row, col });
1716
1795
  this.selectionCurrent.set({ row, col });
1717
- // Add document-level listeners for drag
1718
- this.#mouseMoveListener = this.#renderer.listen('document', 'mousemove', () => this.onDocumentMouseMove());
1719
- this.#mouseUpListener = this.#renderer.listen('document', 'mouseup', () => this.onDocumentMouseUp());
1720
- // Register cleanup
1796
+ this.#pointerDownPos.set({ x: event.clientX, y: event.clientY });
1797
+ const target = event.target;
1798
+ if (target instanceof Element &&
1799
+ typeof target.setPointerCapture === 'function') {
1800
+ try {
1801
+ target.setPointerCapture(event.pointerId);
1802
+ }
1803
+ catch {
1804
+ // Capture may be rejected for synthetic / invalid pointer ids;
1805
+ // document-level listeners still receive bubbled events.
1806
+ }
1807
+ }
1808
+ this.#pointerMoveListener = this.#renderer.listen('document', 'pointermove', (e) => this.onDocumentPointerMove(e));
1809
+ this.#pointerUpListener = this.#renderer.listen('document', 'pointerup', (e) => this.onDocumentPointerUp(e));
1721
1810
  this.#destroyRef.onDestroy(() => {
1722
1811
  this.cleanupListeners();
1723
1812
  });
1724
1813
  }
1725
1814
  /**
1726
- * Handle mouse enter on ghost cell during selection
1815
+ * Track the pointer across cell boundaries during a drag.
1816
+ *
1817
+ * Replaces the old per-cell `mouseenter` handler. Necessary because
1818
+ * pointer capture and (on touch) coalesced events make boundary
1819
+ * crossings unreliable when relying on per-element enter events.
1727
1820
  */
1728
- onGhostCellMouseEnter(row, col) {
1821
+ onDocumentPointerMove(event) {
1729
1822
  if (!this.isSelecting())
1730
1823
  return;
1731
- this.selectionCurrent.set({ row, col });
1732
- }
1733
- /**
1734
- * Handle document mouse move during selection
1735
- */
1736
- onDocumentMouseMove() {
1737
- if (!this.isSelecting())
1824
+ const el = document.elementFromPoint(event.clientX, event.clientY);
1825
+ const cell = el?.closest('.selection-ghost-cell');
1826
+ if (!cell)
1827
+ return;
1828
+ const row = Number(cell.dataset['row']);
1829
+ const col = Number(cell.dataset['col']);
1830
+ if (!Number.isFinite(row) || !Number.isFinite(col))
1738
1831
  return;
1739
- // The actual selection update is handled by onGhostCellMouseEnter
1740
- // This just ensures we capture the event
1832
+ // Skip updates while still inside the same cell — otherwise pointermove
1833
+ // (60–120 Hz) would re-emit a fresh object reference every frame and
1834
+ // trigger downstream rerenders across the whole overlay grid.
1835
+ const cur = this.selectionCurrent();
1836
+ if (cur && cur.row === row && cur.col === col)
1837
+ return;
1838
+ this.selectionCurrent.set({ row, col });
1741
1839
  }
1742
1840
  /**
1743
- * Handle document mouse up to complete selection
1841
+ * Complete a selection on pointerup. Emits `selectionComplete` only when
1842
+ * total pointer movement meets `dragThreshold` — sub-threshold gestures
1843
+ * are treated as clicks and discarded.
1744
1844
  */
1745
- onDocumentMouseUp() {
1845
+ onDocumentPointerUp(event) {
1746
1846
  if (!this.isSelecting())
1747
1847
  return;
1748
1848
  this.isSelecting.set(false);
1749
- // Emit selection event
1750
- const bounds = this.selectionBounds();
1751
- if (bounds) {
1752
- this.selectionComplete.emit({
1753
- topLeft: { row: bounds.startRow, col: bounds.startCol },
1754
- bottomRight: { row: bounds.endRow, col: bounds.endCol },
1755
- });
1849
+ const start = this.#pointerDownPos();
1850
+ const moved = start === null ||
1851
+ Math.hypot(event.clientX - start.x, event.clientY - start.y) >=
1852
+ this.dragThreshold();
1853
+ if (moved) {
1854
+ const bounds = this.selectionBounds();
1855
+ if (bounds) {
1856
+ this.selectionComplete.emit({
1857
+ topLeft: { row: bounds.startRow, col: bounds.startCol },
1858
+ bottomRight: { row: bounds.endRow, col: bounds.endCol },
1859
+ });
1860
+ }
1756
1861
  }
1757
- // Clean up listeners
1862
+ this.#pointerDownPos.set(null);
1758
1863
  this.cleanupListeners();
1759
- // Don't clear selection - let the parent control when to clear
1760
- // Selection remains visible until enableSelection becomes false
1864
+ // Don't clear selection - let the parent control when to clear.
1865
+ // Selection remains visible until enableSelection becomes false.
1761
1866
  }
1762
1867
  /**
1763
1868
  * Clean up document-level event listeners
1764
1869
  */
1765
1870
  cleanupListeners() {
1766
- if (this.#mouseMoveListener) {
1767
- this.#mouseMoveListener();
1768
- this.#mouseMoveListener = undefined;
1871
+ if (this.#pointerMoveListener) {
1872
+ this.#pointerMoveListener();
1873
+ this.#pointerMoveListener = undefined;
1769
1874
  }
1770
- if (this.#mouseUpListener) {
1771
- this.#mouseUpListener();
1772
- this.#mouseUpListener = undefined;
1875
+ if (this.#pointerUpListener) {
1876
+ this.#pointerUpListener();
1877
+ this.#pointerUpListener = undefined;
1773
1878
  }
1774
1879
  }
1775
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1776
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DashboardViewerComponent, isStandalone: true, selector: "ngx-dashboard-viewer", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }, { propertyName: "gridElement", first: true, predicate: ["gridElement"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n (mousedown)=\"onGhostCellMouseDown($event, row, col)\"\n (mouseenter)=\"onGhostCellMouseEnter(row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:auto;-webkit-user-select:none;user-select:none}.selection-ghost-cell{cursor:crosshair;transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell:hover:not(.selecting){background-color:var(--mat-sys-primary);opacity:.08}.selection-ghost-cell.selected{background-color:var(--mat-sys-primary);opacity:.25;border-radius:4px}.selection-ghost-cell.selecting{cursor:crosshair}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1880
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1881
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardViewerComponent, isStandalone: true, selector: "ngx-dashboard-viewer", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, selectionModifier: { classPropertyName: "selectionModifier", publicName: "selectionModifier", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }, { propertyName: "gridElement", first: true, predicate: ["gridElement"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\" [class.armed]=\"armed()\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n [attr.data-row]=\"row\"\n [attr.data-col]=\"col\"\n (pointerdown)=\"onGhostCellPointerDown($event, row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:none;-webkit-user-select:none;user-select:none}.selection-overlay-grid.armed{pointer-events:auto}.selection-ghost-cell{transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell.selected{background-color:var(--mat-sys-primary);opacity:.25;border-radius:4px}.selection-overlay-grid.armed .selection-ghost-cell{cursor:crosshair}.selection-overlay-grid.armed .selection-ghost-cell:hover:not(.selecting){background-color:var(--mat-sys-primary);opacity:.08}.selection-overlay-grid.armed .selection-ghost-cell.selecting{cursor:crosshair}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1777
1882
  }
1778
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardViewerComponent, decorators: [{
1883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewerComponent, decorators: [{
1779
1884
  type: Component,
1780
1885
  args: [{ selector: 'ngx-dashboard-viewer', standalone: true, imports: [CellComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1781
1886
  '[style.--rows]': 'rows()',
1782
1887
  '[style.--columns]': 'columns()',
1783
1888
  '[style.--gutter-size]': 'gutterSize()',
1784
1889
  '[style.--gutters]': 'gutters()',
1785
- }, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n (mousedown)=\"onGhostCellMouseDown($event, row, col)\"\n (mouseenter)=\"onGhostCellMouseEnter(row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:auto;-webkit-user-select:none;user-select:none}.selection-ghost-cell{cursor:crosshair;transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell:hover:not(.selecting){background-color:var(--mat-sys-primary);opacity:.08}.selection-ghost-cell.selected{background-color:var(--mat-sys-primary);opacity:.25;border-radius:4px}.selection-ghost-cell.selecting{cursor:crosshair}\n"] }]
1786
- }], ctorParameters: () => [], propDecorators: { cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CellComponent), { isSignal: true }] }], gridElement: [{ type: i0.ViewChild, args: ['gridElement', { isSignal: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }] } });
1890
+ }, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\" [class.armed]=\"armed()\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n [attr.data-row]=\"row\"\n [attr.data-col]=\"col\"\n (pointerdown)=\"onGhostCellPointerDown($event, row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:none;-webkit-user-select:none;user-select:none}.selection-overlay-grid.armed{pointer-events:auto}.selection-ghost-cell{transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell.selected{background-color:var(--mat-sys-primary);opacity:.25;border-radius:4px}.selection-overlay-grid.armed .selection-ghost-cell{cursor:crosshair}.selection-overlay-grid.armed .selection-ghost-cell:hover:not(.selecting){background-color:var(--mat-sys-primary);opacity:.08}.selection-overlay-grid.armed .selection-ghost-cell.selecting{cursor:crosshair}\n"] }]
1891
+ }], ctorParameters: () => [], propDecorators: { cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CellComponent), { isSignal: true }] }], gridElement: [{ type: i0.ViewChild, args: ['gridElement', { isSignal: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionModifier", required: false }] }], dragThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragThreshold", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }] } });
1787
1892
 
1788
1893
  class CellContextMenuComponent {
1789
1894
  menuTrigger = viewChild.required('menuTrigger', { read: MatMenuTrigger });
@@ -1858,8 +1963,8 @@ class CellContextMenuComponent {
1858
1963
  this.menuService.hide();
1859
1964
  }
1860
1965
  }
1861
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1862
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: CellContextMenuComponent, isStandalone: true, selector: "lib-cell-context-menu", viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: ["menuTrigger"], descendants: true, read: MatMenuTrigger, isSignal: true }], ngImport: i0, template: `
1966
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1967
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CellContextMenuComponent, isStandalone: true, selector: "lib-cell-context-menu", viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: ["menuTrigger"], descendants: true, read: MatMenuTrigger, isSignal: true }], ngImport: i0, template: `
1863
1968
  <!-- Hidden trigger for menu positioned at exact mouse coordinates
1864
1969
 
1865
1970
  IMPORTANT: Angular Material applies its own positioning logic to menus,
@@ -1913,7 +2018,7 @@ class CellContextMenuComponent {
1913
2018
  </mat-menu>
1914
2019
  `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1915
2020
  }
1916
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CellContextMenuComponent, decorators: [{
2021
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CellContextMenuComponent, decorators: [{
1917
2022
  type: Component,
1918
2023
  args: [{ selector: 'lib-cell-context-menu', standalone: true, imports: [MatMenuModule, MatIconModule, MatDividerModule, MatButtonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1919
2024
  <!-- Hidden trigger for menu positioned at exact mouse coordinates
@@ -2004,10 +2109,10 @@ class DefaultEmptyCellContextProvider extends EmptyCellContextProvider {
2004
2109
  handleEmptyCellContext() {
2005
2110
  // Default behavior: do nothing
2006
2111
  }
2007
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DefaultEmptyCellContextProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2008
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DefaultEmptyCellContextProvider, providedIn: 'root' });
2112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DefaultEmptyCellContextProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2113
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DefaultEmptyCellContextProvider, providedIn: 'root' });
2009
2114
  }
2010
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DefaultEmptyCellContextProvider, decorators: [{
2115
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DefaultEmptyCellContextProvider, decorators: [{
2011
2116
  type: Injectable,
2012
2117
  args: [{
2013
2118
  providedIn: 'root',
@@ -2071,10 +2176,10 @@ class EmptyCellContextMenuService {
2071
2176
  setLastSelection(widgetTypeId) {
2072
2177
  this.#lastSelectedWidgetTypeId.set(widgetTypeId);
2073
2178
  }
2074
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyCellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2075
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyCellContextMenuService, providedIn: 'root' });
2179
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EmptyCellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2180
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EmptyCellContextMenuService, providedIn: 'root' });
2076
2181
  }
2077
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyCellContextMenuService, decorators: [{
2182
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EmptyCellContextMenuService, decorators: [{
2078
2183
  type: Injectable,
2079
2184
  args: [{
2080
2185
  providedIn: 'root',
@@ -2189,10 +2294,10 @@ class WidgetListContextMenuProvider extends EmptyCellContextProvider {
2189
2294
  'Ensure you are using a compatible version of the dashboard component.');
2190
2295
  }
2191
2296
  }
2192
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WidgetListContextMenuProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2193
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WidgetListContextMenuProvider });
2297
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WidgetListContextMenuProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2298
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WidgetListContextMenuProvider });
2194
2299
  }
2195
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WidgetListContextMenuProvider, decorators: [{
2300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WidgetListContextMenuProvider, decorators: [{
2196
2301
  type: Injectable
2197
2302
  }] });
2198
2303
 
@@ -2305,10 +2410,10 @@ class DropZoneComponent {
2305
2410
  });
2306
2411
  }
2307
2412
  }
2308
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DropZoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2309
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DropZoneComponent, isStandalone: true, selector: "lib-drop-zone", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, col: { classPropertyName: "col", publicName: "col", isSignal: true, isRequired: true, transformFunction: null }, index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: true, transformFunction: null }, highlight: { classPropertyName: "highlight", publicName: "highlight", isSignal: true, isRequired: false, transformFunction: null }, highlightInvalid: { classPropertyName: "highlightInvalid", publicName: "highlightInvalid", isSignal: true, isRequired: false, transformFunction: null }, highlightResize: { classPropertyName: "highlightResize", publicName: "highlightResize", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragEnter: "dragEnter", dragExit: "dragExit", dragOver: "dragOver", dragDrop: "dragDrop" }, ngImport: i0, template: "<!-- drop-zone.component.html -->\n<div\n class=\"drop-zone\"\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\n [class.drop-zone--invalid]=\"highlightInvalid()\"\n [class.drop-zone--resize]=\"highlightResize()\"\n [style.grid-row]=\"row()\"\n [style.grid-column]=\"col()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n @if (editMode()) {\n <div class=\"edit-mode-cell-number\">\n {{ index() }}<br />\n {{ row() }},{{ col() }}\n </div>\n }\n</div>\n", styles: [".drop-zone{width:100%;height:100%;z-index:0;align-self:stretch;justify-self:stretch;display:block;box-sizing:border-box}.drop-zone--active,.drop-zone--highlight{background-color:#80808080}.drop-zone--invalid{background-color:light-dark(color-mix(in srgb,var(--mat-sys-error) 40%,white),color-mix(in srgb,var(--mat-sys-error) 80%,black))}.drop-zone--resize{background-color:#2196f34d;outline:1px solid rgba(33,150,243,.6)}.edit-mode-cell-number{font-size:10px;line-height:1.1;color:#64646499;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:-1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2413
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DropZoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2414
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DropZoneComponent, isStandalone: true, selector: "lib-drop-zone", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, col: { classPropertyName: "col", publicName: "col", isSignal: true, isRequired: true, transformFunction: null }, index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: true, transformFunction: null }, highlight: { classPropertyName: "highlight", publicName: "highlight", isSignal: true, isRequired: false, transformFunction: null }, highlightInvalid: { classPropertyName: "highlightInvalid", publicName: "highlightInvalid", isSignal: true, isRequired: false, transformFunction: null }, highlightResize: { classPropertyName: "highlightResize", publicName: "highlightResize", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragEnter: "dragEnter", dragExit: "dragExit", dragOver: "dragOver", dragDrop: "dragDrop" }, ngImport: i0, template: "<!-- drop-zone.component.html -->\n<div\n class=\"drop-zone\"\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\n [class.drop-zone--invalid]=\"highlightInvalid()\"\n [class.drop-zone--resize]=\"highlightResize()\"\n [style.grid-row]=\"row()\"\n [style.grid-column]=\"col()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n @if (editMode()) {\n <div class=\"edit-mode-cell-number\">\n {{ index() }}<br />\n {{ row() }},{{ col() }}\n </div>\n }\n</div>\n", styles: [".drop-zone{width:100%;height:100%;z-index:0;align-self:stretch;justify-self:stretch;display:block;box-sizing:border-box}.drop-zone--active,.drop-zone--highlight{background-color:#80808080}.drop-zone--invalid{background-color:light-dark(color-mix(in srgb,var(--mat-sys-error) 40%,white),color-mix(in srgb,var(--mat-sys-error) 80%,black))}.drop-zone--resize{background-color:#2196f34d;outline:1px solid rgba(33,150,243,.6)}.edit-mode-cell-number{font-size:10px;line-height:1.1;color:#64646499;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:-1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2310
2415
  }
2311
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DropZoneComponent, decorators: [{
2416
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DropZoneComponent, decorators: [{
2312
2417
  type: Component,
2313
2418
  args: [{ selector: 'lib-drop-zone', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- drop-zone.component.html -->\n<div\n class=\"drop-zone\"\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\n [class.drop-zone--invalid]=\"highlightInvalid()\"\n [class.drop-zone--resize]=\"highlightResize()\"\n [style.grid-row]=\"row()\"\n [style.grid-column]=\"col()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n @if (editMode()) {\n <div class=\"edit-mode-cell-number\">\n {{ index() }}<br />\n {{ row() }},{{ col() }}\n </div>\n }\n</div>\n", styles: [".drop-zone{width:100%;height:100%;z-index:0;align-self:stretch;justify-self:stretch;display:block;box-sizing:border-box}.drop-zone--active,.drop-zone--highlight{background-color:#80808080}.drop-zone--invalid{background-color:light-dark(color-mix(in srgb,var(--mat-sys-error) 40%,white),color-mix(in srgb,var(--mat-sys-error) 80%,black))}.drop-zone--resize{background-color:#2196f34d;outline:1px solid rgba(33,150,243,.6)}.edit-mode-cell-number{font-size:10px;line-height:1.1;color:#64646499;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:-1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;height:100%}\n"] }]
2314
2419
  }], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], col: [{ type: i0.Input, args: [{ isSignal: true, alias: "col", required: true }] }], index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: true }] }], highlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlight", required: false }] }], highlightInvalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightInvalid", required: false }] }], highlightResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightResize", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], dragEnter: [{ type: i0.Output, args: ["dragEnter"] }], dragExit: [{ type: i0.Output, args: ["dragExit"] }], dragOver: [{ type: i0.Output, args: ["dragOver"] }], dragDrop: [{ type: i0.Output, args: ["dragDrop"] }] } });
@@ -2409,8 +2514,8 @@ class EmptyCellContextMenuComponent {
2409
2514
  sanitizeSvg(svg) {
2410
2515
  return this.#sanitizer.bypassSecurityTrustHtml(svg);
2411
2516
  }
2412
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyCellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2413
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: EmptyCellContextMenuComponent, isStandalone: true, selector: "lib-empty-cell-context-menu", viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: ["menuTrigger"], descendants: true, read: MatMenuTrigger, isSignal: true }], ngImport: i0, template: `
2517
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EmptyCellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2518
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: EmptyCellContextMenuComponent, isStandalone: true, selector: "lib-empty-cell-context-menu", viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: ["menuTrigger"], descendants: true, read: MatMenuTrigger, isSignal: true }], ngImport: i0, template: `
2414
2519
  <!-- Hidden trigger for menu positioned at exact mouse coordinates
2415
2520
 
2416
2521
  IMPORTANT: Angular Material applies its own positioning logic to menus,
@@ -2470,7 +2575,7 @@ class EmptyCellContextMenuComponent {
2470
2575
  </mat-menu>
2471
2576
  `, isInline: true, styles: [":host{display:contents}.empty-cell-widget-menu{max-height:400px;overflow-y:auto}.widget-icon{width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;vertical-align:middle}.widget-icon :deep(svg){width:20px;height:20px;fill:currentColor}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2472
2577
  }
2473
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyCellContextMenuComponent, decorators: [{
2578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EmptyCellContextMenuComponent, decorators: [{
2474
2579
  type: Component,
2475
2580
  args: [{ selector: 'lib-empty-cell-context-menu', standalone: true, imports: [
2476
2581
  MatMenuModule,
@@ -2643,12 +2748,12 @@ class DashboardEditorComponent {
2643
2748
  this.#store.handleDrop(event.data, event.target);
2644
2749
  // Note: Store handles all validation and error handling internally
2645
2750
  }
2646
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2647
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DashboardEditorComponent, isStandalone: true, selector: "ngx-dashboard-editor", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()", "class.is-edit-mode": "true" } }, providers: [
2751
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2752
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardEditorComponent, isStandalone: true, selector: "ngx-dashboard-editor", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()", "class.is-edit-mode": "true" } }, providers: [
2648
2753
  CellContextMenuService,
2649
2754
  ], viewQueries: [{ propertyName: "bottomGridRef", first: true, predicate: ["bottomGrid"], descendants: true, isSignal: true }, { propertyName: "dropZones", predicate: DropZoneComponent, descendants: true, isSignal: true }, { propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- dashboard-editor.component.html -->\n<div class=\"grid-container\">\n <!-- Bottom grid with drop zones -->\n <div class=\"grid\" id=\"bottom-grid\" #bottomGrid>\n @for (position of dropzonePositions(); track position.id) {\n <lib-drop-zone\n class=\"drop-zone\"\n [row]=\"position.row\"\n [col]=\"position.col\"\n [index]=\"position.index\"\n [highlight]=\"highlightMap().has(createCellId(position.row, position.col))\"\n [highlightInvalid]=\"\n invalidHighlightMap().has(createCellId(position.row, position.col))\n \"\n [highlightResize]=\"\n resizePreviewMap().has(createCellId(position.row, position.col))\n \"\n [editMode]=\"true\"\n (dragEnter)=\"onDragEnter($event)\"\n (dragExit)=\"onDragExit()\"\n (dragOver)=\"onDragOver($event)\"\n (dragDrop)=\"onDragDrop($event)\"\n ></lib-drop-zone>\n }\n </div>\n\n <!-- Top grid with interactive cells -->\n <div class=\"grid\" id=\"top-grid\">\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"true\"\n [draggable]=\"true\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n (dragStart)=\"onCellDragStart($event)\"\n (dragEnd)=\"dragEnd()\"\n (delete)=\"onCellDelete($event)\"\n (settings)=\"onCellSettings($event)\"\n (resizeStart)=\"onCellResizeStart($event)\"\n (resizeMove)=\"onCellResizeMove($event)\"\n (resizeEnd)=\"onCellResizeEnd($event)\"\n >\n </lib-cell>\n }\n </div>\n</div>\n\n<!-- Context menus -->\n<lib-cell-context-menu></lib-cell-context-menu>\n<lib-empty-cell-context-menu></lib-empty-cell-context-menu>\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}:host .grid{background-image:linear-gradient(to right,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px);background-size:var(--tile-size) var(--tile-size),var(--tile-size) var(--tile-size),100% 1px;background-position:var(--tile-offset) var(--tile-offset),var(--tile-offset) var(--tile-offset),bottom;background-repeat:repeat,repeat,no-repeat}.grid-container{position:relative;width:100%;height:100%}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);position:absolute;inset:0;width:100%;height:100%;box-sizing:border-box;align-items:stretch;justify-items:stretch;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}#bottom-grid{z-index:1}#top-grid{z-index:2;pointer-events:none}.grid-cell{pointer-events:auto}.grid-cell.is-dragging{pointer-events:none;opacity:.5}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }, { kind: "component", type: DropZoneComponent, selector: "lib-drop-zone", inputs: ["row", "col", "index", "highlight", "highlightInvalid", "highlightResize", "editMode"], outputs: ["dragEnter", "dragExit", "dragOver", "dragDrop"] }, { kind: "component", type: CellContextMenuComponent, selector: "lib-cell-context-menu" }, { kind: "component", type: EmptyCellContextMenuComponent, selector: "lib-empty-cell-context-menu" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2650
2755
  }
2651
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardEditorComponent, decorators: [{
2756
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardEditorComponent, decorators: [{
2652
2757
  type: Component,
2653
2758
  args: [{ selector: 'ngx-dashboard-editor', standalone: true, imports: [
2654
2759
  CellComponent,
@@ -2792,10 +2897,10 @@ class DashboardBridgeService {
2792
2897
  getAllDashboards() {
2793
2898
  return this.dashboards();
2794
2899
  }
2795
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2796
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardBridgeService, providedIn: 'root' });
2900
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2901
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardBridgeService, providedIn: 'root' });
2797
2902
  }
2798
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardBridgeService, decorators: [{
2903
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardBridgeService, decorators: [{
2799
2904
  type: Injectable,
2800
2905
  args: [{ providedIn: 'root' }]
2801
2906
  }] });
@@ -2911,10 +3016,10 @@ class DashboardViewportService {
2911
3016
  constrainedBy
2912
3017
  };
2913
3018
  }, ...(ngDevMode ? [{ debugName: "constraints" }] : /* istanbul ignore next */ []));
2914
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2915
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardViewportService });
3019
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3020
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewportService });
2916
3021
  }
2917
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardViewportService, decorators: [{
3022
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewportService, decorators: [{
2918
3023
  type: Injectable
2919
3024
  }], ctorParameters: () => [] });
2920
3025
 
@@ -2936,6 +3041,8 @@ class DashboardComponent {
2936
3041
  editMode = input(false, ...(ngDevMode ? [{ debugName: "editMode" }] : /* istanbul ignore next */ []));
2937
3042
  reservedSpace = input(...(ngDevMode ? [undefined, { debugName: "reservedSpace" }] : /* istanbul ignore next */ []));
2938
3043
  enableSelection = input(false, ...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
3044
+ selectionModifier = input(null, ...(ngDevMode ? [{ debugName: "selectionModifier" }] : /* istanbul ignore next */ []));
3045
+ dragThreshold = input(4, ...(ngDevMode ? [{ debugName: "dragThreshold" }] : /* istanbul ignore next */ []));
2939
3046
  // Component outputs
2940
3047
  selectionComplete = output();
2941
3048
  // Store signals - shared by both child components
@@ -2952,10 +3059,12 @@ class DashboardComponent {
2952
3059
  this.#destroyRef.onDestroy(() => {
2953
3060
  this.#bridge.unregisterDashboard(this.#store);
2954
3061
  });
2955
- // Initialize from dashboardData
3062
+ // Initialize from dashboardData. Only applies the first emission so that
3063
+ // subsequent re-emissions (e.g. from toSignal() on an HTTP observable)
3064
+ // don't silently overwrite an imperative loadDashboard() call.
2956
3065
  effect(() => {
2957
3066
  const data = this.dashboardData();
2958
- if (data) {
3067
+ if (data && !this.#isInitialized) {
2959
3068
  this.#store.loadDashboard(data);
2960
3069
  // Register with bridge service after dashboard ID is set
2961
3070
  this.#bridge.updateDashboardRegistration(this.#store);
@@ -3070,10 +3179,10 @@ class DashboardComponent {
3070
3179
  this.#isPreservingStates = false;
3071
3180
  }
3072
3181
  }
3073
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3074
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DashboardComponent, isStandalone: true, selector: "ngx-dashboard", inputs: { dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: true, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, reservedSpace: { classPropertyName: "reservedSpace", publicName: "reservedSpace", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "store.rows()", "style.--columns": "store.columns()", "style.--gutter-size": "store.gutterSize()", "style.--gutters": "store.columns() + 1", "class.is-edit-mode": "editMode()", "style.max-width.px": "viewport.constraints().maxWidth", "style.max-height.px": "viewport.constraints().maxHeight" } }, providers: [DashboardStore, DashboardViewportService], viewQueries: [{ propertyName: "dashboardEditor", first: true, predicate: DashboardEditorComponent, descendants: true, isSignal: true }, { propertyName: "dashboardViewer", first: true, predicate: DashboardViewerComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize", "enableSelection"], outputs: ["selectionComplete"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3182
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3183
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardComponent, isStandalone: true, selector: "ngx-dashboard", inputs: { dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: true, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, reservedSpace: { classPropertyName: "reservedSpace", publicName: "reservedSpace", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, selectionModifier: { classPropertyName: "selectionModifier", publicName: "selectionModifier", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "store.rows()", "style.--columns": "store.columns()", "style.--gutter-size": "store.gutterSize()", "style.--gutters": "store.columns() + 1", "class.is-edit-mode": "editMode()", "style.max-width.px": "viewport.constraints().maxWidth", "style.max-height.px": "viewport.constraints().maxHeight" } }, providers: [DashboardStore, DashboardViewportService], viewQueries: [{ propertyName: "dashboardEditor", first: true, predicate: DashboardEditorComponent, descendants: true, isSignal: true }, { propertyName: "dashboardViewer", first: true, predicate: DashboardViewerComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize", "enableSelection", "selectionModifier", "dragThreshold"], outputs: ["selectionComplete"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3075
3184
  }
3076
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardComponent, decorators: [{
3185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardComponent, decorators: [{
3077
3186
  type: Component,
3078
3187
  args: [{ selector: 'ngx-dashboard', standalone: true, imports: [DashboardViewerComponent, DashboardEditorComponent], providers: [DashboardStore, DashboardViewportService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
3079
3188
  '[style.--rows]': 'store.rows()',
@@ -3083,8 +3192,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3083
3192
  '[class.is-edit-mode]': 'editMode()',
3084
3193
  '[style.max-width.px]': 'viewport.constraints().maxWidth',
3085
3194
  '[style.max-height.px]': 'viewport.constraints().maxHeight',
3086
- }, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"] }]
3087
- }], ctorParameters: () => [], propDecorators: { dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: true }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], reservedSpace: [{ type: i0.Input, args: [{ isSignal: true, alias: "reservedSpace", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], dashboardEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardEditorComponent), { isSignal: true }] }], dashboardViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardViewerComponent), { isSignal: true }] }] } });
3195
+ }, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"] }]
3196
+ }], ctorParameters: () => [], propDecorators: { dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: true }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], reservedSpace: [{ type: i0.Input, args: [{ isSignal: true, alias: "reservedSpace", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionModifier", required: false }] }], dragThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragThreshold", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], dashboardEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardEditorComponent), { isSignal: true }] }], dashboardViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardViewerComponent), { isSignal: true }] }] } });
3088
3197
 
3089
3198
  // widget-list.component.ts
3090
3199
  class WidgetListComponent {
@@ -3152,10 +3261,10 @@ class WidgetListComponent {
3152
3261
  // Using $localize for the template pattern
3153
3262
  return $localize `:@@ngx.dashboard.widget.list.item.ariaLabel:${widget.name} widget: ${widget.description}`;
3154
3263
  }
3155
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WidgetListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3156
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WidgetListComponent, isStandalone: true, selector: "ngx-dashboard-widget-list", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- widget-list.component.html -->\n<div\n class=\"widget-list\"\n role=\"list\"\n i18n-aria-label=\"@@ngx.dashboard.widget.list.available\"\n aria-label=\"Available widgets\"\n>\n @for (widget of widgets(); track widget.widgetTypeid) {\n <div\n class=\"widget-list-item\"\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\n draggable=\"true\"\n (dragstart)=\"onDragStart($event, widget)\"\n (dragend)=\"onDragEnd()\"\n role=\"listitem\"\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\n [attr.aria-label]=\"getWidgetAriaLabel(widget)\"\n [matTooltip]=\"widget.description\"\n [matTooltipDisabled]=\"!collapsed()\"\n matTooltipPosition=\"right\"\n tabindex=\"0\"\n >\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\n <div class=\"content\">\n <strong>{{ widget.name }}</strong>\n <small>{{ widget.description }}</small>\n </div>\n </div>\n }\n</div>\n", styles: [":host{background-color:var(--mat-sys-surface-container, #f5f5f5);container-type:inline-size}.widget-list{display:flex;flex-direction:column;gap:var(--mat-sys-spacing-2, 8px)}@container (max-width: 200px){.widget-list{gap:var(--mat-sys-spacing-1, 4px)}}@container (min-width: 400px){.widget-list{gap:var(--mat-sys-spacing-3, 12px)}}.widget-list-item{display:flex;align-items:start;gap:var(--mat-sys-spacing-3, 12px);background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);padding:var(--mat-sys-spacing-3, 12px);border-radius:var(--mat-sys-corner-small, 4px);cursor:grab;transition:background-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),border-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),box-shadow var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out);box-shadow:var(--mat-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, .05))}@container (max-width: 200px){.widget-list-item{padding:var(--mat-sys-spacing-2, 8px);gap:var(--mat-sys-spacing-2, 8px)}}@container (min-width: 400px){.widget-list-item{padding:var(--mat-sys-spacing-4, 16px);gap:var(--mat-sys-spacing-4, 16px)}}.widget-list-item .icon{width:clamp(20px,4vw,28px);height:clamp(20px,4vw,28px);flex-shrink:0;color:var(--mat-sys-on-surface-variant, #5f5f5f);transition:color var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block}.widget-list-item .content{display:flex;flex-direction:column;line-height:1.2;color:var(--mat-sys-on-surface, #1c1c1c);flex:1;min-width:0}.widget-list-item .content strong{color:var(--mat-sys-on-surface, #1c1c1c);font-weight:500;font-size:clamp(.875rem,2.5vw,1rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item .content small{color:var(--mat-sys-on-surface-variant, #5f5f5f);font-size:clamp(.75rem,2vw,.875rem);margin-top:var(--mat-sys-spacing-1, 4px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item:hover{background-color:var(--mat-sys-surface-container-low, #f0f0f0);box-shadow:var(--mat-sys-elevation-level2, 0 2px 4px rgba(0, 0, 0, .1))}.widget-list-item:hover .icon{color:var(--mat-sys-on-surface, #1c1c1c)}.widget-list-item:active{cursor:grabbing;background-color:var(--mat-sys-surface-container, #f5f5f5)}.widget-list-item.active{background-color:var(--mat-sys-primary-container, #e6f2ff);border-color:var(--mat-sys-primary, #1976d2);color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content strong{color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content small{color:var(--mat-sys-on-primary-container, #004a99);opacity:.8}.widget-list-item.active .icon{color:var(--mat-sys-on-primary-container, #004a99)}.drag-ghost{position:absolute;top:0;left:0;z-index:9999;margin:0;pointer-events:none;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);border-radius:var(--mat-sys-corner-small, 4px);box-shadow:var(--mat-sys-elevation-level3, 0 4px 6px rgba(0, 0, 0, .15));opacity:.8}.drag-ghost .icon{display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}.drag-ghost .icon ::ng-deep svg{display:block}\n"], dependencies: [{ kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3264
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WidgetListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3265
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: WidgetListComponent, isStandalone: true, selector: "ngx-dashboard-widget-list", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- widget-list.component.html -->\n<div\n class=\"widget-list\"\n role=\"list\"\n i18n-aria-label=\"@@ngx.dashboard.widget.list.available\"\n aria-label=\"Available widgets\"\n>\n @for (widget of widgets(); track widget.widgetTypeid) {\n <div\n class=\"widget-list-item\"\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\n draggable=\"true\"\n (dragstart)=\"onDragStart($event, widget)\"\n (dragend)=\"onDragEnd()\"\n role=\"listitem\"\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\n [attr.aria-label]=\"getWidgetAriaLabel(widget)\"\n [matTooltip]=\"widget.description\"\n [matTooltipDisabled]=\"!collapsed()\"\n matTooltipPosition=\"right\"\n tabindex=\"0\"\n >\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\n <div class=\"content\">\n <strong>{{ widget.name }}</strong>\n <small>{{ widget.description }}</small>\n </div>\n </div>\n }\n</div>\n", styles: [":host{background-color:var(--mat-sys-surface-container, #f5f5f5);container-type:inline-size}.widget-list{display:flex;flex-direction:column;gap:var(--mat-sys-spacing-2, 8px)}@container (max-width: 200px){.widget-list{gap:var(--mat-sys-spacing-1, 4px)}}@container (min-width: 400px){.widget-list{gap:var(--mat-sys-spacing-3, 12px)}}.widget-list-item{display:flex;align-items:start;gap:var(--mat-sys-spacing-3, 12px);background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);padding:var(--mat-sys-spacing-3, 12px);border-radius:var(--mat-sys-corner-small, 4px);cursor:grab;transition:background-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),border-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),box-shadow var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out);box-shadow:var(--mat-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, .05))}@container (max-width: 200px){.widget-list-item{padding:var(--mat-sys-spacing-2, 8px);gap:var(--mat-sys-spacing-2, 8px)}}@container (min-width: 400px){.widget-list-item{padding:var(--mat-sys-spacing-4, 16px);gap:var(--mat-sys-spacing-4, 16px)}}.widget-list-item .icon{width:clamp(20px,4vw,28px);height:clamp(20px,4vw,28px);flex-shrink:0;color:var(--mat-sys-on-surface-variant, #5f5f5f);transition:color var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block}.widget-list-item .content{display:flex;flex-direction:column;line-height:1.2;color:var(--mat-sys-on-surface, #1c1c1c);flex:1;min-width:0}.widget-list-item .content strong{color:var(--mat-sys-on-surface, #1c1c1c);font-weight:500;font-size:clamp(.875rem,2.5vw,1rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item .content small{color:var(--mat-sys-on-surface-variant, #5f5f5f);font-size:clamp(.75rem,2vw,.875rem);margin-top:var(--mat-sys-spacing-1, 4px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item:hover{background-color:var(--mat-sys-surface-container-low, #f0f0f0);box-shadow:var(--mat-sys-elevation-level2, 0 2px 4px rgba(0, 0, 0, .1))}.widget-list-item:hover .icon{color:var(--mat-sys-on-surface, #1c1c1c)}.widget-list-item:active{cursor:grabbing;background-color:var(--mat-sys-surface-container, #f5f5f5)}.widget-list-item.active{background-color:var(--mat-sys-primary-container, #e6f2ff);border-color:var(--mat-sys-primary, #1976d2);color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content strong{color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content small{color:var(--mat-sys-on-primary-container, #004a99);opacity:.8}.widget-list-item.active .icon{color:var(--mat-sys-on-primary-container, #004a99)}.drag-ghost{position:absolute;top:0;left:0;z-index:9999;margin:0;pointer-events:none;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);border-radius:var(--mat-sys-corner-small, 4px);box-shadow:var(--mat-sys-elevation-level3, 0 4px 6px rgba(0, 0, 0, .15));opacity:.8}.drag-ghost .icon{display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}.drag-ghost .icon ::ng-deep svg{display:block}\n"], dependencies: [{ kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3157
3266
  }
3158
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WidgetListComponent, decorators: [{
3267
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: WidgetListComponent, decorators: [{
3159
3268
  type: Component,
3160
3269
  args: [{ selector: 'ngx-dashboard-widget-list', standalone: true, imports: [MatTooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- widget-list.component.html -->\n<div\n class=\"widget-list\"\n role=\"list\"\n i18n-aria-label=\"@@ngx.dashboard.widget.list.available\"\n aria-label=\"Available widgets\"\n>\n @for (widget of widgets(); track widget.widgetTypeid) {\n <div\n class=\"widget-list-item\"\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\n draggable=\"true\"\n (dragstart)=\"onDragStart($event, widget)\"\n (dragend)=\"onDragEnd()\"\n role=\"listitem\"\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\n [attr.aria-label]=\"getWidgetAriaLabel(widget)\"\n [matTooltip]=\"widget.description\"\n [matTooltipDisabled]=\"!collapsed()\"\n matTooltipPosition=\"right\"\n tabindex=\"0\"\n >\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\n <div class=\"content\">\n <strong>{{ widget.name }}</strong>\n <small>{{ widget.description }}</small>\n </div>\n </div>\n }\n</div>\n", styles: [":host{background-color:var(--mat-sys-surface-container, #f5f5f5);container-type:inline-size}.widget-list{display:flex;flex-direction:column;gap:var(--mat-sys-spacing-2, 8px)}@container (max-width: 200px){.widget-list{gap:var(--mat-sys-spacing-1, 4px)}}@container (min-width: 400px){.widget-list{gap:var(--mat-sys-spacing-3, 12px)}}.widget-list-item{display:flex;align-items:start;gap:var(--mat-sys-spacing-3, 12px);background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);padding:var(--mat-sys-spacing-3, 12px);border-radius:var(--mat-sys-corner-small, 4px);cursor:grab;transition:background-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),border-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),box-shadow var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out);box-shadow:var(--mat-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, .05))}@container (max-width: 200px){.widget-list-item{padding:var(--mat-sys-spacing-2, 8px);gap:var(--mat-sys-spacing-2, 8px)}}@container (min-width: 400px){.widget-list-item{padding:var(--mat-sys-spacing-4, 16px);gap:var(--mat-sys-spacing-4, 16px)}}.widget-list-item .icon{width:clamp(20px,4vw,28px);height:clamp(20px,4vw,28px);flex-shrink:0;color:var(--mat-sys-on-surface-variant, #5f5f5f);transition:color var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block}.widget-list-item .content{display:flex;flex-direction:column;line-height:1.2;color:var(--mat-sys-on-surface, #1c1c1c);flex:1;min-width:0}.widget-list-item .content strong{color:var(--mat-sys-on-surface, #1c1c1c);font-weight:500;font-size:clamp(.875rem,2.5vw,1rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item .content small{color:var(--mat-sys-on-surface-variant, #5f5f5f);font-size:clamp(.75rem,2vw,.875rem);margin-top:var(--mat-sys-spacing-1, 4px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item:hover{background-color:var(--mat-sys-surface-container-low, #f0f0f0);box-shadow:var(--mat-sys-elevation-level2, 0 2px 4px rgba(0, 0, 0, .1))}.widget-list-item:hover .icon{color:var(--mat-sys-on-surface, #1c1c1c)}.widget-list-item:active{cursor:grabbing;background-color:var(--mat-sys-surface-container, #f5f5f5)}.widget-list-item.active{background-color:var(--mat-sys-primary-container, #e6f2ff);border-color:var(--mat-sys-primary, #1976d2);color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content strong{color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content small{color:var(--mat-sys-on-primary-container, #004a99);opacity:.8}.widget-list-item.active .icon{color:var(--mat-sys-on-primary-container, #004a99)}.drag-ghost{position:absolute;top:0;left:0;z-index:9999;margin:0;pointer-events:none;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);border-radius:var(--mat-sys-corner-small, 4px);box-shadow:var(--mat-sys-elevation-level3, 0 4px 6px rgba(0, 0, 0, .15));opacity:.8}.drag-ghost .icon{display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}.drag-ghost .icon ::ng-deep svg{display:block}\n"] }]
3161
3270
  }], propDecorators: { collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });