@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,
|
|
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
|
|
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
|
|
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.
|
|
179
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.
|
|
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.
|
|
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.
|
|
227
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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,
|
|
297
|
+
isCellOccupied(cells, row, col, excludeWidgetId) {
|
|
239
298
|
return cells.some((cell) => {
|
|
240
|
-
// Skip checking against the
|
|
241
|
-
if (
|
|
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
|
|
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,
|
|
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
|
-
|
|
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.
|
|
397
|
+
cells: computed(() => Object.values(store.widgetsById())),
|
|
339
398
|
})), withMethods((store) => ({
|
|
340
399
|
addWidget(cell) {
|
|
341
|
-
const
|
|
400
|
+
const widgetKey = WidgetIdUtils.toString(cell.widgetId);
|
|
342
401
|
patchState(store, {
|
|
343
|
-
|
|
402
|
+
widgetsById: { ...store.widgetsById(), [widgetKey]: cell },
|
|
344
403
|
});
|
|
345
404
|
},
|
|
346
|
-
removeWidget(
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
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(
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
if (
|
|
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
|
-
|
|
357
|
-
...store.
|
|
358
|
-
[
|
|
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
|
|
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
|
|
438
|
+
const widgetKey = WidgetIdUtils.toString(widgetId);
|
|
375
439
|
patchState(store, {
|
|
376
|
-
|
|
440
|
+
widgetsById: { ...store.widgetsById(), [widgetKey]: cell },
|
|
377
441
|
});
|
|
378
442
|
},
|
|
379
|
-
updateCellSettings(
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
if (
|
|
443
|
+
updateCellSettings(widgetId, flat) {
|
|
444
|
+
const widgetKey = WidgetIdUtils.toString(widgetId);
|
|
445
|
+
const existingWidget = store.widgetsById()[widgetKey];
|
|
446
|
+
if (existingWidget) {
|
|
383
447
|
patchState(store, {
|
|
384
|
-
|
|
385
|
-
...store.
|
|
386
|
-
[
|
|
448
|
+
widgetsById: {
|
|
449
|
+
...store.widgetsById(),
|
|
450
|
+
[widgetKey]: { ...existingWidget, flat },
|
|
387
451
|
},
|
|
388
452
|
});
|
|
389
453
|
}
|
|
390
454
|
},
|
|
391
|
-
updateWidgetSpan(
|
|
392
|
-
const
|
|
393
|
-
const
|
|
394
|
-
if (
|
|
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
|
-
|
|
397
|
-
...store.
|
|
398
|
-
[
|
|
460
|
+
widgetsById: {
|
|
461
|
+
...store.widgetsById(),
|
|
462
|
+
[widgetKey]: { ...existingWidget, rowSpan, colSpan },
|
|
399
463
|
},
|
|
400
464
|
});
|
|
401
465
|
}
|
|
402
466
|
},
|
|
403
|
-
updateWidgetState(
|
|
404
|
-
const
|
|
405
|
-
const
|
|
406
|
-
if (
|
|
467
|
+
updateWidgetState(widgetId, widgetState) {
|
|
468
|
+
const widgetKey = WidgetIdUtils.toString(widgetId);
|
|
469
|
+
const existingWidget = store.widgetsById()[widgetKey];
|
|
470
|
+
if (existingWidget) {
|
|
407
471
|
patchState(store, {
|
|
408
|
-
|
|
409
|
-
...store.
|
|
410
|
-
[
|
|
472
|
+
widgetsById: {
|
|
473
|
+
...store.widgetsById(),
|
|
474
|
+
[widgetKey]: { ...existingWidget, widgetState },
|
|
411
475
|
},
|
|
412
476
|
});
|
|
413
477
|
}
|
|
414
478
|
},
|
|
415
|
-
updateAllWidgetStates(
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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, {
|
|
493
|
+
patchState(store, { widgetsById: updatedWidgetsById });
|
|
424
494
|
},
|
|
425
495
|
clearDashboard() {
|
|
426
|
-
patchState(store, {
|
|
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.
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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.
|
|
836
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.
|
|
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:
|
|
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.
|
|
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: () => [
|
|
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.
|
|
934
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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.
|
|
969
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1220
|
+
this.delete.emit(this.widgetId());
|
|
1147
1221
|
}
|
|
1148
1222
|
async onSettings() {
|
|
1149
1223
|
const currentSettings = {
|
|
1150
|
-
id: CellIdUtils.toString(this.
|
|
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.
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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.
|
|
1233
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
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.
|
|
1289
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
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.
|
|
1359
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
1549
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1685
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1834
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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.
|
|
1953
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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.
|
|
2086
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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.
|
|
2161
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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
|
|
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
|