@dragonworks/ngx-dashboard 20.0.5 → 20.1.0

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.
@@ -1,15 +1,15 @@
1
1
  import { CommonModule, isPlatformBrowser } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { signal, computed, ChangeDetectionStrategy, Component, Injectable, inject, Inject, InjectionToken, input, model, output, viewChild, ViewContainerRef, DestroyRef, Renderer2, ElementRef, effect, viewChildren, afterNextRender, PLATFORM_ID, untracked } from '@angular/core';
3
+ import { signal, computed, ChangeDetectionStrategy, Component, Injectable, inject, InjectionToken, input, model, output, viewChild, ViewContainerRef, DestroyRef, Renderer2, effect, viewChildren, ElementRef, afterNextRender, PLATFORM_ID, untracked } from '@angular/core';
4
4
  import { signalStoreFeature, withState, withMethods, patchState, withComputed, signalStore, withProps } from '@ngrx/signals';
5
5
  import * as i1 from '@angular/material/icon';
6
6
  import { MatIconModule } from '@angular/material/icon';
7
7
  import * as i2 from '@angular/material/tooltip';
8
8
  import { MatTooltipModule } from '@angular/material/tooltip';
9
- import * as i1$1 from '@angular/material/dialog';
10
- import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
9
+ import * as i2$1 from '@angular/material/dialog';
10
+ import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule, MatDialog } from '@angular/material/dialog';
11
11
  import { firstValueFrom } from 'rxjs';
12
- import * as i2$1 from '@angular/forms';
12
+ import * as i1$1 from '@angular/forms';
13
13
  import { FormsModule } from '@angular/forms';
14
14
  import * as i3 from '@angular/material/button';
15
15
  import { MatButtonModule } from '@angular/material/button';
@@ -93,6 +93,65 @@ const CellIdUtils = {
93
93
  },
94
94
  };
95
95
 
96
+ /**
97
+ * Utility functions for working with WidgetId branded type.
98
+ * WidgetIds are UUIDs that uniquely identify widget instances throughout their lifecycle,
99
+ * independent of their position on the dashboard grid.
100
+ */
101
+ const WidgetIdUtils = {
102
+ /**
103
+ * Generates a new unique WidgetId.
104
+ * Uses crypto.randomUUID() when available, falls back to timestamp-based ID for older browsers.
105
+ * @returns A new unique WidgetId
106
+ */
107
+ generate() {
108
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
109
+ return crypto.randomUUID();
110
+ }
111
+ // Fallback for older browsers
112
+ return `widget-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
113
+ },
114
+ /**
115
+ * Validates if a string is a valid WidgetId format.
116
+ * @param id - The string to validate
117
+ * @returns True if the string is a valid WidgetId format
118
+ */
119
+ validate(id) {
120
+ // UUID v4 format or fallback format
121
+ return (/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(id) ||
122
+ /^widget-\d+-[a-z0-9]{9}$/i.test(id));
123
+ },
124
+ /**
125
+ * Converts a WidgetId to a string for use as map keys or serialization.
126
+ * @param id - The WidgetId to convert
127
+ * @returns The string representation of the WidgetId
128
+ */
129
+ toString(id) {
130
+ return id;
131
+ },
132
+ /**
133
+ * Creates a WidgetId from a string, validating the format.
134
+ * @param str - The string to convert to WidgetId
135
+ * @returns A WidgetId
136
+ * @throws Error if the string is not a valid WidgetId format
137
+ */
138
+ fromString(str) {
139
+ if (!this.validate(str)) {
140
+ throw new Error(`Invalid WidgetId format: ${str}`);
141
+ }
142
+ return str;
143
+ },
144
+ /**
145
+ * Checks if two WidgetIds are equal.
146
+ * @param a - First WidgetId
147
+ * @param b - Second WidgetId
148
+ * @returns True if the WidgetIds are the same
149
+ */
150
+ equals(a, b) {
151
+ return a === b;
152
+ },
153
+ };
154
+
96
155
  /**
97
156
  * Creates an empty dashboard configuration with the specified dimensions.
98
157
  * This is a convenience function for creating a basic dashboard without any cells.
@@ -165,8 +224,8 @@ class UnknownWidgetComponent {
165
224
  };
166
225
  state = signal({
167
226
  originalWidgetTypeid: 'unknown',
168
- });
169
- tooltipText = computed(() => `${this.state().originalWidgetTypeid}`);
227
+ }, ...(ngDevMode ? [{ debugName: "state" }] : []));
228
+ tooltipText = computed(() => `${this.state().originalWidgetTypeid}`, ...(ngDevMode ? [{ debugName: "tooltipText" }] : []));
170
229
  dashboardSetState(state) {
171
230
  if (state && typeof state === 'object' && 'originalWidgetTypeid' in state) {
172
231
  this.state.set(state);
@@ -175,14 +234,14 @@ class UnknownWidgetComponent {
175
234
  dashboardGetState() {
176
235
  return this.state();
177
236
  }
178
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: UnknownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
179
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: UnknownWidgetComponent, isStandalone: true, selector: "lib-unknown-widget", ngImport: i0, template: `
237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: UnknownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.2.1", type: UnknownWidgetComponent, isStandalone: true, selector: "lib-unknown-widget", ngImport: i0, template: `
180
239
  <div class="unknown-widget-container" [matTooltip]="tooltipText()">
181
240
  <mat-icon class="unknown-widget-icon">error_outline</mat-icon>
182
241
  </div>
183
242
  `, 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: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
184
243
  }
185
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: UnknownWidgetComponent, decorators: [{
244
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: UnknownWidgetComponent, decorators: [{
186
245
  type: Component,
187
246
  args: [{ selector: 'lib-unknown-widget', imports: [MatIconModule, MatTooltipModule], template: `
188
247
  <div class="unknown-widget-container" [matTooltip]="tooltipText()">
@@ -193,7 +252,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
193
252
 
194
253
  // dashboard.service.ts
195
254
  class DashboardService {
196
- #widgetTypes = signal([]);
255
+ #widgetTypes = signal([], ...(ngDevMode ? [{ debugName: "#widgetTypes" }] : []));
197
256
  #widgetFactoryMap = new Map();
198
257
  #unknownWidgetFactory = createFactoryFromComponent(UnknownWidgetComponent);
199
258
  widgetTypes = this.#widgetTypes.asReadonly(); // make the widget list available as a readonly signal
@@ -217,16 +276,16 @@ class DashboardService {
217
276
  createInstance: (container, state) => {
218
277
  const ref = this.#unknownWidgetFactory.createInstance(container, {
219
278
  originalWidgetTypeid: widgetTypeid,
220
- ...(state || {}),
279
+ ...(state && typeof state === 'object' ? state : {}),
221
280
  });
222
281
  return ref;
223
282
  },
224
283
  };
225
284
  }
226
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
227
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardService, providedIn: 'root' });
285
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
286
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardService, providedIn: 'root' });
228
287
  }
229
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardService, decorators: [{
288
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardService, decorators: [{
230
289
  type: Injectable,
231
290
  args: [{
232
291
  providedIn: 'root',
@@ -235,10 +294,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
235
294
 
236
295
  // Internal utility functions used by collision detection, resize logic, and tests
237
296
  const GridQueryInternalUtils = {
238
- isCellOccupied(cells, row, col, excludeId) {
297
+ isCellOccupied(cells, row, col, excludeWidgetId) {
239
298
  return cells.some((cell) => {
240
- // Skip checking against the cell being dragged
241
- if (excludeId && CellIdUtils.equals(cell.cellId, excludeId))
299
+ // Skip checking against the widget being dragged (use widgetId for stable identity)
300
+ if (excludeWidgetId && cell.widgetId === excludeWidgetId)
242
301
  return false;
243
302
  const endRow = cell.row + cell.rowSpan - 1;
244
303
  const endCol = cell.col + cell.colSpan - 1;
@@ -276,9 +335,9 @@ function calculateCollisionInfo(dragData, hovered, cells, rows, columns) {
276
335
  footprint.push({ row: hovered.row + r, col: hovered.col + c });
277
336
  }
278
337
  }
279
- const excludeId = isCell ? dragData.content.cellId : undefined;
338
+ const excludeWidgetId = isCell ? dragData.content.widgetId : undefined;
280
339
  // Check for actual collisions with other widgets (not self)
281
- const hasCollisions = footprint.some((pos) => GridQueryInternalUtils.isCellOccupied(cells, pos.row, pos.col, excludeId));
340
+ const hasCollisions = footprint.some((pos) => GridQueryInternalUtils.isCellOccupied(cells, pos.row, pos.col, excludeWidgetId));
282
341
  // Generate invalid cell IDs
283
342
  const invalidCells = [];
284
343
  if (hasCollisions || outOfBounds) {
@@ -330,39 +389,44 @@ const withGridConfig = () => signalStoreFeature(withState(initialGridConfigState
330
389
  })));
331
390
 
332
391
  const initialWidgetManagementState = {
333
- cellsById: {},
392
+ widgetsById: {},
334
393
  };
335
394
  const withWidgetManagement = () => signalStoreFeature(withState(initialWidgetManagementState),
336
395
  // Computed cells array - lazy evaluation, automatic memoization
337
396
  withComputed((store) => ({
338
- cells: computed(() => Object.values(store.cellsById())),
397
+ cells: computed(() => Object.values(store.widgetsById())),
339
398
  })), withMethods((store) => ({
340
399
  addWidget(cell) {
341
- const cellKey = CellIdUtils.toString(cell.cellId);
400
+ const widgetKey = WidgetIdUtils.toString(cell.widgetId);
342
401
  patchState(store, {
343
- cellsById: { ...store.cellsById(), [cellKey]: cell },
402
+ widgetsById: { ...store.widgetsById(), [widgetKey]: cell },
344
403
  });
345
404
  },
346
- removeWidget(cellId) {
347
- const cellKey = CellIdUtils.toString(cellId);
348
- const { [cellKey]: removed, ...remaining } = store.cellsById();
349
- patchState(store, { cellsById: remaining });
405
+ removeWidget(widgetId) {
406
+ const widgetKey = WidgetIdUtils.toString(widgetId);
407
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
408
+ const { [widgetKey]: _, ...remaining } = store.widgetsById();
409
+ patchState(store, { widgetsById: remaining });
350
410
  },
351
- updateWidgetPosition(cellId, row, col) {
352
- const cellKey = CellIdUtils.toString(cellId);
353
- const existingCell = store.cellsById()[cellKey];
354
- if (existingCell) {
411
+ updateWidgetPosition(widgetId, row, col) {
412
+ const widgetKey = WidgetIdUtils.toString(widgetId);
413
+ const existingWidget = store.widgetsById()[widgetKey];
414
+ if (existingWidget) {
415
+ // Update position and recalculate cellId based on new position
416
+ const newCellId = CellIdUtils.create(row, col);
355
417
  patchState(store, {
356
- cellsById: {
357
- ...store.cellsById(),
358
- [cellKey]: { ...existingCell, row, col },
418
+ widgetsById: {
419
+ ...store.widgetsById(),
420
+ [widgetKey]: { ...existingWidget, row, col, cellId: newCellId },
359
421
  },
360
422
  });
361
423
  }
362
424
  },
363
425
  createWidget(row, col, widgetFactory, widgetState) {
364
- const cellId = CellIdUtils.create(row, col);
426
+ const widgetId = WidgetIdUtils.generate(); // Generate unique widget ID
427
+ const cellId = CellIdUtils.create(row, col); // Calculate position-based cell ID
365
428
  const cell = {
429
+ widgetId,
366
430
  cellId,
367
431
  row,
368
432
  col,
@@ -371,59 +435,65 @@ withComputed((store) => ({
371
435
  widgetFactory,
372
436
  widgetState,
373
437
  };
374
- const cellKey = CellIdUtils.toString(cellId);
438
+ const widgetKey = WidgetIdUtils.toString(widgetId);
375
439
  patchState(store, {
376
- cellsById: { ...store.cellsById(), [cellKey]: cell },
440
+ widgetsById: { ...store.widgetsById(), [widgetKey]: cell },
377
441
  });
378
442
  },
379
- updateCellSettings(id, flat) {
380
- const cellKey = CellIdUtils.toString(id);
381
- const existingCell = store.cellsById()[cellKey];
382
- if (existingCell) {
443
+ updateCellSettings(widgetId, flat) {
444
+ const widgetKey = WidgetIdUtils.toString(widgetId);
445
+ const existingWidget = store.widgetsById()[widgetKey];
446
+ if (existingWidget) {
383
447
  patchState(store, {
384
- cellsById: {
385
- ...store.cellsById(),
386
- [cellKey]: { ...existingCell, flat },
448
+ widgetsById: {
449
+ ...store.widgetsById(),
450
+ [widgetKey]: { ...existingWidget, flat },
387
451
  },
388
452
  });
389
453
  }
390
454
  },
391
- updateWidgetSpan(id, rowSpan, colSpan) {
392
- const cellKey = CellIdUtils.toString(id);
393
- const existingCell = store.cellsById()[cellKey];
394
- if (existingCell) {
455
+ updateWidgetSpan(widgetId, rowSpan, colSpan) {
456
+ const widgetKey = WidgetIdUtils.toString(widgetId);
457
+ const existingWidget = store.widgetsById()[widgetKey];
458
+ if (existingWidget) {
395
459
  patchState(store, {
396
- cellsById: {
397
- ...store.cellsById(),
398
- [cellKey]: { ...existingCell, rowSpan, colSpan },
460
+ widgetsById: {
461
+ ...store.widgetsById(),
462
+ [widgetKey]: { ...existingWidget, rowSpan, colSpan },
399
463
  },
400
464
  });
401
465
  }
402
466
  },
403
- updateWidgetState(cellId, widgetState) {
404
- const cellKey = CellIdUtils.toString(cellId);
405
- const existingCell = store.cellsById()[cellKey];
406
- if (existingCell) {
467
+ updateWidgetState(widgetId, widgetState) {
468
+ const widgetKey = WidgetIdUtils.toString(widgetId);
469
+ const existingWidget = store.widgetsById()[widgetKey];
470
+ if (existingWidget) {
407
471
  patchState(store, {
408
- cellsById: {
409
- ...store.cellsById(),
410
- [cellKey]: { ...existingCell, widgetState },
472
+ widgetsById: {
473
+ ...store.widgetsById(),
474
+ [widgetKey]: { ...existingWidget, widgetState },
411
475
  },
412
476
  });
413
477
  }
414
478
  },
415
- updateAllWidgetStates(widgetStates) {
416
- const updatedCellsById = { ...store.cellsById() };
417
- for (const [cellIdString, newState] of widgetStates) {
418
- const existingCell = updatedCellsById[cellIdString];
419
- if (existingCell) {
420
- updatedCellsById[cellIdString] = { ...existingCell, widgetState: newState };
479
+ updateAllWidgetStates(cellStates) {
480
+ const updatedWidgetsById = { ...store.widgetsById() };
481
+ // Convert cell ID keys to widget IDs and update states
482
+ for (const [cellIdString, newState] of cellStates) {
483
+ // Find the widget with the matching cell ID
484
+ const widget = Object.values(updatedWidgetsById).find(w => CellIdUtils.toString(w.cellId) === cellIdString);
485
+ if (widget) {
486
+ const widgetIdString = WidgetIdUtils.toString(widget.widgetId);
487
+ updatedWidgetsById[widgetIdString] = {
488
+ ...updatedWidgetsById[widgetIdString],
489
+ widgetState: newState,
490
+ };
421
491
  }
422
492
  }
423
- patchState(store, { cellsById: updatedCellsById });
493
+ patchState(store, { widgetsById: updatedWidgetsById });
424
494
  },
425
495
  clearDashboard() {
426
- patchState(store, { cellsById: {} });
496
+ patchState(store, { widgetsById: {} });
427
497
  },
428
498
  })));
429
499
 
@@ -445,9 +515,6 @@ const withDragDrop = () => signalStoreFeature(withState(initialDragDropState), w
445
515
  return map;
446
516
  }),
447
517
  })), withMethods((store) => ({
448
- syncDragState(dragData) {
449
- patchState(store, { dragData });
450
- },
451
518
  startDrag(dragData) {
452
519
  patchState(store, { dragData });
453
520
  },
@@ -481,7 +548,8 @@ withMethods((store) => ({
481
548
  }
482
549
  // 5. Handle cell movement
483
550
  if (dragData.kind === 'cell') {
484
- dependencies.updateWidgetPosition(dragData.content.cellId, targetPosition.row, targetPosition.col);
551
+ dependencies.updateWidgetPosition(dragData.content.widgetId, // Use widgetId instead of cellId
552
+ targetPosition.row, targetPosition.col);
485
553
  return true;
486
554
  }
487
555
  return false;
@@ -707,7 +775,13 @@ withMethods((store) => ({
707
775
  },
708
776
  endResize(apply) {
709
777
  store._endResize(apply, {
710
- updateWidgetSpan: store.updateWidgetSpan,
778
+ updateWidgetSpan: (cellId, rowSpan, colSpan) => {
779
+ // Adapter: find widget by cellId and update using widgetId
780
+ const widget = store.cells().find(c => CellIdUtils.equals(c.cellId, cellId));
781
+ if (widget) {
782
+ store.updateWidgetSpan(widget.widgetId, rowSpan, colSpan);
783
+ }
784
+ }
711
785
  });
712
786
  },
713
787
  // EXPORT/IMPORT METHODS (need access to multiple features)
@@ -739,10 +813,12 @@ withMethods((store) => ({
739
813
  },
740
814
  loadDashboard(data) {
741
815
  // Import full dashboard data with grid configuration
742
- const cellsById = {};
816
+ const widgetsById = {};
743
817
  data.cells.forEach((cellData) => {
744
818
  const factory = store.dashboardService.getFactory(cellData.widgetTypeid);
819
+ const widgetId = WidgetIdUtils.generate();
745
820
  const cell = {
821
+ widgetId,
746
822
  cellId: CellIdUtils.create(cellData.row, cellData.col),
747
823
  row: cellData.row,
748
824
  col: cellData.col,
@@ -752,23 +828,25 @@ withMethods((store) => ({
752
828
  widgetFactory: factory,
753
829
  widgetState: cellData.widgetState,
754
830
  };
755
- cellsById[CellIdUtils.toString(cell.cellId)] = cell;
831
+ widgetsById[WidgetIdUtils.toString(widgetId)] = cell;
756
832
  });
757
833
  patchState(store, {
758
834
  dashboardId: data.dashboardId,
759
835
  rows: data.rows,
760
836
  columns: data.columns,
761
837
  gutterSize: data.gutterSize,
762
- cellsById,
838
+ widgetsById,
763
839
  });
764
840
  },
765
841
  // INITIALIZATION METHODS
766
842
  initializeFromDto(dashboardData) {
767
843
  // Inline the loadDashboard logic since it's defined later in the same methods block
768
- const cellsById = {};
844
+ const widgetsById = {};
769
845
  dashboardData.cells.forEach((cellData) => {
770
846
  const factory = store.dashboardService.getFactory(cellData.widgetTypeid);
847
+ const widgetId = WidgetIdUtils.generate();
771
848
  const cell = {
849
+ widgetId,
772
850
  cellId: CellIdUtils.create(cellData.row, cellData.col),
773
851
  row: cellData.row,
774
852
  col: cellData.col,
@@ -778,14 +856,14 @@ withMethods((store) => ({
778
856
  widgetFactory: factory,
779
857
  widgetState: cellData.widgetState,
780
858
  };
781
- cellsById[CellIdUtils.toString(cell.cellId)] = cell;
859
+ widgetsById[WidgetIdUtils.toString(widgetId)] = cell;
782
860
  });
783
861
  patchState(store, {
784
862
  dashboardId: dashboardData.dashboardId,
785
863
  rows: dashboardData.rows,
786
864
  columns: dashboardData.columns,
787
865
  gutterSize: dashboardData.gutterSize,
788
- cellsById,
866
+ widgetsById,
789
867
  });
790
868
  },
791
869
  })),
@@ -812,14 +890,12 @@ class CellSettingsDialogProvider {
812
890
  }
813
891
 
814
892
  class CellSettingsDialogComponent {
815
- data;
816
- dialogRef;
817
893
  selectedMode;
818
894
  currentMode;
819
- constructor(data, dialogRef) {
820
- this.data = data;
821
- this.dialogRef = dialogRef;
822
- this.currentMode = data.flat ? 'flat' : 'normal';
895
+ data = inject(MAT_DIALOG_DATA);
896
+ dialogRef = inject((MatDialogRef));
897
+ constructor() {
898
+ this.currentMode = this.data.flat ? 'flat' : 'normal';
823
899
  this.selectedMode = this.currentMode;
824
900
  }
825
901
  onCancel() {
@@ -832,8 +908,8 @@ class CellSettingsDialogComponent {
832
908
  };
833
909
  this.dialogRef.close(newData);
834
910
  }
835
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellSettingsDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1$1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
836
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: CellSettingsDialogComponent, isStandalone: true, selector: "lib-cell-settings-dialog", ngImport: i0, template: `
911
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellSettingsDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
912
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.2.1", type: CellSettingsDialogComponent, isStandalone: true, selector: "lib-cell-settings-dialog", ngImport: i0, template: `
837
913
  <h2 mat-dialog-title>Cell Display Settings</h2>
838
914
  <mat-dialog-content>
839
915
  <p class="cell-info">Cell ID: <strong>{{ data.id }}</strong></p>
@@ -865,9 +941,9 @@ class CellSettingsDialogComponent {
865
941
  Apply
866
942
  </button>
867
943
  </mat-dialog-actions>
868
- `, 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: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i4.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"] }] });
944
+ `, 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: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i4.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"] }] });
869
945
  }
870
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellSettingsDialogComponent, decorators: [{
946
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellSettingsDialogComponent, decorators: [{
871
947
  type: Component,
872
948
  args: [{ selector: 'lib-cell-settings-dialog', standalone: true, imports: [
873
949
  CommonModule,
@@ -908,10 +984,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
908
984
  </button>
909
985
  </mat-dialog-actions>
910
986
  `, 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"] }]
911
- }], ctorParameters: () => [{ type: undefined, decorators: [{
912
- type: Inject,
913
- args: [MAT_DIALOG_DATA]
914
- }] }, { type: i1$1.MatDialogRef }] });
987
+ }], ctorParameters: () => [] });
915
988
 
916
989
  /**
917
990
  * Default cell dialog provider that uses Material Design dialogs.
@@ -930,10 +1003,10 @@ class DefaultCellSettingsDialogProvider extends CellSettingsDialogProvider {
930
1003
  const result = await firstValueFrom(dialogRef.afterClosed());
931
1004
  return result;
932
1005
  }
933
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DefaultCellSettingsDialogProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
934
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DefaultCellSettingsDialogProvider, providedIn: 'root' });
1006
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DefaultCellSettingsDialogProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1007
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DefaultCellSettingsDialogProvider, providedIn: 'root' });
935
1008
  }
936
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DefaultCellSettingsDialogProvider, decorators: [{
1009
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DefaultCellSettingsDialogProvider, decorators: [{
937
1010
  type: Injectable,
938
1011
  args: [{
939
1012
  providedIn: 'root',
@@ -957,7 +1030,7 @@ const CELL_SETTINGS_DIALOG_PROVIDER = new InjectionToken('CellSettingsDialogProv
957
1030
  });
958
1031
 
959
1032
  class CellContextMenuService {
960
- #activeMenu = signal(null);
1033
+ #activeMenu = signal(null, ...(ngDevMode ? [{ debugName: "#activeMenu" }] : []));
961
1034
  activeMenu = this.#activeMenu.asReadonly();
962
1035
  show(x, y, items) {
963
1036
  this.#activeMenu.set({ x, y, items });
@@ -965,25 +1038,26 @@ class CellContextMenuService {
965
1038
  hide() {
966
1039
  this.#activeMenu.set(null);
967
1040
  }
968
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
969
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellContextMenuService });
1041
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1042
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellContextMenuService });
970
1043
  }
971
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellContextMenuService, decorators: [{
1044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellContextMenuService, decorators: [{
972
1045
  type: Injectable
973
1046
  }] });
974
1047
 
975
1048
  // cell.component.ts
976
1049
  class CellComponent {
977
- id = input.required();
978
- widgetFactory = input(undefined);
979
- widgetState = input(undefined);
980
- isEditMode = input(false);
981
- flat = input(undefined);
982
- row = model.required();
983
- column = model.required();
984
- rowSpan = input(1);
985
- colSpan = input(1);
986
- draggable = input(false);
1050
+ widgetId = input.required(...(ngDevMode ? [{ debugName: "widgetId" }] : [])); // Unique widget instance identifier
1051
+ cellId = input.required(...(ngDevMode ? [{ debugName: "cellId" }] : [])); // Current grid position
1052
+ widgetFactory = input(undefined, ...(ngDevMode ? [{ debugName: "widgetFactory" }] : []));
1053
+ widgetState = input(undefined, ...(ngDevMode ? [{ debugName: "widgetState" }] : []));
1054
+ isEditMode = input(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
1055
+ flat = input(undefined, ...(ngDevMode ? [{ debugName: "flat" }] : []));
1056
+ row = model.required(...(ngDevMode ? [{ debugName: "row" }] : []));
1057
+ column = model.required(...(ngDevMode ? [{ debugName: "column" }] : []));
1058
+ rowSpan = input(1, ...(ngDevMode ? [{ debugName: "rowSpan" }] : []));
1059
+ colSpan = input(1, ...(ngDevMode ? [{ debugName: "colSpan" }] : []));
1060
+ draggable = input(false, ...(ngDevMode ? [{ debugName: "draggable" }] : []));
987
1061
  dragStart = output();
988
1062
  dragEnd = output();
989
1063
  edit = output();
@@ -1000,25 +1074,24 @@ class CellComponent {
1000
1074
  #contextMenuService = inject(CellContextMenuService, {
1001
1075
  optional: true,
1002
1076
  });
1003
- #elementRef = inject(ElementRef);
1004
1077
  #widgetRef;
1005
1078
  // Document event listeners cleanup function
1006
1079
  // Performance: Only created when actively resizing, not for every cell
1007
1080
  #documentListeners;
1008
- isDragging = signal(false);
1009
- gridRowStyle = computed(() => `${this.row()} / span ${this.rowSpan()}`);
1010
- gridColumnStyle = computed(() => `${this.column()} / span ${this.colSpan()}`);
1081
+ isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
1082
+ gridRowStyle = computed(() => `${this.row()} / span ${this.rowSpan()}`, ...(ngDevMode ? [{ debugName: "gridRowStyle" }] : []));
1083
+ gridColumnStyle = computed(() => `${this.column()} / span ${this.colSpan()}`, ...(ngDevMode ? [{ debugName: "gridColumnStyle" }] : []));
1011
1084
  isResizing = computed(() => {
1012
1085
  const resizeData = this.#store.resizeData();
1013
1086
  return resizeData
1014
- ? CellIdUtils.equals(resizeData.cellId, this.id())
1087
+ ? CellIdUtils.equals(resizeData.cellId, this.cellId())
1015
1088
  : false;
1016
- });
1017
- isDragActive = computed(() => !!this.#store.dragData());
1089
+ }, ...(ngDevMode ? [{ debugName: "isResizing" }] : []));
1090
+ isDragActive = computed(() => !!this.#store.dragData(), ...(ngDevMode ? [{ debugName: "isDragActive" }] : []));
1018
1091
  resizeData = this.#store.resizeData;
1019
1092
  gridCellDimensions = this.#store.gridCellDimensions;
1020
- resizeDirection = signal(null);
1021
- resizeStartPos = signal({ x: 0, y: 0 });
1093
+ resizeDirection = signal(null, ...(ngDevMode ? [{ debugName: "resizeDirection" }] : []));
1094
+ resizeStartPos = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "resizeStartPos" }] : []));
1022
1095
  constructor() {
1023
1096
  // widget creation - triggers when factory or state changes
1024
1097
  effect(() => {
@@ -1083,7 +1156,8 @@ class CellComponent {
1083
1156
  return;
1084
1157
  event.dataTransfer.effectAllowed = 'move';
1085
1158
  const cell = {
1086
- cellId: this.id(),
1159
+ cellId: this.cellId(),
1160
+ widgetId: this.widgetId(),
1087
1161
  row: this.row(),
1088
1162
  col: this.column(),
1089
1163
  rowSpan: this.rowSpan(),
@@ -1136,25 +1210,25 @@ class CellComponent {
1136
1210
  return false;
1137
1211
  }
1138
1212
  onEdit() {
1139
- this.edit.emit(this.id());
1213
+ this.edit.emit(this.widgetId());
1140
1214
  // Call the widget's edit dialog method if it exists
1141
1215
  if (this.#widgetRef?.instance?.dashboardEditState) {
1142
1216
  this.#widgetRef.instance.dashboardEditState();
1143
1217
  }
1144
1218
  }
1145
1219
  onDelete() {
1146
- this.delete.emit(this.id());
1220
+ this.delete.emit(this.widgetId());
1147
1221
  }
1148
1222
  async onSettings() {
1149
1223
  const currentSettings = {
1150
- id: CellIdUtils.toString(this.id()),
1224
+ id: CellIdUtils.toString(this.cellId()), // Use cellId for display position
1151
1225
  flat: this.flat(),
1152
1226
  };
1153
1227
  try {
1154
1228
  const result = await this.#dialogProvider.openCellSettings(currentSettings);
1155
1229
  if (result) {
1156
1230
  this.settings.emit({
1157
- id: this.id(),
1231
+ id: this.widgetId(),
1158
1232
  flat: result.flat ?? false,
1159
1233
  });
1160
1234
  }
@@ -1173,7 +1247,7 @@ class CellComponent {
1173
1247
  event.stopPropagation();
1174
1248
  this.resizeDirection.set(direction);
1175
1249
  this.resizeStartPos.set({ x: event.clientX, y: event.clientY });
1176
- this.resizeStart.emit({ id: this.id(), direction });
1250
+ this.resizeStart.emit({ cellId: this.cellId(), direction });
1177
1251
  // Setup document listeners only when actively resizing
1178
1252
  this.setupDocumentListeners();
1179
1253
  const cursorClass = direction === 'horizontal' ? 'cursor-col-resize' : 'cursor-row-resize';
@@ -1193,12 +1267,12 @@ class CellComponent {
1193
1267
  if (direction === 'horizontal') {
1194
1268
  const deltaX = event.clientX - startPos.x;
1195
1269
  const deltaSpan = Math.round(deltaX / cellSize.width);
1196
- this.resizeMove.emit({ id: this.id(), direction, delta: deltaSpan });
1270
+ this.resizeMove.emit({ cellId: this.cellId(), direction, delta: deltaSpan });
1197
1271
  }
1198
1272
  else {
1199
1273
  const deltaY = event.clientY - startPos.y;
1200
1274
  const deltaSpan = Math.round(deltaY / cellSize.height);
1201
- this.resizeMove.emit({ id: this.id(), direction, delta: deltaSpan });
1275
+ this.resizeMove.emit({ cellId: this.cellId(), direction, delta: deltaSpan });
1202
1276
  }
1203
1277
  }
1204
1278
  /**
@@ -1211,7 +1285,7 @@ class CellComponent {
1211
1285
  this.#renderer.removeClass(document.body, 'cursor-row-resize');
1212
1286
  // Clean up document listeners immediately
1213
1287
  this.#cleanupDocumentListeners();
1214
- this.resizeEnd.emit({ id: this.id(), apply: true });
1288
+ this.resizeEnd.emit({ cellId: this.cellId(), apply: true });
1215
1289
  this.resizeDirection.set(null);
1216
1290
  }
1217
1291
  /**
@@ -1229,10 +1303,10 @@ class CellComponent {
1229
1303
  // Fall back to stored state if widget doesn't implement dashboardGetState
1230
1304
  return this.widgetState();
1231
1305
  }
1232
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1233
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CellComponent, isStandalone: true, selector: "lib-cell", inputs: { id: { classPropertyName: "id", publicName: "id", 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 -->\r\n<div\r\n class=\"cell\"\r\n [class.is-resizing]=\"isResizing()\"\r\n [class.flat]=\"flat() === true\"\r\n [draggable]=\"draggable()\"\r\n (dragstart)=\"onDragStart($event)\"\r\n (dragend)=\"onDragEnd()\"\r\n (contextmenu)=\"onContextMenu($event)\"\r\n>\r\n <div class=\"content-area\">\r\n <ng-template #container></ng-template>\r\n </div>\r\n @if (isEditMode() && !isDragging()) {\r\n <!-- Right resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--right\"\r\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n <!-- Bottom resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--bottom\"\r\n (mousedown)=\"onResizeStart($event, 'vertical')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n }\r\n</div>\r\n\r\n@if (isResizing()) {\r\n<div class=\"resize-preview\">\r\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\r\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\r\n</div>\r\n}\r\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(: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}.cell.flat .content-area{pointer-events:auto}.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"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1306
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1307
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", 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 -->\r\n<div\r\n class=\"cell\"\r\n [class.is-resizing]=\"isResizing()\"\r\n [class.flat]=\"flat() === true\"\r\n [draggable]=\"draggable()\"\r\n (dragstart)=\"onDragStart($event)\"\r\n (dragend)=\"onDragEnd()\"\r\n (contextmenu)=\"onContextMenu($event)\"\r\n>\r\n <div class=\"content-area\">\r\n <ng-template #container></ng-template>\r\n </div>\r\n @if (isEditMode() && !isDragging()) {\r\n <!-- Right resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--right\"\r\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n <!-- Bottom resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--bottom\"\r\n (mousedown)=\"onResizeStart($event, 'vertical')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n }\r\n</div>\r\n\r\n@if (isResizing()) {\r\n<div class=\"resize-preview\">\r\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\r\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\r\n</div>\r\n}\r\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"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1234
1308
  }
1235
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellComponent, decorators: [{
1309
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellComponent, decorators: [{
1236
1310
  type: Component,
1237
1311
  args: [{ selector: 'lib-cell', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1238
1312
  '[style.grid-row]': 'gridRowStyle()',
@@ -1240,16 +1314,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1240
1314
  '[class.is-dragging]': 'isDragging()',
1241
1315
  '[class.drag-active]': 'isDragActive()',
1242
1316
  '[class.flat]': 'flat() === true',
1243
- }, template: "<!-- cell.component.html -->\r\n<div\r\n class=\"cell\"\r\n [class.is-resizing]=\"isResizing()\"\r\n [class.flat]=\"flat() === true\"\r\n [draggable]=\"draggable()\"\r\n (dragstart)=\"onDragStart($event)\"\r\n (dragend)=\"onDragEnd()\"\r\n (contextmenu)=\"onContextMenu($event)\"\r\n>\r\n <div class=\"content-area\">\r\n <ng-template #container></ng-template>\r\n </div>\r\n @if (isEditMode() && !isDragging()) {\r\n <!-- Right resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--right\"\r\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n <!-- Bottom resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--bottom\"\r\n (mousedown)=\"onResizeStart($event, 'vertical')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n }\r\n</div>\r\n\r\n@if (isResizing()) {\r\n<div class=\"resize-preview\">\r\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\r\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\r\n</div>\r\n}\r\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(: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}.cell.flat .content-area{pointer-events:auto}.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"] }]
1317
+ }, template: "<!-- cell.component.html -->\r\n<div\r\n class=\"cell\"\r\n [class.is-resizing]=\"isResizing()\"\r\n [class.flat]=\"flat() === true\"\r\n [draggable]=\"draggable()\"\r\n (dragstart)=\"onDragStart($event)\"\r\n (dragend)=\"onDragEnd()\"\r\n (contextmenu)=\"onContextMenu($event)\"\r\n>\r\n <div class=\"content-area\">\r\n <ng-template #container></ng-template>\r\n </div>\r\n @if (isEditMode() && !isDragging()) {\r\n <!-- Right resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--right\"\r\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n <!-- Bottom resize handle -->\r\n <div\r\n class=\"resize-handle resize-handle--bottom\"\r\n (mousedown)=\"onResizeStart($event, 'vertical')\"\r\n >\r\n <div class=\"resize-handle-line\"></div>\r\n </div>\r\n }\r\n</div>\r\n\r\n@if (isResizing()) {\r\n<div class=\"resize-preview\">\r\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\r\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\r\n</div>\r\n}\r\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"] }]
1244
1318
  }], ctorParameters: () => [] });
1245
1319
 
1246
1320
  class DashboardViewerComponent {
1247
1321
  #store = inject(DashboardStore);
1248
- cellComponents = viewChildren(CellComponent);
1249
- rows = input.required();
1250
- columns = input.required();
1251
- gutterSize = input('1em');
1252
- gutters = computed(() => this.columns() + 1);
1322
+ cellComponents = viewChildren(CellComponent, ...(ngDevMode ? [{ debugName: "cellComponents" }] : []));
1323
+ rows = input.required(...(ngDevMode ? [{ debugName: "rows" }] : []));
1324
+ columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : []));
1325
+ gutterSize = input('1em', ...(ngDevMode ? [{ debugName: "gutterSize" }] : []));
1326
+ gutters = computed(() => this.columns() + 1, ...(ngDevMode ? [{ debugName: "gutters" }] : []));
1253
1327
  // store signals - read-only
1254
1328
  cells = this.#store.cells;
1255
1329
  constructor() {
@@ -1270,7 +1344,7 @@ class DashboardViewerComponent {
1270
1344
  const stateMap = new Map();
1271
1345
  const cells = this.cellComponents();
1272
1346
  for (const cell of cells) {
1273
- const cellId = cell.id();
1347
+ const cellId = cell.cellId();
1274
1348
  const currentState = cell.getCurrentWidgetState();
1275
1349
  if (currentState !== undefined) {
1276
1350
  stateMap.set(CellIdUtils.toString(cellId), currentState);
@@ -1285,17 +1359,17 @@ class DashboardViewerComponent {
1285
1359
  exportDashboard() {
1286
1360
  return this.#store.exportDashboard(() => this.getCurrentWidgetStates());
1287
1361
  }
1288
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1289
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", 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 } }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\r\n<div class=\"grid top-grid\">\r\n @for (cell of cells(); track cell.cellId) {\r\n <lib-cell\r\n class=\"grid-cell\"\r\n [id]=\"cell.cellId\"\r\n [isEditMode]=\"false\"\r\n [draggable]=\"false\"\r\n [row]=\"cell.row\"\r\n [column]=\"cell.col\"\r\n [rowSpan]=\"cell.rowSpan\"\r\n [colSpan]=\"cell.colSpan\"\r\n [flat]=\"cell.flat\"\r\n [widgetFactory]=\"cell.widgetFactory\"\r\n [widgetState]=\"cell.widgetState\"\r\n >\r\n </lib-cell>\r\n }\r\n</div>\r\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;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}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["id", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }, { kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1362
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1363
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", 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 } }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\r\n<div class=\"grid top-grid\">\r\n @for (cell of cells(); track cell.widgetId) {\r\n <lib-cell\r\n class=\"grid-cell\"\r\n [widgetId]=\"cell.widgetId\"\r\n [cellId]=\"cell.cellId\"\r\n [isEditMode]=\"false\"\r\n [draggable]=\"false\"\r\n [row]=\"cell.row\"\r\n [column]=\"cell.col\"\r\n [rowSpan]=\"cell.rowSpan\"\r\n [colSpan]=\"cell.colSpan\"\r\n [flat]=\"cell.flat\"\r\n [widgetFactory]=\"cell.widgetFactory\"\r\n [widgetState]=\"cell.widgetState\"\r\n >\r\n </lib-cell>\r\n }\r\n</div>\r\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;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}\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: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1290
1364
  }
1291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardViewerComponent, decorators: [{
1365
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardViewerComponent, decorators: [{
1292
1366
  type: Component,
1293
1367
  args: [{ selector: 'ngx-dashboard-viewer', standalone: true, imports: [CellComponent, CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1294
1368
  '[style.--rows]': 'rows()',
1295
1369
  '[style.--columns]': 'columns()',
1296
1370
  '[style.--gutter-size]': 'gutterSize()',
1297
1371
  '[style.--gutters]': 'gutters()',
1298
- }, template: "<!-- Dashboard viewer - read-only grid -->\r\n<div class=\"grid top-grid\">\r\n @for (cell of cells(); track cell.cellId) {\r\n <lib-cell\r\n class=\"grid-cell\"\r\n [id]=\"cell.cellId\"\r\n [isEditMode]=\"false\"\r\n [draggable]=\"false\"\r\n [row]=\"cell.row\"\r\n [column]=\"cell.col\"\r\n [rowSpan]=\"cell.rowSpan\"\r\n [colSpan]=\"cell.colSpan\"\r\n [flat]=\"cell.flat\"\r\n [widgetFactory]=\"cell.widgetFactory\"\r\n [widgetState]=\"cell.widgetState\"\r\n >\r\n </lib-cell>\r\n }\r\n</div>\r\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;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}\n"] }]
1372
+ }, template: "<!-- Dashboard viewer - read-only grid -->\r\n<div class=\"grid top-grid\">\r\n @for (cell of cells(); track cell.widgetId) {\r\n <lib-cell\r\n class=\"grid-cell\"\r\n [widgetId]=\"cell.widgetId\"\r\n [cellId]=\"cell.cellId\"\r\n [isEditMode]=\"false\"\r\n [draggable]=\"false\"\r\n [row]=\"cell.row\"\r\n [column]=\"cell.col\"\r\n [rowSpan]=\"cell.rowSpan\"\r\n [colSpan]=\"cell.colSpan\"\r\n [flat]=\"cell.flat\"\r\n [widgetFactory]=\"cell.widgetFactory\"\r\n [widgetState]=\"cell.widgetState\"\r\n >\r\n </lib-cell>\r\n }\r\n</div>\r\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;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}\n"] }]
1299
1373
  }], ctorParameters: () => [] });
1300
1374
 
1301
1375
  class CellContextMenuComponent {
@@ -1304,11 +1378,11 @@ class CellContextMenuComponent {
1304
1378
  menuPosition = computed(() => {
1305
1379
  const menu = this.menuService.activeMenu();
1306
1380
  return menu ? { left: `${menu.x}px`, top: `${menu.y}px` } : { left: '0px', top: '0px' };
1307
- });
1381
+ }, ...(ngDevMode ? [{ debugName: "menuPosition" }] : []));
1308
1382
  menuItems = computed(() => {
1309
1383
  const menu = this.menuService.activeMenu();
1310
1384
  return menu?.items || [];
1311
- });
1385
+ }, ...(ngDevMode ? [{ debugName: "menuItems" }] : []));
1312
1386
  constructor() {
1313
1387
  effect(() => {
1314
1388
  const menu = this.menuService.activeMenu();
@@ -1346,17 +1420,14 @@ class CellContextMenuComponent {
1346
1420
  }
1347
1421
  });
1348
1422
  }
1349
- ngAfterViewInit() {
1350
- // Effects moved to constructor to be within injection context
1351
- }
1352
1423
  executeAction(item) {
1353
1424
  if (!item.divider && item.action) {
1354
1425
  item.action();
1355
1426
  this.menuService.hide();
1356
1427
  }
1357
1428
  }
1358
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1359
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", 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: `
1429
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1430
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", 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: `
1360
1431
  <!-- Hidden trigger for menu positioned at exact mouse coordinates
1361
1432
 
1362
1433
  IMPORTANT: Angular Material applies its own positioning logic to menus,
@@ -1410,7 +1481,7 @@ class CellContextMenuComponent {
1410
1481
  </mat-menu>
1411
1482
  `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.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$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$2.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: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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 });
1412
1483
  }
1413
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CellContextMenuComponent, decorators: [{
1484
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CellContextMenuComponent, decorators: [{
1414
1485
  type: Component,
1415
1486
  args: [{ selector: 'lib-cell-context-menu', standalone: true, imports: [MatMenuModule, MatIconModule, MatDividerModule, MatButtonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1416
1487
  <!-- Hidden trigger for menu positioned at exact mouse coordinates
@@ -1470,27 +1541,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1470
1541
  // drop-zone.component.ts
1471
1542
  class DropZoneComponent {
1472
1543
  // Required inputs
1473
- row = input.required();
1474
- col = input.required();
1475
- index = input.required();
1544
+ row = input.required(...(ngDevMode ? [{ debugName: "row" }] : []));
1545
+ col = input.required(...(ngDevMode ? [{ debugName: "col" }] : []));
1546
+ index = input.required(...(ngDevMode ? [{ debugName: "index" }] : []));
1476
1547
  // Optional inputs with defaults
1477
- highlight = input(false);
1478
- highlightInvalid = input(false);
1479
- highlightResize = input(false);
1480
- editMode = input(false);
1548
+ highlight = input(false, ...(ngDevMode ? [{ debugName: "highlight" }] : []));
1549
+ highlightInvalid = input(false, ...(ngDevMode ? [{ debugName: "highlightInvalid" }] : []));
1550
+ highlightResize = input(false, ...(ngDevMode ? [{ debugName: "highlightResize" }] : []));
1551
+ editMode = input(false, ...(ngDevMode ? [{ debugName: "editMode" }] : []));
1481
1552
  // Outputs
1482
1553
  dragEnter = output();
1483
1554
  dragExit = output();
1484
1555
  dragOver = output();
1485
1556
  dragDrop = output();
1486
1557
  // Computed properties
1487
- dropZoneId = computed(() => `drop-zone-${this.row()}-${this.col()}`);
1558
+ dropZoneId = computed(() => `drop-zone-${this.row()}-${this.col()}`, ...(ngDevMode ? [{ debugName: "dropZoneId" }] : []));
1488
1559
  dropData = computed(() => ({
1489
1560
  row: this.row(),
1490
1561
  col: this.col(),
1491
- }));
1562
+ }), ...(ngDevMode ? [{ debugName: "dropData" }] : []));
1492
1563
  // Abstract drag state from store
1493
- dragData = computed(() => this.#store.dragData());
1564
+ dragData = computed(() => this.#store.dragData(), ...(ngDevMode ? [{ debugName: "dragData" }] : []));
1494
1565
  // Computed drop effect based on drag data and validity
1495
1566
  dropEffect = computed(() => {
1496
1567
  const data = this.dragData();
@@ -1498,7 +1569,7 @@ class DropZoneComponent {
1498
1569
  return 'none';
1499
1570
  }
1500
1571
  return data.kind === 'cell' ? 'move' : 'copy';
1501
- });
1572
+ }, ...(ngDevMode ? [{ debugName: "dropEffect" }] : []));
1502
1573
  #store = inject(DashboardStore);
1503
1574
  #elementRef = inject(ElementRef);
1504
1575
  get nativeElement() {
@@ -1545,10 +1616,10 @@ class DropZoneComponent {
1545
1616
  });
1546
1617
  }
1547
1618
  }
1548
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DropZoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1549
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", 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 -->\r\n<div\r\n class=\"drop-zone\"\r\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\r\n [class.drop-zone--invalid]=\"highlightInvalid()\"\r\n [class.drop-zone--resize]=\"highlightResize()\"\r\n [style.grid-row]=\"row()\"\r\n [style.grid-column]=\"col()\"\r\n (dragenter)=\"onDragEnter($event)\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n>\r\n @if (editMode()) {\r\n <div class=\"edit-mode-cell-number\">\r\n {{ index() }}<br />\r\n {{ row() }},{{ col() }}\r\n </div>\r\n }\r\n</div>\r\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;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"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1619
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DropZoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1620
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", 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 -->\r\n<div\r\n class=\"drop-zone\"\r\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\r\n [class.drop-zone--invalid]=\"highlightInvalid()\"\r\n [class.drop-zone--resize]=\"highlightResize()\"\r\n [style.grid-row]=\"row()\"\r\n [style.grid-column]=\"col()\"\r\n (dragenter)=\"onDragEnter($event)\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n>\r\n @if (editMode()) {\r\n <div class=\"edit-mode-cell-number\">\r\n {{ index() }}<br />\r\n {{ row() }},{{ col() }}\r\n </div>\r\n }\r\n</div>\r\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;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"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1550
1621
  }
1551
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DropZoneComponent, decorators: [{
1622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DropZoneComponent, decorators: [{
1552
1623
  type: Component,
1553
1624
  args: [{ selector: 'lib-drop-zone', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- drop-zone.component.html -->\r\n<div\r\n class=\"drop-zone\"\r\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\r\n [class.drop-zone--invalid]=\"highlightInvalid()\"\r\n [class.drop-zone--resize]=\"highlightResize()\"\r\n [style.grid-row]=\"row()\"\r\n [style.grid-column]=\"col()\"\r\n (dragenter)=\"onDragEnter($event)\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n>\r\n @if (editMode()) {\r\n <div class=\"edit-mode-cell-number\">\r\n {{ index() }}<br />\r\n {{ row() }},{{ col() }}\r\n </div>\r\n }\r\n</div>\r\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;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"] }]
1554
1625
  }] });
@@ -1556,15 +1627,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1556
1627
  // dashboard-editor.component.ts
1557
1628
  class DashboardEditorComponent {
1558
1629
  bottomGridRef = viewChild.required('bottomGrid');
1559
- dropZones = viewChildren(DropZoneComponent);
1560
- cellComponents = viewChildren(CellComponent);
1630
+ dropZones = viewChildren(DropZoneComponent, ...(ngDevMode ? [{ debugName: "dropZones" }] : []));
1631
+ cellComponents = viewChildren(CellComponent, ...(ngDevMode ? [{ debugName: "cellComponents" }] : []));
1561
1632
  #store = inject(DashboardStore);
1562
1633
  #destroyRef = inject(DestroyRef);
1563
1634
  #resizeObserver;
1564
- rows = input.required();
1565
- columns = input.required();
1566
- gutterSize = input('1em');
1567
- gutters = computed(() => this.columns() + 1);
1635
+ rows = input.required(...(ngDevMode ? [{ debugName: "rows" }] : []));
1636
+ columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : []));
1637
+ gutterSize = input('1em', ...(ngDevMode ? [{ debugName: "gutterSize" }] : []));
1638
+ gutters = computed(() => this.columns() + 1, ...(ngDevMode ? [{ debugName: "gutters" }] : []));
1568
1639
  // store signals
1569
1640
  cells = this.#store.cells;
1570
1641
  highlightedZones = this.#store.highlightedZones;
@@ -1586,7 +1657,7 @@ class DashboardEditorComponent {
1586
1657
  }
1587
1658
  }
1588
1659
  return positions;
1589
- });
1660
+ }, ...(ngDevMode ? [{ debugName: "dropzonePositions" }] : []));
1590
1661
  // Helper method for template
1591
1662
  createCellId(row, col) {
1592
1663
  return CellIdUtils.create(row, col);
@@ -1650,7 +1721,7 @@ class DashboardEditorComponent {
1650
1721
  // Handle drag events from cell component
1651
1722
  onCellDragStart = (dragData) => this.#store.startDrag(dragData);
1652
1723
  // Handle resize events from cell component
1653
- onCellResizeStart = (event) => this.#store.startResize(event.id);
1724
+ onCellResizeStart = (event) => this.#store.startResize(event.cellId);
1654
1725
  onCellResizeMove = (event) => this.#store.updateResizePreview(event.direction, event.delta);
1655
1726
  onCellResizeEnd = (event) => this.#store.endResize(event.apply);
1656
1727
  // Handle drop events by delegating to store's business logic
@@ -1666,7 +1737,7 @@ class DashboardEditorComponent {
1666
1737
  const stateMap = new Map();
1667
1738
  const cells = this.cellComponents();
1668
1739
  for (const cell of cells) {
1669
- const cellId = cell.id();
1740
+ const cellId = cell.cellId();
1670
1741
  const currentState = cell.getCurrentWidgetState();
1671
1742
  if (currentState !== undefined) {
1672
1743
  stateMap.set(CellIdUtils.toString(cellId), currentState);
@@ -1681,12 +1752,12 @@ class DashboardEditorComponent {
1681
1752
  exportDashboard() {
1682
1753
  return this.#store.exportDashboard(() => this.getCurrentWidgetStates());
1683
1754
  }
1684
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1685
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", 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: [
1755
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1756
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", 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: [
1686
1757
  CellContextMenuService,
1687
- ], 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.cellId) {\n <lib-cell\n class=\"grid-cell\"\n [id]=\"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 menu -->\n<lib-cell-context-menu></lib-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: ["id", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }, { kind: "ngmodule", type: CommonModule }, { 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" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1758
+ ], 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 menu -->\n<lib-cell-context-menu></lib-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: "ngmodule", type: CommonModule }, { 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" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1688
1759
  }
1689
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardEditorComponent, decorators: [{
1760
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardEditorComponent, decorators: [{
1690
1761
  type: Component,
1691
1762
  args: [{ selector: 'ngx-dashboard-editor', standalone: true, imports: [
1692
1763
  CellComponent,
@@ -1701,7 +1772,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1701
1772
  '[style.--gutter-size]': 'gutterSize()',
1702
1773
  '[style.--gutters]': 'gutters()',
1703
1774
  '[class.is-edit-mode]': 'true', // Always in edit mode
1704
- }, 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.cellId) {\n <lib-cell\n class=\"grid-cell\"\n [id]=\"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 menu -->\n<lib-cell-context-menu></lib-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"] }]
1775
+ }, 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 menu -->\n<lib-cell-context-menu></lib-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"] }]
1705
1776
  }], ctorParameters: () => [] });
1706
1777
 
1707
1778
  // dashboard-bridge.service.ts
@@ -1713,7 +1784,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
1713
1784
  */
1714
1785
  class DashboardBridgeService {
1715
1786
  // Map of registered dashboard instances with their reactive dimensions
1716
- dashboards = signal(new Map());
1787
+ dashboards = signal(new Map(), ...(ngDevMode ? [{ debugName: "dashboards" }] : []));
1717
1788
  /**
1718
1789
  * Register a dashboard store instance using its dashboard ID
1719
1790
  */
@@ -1764,7 +1835,7 @@ class DashboardBridgeService {
1764
1835
  }
1765
1836
  // Return dimensions from first available dashboard with fallback for undefined
1766
1837
  return dashboardEntries[0].dimensions() || { width: 100, height: 100 };
1767
- });
1838
+ }, ...(ngDevMode ? [{ debugName: "availableDimensions" }] : []));
1768
1839
  /**
1769
1840
  * Start drag operation on the first available dashboard
1770
1841
  * (Widget lists need some dashboard to coordinate with during drag)
@@ -1787,15 +1858,15 @@ class DashboardBridgeService {
1787
1858
  /**
1788
1859
  * Get all registered dashboard IDs
1789
1860
  */
1790
- registeredDashboards = computed(() => Array.from(this.dashboards().keys()));
1861
+ registeredDashboards = computed(() => Array.from(this.dashboards().keys()), ...(ngDevMode ? [{ debugName: "registeredDashboards" }] : []));
1791
1862
  /**
1792
1863
  * Get the number of registered dashboards
1793
1864
  */
1794
- dashboardCount = computed(() => this.dashboards().size);
1865
+ dashboardCount = computed(() => this.dashboards().size, ...(ngDevMode ? [{ debugName: "dashboardCount" }] : []));
1795
1866
  /**
1796
1867
  * Check if any dashboards are registered
1797
1868
  */
1798
- hasDashboards = computed(() => this.dashboards().size > 0);
1869
+ hasDashboards = computed(() => this.dashboards().size > 0, ...(ngDevMode ? [{ debugName: "hasDashboards" }] : []));
1799
1870
  /**
1800
1871
  * Update registration for a dashboard store when its ID becomes available
1801
1872
  */
@@ -1830,10 +1901,10 @@ class DashboardBridgeService {
1830
1901
  getAllDashboards() {
1831
1902
  return this.dashboards();
1832
1903
  }
1833
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1834
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardBridgeService, providedIn: 'root' });
1904
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1905
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardBridgeService, providedIn: 'root' });
1835
1906
  }
1836
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardBridgeService, decorators: [{
1907
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardBridgeService, decorators: [{
1837
1908
  type: Injectable,
1838
1909
  args: [{ providedIn: 'root' }]
1839
1910
  }] });
@@ -1848,8 +1919,8 @@ class DashboardViewportService {
1848
1919
  platformId = inject(PLATFORM_ID);
1849
1920
  destroyRef = inject(DestroyRef);
1850
1921
  store = inject(DashboardStore);
1851
- viewportSize = signal({ width: 0, height: 0 });
1852
- reservedSpace = signal(DEFAULT_RESERVED_SPACE);
1922
+ viewportSize = signal({ width: 0, height: 0 }, ...(ngDevMode ? [{ debugName: "viewportSize" }] : []));
1923
+ reservedSpace = signal(DEFAULT_RESERVED_SPACE, ...(ngDevMode ? [{ debugName: "reservedSpace" }] : []));
1853
1924
  resizeObserver = null;
1854
1925
  constructor() {
1855
1926
  if (isPlatformBrowser(this.platformId)) {
@@ -1907,7 +1978,7 @@ class DashboardViewportService {
1907
1978
  width: Math.max(0, viewport.width - reserved.left - reserved.right),
1908
1979
  height: Math.max(0, viewport.height - reserved.top - reserved.bottom)
1909
1980
  };
1910
- });
1981
+ }, ...(ngDevMode ? [{ debugName: "availableSpace" }] : []));
1911
1982
  /**
1912
1983
  * Calculate dashboard constraints for this dashboard instance
1913
1984
  */
@@ -1948,11 +2019,11 @@ class DashboardViewportService {
1948
2019
  maxHeight: Math.max(0, maxHeight),
1949
2020
  constrainedBy
1950
2021
  };
1951
- });
1952
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1953
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardViewportService });
2022
+ }, ...(ngDevMode ? [{ debugName: "constraints" }] : []));
2023
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2024
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardViewportService });
1954
2025
  }
1955
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardViewportService, decorators: [{
2026
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardViewportService, decorators: [{
1956
2027
  type: Injectable
1957
2028
  }], ctorParameters: () => [] });
1958
2029
 
@@ -1969,14 +2040,14 @@ class DashboardComponent {
1969
2040
  store = this.#store;
1970
2041
  viewport = this.#viewport;
1971
2042
  // Component inputs
1972
- dashboardData = input.required();
1973
- editMode = input(false);
1974
- reservedSpace = input();
2043
+ dashboardData = input.required(...(ngDevMode ? [{ debugName: "dashboardData" }] : []));
2044
+ editMode = input(false, ...(ngDevMode ? [{ debugName: "editMode" }] : []));
2045
+ reservedSpace = input(...(ngDevMode ? [undefined, { debugName: "reservedSpace" }] : []));
1975
2046
  // Store signals - shared by both child components
1976
2047
  cells = this.#store.cells;
1977
2048
  // ViewChild references for export/import functionality
1978
- dashboardEditor = viewChild(DashboardEditorComponent);
1979
- dashboardViewer = viewChild(DashboardViewerComponent);
2049
+ dashboardEditor = viewChild(DashboardEditorComponent, ...(ngDevMode ? [{ debugName: "dashboardEditor" }] : []));
2050
+ dashboardViewer = viewChild(DashboardViewerComponent, ...(ngDevMode ? [{ debugName: "dashboardViewer" }] : []));
1980
2051
  // Track if we're in the middle of preserving states
1981
2052
  #isPreservingStates = false;
1982
2053
  // Track if component has been initialized
@@ -2082,10 +2153,10 @@ class DashboardComponent {
2082
2153
  this.#isPreservingStates = false;
2083
2154
  }
2084
2155
  }
2085
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2086
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", 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 } }, 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 -->\r\n<div class=\"grid-container\">\r\n @if (editMode()) {\r\n <!-- Full editor with drag & drop capabilities -->\r\n <ngx-dashboard-editor\r\n [rows]=\"store.rows()\"\r\n [columns]=\"store.columns()\"\r\n [gutterSize]=\"store.gutterSize()\"\r\n ></ngx-dashboard-editor>\r\n } @else {\r\n <!-- Read-only viewer -->\r\n <ngx-dashboard-viewer\r\n [rows]=\"store.rows()\"\r\n [columns]=\"store.columns()\"\r\n [gutterSize]=\"store.gutterSize()\"\r\n ></ngx-dashboard-viewer>\r\n }\r\n</div>\r\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: "ngmodule", type: CommonModule }, { kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2156
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2157
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", 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 } }, 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 -->\r\n<div class=\"grid-container\">\r\n @if (editMode()) {\r\n <!-- Full editor with drag & drop capabilities -->\r\n <ngx-dashboard-editor\r\n [rows]=\"store.rows()\"\r\n [columns]=\"store.columns()\"\r\n [gutterSize]=\"store.gutterSize()\"\r\n ></ngx-dashboard-editor>\r\n } @else {\r\n <!-- Read-only viewer -->\r\n <ngx-dashboard-viewer\r\n [rows]=\"store.rows()\"\r\n [columns]=\"store.columns()\"\r\n [gutterSize]=\"store.gutterSize()\"\r\n ></ngx-dashboard-viewer>\r\n }\r\n</div>\r\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: "ngmodule", type: CommonModule }, { kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2087
2158
  }
2088
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DashboardComponent, decorators: [{
2159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: DashboardComponent, decorators: [{
2089
2160
  type: Component,
2090
2161
  args: [{ selector: 'ngx-dashboard', standalone: true, imports: [CommonModule, DashboardViewerComponent, DashboardEditorComponent], providers: [DashboardStore, DashboardViewportService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
2091
2162
  '[style.--rows]': 'store.rows()',
@@ -2104,13 +2175,13 @@ class WidgetListComponent {
2104
2175
  #sanitizer = inject(DomSanitizer);
2105
2176
  #renderer = inject(Renderer2);
2106
2177
  #bridge = inject(DashboardBridgeService);
2107
- activeWidget = signal(null);
2178
+ activeWidget = signal(null, ...(ngDevMode ? [{ debugName: "activeWidget" }] : []));
2108
2179
  // Get grid cell dimensions from bridge service (uses first available dashboard)
2109
2180
  gridCellDimensions = this.#bridge.availableDimensions;
2110
2181
  widgets = computed(() => this.#service.widgetTypes().map((w) => ({
2111
2182
  ...w.metadata,
2112
2183
  safeSvgIcon: this.#sanitizer.bypassSecurityTrustHtml(w.metadata.svgIcon),
2113
- })));
2184
+ })), ...(ngDevMode ? [{ debugName: "widgets" }] : []));
2114
2185
  onDragStart(event, widget) {
2115
2186
  if (!event.dataTransfer)
2116
2187
  return;
@@ -2125,6 +2196,7 @@ class WidgetListComponent {
2125
2196
  const ghost = this.#createDragGhost(widget.svgIcon);
2126
2197
  document.body.appendChild(ghost);
2127
2198
  // Force reflow to ensure element is rendered
2199
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2128
2200
  const _reflow = ghost.offsetHeight;
2129
2201
  event.dataTransfer.setDragImage(ghost, 10, 10);
2130
2202
  // Delay removal to ensure browser has time to snapshot the drag image
@@ -2157,12 +2229,12 @@ class WidgetListComponent {
2157
2229
  }
2158
2230
  return el;
2159
2231
  }
2160
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: WidgetListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2161
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: WidgetListComponent, isStandalone: true, selector: "ngx-dashboard-widget-list", ngImport: i0, template: "<!-- widget-list.component.html -->\r\n<div class=\"widget-list\" role=\"list\" aria-label=\"Available widgets\">\r\n @for (widget of widgets(); track widget.widgetTypeid) {\r\n <div\r\n class=\"widget-list-item\"\r\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\r\n draggable=\"true\"\r\n (dragstart)=\"onDragStart($event, widget)\"\r\n (dragend)=\"onDragEnd()\"\r\n role=\"listitem\"\r\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\r\n [attr.aria-label]=\"widget.name + ' widget: ' + widget.description\"\r\n tabindex=\"0\"\r\n >\r\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\r\n <div class=\"content\">\r\n <strong>{{ widget.name }}</strong>\r\n <small>{{ widget.description }}</small>\r\n </div>\r\n </div>\r\n }\r\n</div>", 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}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block;fill:var(--mat-sys-on-surface-variant, #5f5f5f);transition:fill var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.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 ::ng-deep svg{fill: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 ::ng-deep svg{fill: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}.drag-ghost .icon ::ng-deep svg{display:block;fill:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2232
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: WidgetListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2233
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: WidgetListComponent, isStandalone: true, selector: "ngx-dashboard-widget-list", ngImport: i0, template: "<!-- widget-list.component.html -->\r\n<div class=\"widget-list\" role=\"list\" aria-label=\"Available widgets\">\r\n @for (widget of widgets(); track widget.widgetTypeid) {\r\n <div\r\n class=\"widget-list-item\"\r\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\r\n draggable=\"true\"\r\n (dragstart)=\"onDragStart($event, widget)\"\r\n (dragend)=\"onDragEnd()\"\r\n role=\"listitem\"\r\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\r\n [attr.aria-label]=\"widget.name + ' widget: ' + widget.description\"\r\n tabindex=\"0\"\r\n >\r\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\r\n <div class=\"content\">\r\n <strong>{{ widget.name }}</strong>\r\n <small>{{ widget.description }}</small>\r\n </div>\r\n </div>\r\n }\r\n</div>", 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"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2162
2234
  }
2163
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: WidgetListComponent, decorators: [{
2235
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: WidgetListComponent, decorators: [{
2164
2236
  type: Component,
2165
- args: [{ selector: 'ngx-dashboard-widget-list', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- widget-list.component.html -->\r\n<div class=\"widget-list\" role=\"list\" aria-label=\"Available widgets\">\r\n @for (widget of widgets(); track widget.widgetTypeid) {\r\n <div\r\n class=\"widget-list-item\"\r\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\r\n draggable=\"true\"\r\n (dragstart)=\"onDragStart($event, widget)\"\r\n (dragend)=\"onDragEnd()\"\r\n role=\"listitem\"\r\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\r\n [attr.aria-label]=\"widget.name + ' widget: ' + widget.description\"\r\n tabindex=\"0\"\r\n >\r\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\r\n <div class=\"content\">\r\n <strong>{{ widget.name }}</strong>\r\n <small>{{ widget.description }}</small>\r\n </div>\r\n </div>\r\n }\r\n</div>", 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}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block;fill:var(--mat-sys-on-surface-variant, #5f5f5f);transition:fill var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.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 ::ng-deep svg{fill: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 ::ng-deep svg{fill: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}.drag-ghost .icon ::ng-deep svg{display:block;fill:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}\n"] }]
2237
+ args: [{ selector: 'ngx-dashboard-widget-list', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- widget-list.component.html -->\r\n<div class=\"widget-list\" role=\"list\" aria-label=\"Available widgets\">\r\n @for (widget of widgets(); track widget.widgetTypeid) {\r\n <div\r\n class=\"widget-list-item\"\r\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\r\n draggable=\"true\"\r\n (dragstart)=\"onDragStart($event, widget)\"\r\n (dragend)=\"onDragEnd()\"\r\n role=\"listitem\"\r\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\r\n [attr.aria-label]=\"widget.name + ' widget: ' + widget.description\"\r\n tabindex=\"0\"\r\n >\r\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\r\n <div class=\"content\">\r\n <strong>{{ widget.name }}</strong>\r\n <small>{{ widget.description }}</small>\r\n </div>\r\n </div>\r\n }\r\n</div>", 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"] }]
2166
2238
  }] });
2167
2239
 
2168
2240
  /*
@@ -2174,5 +2246,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
2174
2246
  * Generated bundle index. Do not edit.
2175
2247
  */
2176
2248
 
2177
- export { CELL_SETTINGS_DIALOG_PROVIDER, CellIdUtils, CellSettingsDialogProvider, DEFAULT_RESERVED_SPACE, DashboardComponent, DashboardEditorComponent, DashboardService, DashboardViewerComponent, DefaultCellSettingsDialogProvider, WidgetListComponent, createDefaultDashboard, createEmptyDashboard, createFactoryFromComponent };
2249
+ export { CELL_SETTINGS_DIALOG_PROVIDER, CellIdUtils, CellSettingsDialogProvider, DEFAULT_RESERVED_SPACE, DashboardComponent, DashboardEditorComponent, DashboardService, DashboardViewerComponent, DefaultCellSettingsDialogProvider, WidgetIdUtils, WidgetListComponent, createDefaultDashboard, createEmptyDashboard, createFactoryFromComponent };
2178
2250
  //# sourceMappingURL=dragonworks-ngx-dashboard.mjs.map