@dragonworks/ngx-dashboard 21.2.2 → 22.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.
|
@@ -23,7 +23,7 @@ import { isPlatformBrowser } from '@angular/common';
|
|
|
23
23
|
|
|
24
24
|
// Auto-generated by scripts/generate-versions.js
|
|
25
25
|
// Do not edit manually
|
|
26
|
-
const NGX_DASHBOARD_VERSION = '
|
|
26
|
+
const NGX_DASHBOARD_VERSION = '22.1.0';
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Maximum number of columns supported by the grid.
|
|
@@ -232,8 +232,10 @@ class UnknownWidgetComponent {
|
|
|
232
232
|
};
|
|
233
233
|
state = signal({
|
|
234
234
|
originalWidgetTypeid: 'unknown',
|
|
235
|
-
},
|
|
236
|
-
|
|
235
|
+
}, /* @ts-ignore */
|
|
236
|
+
...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
237
|
+
tooltipText = computed(() => `${this.state().originalWidgetTypeid}`, /* @ts-ignore */
|
|
238
|
+
...(ngDevMode ? [{ debugName: "tooltipText" }] : /* istanbul ignore next */ []));
|
|
237
239
|
dashboardSetState(state) {
|
|
238
240
|
if (state && typeof state === 'object' && 'originalWidgetTypeid' in state) {
|
|
239
241
|
this.state.set(state);
|
|
@@ -242,14 +244,14 @@ class UnknownWidgetComponent {
|
|
|
242
244
|
dashboardGetState() {
|
|
243
245
|
return this.state();
|
|
244
246
|
}
|
|
245
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
246
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
247
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UnknownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
248
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.4", type: UnknownWidgetComponent, isStandalone: true, selector: "lib-unknown-widget", ngImport: i0, template: `
|
|
247
249
|
<div class="unknown-widget-container" [matTooltip]="tooltipText()">
|
|
248
250
|
<mat-icon class="unknown-widget-icon">error_outline</mat-icon>
|
|
249
251
|
</div>
|
|
250
252
|
`, isInline: true, styles: [".unknown-widget-container{display:flex;align-items:center;justify-content:center;width:100%;height:100%;background-color:var(--mat-sys-error);border-radius:8px;container-type:size}.unknown-widget-icon{color:var(--mat-sys-on-error);font-size:clamp(12px,75cqmin,68px);width:clamp(12px,75cqmin,68px);height:clamp(12px,75cqmin,68px)}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
251
253
|
}
|
|
252
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
254
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UnknownWidgetComponent, decorators: [{
|
|
253
255
|
type: Component,
|
|
254
256
|
args: [{ selector: 'lib-unknown-widget', imports: [MatIconModule, MatTooltipModule], template: `
|
|
255
257
|
<div class="unknown-widget-container" [matTooltip]="tooltipText()">
|
|
@@ -260,7 +262,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
260
262
|
|
|
261
263
|
// dashboard.service.ts
|
|
262
264
|
class DashboardService {
|
|
263
|
-
#widgetTypes = signal([],
|
|
265
|
+
#widgetTypes = signal([], /* @ts-ignore */
|
|
266
|
+
...(ngDevMode ? [{ debugName: "#widgetTypes" }] : /* istanbul ignore next */ []));
|
|
264
267
|
#widgetFactoryMap = new Map();
|
|
265
268
|
#sharedStateProviders = new Map();
|
|
266
269
|
#pendingSharedStates = new Map();
|
|
@@ -362,10 +365,10 @@ class DashboardService {
|
|
|
362
365
|
}
|
|
363
366
|
}
|
|
364
367
|
}
|
|
365
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
366
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
368
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
369
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardService, providedIn: 'root' });
|
|
367
370
|
}
|
|
368
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
371
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardService, decorators: [{
|
|
369
372
|
type: Injectable,
|
|
370
373
|
args: [{
|
|
371
374
|
providedIn: 'root',
|
|
@@ -556,6 +559,38 @@ function applySelectionFilter(selection, allCells, options = {}) {
|
|
|
556
559
|
};
|
|
557
560
|
}
|
|
558
561
|
|
|
562
|
+
/** Floor a requested track count to a positive integer; non-finite -> 1. */
|
|
563
|
+
function sanitizeRequest(value) {
|
|
564
|
+
return Number.isFinite(value) ? Math.max(1, Math.floor(value)) : 1;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Clamp a requested grid size to the smallest size that still contains every
|
|
568
|
+
* widget's full footprint (the content floor). Pure: computes the result but
|
|
569
|
+
* does not mutate any state, so it is shared by both the committed resize
|
|
570
|
+
* (`setGridSize`) and the in-progress drag preview.
|
|
571
|
+
*
|
|
572
|
+
* Values below 1 are treated as 1; fractional values are floored.
|
|
573
|
+
*/
|
|
574
|
+
function clampGridSize(requestedRows, requestedColumns, cells) {
|
|
575
|
+
// The bounding box's max edges are span-aware (a widget at col 14 spanning
|
|
576
|
+
// 3 columns needs at least 16 columns). null = empty dashboard.
|
|
577
|
+
const bounds = calculateMinimalBoundingBox(cells);
|
|
578
|
+
const minRows = bounds?.maxRow ?? 1;
|
|
579
|
+
const minColumns = bounds?.maxCol ?? 1;
|
|
580
|
+
// Sanitize non-finite input (NaN/Infinity from e.g. parseInt of empty user
|
|
581
|
+
// input) to 1 so it can never reach committed grid state; clamp-to-content
|
|
582
|
+
// then floors it at the occupied extent.
|
|
583
|
+
const reqRows = sanitizeRequest(requestedRows);
|
|
584
|
+
const reqColumns = sanitizeRequest(requestedColumns);
|
|
585
|
+
const rows = Math.max(minRows, reqRows);
|
|
586
|
+
const columns = Math.max(minColumns, reqColumns);
|
|
587
|
+
return {
|
|
588
|
+
rows,
|
|
589
|
+
columns,
|
|
590
|
+
clamped: rows !== reqRows || columns !== reqColumns,
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
559
594
|
const initialGridConfigState = {
|
|
560
595
|
rows: 8,
|
|
561
596
|
columns: 16,
|
|
@@ -719,6 +754,9 @@ const initialDragDropState = {
|
|
|
719
754
|
hoveredDropZone: null,
|
|
720
755
|
};
|
|
721
756
|
const withDragDrop = () => signalStoreFeature(withState(initialDragDropState), withComputed((store) => ({
|
|
757
|
+
// True while any widget drag is in progress. Shared by components that
|
|
758
|
+
// need to suppress conflicting affordances during a drag.
|
|
759
|
+
isDragActive: computed(() => !!store.dragData()),
|
|
722
760
|
// Highlighted zones during drag
|
|
723
761
|
highlightedZones: computed(() => calculateHighlightedZones(store.dragData(), store.hoveredDropZone())),
|
|
724
762
|
})), withComputed((store) => ({
|
|
@@ -945,6 +983,32 @@ const withResize = () => signalStoreFeature(withState(initialResizeState), withM
|
|
|
945
983
|
},
|
|
946
984
|
})));
|
|
947
985
|
|
|
986
|
+
const initialGridResizeState = {
|
|
987
|
+
gridResizePreview: null,
|
|
988
|
+
};
|
|
989
|
+
const withGridResize = () => signalStoreFeature(withState(initialGridResizeState), withMethods((store) => ({
|
|
990
|
+
// Needs cross-feature dependencies (current size + cells for the floor),
|
|
991
|
+
// injected by the store wrapper. Skips the patch when the clamped result
|
|
992
|
+
// is unchanged — e.g. dragging further past the content floor yields new
|
|
993
|
+
// raw deltas but the same clamped preview — avoiding redundant re-renders.
|
|
994
|
+
_previewGridResize(deltaRows, deltaColumns, dependencies) {
|
|
995
|
+
const preview = clampGridSize(dependencies.rows + deltaRows, dependencies.columns + deltaColumns, dependencies.cells);
|
|
996
|
+
const current = store.gridResizePreview();
|
|
997
|
+
if (current &&
|
|
998
|
+
current.rows === preview.rows &&
|
|
999
|
+
current.columns === preview.columns &&
|
|
1000
|
+
current.clamped === preview.clamped) {
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
patchState(store, { gridResizePreview: preview });
|
|
1004
|
+
},
|
|
1005
|
+
clearGridResizePreview() {
|
|
1006
|
+
if (store.gridResizePreview() !== null) {
|
|
1007
|
+
patchState(store, { gridResizePreview: null });
|
|
1008
|
+
}
|
|
1009
|
+
},
|
|
1010
|
+
})));
|
|
1011
|
+
|
|
948
1012
|
/** Returns the intended widget type ID, falling back to the factory's type ID */
|
|
949
1013
|
function effectiveWidgetTypeid(cell) {
|
|
950
1014
|
return cell.widgetTypeid ?? cell.widgetFactory.widgetTypeid;
|
|
@@ -954,9 +1018,15 @@ const initialState = {
|
|
|
954
1018
|
};
|
|
955
1019
|
const DashboardStore = signalStore(withState(initialState), withProps(() => ({
|
|
956
1020
|
dashboardService: inject(DashboardService),
|
|
957
|
-
})), withGridConfig(), withWidgetManagement(), withResize(), withDragDrop(),
|
|
1021
|
+
})), withGridConfig(), withWidgetManagement(), withResize(), withGridResize(), withDragDrop(),
|
|
958
1022
|
// Cross-feature computed properties (need access to multiple features)
|
|
959
1023
|
withComputed((store) => ({
|
|
1024
|
+
// Effective grid size: the live resize preview when a handle drag is in
|
|
1025
|
+
// progress, otherwise the committed size. Consumed wherever the rendered
|
|
1026
|
+
// grid size matters (editor template, outer frame, viewport letterboxing)
|
|
1027
|
+
// so they all reflow together during a drag.
|
|
1028
|
+
effectiveRows: computed(() => store.gridResizePreview()?.rows ?? store.rows()),
|
|
1029
|
+
effectiveColumns: computed(() => store.gridResizePreview()?.columns ?? store.columns()),
|
|
960
1030
|
// Invalid zones (collision detection)
|
|
961
1031
|
invalidHighlightMap: computed(() => {
|
|
962
1032
|
const collisionInfo = calculateCollisionInfo(store.dragData(), store.hoveredDropZone(), store.cells(), store.rows(), store.columns());
|
|
@@ -1007,6 +1077,24 @@ withMethods((store) => ({
|
|
|
1007
1077
|
},
|
|
1008
1078
|
});
|
|
1009
1079
|
},
|
|
1080
|
+
// GRID RESIZE (change row/column counts on a populated dashboard)
|
|
1081
|
+
// Clamp-to-content policy: a requested size that would push a widget out
|
|
1082
|
+
// of bounds is snapped up to the smallest size that still contains every
|
|
1083
|
+
// widget's full footprint, so shrinking never orphans a widget.
|
|
1084
|
+
setGridSize(rows, columns) {
|
|
1085
|
+
const result = clampGridSize(rows, columns, store.cells());
|
|
1086
|
+
store.setGridConfig({ rows: result.rows, columns: result.columns });
|
|
1087
|
+
return result;
|
|
1088
|
+
},
|
|
1089
|
+
// Preview a relative grid resize during a handle drag (no commit). Stores
|
|
1090
|
+
// the clamped target in gridResizePreview so the editor can live-reflow.
|
|
1091
|
+
previewGridResize(deltaRows, deltaColumns) {
|
|
1092
|
+
store._previewGridResize(deltaRows, deltaColumns, {
|
|
1093
|
+
rows: store.rows(),
|
|
1094
|
+
columns: store.columns(),
|
|
1095
|
+
cells: store.cells(),
|
|
1096
|
+
});
|
|
1097
|
+
},
|
|
1010
1098
|
// EXPORT/IMPORT METHODS (need access to multiple features)
|
|
1011
1099
|
exportDashboard(getCurrentWidgetStates, selection, selectionOptions) {
|
|
1012
1100
|
// Get live widget states if callback provided, otherwise use stored states
|
|
@@ -1102,6 +1190,27 @@ withMethods((store) => ({
|
|
|
1102
1190
|
});
|
|
1103
1191
|
},
|
|
1104
1192
|
})),
|
|
1193
|
+
// End a grid resize gesture atomically (mirrors withResize._endResize):
|
|
1194
|
+
// clear the live preview, no-op on a zero delta, otherwise commit the
|
|
1195
|
+
// relative resize. Returns null (no committed change) when the delta is zero
|
|
1196
|
+
// or clamp-to-content leaves the size unchanged, so callers don't signal a
|
|
1197
|
+
// resize that did nothing. Split into its own block so it can call the
|
|
1198
|
+
// absolute setGridSize above (siblings in one withMethods block aren't
|
|
1199
|
+
// visible to each other).
|
|
1200
|
+
withMethods((store) => ({
|
|
1201
|
+
endGridResize(deltaRows, deltaColumns) {
|
|
1202
|
+
store.clearGridResizePreview();
|
|
1203
|
+
if (deltaRows === 0 && deltaColumns === 0)
|
|
1204
|
+
return null;
|
|
1205
|
+
const beforeRows = store.rows();
|
|
1206
|
+
const beforeColumns = store.columns();
|
|
1207
|
+
const result = store.setGridSize(beforeRows + deltaRows, beforeColumns + deltaColumns);
|
|
1208
|
+
if (result.rows === beforeRows && result.columns === beforeColumns) {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
return result;
|
|
1212
|
+
},
|
|
1213
|
+
})),
|
|
1105
1214
|
// Cross-feature computed properties that depend on resize + widget data (using utility functions)
|
|
1106
1215
|
withComputed((store) => ({
|
|
1107
1216
|
// Compute preview cells during resize using utility function
|
|
@@ -1143,8 +1252,8 @@ class CellSettingsDialogComponent {
|
|
|
1143
1252
|
};
|
|
1144
1253
|
this.dialogRef.close(newData);
|
|
1145
1254
|
}
|
|
1146
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1147
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
1255
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellSettingsDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1256
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.4", type: CellSettingsDialogComponent, isStandalone: true, selector: "lib-cell-settings-dialog", ngImport: i0, template: `
|
|
1148
1257
|
<h2 mat-dialog-title i18n="@@ngx.dashboard.cell.settings.title">
|
|
1149
1258
|
Cell Display Settings
|
|
1150
1259
|
</h2>
|
|
@@ -1210,7 +1319,7 @@ class CellSettingsDialogComponent {
|
|
|
1210
1319
|
</mat-dialog-actions>
|
|
1211
1320
|
`, isInline: true, styles: ["mat-dialog-content{display:block;overflow-y:auto;overflow-x:hidden;padding-top:.5rem}.cell-info{margin:0 0 1.5rem;padding-bottom:1rem}.radio-group{width:100%}mat-radio-group{display:block}mat-radio-button{width:100%;display:block;margin-bottom:1rem}mat-radio-button:last-child{margin-bottom:0}.radio-option{margin-left:.75rem;padding:.25rem 0}.option-title{display:block;margin-bottom:.25rem}.option-description{display:block}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i4$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i4$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1212
1321
|
}
|
|
1213
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1322
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellSettingsDialogComponent, decorators: [{
|
|
1214
1323
|
type: Component,
|
|
1215
1324
|
args: [{ selector: 'lib-cell-settings-dialog', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1216
1325
|
FormsModule,
|
|
@@ -1301,10 +1410,10 @@ class DefaultCellSettingsDialogProvider extends CellSettingsDialogProvider {
|
|
|
1301
1410
|
const result = await firstValueFrom(dialogRef.afterClosed());
|
|
1302
1411
|
return result;
|
|
1303
1412
|
}
|
|
1304
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1305
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1413
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DefaultCellSettingsDialogProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
1414
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DefaultCellSettingsDialogProvider, providedIn: 'root' });
|
|
1306
1415
|
}
|
|
1307
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1416
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DefaultCellSettingsDialogProvider, decorators: [{
|
|
1308
1417
|
type: Injectable,
|
|
1309
1418
|
args: [{
|
|
1310
1419
|
providedIn: 'root',
|
|
@@ -1328,7 +1437,8 @@ const CELL_SETTINGS_DIALOG_PROVIDER = new InjectionToken('CellSettingsDialogProv
|
|
|
1328
1437
|
});
|
|
1329
1438
|
|
|
1330
1439
|
class CellContextMenuService {
|
|
1331
|
-
#activeMenu = signal(null,
|
|
1440
|
+
#activeMenu = signal(null, /* @ts-ignore */
|
|
1441
|
+
...(ngDevMode ? [{ debugName: "#activeMenu" }] : /* istanbul ignore next */ []));
|
|
1332
1442
|
activeMenu = this.#activeMenu.asReadonly();
|
|
1333
1443
|
show(x, y, items) {
|
|
1334
1444
|
this.#activeMenu.set({ x, y, items });
|
|
@@ -1336,26 +1446,37 @@ class CellContextMenuService {
|
|
|
1336
1446
|
hide() {
|
|
1337
1447
|
this.#activeMenu.set(null);
|
|
1338
1448
|
}
|
|
1339
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1340
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1449
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1450
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellContextMenuService });
|
|
1341
1451
|
}
|
|
1342
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1452
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellContextMenuService, decorators: [{
|
|
1343
1453
|
type: Injectable
|
|
1344
1454
|
}] });
|
|
1345
1455
|
|
|
1346
1456
|
// cell.component.ts
|
|
1347
1457
|
class CellComponent {
|
|
1348
|
-
widgetId = input.required(
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1458
|
+
widgetId = input.required(/* @ts-ignore */
|
|
1459
|
+
...(ngDevMode ? [{ debugName: "widgetId" }] : /* istanbul ignore next */ [])); // Unique widget instance identifier
|
|
1460
|
+
cellId = input.required(/* @ts-ignore */
|
|
1461
|
+
...(ngDevMode ? [{ debugName: "cellId" }] : /* istanbul ignore next */ [])); // Current grid position
|
|
1462
|
+
widgetFactory = input(undefined, /* @ts-ignore */
|
|
1463
|
+
...(ngDevMode ? [{ debugName: "widgetFactory" }] : /* istanbul ignore next */ []));
|
|
1464
|
+
widgetState = input(undefined, /* @ts-ignore */
|
|
1465
|
+
...(ngDevMode ? [{ debugName: "widgetState" }] : /* istanbul ignore next */ []));
|
|
1466
|
+
isEditMode = input(false, /* @ts-ignore */
|
|
1467
|
+
...(ngDevMode ? [{ debugName: "isEditMode" }] : /* istanbul ignore next */ []));
|
|
1468
|
+
flat = input(undefined, /* @ts-ignore */
|
|
1469
|
+
...(ngDevMode ? [{ debugName: "flat" }] : /* istanbul ignore next */ []));
|
|
1470
|
+
row = model.required(/* @ts-ignore */
|
|
1471
|
+
...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
1472
|
+
column = model.required(/* @ts-ignore */
|
|
1473
|
+
...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
1474
|
+
rowSpan = input(1, /* @ts-ignore */
|
|
1475
|
+
...(ngDevMode ? [{ debugName: "rowSpan" }] : /* istanbul ignore next */ []));
|
|
1476
|
+
colSpan = input(1, /* @ts-ignore */
|
|
1477
|
+
...(ngDevMode ? [{ debugName: "colSpan" }] : /* istanbul ignore next */ []));
|
|
1478
|
+
draggable = input(false, /* @ts-ignore */
|
|
1479
|
+
...(ngDevMode ? [{ debugName: "draggable" }] : /* istanbul ignore next */ []));
|
|
1359
1480
|
dragStart = output();
|
|
1360
1481
|
dragEnd = output();
|
|
1361
1482
|
edit = output();
|
|
@@ -1376,20 +1497,26 @@ class CellComponent {
|
|
|
1376
1497
|
// Document event listeners cleanup function
|
|
1377
1498
|
// Performance: Only created when actively resizing, not for every cell
|
|
1378
1499
|
#documentListeners;
|
|
1379
|
-
isDragging = signal(false,
|
|
1380
|
-
|
|
1381
|
-
|
|
1500
|
+
isDragging = signal(false, /* @ts-ignore */
|
|
1501
|
+
...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
|
|
1502
|
+
gridRowStyle = computed(() => `${this.row()} / span ${this.rowSpan()}`, /* @ts-ignore */
|
|
1503
|
+
...(ngDevMode ? [{ debugName: "gridRowStyle" }] : /* istanbul ignore next */ []));
|
|
1504
|
+
gridColumnStyle = computed(() => `${this.column()} / span ${this.colSpan()}`, /* @ts-ignore */
|
|
1505
|
+
...(ngDevMode ? [{ debugName: "gridColumnStyle" }] : /* istanbul ignore next */ []));
|
|
1382
1506
|
isResizing = computed(() => {
|
|
1383
1507
|
const resizeData = this.#store.resizeData();
|
|
1384
1508
|
return resizeData
|
|
1385
1509
|
? CellIdUtils.equals(resizeData.cellId, this.cellId())
|
|
1386
1510
|
: false;
|
|
1387
|
-
},
|
|
1388
|
-
|
|
1511
|
+
}, /* @ts-ignore */
|
|
1512
|
+
...(ngDevMode ? [{ debugName: "isResizing" }] : /* istanbul ignore next */ []));
|
|
1513
|
+
isDragActive = this.#store.isDragActive;
|
|
1389
1514
|
resizeData = this.#store.resizeData;
|
|
1390
1515
|
gridCellDimensions = this.#store.gridCellDimensions;
|
|
1391
|
-
resizeDirection = signal(null,
|
|
1392
|
-
|
|
1516
|
+
resizeDirection = signal(null, /* @ts-ignore */
|
|
1517
|
+
...(ngDevMode ? [{ debugName: "resizeDirection" }] : /* istanbul ignore next */ []));
|
|
1518
|
+
resizeStartPos = signal({ x: 0, y: 0 }, /* @ts-ignore */
|
|
1519
|
+
...(ngDevMode ? [{ debugName: "resizeStartPos" }] : /* istanbul ignore next */ []));
|
|
1393
1520
|
constructor() {
|
|
1394
1521
|
// widget creation - triggers when factory or state changes
|
|
1395
1522
|
effect(() => {
|
|
@@ -1624,10 +1751,10 @@ class CellComponent {
|
|
|
1624
1751
|
// Fall back to stored state if widget doesn't implement dashboardGetState
|
|
1625
1752
|
return this.widgetState();
|
|
1626
1753
|
}
|
|
1627
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1628
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1754
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1755
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: CellComponent, isStandalone: true, selector: "lib-cell", inputs: { widgetId: { classPropertyName: "widgetId", publicName: "widgetId", isSignal: true, isRequired: true, transformFunction: null }, cellId: { classPropertyName: "cellId", publicName: "cellId", isSignal: true, isRequired: true, transformFunction: null }, widgetFactory: { classPropertyName: "widgetFactory", publicName: "widgetFactory", isSignal: true, isRequired: false, transformFunction: null }, widgetState: { classPropertyName: "widgetState", publicName: "widgetState", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, rowSpan: { classPropertyName: "rowSpan", publicName: "rowSpan", isSignal: true, isRequired: false, transformFunction: null }, colSpan: { classPropertyName: "colSpan", publicName: "colSpan", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { row: "rowChange", column: "columnChange", dragStart: "dragStart", dragEnd: "dragEnd", edit: "edit", delete: "delete", settings: "settings", resizeStart: "resizeStart", resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { properties: { "style.grid-row": "gridRowStyle()", "style.grid-column": "gridColumnStyle()", "class.is-dragging": "isDragging()", "class.drag-active": "isDragActive()", "class.flat": "flat() === true" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}:root .cursor-nwse-resize{cursor:nwse-resize!important}: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}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1629
1756
|
}
|
|
1630
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1757
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellComponent, decorators: [{
|
|
1631
1758
|
type: Component,
|
|
1632
1759
|
args: [{ selector: 'lib-cell', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1633
1760
|
'[style.grid-row]': 'gridRowStyle()',
|
|
@@ -1635,7 +1762,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1635
1762
|
'[class.is-dragging]': 'isDragging()',
|
|
1636
1763
|
'[class.drag-active]': 'isDragActive()',
|
|
1637
1764
|
'[class.flat]': 'flat() === true',
|
|
1638
|
-
}, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":host{display:block;width:100%;height:100%;position:relative;z-index:1;container-type:inline-size}:host(.drag-active):not(.is-dragging){pointer-events:none}:host(.is-dragging){z-index:100;opacity:.5;pointer-events:none}:host(.is-dragging) .content-area{pointer-events:none}:host(:hover) .resize-handle{opacity:1}.cell{width:100%;height:100%;border-radius:4px;box-shadow:0 2px 6px #0000001a;padding:0;box-sizing:border-box;overflow:hidden;position:relative;container-type:inline-size}.cell:hover{box-shadow:0 4px 10px #00000026;transform:translateY(-2px)}.cell.flat{box-shadow:none;border:none}.cell.flat:hover{box-shadow:none;transform:none;border-color:#bdbdbd}.cell.resizing{-webkit-user-select:none;user-select:none}.content-area{width:100%;height:100%;overflow:auto;pointer-events:auto;position:relative;z-index:1}.content-area:hover{transform:initial}:host(:not(.is-dragging)) .cell.flat .content-area{pointer-events:auto}:host(:not(.is-dragging)) .cell.flat .content-area:hover{transform:initial}.resize-handle{position:absolute;z-index:20}.resize-handle--right{cursor:col-resize;width:16px;height:100%;right:-8px;top:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--right:hover{opacity:1}.resize-handle--right:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle--bottom{cursor:row-resize;width:100%;height:16px;bottom:-8px;left:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--bottom:hover{opacity:1}.resize-handle--bottom:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle-line{background-color:#0000001a}.resize-handle--right .resize-handle-line{width:8px;height:40px;border-radius:2px}.resize-handle--bottom .resize-handle-line{width:40px;height:8px;border-radius:2px}.resize-preview{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary);padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;z-index:30}.cell.is-resizing{opacity:.6}.cell.is-resizing .resize-handle{background-color:#2196f380}
|
|
1765
|
+
}, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}:root .cursor-nwse-resize{cursor:nwse-resize!important}: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}\n"] }]
|
|
1639
1766
|
}], ctorParameters: () => [], propDecorators: { widgetId: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetId", required: true }] }], cellId: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellId", required: true }] }], widgetFactory: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetFactory", required: false }] }], widgetState: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetState", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: false }] }], flat: [{ type: i0.Input, args: [{ isSignal: true, alias: "flat", required: false }] }], row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }, { type: i0.Output, args: ["rowChange"] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }, { type: i0.Output, args: ["columnChange"] }], rowSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSpan", required: false }] }], colSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "colSpan", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], dragStart: [{ type: i0.Output, args: ["dragStart"] }], dragEnd: [{ type: i0.Output, args: ["dragEnd"] }], edit: [{ type: i0.Output, args: ["edit"] }], delete: [{ type: i0.Output, args: ["delete"] }], settings: [{ type: i0.Output, args: ["settings"] }], resizeStart: [{ type: i0.Output, args: ["resizeStart"] }], resizeMove: [{ type: i0.Output, args: ["resizeMove"] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], container: [{ type: i0.ViewChild, args: ['container', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
1640
1767
|
|
|
1641
1768
|
/**
|
|
@@ -1653,15 +1780,23 @@ class DashboardViewerComponent {
|
|
|
1653
1780
|
#store = inject(DashboardStore);
|
|
1654
1781
|
#renderer = inject(Renderer2);
|
|
1655
1782
|
#destroyRef = inject(DestroyRef);
|
|
1656
|
-
cellComponents = viewChildren(CellComponent,
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1783
|
+
cellComponents = viewChildren(CellComponent, /* @ts-ignore */
|
|
1784
|
+
...(ngDevMode ? [{ debugName: "cellComponents" }] : /* istanbul ignore next */ []));
|
|
1785
|
+
gridElement = viewChild('gridElement', /* @ts-ignore */
|
|
1786
|
+
...(ngDevMode ? [{ debugName: "gridElement" }] : /* istanbul ignore next */ []));
|
|
1787
|
+
rows = input.required(/* @ts-ignore */
|
|
1788
|
+
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
1789
|
+
columns = input.required(/* @ts-ignore */
|
|
1790
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
1791
|
+
gutterSize = input('1em', /* @ts-ignore */
|
|
1792
|
+
...(ngDevMode ? [{ debugName: "gutterSize" }] : /* istanbul ignore next */ []));
|
|
1793
|
+
gutters = computed(() => this.columns() + 1, /* @ts-ignore */
|
|
1794
|
+
...(ngDevMode ? [{ debugName: "gutters" }] : /* istanbul ignore next */ []));
|
|
1662
1795
|
// Selection feature
|
|
1663
|
-
enableSelection = input(false,
|
|
1664
|
-
|
|
1796
|
+
enableSelection = input(false, /* @ts-ignore */
|
|
1797
|
+
...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
|
|
1798
|
+
selectionModifier = input(null, /* @ts-ignore */
|
|
1799
|
+
...(ngDevMode ? [{ debugName: "selectionModifier" }] : /* istanbul ignore next */ []));
|
|
1665
1800
|
/**
|
|
1666
1801
|
* Minimum pointer movement (in CSS pixels) between pointerdown and
|
|
1667
1802
|
* pointerup required to emit `selectionComplete`. Below the threshold,
|
|
@@ -1670,16 +1805,21 @@ class DashboardViewerComponent {
|
|
|
1670
1805
|
* Default 4 — matches OS-native click-vs-drag thresholds. Set to 0 to
|
|
1671
1806
|
* preserve the legacy behavior where every pointerup emits.
|
|
1672
1807
|
*/
|
|
1673
|
-
dragThreshold = input(4,
|
|
1808
|
+
dragThreshold = input(4, /* @ts-ignore */
|
|
1809
|
+
...(ngDevMode ? [{ debugName: "dragThreshold" }] : /* istanbul ignore next */ []));
|
|
1674
1810
|
selectionComplete = output();
|
|
1675
1811
|
// store signals - read-only
|
|
1676
1812
|
cells = this.#store.cells;
|
|
1677
1813
|
// Selection state
|
|
1678
|
-
isSelecting = signal(false,
|
|
1679
|
-
|
|
1680
|
-
|
|
1814
|
+
isSelecting = signal(false, /* @ts-ignore */
|
|
1815
|
+
...(ngDevMode ? [{ debugName: "isSelecting" }] : /* istanbul ignore next */ []));
|
|
1816
|
+
selectionStart = signal(null, /* @ts-ignore */
|
|
1817
|
+
...(ngDevMode ? [{ debugName: "selectionStart" }] : /* istanbul ignore next */ []));
|
|
1818
|
+
selectionCurrent = signal(null, /* @ts-ignore */
|
|
1819
|
+
...(ngDevMode ? [{ debugName: "selectionCurrent" }] : /* istanbul ignore next */ []));
|
|
1681
1820
|
// Modifier-key gating state for selectionModifier
|
|
1682
|
-
#modifierHeld = signal(false,
|
|
1821
|
+
#modifierHeld = signal(false, /* @ts-ignore */
|
|
1822
|
+
...(ngDevMode ? [{ debugName: "#modifierHeld" }] : /* istanbul ignore next */ []));
|
|
1683
1823
|
/**
|
|
1684
1824
|
* Whether the selection overlay is currently interactive (intercepts
|
|
1685
1825
|
* pointer events). Always false when `enableSelection` is false.
|
|
@@ -1694,7 +1834,8 @@ class DashboardViewerComponent {
|
|
|
1694
1834
|
if (this.selectionModifier() === null)
|
|
1695
1835
|
return true;
|
|
1696
1836
|
return this.#modifierHeld() || this.isSelecting();
|
|
1697
|
-
},
|
|
1837
|
+
}, /* @ts-ignore */
|
|
1838
|
+
...(ngDevMode ? [{ debugName: "armed" }] : /* istanbul ignore next */ []));
|
|
1698
1839
|
// Computed selection bounds (normalized)
|
|
1699
1840
|
selectionBounds = computed(() => {
|
|
1700
1841
|
const start = this.selectionStart();
|
|
@@ -1707,15 +1848,19 @@ class DashboardViewerComponent {
|
|
|
1707
1848
|
startCol: Math.min(start.col, current.col),
|
|
1708
1849
|
endCol: Math.max(start.col, current.col),
|
|
1709
1850
|
};
|
|
1710
|
-
},
|
|
1851
|
+
}, /* @ts-ignore */
|
|
1852
|
+
...(ngDevMode ? [{ debugName: "selectionBounds" }] : /* istanbul ignore next */ []));
|
|
1711
1853
|
// Generate array for template iteration
|
|
1712
|
-
rowNumbers = computed(() => Array.from({ length: this.rows() }, (_, i) => i + 1),
|
|
1713
|
-
|
|
1854
|
+
rowNumbers = computed(() => Array.from({ length: this.rows() }, (_, i) => i + 1), /* @ts-ignore */
|
|
1855
|
+
...(ngDevMode ? [{ debugName: "rowNumbers" }] : /* istanbul ignore next */ []));
|
|
1856
|
+
colNumbers = computed(() => Array.from({ length: this.columns() }, (_, i) => i + 1), /* @ts-ignore */
|
|
1857
|
+
...(ngDevMode ? [{ debugName: "colNumbers" }] : /* istanbul ignore next */ []));
|
|
1714
1858
|
// Document-level pointer listeners (cleanup needed)
|
|
1715
1859
|
#pointerMoveListener;
|
|
1716
1860
|
#pointerUpListener;
|
|
1717
1861
|
// Pointer position at the start of a drag, for dragThreshold checks
|
|
1718
|
-
#pointerDownPos = signal(null,
|
|
1862
|
+
#pointerDownPos = signal(null, /* @ts-ignore */
|
|
1863
|
+
...(ngDevMode ? [{ debugName: "#pointerDownPos" }] : /* istanbul ignore next */ []));
|
|
1719
1864
|
constructor() {
|
|
1720
1865
|
// Sync grid configuration with store when inputs change
|
|
1721
1866
|
effect(() => {
|
|
@@ -1886,10 +2031,10 @@ class DashboardViewerComponent {
|
|
|
1886
2031
|
this.#pointerUpListener = undefined;
|
|
1887
2032
|
}
|
|
1888
2033
|
}
|
|
1889
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1890
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2034
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2035
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: DashboardViewerComponent, isStandalone: true, selector: "ngx-dashboard-viewer", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, selectionModifier: { classPropertyName: "selectionModifier", publicName: "selectionModifier", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }, { propertyName: "gridElement", first: true, predicate: ["gridElement"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\" [class.armed]=\"armed()\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n [attr.data-row]=\"row\"\n [attr.data-col]=\"col\"\n (pointerdown)=\"onGhostCellPointerDown($event, row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:none;-webkit-user-select:none;user-select:none}.selection-overlay-grid.armed{pointer-events:auto}.selection-ghost-cell{transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell.selected{background-color:color-mix(in srgb,var(--mat-sys-primary) 25%,transparent);border-radius:4px}.selection-overlay-grid.armed .selection-ghost-cell{cursor:crosshair}.selection-overlay-grid.armed .selection-ghost-cell:hover:not(.selecting){background-color:color-mix(in srgb,var(--mat-sys-primary) 8%,transparent)}.selection-overlay-grid.armed .selection-ghost-cell.selecting{cursor:crosshair}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1891
2036
|
}
|
|
1892
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2037
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardViewerComponent, decorators: [{
|
|
1893
2038
|
type: Component,
|
|
1894
2039
|
args: [{ selector: 'ngx-dashboard-viewer', standalone: true, imports: [CellComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1895
2040
|
'[style.--rows]': 'rows()',
|
|
@@ -1907,11 +2052,13 @@ class CellContextMenuComponent {
|
|
|
1907
2052
|
menuPosition = computed(() => {
|
|
1908
2053
|
const menu = this.menuService.activeMenu();
|
|
1909
2054
|
return menu ? { left: `${menu.x}px`, top: `${menu.y}px` } : { left: '0px', top: '0px' };
|
|
1910
|
-
},
|
|
2055
|
+
}, /* @ts-ignore */
|
|
2056
|
+
...(ngDevMode ? [{ debugName: "menuPosition" }] : /* istanbul ignore next */ []));
|
|
1911
2057
|
menuItems = computed(() => {
|
|
1912
2058
|
const menu = this.menuService.activeMenu();
|
|
1913
2059
|
return menu?.items || [];
|
|
1914
|
-
},
|
|
2060
|
+
}, /* @ts-ignore */
|
|
2061
|
+
...(ngDevMode ? [{ debugName: "menuItems" }] : /* istanbul ignore next */ []));
|
|
1915
2062
|
constructor() {
|
|
1916
2063
|
// Material Menu has a backdrop that blocks events from reaching other elements.
|
|
1917
2064
|
// When any right-click occurs while menu is open, we need to:
|
|
@@ -1972,8 +2119,8 @@ class CellContextMenuComponent {
|
|
|
1972
2119
|
this.menuService.hide();
|
|
1973
2120
|
}
|
|
1974
2121
|
}
|
|
1975
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1976
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2122
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2123
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", 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: `
|
|
1977
2124
|
<!-- Hidden trigger for menu positioned at exact mouse coordinates
|
|
1978
2125
|
|
|
1979
2126
|
IMPORTANT: Angular Material applies its own positioning logic to menus,
|
|
@@ -2027,7 +2174,7 @@ class CellContextMenuComponent {
|
|
|
2027
2174
|
</mat-menu>
|
|
2028
2175
|
`, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2029
2176
|
}
|
|
2030
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2177
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CellContextMenuComponent, decorators: [{
|
|
2031
2178
|
type: Component,
|
|
2032
2179
|
args: [{ selector: 'lib-cell-context-menu', standalone: true, imports: [MatMenuModule, MatIconModule, MatDividerModule, MatButtonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2033
2180
|
<!-- Hidden trigger for menu positioned at exact mouse coordinates
|
|
@@ -2118,10 +2265,10 @@ class DefaultEmptyCellContextProvider extends EmptyCellContextProvider {
|
|
|
2118
2265
|
handleEmptyCellContext() {
|
|
2119
2266
|
// Default behavior: do nothing
|
|
2120
2267
|
}
|
|
2121
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2122
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2268
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DefaultEmptyCellContextProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
2269
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DefaultEmptyCellContextProvider, providedIn: 'root' });
|
|
2123
2270
|
}
|
|
2124
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2271
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DefaultEmptyCellContextProvider, decorators: [{
|
|
2125
2272
|
type: Injectable,
|
|
2126
2273
|
args: [{
|
|
2127
2274
|
providedIn: 'root',
|
|
@@ -2156,8 +2303,10 @@ const EMPTY_CELL_CONTEXT_PROVIDER = new InjectionToken('EmptyCellContextProvider
|
|
|
2156
2303
|
* of the context menu that appears when right-clicking on empty dashboard cells.
|
|
2157
2304
|
*/
|
|
2158
2305
|
class EmptyCellContextMenuService {
|
|
2159
|
-
#activeMenu = signal(null,
|
|
2160
|
-
|
|
2306
|
+
#activeMenu = signal(null, /* @ts-ignore */
|
|
2307
|
+
...(ngDevMode ? [{ debugName: "#activeMenu" }] : /* istanbul ignore next */ []));
|
|
2308
|
+
#lastSelectedWidgetTypeId = signal(null, /* @ts-ignore */
|
|
2309
|
+
...(ngDevMode ? [{ debugName: "#lastSelectedWidgetTypeId" }] : /* istanbul ignore next */ []));
|
|
2161
2310
|
activeMenu = this.#activeMenu.asReadonly();
|
|
2162
2311
|
lastSelectedWidgetTypeId = this.#lastSelectedWidgetTypeId.asReadonly();
|
|
2163
2312
|
/**
|
|
@@ -2185,10 +2334,10 @@ class EmptyCellContextMenuService {
|
|
|
2185
2334
|
setLastSelection(widgetTypeId) {
|
|
2186
2335
|
this.#lastSelectedWidgetTypeId.set(widgetTypeId);
|
|
2187
2336
|
}
|
|
2188
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2189
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2337
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: EmptyCellContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2338
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: EmptyCellContextMenuService, providedIn: 'root' });
|
|
2190
2339
|
}
|
|
2191
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2340
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: EmptyCellContextMenuService, decorators: [{
|
|
2192
2341
|
type: Injectable,
|
|
2193
2342
|
args: [{
|
|
2194
2343
|
providedIn: 'root',
|
|
@@ -2303,37 +2452,49 @@ class WidgetListContextMenuProvider extends EmptyCellContextProvider {
|
|
|
2303
2452
|
'Ensure you are using a compatible version of the dashboard component.');
|
|
2304
2453
|
}
|
|
2305
2454
|
}
|
|
2306
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2307
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2455
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WidgetListContextMenuProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
2456
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WidgetListContextMenuProvider });
|
|
2308
2457
|
}
|
|
2309
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2458
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WidgetListContextMenuProvider, decorators: [{
|
|
2310
2459
|
type: Injectable
|
|
2311
2460
|
}] });
|
|
2312
2461
|
|
|
2313
2462
|
// drop-zone.component.ts
|
|
2314
2463
|
class DropZoneComponent {
|
|
2315
2464
|
// Required inputs
|
|
2316
|
-
row = input.required(
|
|
2317
|
-
|
|
2318
|
-
|
|
2465
|
+
row = input.required(/* @ts-ignore */
|
|
2466
|
+
...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
2467
|
+
col = input.required(/* @ts-ignore */
|
|
2468
|
+
...(ngDevMode ? [{ debugName: "col" }] : /* istanbul ignore next */ []));
|
|
2469
|
+
index = input.required(/* @ts-ignore */
|
|
2470
|
+
...(ngDevMode ? [{ debugName: "index" }] : /* istanbul ignore next */ []));
|
|
2319
2471
|
// Optional inputs with defaults
|
|
2320
|
-
highlight = input(false,
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2472
|
+
highlight = input(false, /* @ts-ignore */
|
|
2473
|
+
...(ngDevMode ? [{ debugName: "highlight" }] : /* istanbul ignore next */ []));
|
|
2474
|
+
highlightInvalid = input(false, /* @ts-ignore */
|
|
2475
|
+
...(ngDevMode ? [{ debugName: "highlightInvalid" }] : /* istanbul ignore next */ []));
|
|
2476
|
+
highlightResize = input(false, /* @ts-ignore */
|
|
2477
|
+
...(ngDevMode ? [{ debugName: "highlightResize" }] : /* istanbul ignore next */ []));
|
|
2478
|
+
highlightPreview = input(false, /* @ts-ignore */
|
|
2479
|
+
...(ngDevMode ? [{ debugName: "highlightPreview" }] : /* istanbul ignore next */ []));
|
|
2480
|
+
editMode = input(false, /* @ts-ignore */
|
|
2481
|
+
...(ngDevMode ? [{ debugName: "editMode" }] : /* istanbul ignore next */ []));
|
|
2324
2482
|
// Outputs
|
|
2325
2483
|
dragEnter = output();
|
|
2326
2484
|
dragExit = output();
|
|
2327
2485
|
dragOver = output();
|
|
2328
2486
|
dragDrop = output();
|
|
2329
2487
|
// Computed properties
|
|
2330
|
-
dropZoneId = computed(() => `drop-zone-${this.row()}-${this.col()}`,
|
|
2488
|
+
dropZoneId = computed(() => `drop-zone-${this.row()}-${this.col()}`, /* @ts-ignore */
|
|
2489
|
+
...(ngDevMode ? [{ debugName: "dropZoneId" }] : /* istanbul ignore next */ []));
|
|
2331
2490
|
dropData = computed(() => ({
|
|
2332
2491
|
row: this.row(),
|
|
2333
2492
|
col: this.col(),
|
|
2334
|
-
}),
|
|
2493
|
+
}), /* @ts-ignore */
|
|
2494
|
+
...(ngDevMode ? [{ debugName: "dropData" }] : /* istanbul ignore next */ []));
|
|
2335
2495
|
// Abstract drag state from store
|
|
2336
|
-
dragData = computed(() => this.#store.dragData(),
|
|
2496
|
+
dragData = computed(() => this.#store.dragData(), /* @ts-ignore */
|
|
2497
|
+
...(ngDevMode ? [{ debugName: "dragData" }] : /* istanbul ignore next */ []));
|
|
2337
2498
|
// Computed drop effect based on drag data and validity
|
|
2338
2499
|
dropEffect = computed(() => {
|
|
2339
2500
|
const data = this.dragData();
|
|
@@ -2341,7 +2502,8 @@ class DropZoneComponent {
|
|
|
2341
2502
|
return 'none';
|
|
2342
2503
|
}
|
|
2343
2504
|
return data.kind === 'cell' ? 'move' : 'copy';
|
|
2344
|
-
},
|
|
2505
|
+
}, /* @ts-ignore */
|
|
2506
|
+
...(ngDevMode ? [{ debugName: "dropEffect" }] : /* istanbul ignore next */ []));
|
|
2345
2507
|
#store = inject(DashboardStore);
|
|
2346
2508
|
#elementRef = inject(ElementRef);
|
|
2347
2509
|
#dashboardService = inject(DashboardService);
|
|
@@ -2419,13 +2581,13 @@ class DropZoneComponent {
|
|
|
2419
2581
|
});
|
|
2420
2582
|
}
|
|
2421
2583
|
}
|
|
2422
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2423
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2584
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DropZoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2585
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", 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 }, highlightPreview: { classPropertyName: "highlightPreview", publicName: "highlightPreview", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragEnter: "dragEnter", dragExit: "dragExit", dragOver: "dragOver", dragDrop: "dragDrop" }, ngImport: i0, template: "<!-- drop-zone.component.html -->\n<div\n class=\"drop-zone\"\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\n [class.drop-zone--invalid]=\"highlightInvalid()\"\n [class.drop-zone--resize]=\"highlightResize()\"\n [class.drop-zone--preview]=\"highlightPreview()\"\n [style.grid-row]=\"row()\"\n [style.grid-column]=\"col()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n @if (editMode()) {\n <div class=\"edit-mode-cell-number\">\n {{ index() }}<br />\n {{ row() }},{{ col() }}\n </div>\n }\n</div>\n", styles: [".drop-zone{width:100%;height:100%;z-index:0;align-self:stretch;justify-self:stretch;display:block;box-sizing:border-box}.drop-zone--active,.drop-zone--highlight{background-color:#80808080}.drop-zone--invalid{background-color:light-dark(color-mix(in srgb,var(--mat-sys-error) 40%,white),color-mix(in srgb,var(--mat-sys-error) 80%,black))}.drop-zone--resize{background-color:#2196f34d;outline:1px solid rgba(33,150,243,.6)}.drop-zone--preview{background-color:color-mix(in srgb,var(--mat-sys-primary) 18%,transparent);outline:1px dashed color-mix(in srgb,var(--mat-sys-primary) 50%,transparent)}.edit-mode-cell-number{font-size:10px;line-height:1.1;color:#64646499;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:-1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2424
2586
|
}
|
|
2425
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2587
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DropZoneComponent, decorators: [{
|
|
2426
2588
|
type: Component,
|
|
2427
|
-
args: [{ selector: 'lib-drop-zone', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- drop-zone.component.html -->\n<div\n class=\"drop-zone\"\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\n [class.drop-zone--invalid]=\"highlightInvalid()\"\n [class.drop-zone--resize]=\"highlightResize()\"\n [style.grid-row]=\"row()\"\n [style.grid-column]=\"col()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n @if (editMode()) {\n <div class=\"edit-mode-cell-number\">\n {{ index() }}<br />\n {{ row() }},{{ col() }}\n </div>\n }\n</div>\n", styles: [".drop-zone{width:100%;height:100%;z-index:0;align-self:stretch;justify-self:stretch;display:block;box-sizing:border-box}.drop-zone--active,.drop-zone--highlight{background-color:#80808080}.drop-zone--invalid{background-color:light-dark(color-mix(in srgb,var(--mat-sys-error) 40%,white),color-mix(in srgb,var(--mat-sys-error) 80%,black))}.drop-zone--resize{background-color:#2196f34d;outline:1px solid rgba(33,150,243,.6)}.edit-mode-cell-number{font-size:10px;line-height:1.1;color:#64646499;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:-1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;height:100%}\n"] }]
|
|
2428
|
-
}], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], col: [{ type: i0.Input, args: [{ isSignal: true, alias: "col", required: true }] }], index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: true }] }], highlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlight", required: false }] }], highlightInvalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightInvalid", required: false }] }], highlightResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightResize", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], dragEnter: [{ type: i0.Output, args: ["dragEnter"] }], dragExit: [{ type: i0.Output, args: ["dragExit"] }], dragOver: [{ type: i0.Output, args: ["dragOver"] }], dragDrop: [{ type: i0.Output, args: ["dragDrop"] }] } });
|
|
2589
|
+
args: [{ selector: 'lib-drop-zone', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- drop-zone.component.html -->\n<div\n class=\"drop-zone\"\n [class.drop-zone--highlight]=\"highlight() && !highlightInvalid()\"\n [class.drop-zone--invalid]=\"highlightInvalid()\"\n [class.drop-zone--resize]=\"highlightResize()\"\n [class.drop-zone--preview]=\"highlightPreview()\"\n [style.grid-row]=\"row()\"\n [style.grid-column]=\"col()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n @if (editMode()) {\n <div class=\"edit-mode-cell-number\">\n {{ index() }}<br />\n {{ row() }},{{ col() }}\n </div>\n }\n</div>\n", styles: [".drop-zone{width:100%;height:100%;z-index:0;align-self:stretch;justify-self:stretch;display:block;box-sizing:border-box}.drop-zone--active,.drop-zone--highlight{background-color:#80808080}.drop-zone--invalid{background-color:light-dark(color-mix(in srgb,var(--mat-sys-error) 40%,white),color-mix(in srgb,var(--mat-sys-error) 80%,black))}.drop-zone--resize{background-color:#2196f34d;outline:1px solid rgba(33,150,243,.6)}.drop-zone--preview{background-color:color-mix(in srgb,var(--mat-sys-primary) 18%,transparent);outline:1px dashed color-mix(in srgb,var(--mat-sys-primary) 50%,transparent)}.edit-mode-cell-number{font-size:10px;line-height:1.1;color:#64646499;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:-1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;height:100%}\n"] }]
|
|
2590
|
+
}], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], col: [{ type: i0.Input, args: [{ isSignal: true, alias: "col", required: true }] }], index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: true }] }], highlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlight", required: false }] }], highlightInvalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightInvalid", required: false }] }], highlightResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightResize", required: false }] }], highlightPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightPreview", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], dragEnter: [{ type: i0.Output, args: ["dragEnter"] }], dragExit: [{ type: i0.Output, args: ["dragExit"] }], dragOver: [{ type: i0.Output, args: ["dragOver"] }], dragDrop: [{ type: i0.Output, args: ["dragDrop"] }] } });
|
|
2429
2591
|
|
|
2430
2592
|
/**
|
|
2431
2593
|
* Context menu component for empty dashboard cells.
|
|
@@ -2447,11 +2609,13 @@ class EmptyCellContextMenuComponent {
|
|
|
2447
2609
|
return menu
|
|
2448
2610
|
? { left: `${menu.x}px`, top: `${menu.y}px` }
|
|
2449
2611
|
: { left: '0px', top: '0px' };
|
|
2450
|
-
},
|
|
2612
|
+
}, /* @ts-ignore */
|
|
2613
|
+
...(ngDevMode ? [{ debugName: "menuPosition" }] : /* istanbul ignore next */ []));
|
|
2451
2614
|
menuItems = computed(() => {
|
|
2452
2615
|
const menu = this.menuService.activeMenu();
|
|
2453
2616
|
return menu?.items || [];
|
|
2454
|
-
},
|
|
2617
|
+
}, /* @ts-ignore */
|
|
2618
|
+
...(ngDevMode ? [{ debugName: "menuItems" }] : /* istanbul ignore next */ []));
|
|
2455
2619
|
constructor() {
|
|
2456
2620
|
// Material Menu has a backdrop that blocks events from reaching other elements.
|
|
2457
2621
|
// When any right-click occurs while menu is open, we need to:
|
|
@@ -2523,8 +2687,8 @@ class EmptyCellContextMenuComponent {
|
|
|
2523
2687
|
sanitizeSvg(svg) {
|
|
2524
2688
|
return this.#sanitizer.bypassSecurityTrustHtml(svg);
|
|
2525
2689
|
}
|
|
2526
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2527
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2690
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: EmptyCellContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2691
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: EmptyCellContextMenuComponent, isStandalone: true, selector: "lib-empty-cell-context-menu", viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: ["menuTrigger"], descendants: true, read: MatMenuTrigger, isSignal: true }], ngImport: i0, template: `
|
|
2528
2692
|
<!-- Hidden trigger for menu positioned at exact mouse coordinates
|
|
2529
2693
|
|
|
2530
2694
|
IMPORTANT: Angular Material applies its own positioning logic to menus,
|
|
@@ -2584,7 +2748,7 @@ class EmptyCellContextMenuComponent {
|
|
|
2584
2748
|
</mat-menu>
|
|
2585
2749
|
`, isInline: true, styles: [":host{display:contents}.empty-cell-widget-menu{max-height:400px;overflow-y:auto}.widget-icon{width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;vertical-align:middle}.widget-icon :deep(svg){width:20px;height:20px;fill:currentColor}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2586
2750
|
}
|
|
2587
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2751
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: EmptyCellContextMenuComponent, decorators: [{
|
|
2588
2752
|
type: Component,
|
|
2589
2753
|
args: [{ selector: 'lib-empty-cell-context-menu', standalone: true, imports: [
|
|
2590
2754
|
MatMenuModule,
|
|
@@ -2652,18 +2816,173 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
2652
2816
|
`, styles: [":host{display:contents}.empty-cell-widget-menu{max-height:400px;overflow-y:auto}.widget-icon{width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;vertical-align:middle}.widget-icon :deep(svg){width:20px;height:20px;fill:currentColor}\n"] }]
|
|
2653
2817
|
}], ctorParameters: () => [], propDecorators: { menuTrigger: [{ type: i0.ViewChild, args: ['menuTrigger', { ...{ read: MatMenuTrigger }, isSignal: true }] }] } });
|
|
2654
2818
|
|
|
2819
|
+
// grid-resize-handle.component.ts
|
|
2820
|
+
//
|
|
2821
|
+
// A small, self-contained drag handle for resizing the dashboard grid's
|
|
2822
|
+
// row/column counts from the editor. Uses PointerEvents (with pointer capture)
|
|
2823
|
+
// so mouse, touch and pen all work uniformly, and reports a whole-grid delta
|
|
2824
|
+
// in track counts rather than a per-widget span change.
|
|
2825
|
+
//
|
|
2826
|
+
// The handle is intentionally store-agnostic: it converts pointer movement
|
|
2827
|
+
// into track-count deltas using the cell footprint passed in, and emits them.
|
|
2828
|
+
// The editor owns the actual grid mutation (clamp-to-content lives there).
|
|
2829
|
+
/**
|
|
2830
|
+
* Round half away from zero so inward and outward half-cell drags behave
|
|
2831
|
+
* symmetrically. `Math.round` rounds 0.5 to 1 but -0.5 to 0, which makes a
|
|
2832
|
+
* half-cell shrink "stick" while a half-cell grow responds.
|
|
2833
|
+
*/
|
|
2834
|
+
function symmetricRound(value) {
|
|
2835
|
+
return Math.sign(value) * Math.round(Math.abs(value));
|
|
2836
|
+
}
|
|
2837
|
+
class GridResizeHandleComponent {
|
|
2838
|
+
axis = input.required(/* @ts-ignore */
|
|
2839
|
+
...(ngDevMode ? [{ debugName: "axis" }] : /* istanbul ignore next */ []));
|
|
2840
|
+
/** Current grid cell footprint in px; converts pointer delta to track counts. */
|
|
2841
|
+
cellWidth = input.required(/* @ts-ignore */
|
|
2842
|
+
...(ngDevMode ? [{ debugName: "cellWidth" }] : /* istanbul ignore next */ []));
|
|
2843
|
+
cellHeight = input.required(/* @ts-ignore */
|
|
2844
|
+
...(ngDevMode ? [{ debugName: "cellHeight" }] : /* istanbul ignore next */ []));
|
|
2845
|
+
resizeMove = output();
|
|
2846
|
+
resizeEnd = output();
|
|
2847
|
+
#host = inject(ElementRef);
|
|
2848
|
+
#renderer = inject(Renderer2);
|
|
2849
|
+
#destroyRef = inject(DestroyRef);
|
|
2850
|
+
isActive = signal(false, /* @ts-ignore */
|
|
2851
|
+
...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
|
|
2852
|
+
#startX = 0;
|
|
2853
|
+
#startY = 0;
|
|
2854
|
+
// Cell footprint snapshot taken at gesture start. Reading the live signal
|
|
2855
|
+
// would feed back on itself: the editor's live preview shrinks cells as
|
|
2856
|
+
// columns are added, which would shrink this px->track divisor mid-drag and
|
|
2857
|
+
// make the grid overshoot.
|
|
2858
|
+
#cellWidth = 0;
|
|
2859
|
+
#cellHeight = 0;
|
|
2860
|
+
#pointerId = null;
|
|
2861
|
+
#delta = { deltaColumns: 0, deltaRows: 0 };
|
|
2862
|
+
#cleanup;
|
|
2863
|
+
constructor() {
|
|
2864
|
+
// Defensive: drop listeners / capture if the handle is torn down mid-drag.
|
|
2865
|
+
this.#destroyRef.onDestroy(() => this.#stop());
|
|
2866
|
+
}
|
|
2867
|
+
onResizeStart(event) {
|
|
2868
|
+
event.preventDefault();
|
|
2869
|
+
event.stopPropagation();
|
|
2870
|
+
this.#startX = event.clientX;
|
|
2871
|
+
this.#startY = event.clientY;
|
|
2872
|
+
this.#cellWidth = this.cellWidth();
|
|
2873
|
+
this.#cellHeight = this.cellHeight();
|
|
2874
|
+
this.#delta = { deltaColumns: 0, deltaRows: 0 };
|
|
2875
|
+
this.isActive.set(true);
|
|
2876
|
+
// Capture so the gesture keeps receiving events even if the pointer leaves
|
|
2877
|
+
// the thin handle strip. try/catch tolerates environments without capture
|
|
2878
|
+
// support (TypeError) and synthetic test events with no active pointer.
|
|
2879
|
+
try {
|
|
2880
|
+
this.#host.nativeElement.setPointerCapture(event.pointerId);
|
|
2881
|
+
this.#pointerId = event.pointerId;
|
|
2882
|
+
}
|
|
2883
|
+
catch {
|
|
2884
|
+
// No capture; the document listeners still drive the gesture.
|
|
2885
|
+
}
|
|
2886
|
+
// Document/window listeners only exist while actively dragging this handle.
|
|
2887
|
+
const unlistenMove = this.#renderer.listen('document', 'pointermove', this.#onMove);
|
|
2888
|
+
const unlistenUp = this.#renderer.listen('document', 'pointerup', this.#onUp);
|
|
2889
|
+
const unlistenCancel = this.#renderer.listen('document', 'pointercancel', this.#onAbort);
|
|
2890
|
+
// A pointerup that lands outside the window never fires; window blur is the
|
|
2891
|
+
// backstop that aborts a gesture the browser has otherwise abandoned.
|
|
2892
|
+
const unlistenBlur = this.#renderer.listen('window', 'blur', this.#onAbort);
|
|
2893
|
+
this.#cleanup = () => {
|
|
2894
|
+
unlistenMove();
|
|
2895
|
+
unlistenUp();
|
|
2896
|
+
unlistenCancel();
|
|
2897
|
+
unlistenBlur();
|
|
2898
|
+
};
|
|
2899
|
+
this.#renderer.addClass(document.body, this.#cursorClass());
|
|
2900
|
+
}
|
|
2901
|
+
// Arrow fields keep `this` bound when used as Renderer2 listener callbacks.
|
|
2902
|
+
#onMove = (event) => {
|
|
2903
|
+
const axis = this.axis();
|
|
2904
|
+
const next = {
|
|
2905
|
+
deltaColumns: axis !== 'vertical' && this.#cellWidth > 0
|
|
2906
|
+
? symmetricRound((event.clientX - this.#startX) / this.#cellWidth)
|
|
2907
|
+
: 0,
|
|
2908
|
+
deltaRows: axis !== 'horizontal' && this.#cellHeight > 0
|
|
2909
|
+
? symmetricRound((event.clientY - this.#startY) / this.#cellHeight)
|
|
2910
|
+
: 0,
|
|
2911
|
+
};
|
|
2912
|
+
// Only emit when the rounded track delta actually changes, so sub-cell
|
|
2913
|
+
// pointer movement doesn't spam the live preview.
|
|
2914
|
+
if (next.deltaColumns === this.#delta.deltaColumns &&
|
|
2915
|
+
next.deltaRows === this.#delta.deltaRows) {
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
this.#delta = next;
|
|
2919
|
+
this.resizeMove.emit(next);
|
|
2920
|
+
};
|
|
2921
|
+
#onUp = () => this.#finish(this.#delta);
|
|
2922
|
+
// Abort (pointercancel / window blur): discard the in-progress delta so the
|
|
2923
|
+
// editor clears the preview without committing a half-finished gesture.
|
|
2924
|
+
#onAbort = () => this.#finish({ deltaColumns: 0, deltaRows: 0 });
|
|
2925
|
+
#finish(delta) {
|
|
2926
|
+
if (!this.isActive())
|
|
2927
|
+
return;
|
|
2928
|
+
this.#stop();
|
|
2929
|
+
this.resizeEnd.emit(delta);
|
|
2930
|
+
}
|
|
2931
|
+
#stop() {
|
|
2932
|
+
this.isActive.set(false);
|
|
2933
|
+
this.#renderer.removeClass(document.body, this.#cursorClass());
|
|
2934
|
+
if (this.#pointerId !== null) {
|
|
2935
|
+
try {
|
|
2936
|
+
this.#host.nativeElement.releasePointerCapture(this.#pointerId);
|
|
2937
|
+
}
|
|
2938
|
+
catch {
|
|
2939
|
+
// Capture may already be gone (e.g. pointercancel released it).
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
this.#pointerId = null;
|
|
2943
|
+
this.#cleanup?.();
|
|
2944
|
+
this.#cleanup = undefined;
|
|
2945
|
+
}
|
|
2946
|
+
#cursorClass() {
|
|
2947
|
+
switch (this.axis()) {
|
|
2948
|
+
case 'horizontal':
|
|
2949
|
+
return 'cursor-col-resize';
|
|
2950
|
+
case 'vertical':
|
|
2951
|
+
return 'cursor-row-resize';
|
|
2952
|
+
default:
|
|
2953
|
+
return 'cursor-nwse-resize';
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: GridResizeHandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2957
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: GridResizeHandleComponent, isStandalone: true, selector: "lib-grid-resize-handle", inputs: { axis: { classPropertyName: "axis", publicName: "axis", isSignal: true, isRequired: true, transformFunction: null }, cellWidth: { classPropertyName: "cellWidth", publicName: "cellWidth", isSignal: true, isRequired: true, transformFunction: null }, cellHeight: { classPropertyName: "cellHeight", publicName: "cellHeight", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { listeners: { "pointerdown": "onResizeStart($event)" }, properties: { "class": "'axis-' + axis()", "class.is-active": "isActive()" } }, ngImport: i0, template: "<!-- grid-resize-handle.component.html -->\n<div class=\"grip-line\"></div>\n", styles: [":root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}:root .cursor-nwse-resize{cursor:nwse-resize!important}:host{position:absolute;z-index:25;display:flex;align-items:center;justify-content:center;opacity:.3;transition:opacity .15s ease;touch-action:none}:host(.axis-horizontal){cursor:col-resize;top:0;right:0;width:max(var(--gutter-size, 8px),6px);height:100%}:host(.axis-vertical){cursor:row-resize;left:0;bottom:0;width:100%;height:max(var(--gutter-size, 8px),6px)}:host(.axis-both){cursor:nwse-resize;right:0;bottom:0;width:max(var(--gutter-size, 8px),8px);height:max(var(--gutter-size, 8px),8px);z-index:26}:host(:hover),:host(.is-active){opacity:1}.grip-line{background-color:var(--mat-sys-outline-variant);border-radius:2px}:host(.axis-horizontal) .grip-line{width:4px;height:48px;max-height:60%}:host(.axis-vertical) .grip-line{width:48px;max-width:60%;height:4px}:host(.axis-both) .grip-line{width:6px;height:6px;border-bottom-right-radius:3px}:host(:hover) .grip-line,:host(.is-active) .grip-line{background-color:var(--mat-sys-primary)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2958
|
+
}
|
|
2959
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: GridResizeHandleComponent, decorators: [{
|
|
2960
|
+
type: Component,
|
|
2961
|
+
args: [{ selector: 'lib-grid-resize-handle', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
2962
|
+
'[class]': "'axis-' + axis()",
|
|
2963
|
+
'[class.is-active]': 'isActive()',
|
|
2964
|
+
'(pointerdown)': 'onResizeStart($event)',
|
|
2965
|
+
}, template: "<!-- grid-resize-handle.component.html -->\n<div class=\"grip-line\"></div>\n", styles: [":root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}:root .cursor-nwse-resize{cursor:nwse-resize!important}:host{position:absolute;z-index:25;display:flex;align-items:center;justify-content:center;opacity:.3;transition:opacity .15s ease;touch-action:none}:host(.axis-horizontal){cursor:col-resize;top:0;right:0;width:max(var(--gutter-size, 8px),6px);height:100%}:host(.axis-vertical){cursor:row-resize;left:0;bottom:0;width:100%;height:max(var(--gutter-size, 8px),6px)}:host(.axis-both){cursor:nwse-resize;right:0;bottom:0;width:max(var(--gutter-size, 8px),8px);height:max(var(--gutter-size, 8px),8px);z-index:26}:host(:hover),:host(.is-active){opacity:1}.grip-line{background-color:var(--mat-sys-outline-variant);border-radius:2px}:host(.axis-horizontal) .grip-line{width:4px;height:48px;max-height:60%}:host(.axis-vertical) .grip-line{width:48px;max-width:60%;height:4px}:host(.axis-both) .grip-line{width:6px;height:6px;border-bottom-right-radius:3px}:host(:hover) .grip-line,:host(.is-active) .grip-line{background-color:var(--mat-sys-primary)}\n"] }]
|
|
2966
|
+
}], ctorParameters: () => [], propDecorators: { axis: [{ type: i0.Input, args: [{ isSignal: true, alias: "axis", required: true }] }], cellWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellWidth", required: true }] }], cellHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellHeight", required: true }] }], resizeMove: [{ type: i0.Output, args: ["resizeMove"] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }] } });
|
|
2967
|
+
|
|
2655
2968
|
// dashboard-editor.component.ts
|
|
2656
2969
|
class DashboardEditorComponent {
|
|
2657
2970
|
bottomGridRef = viewChild.required('bottomGrid');
|
|
2658
|
-
dropZones = viewChildren(DropZoneComponent,
|
|
2659
|
-
|
|
2971
|
+
dropZones = viewChildren(DropZoneComponent, /* @ts-ignore */
|
|
2972
|
+
...(ngDevMode ? [{ debugName: "dropZones" }] : /* istanbul ignore next */ []));
|
|
2973
|
+
cellComponents = viewChildren(CellComponent, /* @ts-ignore */
|
|
2974
|
+
...(ngDevMode ? [{ debugName: "cellComponents" }] : /* istanbul ignore next */ []));
|
|
2660
2975
|
#store = inject(DashboardStore);
|
|
2661
2976
|
#destroyRef = inject(DestroyRef);
|
|
2662
2977
|
#resizeObserver;
|
|
2663
|
-
rows = input.required(
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2978
|
+
rows = input.required(/* @ts-ignore */
|
|
2979
|
+
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
2980
|
+
columns = input.required(/* @ts-ignore */
|
|
2981
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
2982
|
+
gutterSize = input('1em', /* @ts-ignore */
|
|
2983
|
+
...(ngDevMode ? [{ debugName: "gutterSize" }] : /* istanbul ignore next */ []));
|
|
2984
|
+
// Emitted when a grid resize handle commits a new size (after clamp-to-content).
|
|
2985
|
+
gridResized = output();
|
|
2667
2986
|
// store signals
|
|
2668
2987
|
cells = this.#store.cells;
|
|
2669
2988
|
highlightedZones = this.#store.highlightedZones;
|
|
@@ -2671,21 +2990,48 @@ class DashboardEditorComponent {
|
|
|
2671
2990
|
invalidHighlightMap = this.#store.invalidHighlightMap;
|
|
2672
2991
|
hoveredDropZone = this.#store.hoveredDropZone;
|
|
2673
2992
|
resizePreviewMap = this.#store.resizePreviewMap;
|
|
2674
|
-
|
|
2993
|
+
cellDimensions = this.#store.gridCellDimensions;
|
|
2994
|
+
gridResizePreview = this.#store.gridResizePreview;
|
|
2995
|
+
// Effective grid size (live preview when dragging, else committed) — shared
|
|
2996
|
+
// from the store so the editor grid, the outer frame and the viewport
|
|
2997
|
+
// letterboxing all reflow together. Drives the grid template, aspect-ratio
|
|
2998
|
+
// and drop zones so the editor reflows under the handle without committing.
|
|
2999
|
+
effectiveRows = this.#store.effectiveRows;
|
|
3000
|
+
effectiveColumns = this.#store.effectiveColumns;
|
|
3001
|
+
// Hide grid resize handles while a widget drag is in progress to avoid
|
|
3002
|
+
// conflicting gestures.
|
|
3003
|
+
isDragActive = this.#store.isDragActive;
|
|
3004
|
+
// Axes rendered as grid resize handles (right edge, bottom edge, corner).
|
|
3005
|
+
resizeAxes = [
|
|
3006
|
+
'horizontal',
|
|
3007
|
+
'vertical',
|
|
3008
|
+
'both',
|
|
3009
|
+
];
|
|
3010
|
+
// Generate all possible cell positions for the grid (using the effective
|
|
3011
|
+
// size so the drop-zone grid grows/shrinks with the live resize preview).
|
|
2675
3012
|
dropzonePositions = computed(() => {
|
|
3013
|
+
const rows = this.effectiveRows();
|
|
3014
|
+
const columns = this.effectiveColumns();
|
|
2676
3015
|
const positions = [];
|
|
2677
|
-
for (let row = 1; row <=
|
|
2678
|
-
for (let col = 1; col <=
|
|
3016
|
+
for (let row = 1; row <= rows; row++) {
|
|
3017
|
+
for (let col = 1; col <= columns; col++) {
|
|
2679
3018
|
positions.push({
|
|
2680
3019
|
row,
|
|
2681
3020
|
col,
|
|
2682
3021
|
id: `dropzone-${row}-${col}`,
|
|
2683
|
-
index: (row - 1) *
|
|
3022
|
+
index: (row - 1) * columns + col,
|
|
2684
3023
|
});
|
|
2685
3024
|
}
|
|
2686
3025
|
}
|
|
2687
3026
|
return positions;
|
|
2688
|
-
},
|
|
3027
|
+
}, /* @ts-ignore */
|
|
3028
|
+
...(ngDevMode ? [{ debugName: "dropzonePositions" }] : /* istanbul ignore next */ []));
|
|
3029
|
+
// True for drop zones in the about-to-be-added region during a grow preview,
|
|
3030
|
+
// so the template can tint the tracks the resize is adding.
|
|
3031
|
+
isPreviewAdded(row, col) {
|
|
3032
|
+
return (this.gridResizePreview() !== null &&
|
|
3033
|
+
(row > this.rows() || col > this.columns()));
|
|
3034
|
+
}
|
|
2689
3035
|
// Helper method for template
|
|
2690
3036
|
createCellId(row, col) {
|
|
2691
3037
|
return CellIdUtils.create(row, col);
|
|
@@ -2707,6 +3053,10 @@ class DashboardEditorComponent {
|
|
|
2707
3053
|
effect(() => {
|
|
2708
3054
|
this.#store.setEditMode(true);
|
|
2709
3055
|
});
|
|
3056
|
+
// Drop any in-progress resize preview if the editor is torn down mid-drag
|
|
3057
|
+
// (e.g. editMode toggled off): the store outlives this component, so a
|
|
3058
|
+
// stale preview would otherwise render a phantom grid on the next mount.
|
|
3059
|
+
this.#destroyRef.onDestroy(() => this.#store.clearGridResizePreview());
|
|
2710
3060
|
}
|
|
2711
3061
|
#observeGridSize() {
|
|
2712
3062
|
const gridEl = this.bottomGridRef()?.nativeElement;
|
|
@@ -2757,28 +3107,41 @@ class DashboardEditorComponent {
|
|
|
2757
3107
|
this.#store.handleDrop(event.data, event.target);
|
|
2758
3108
|
// Note: Store handles all validation and error handling internally
|
|
2759
3109
|
}
|
|
2760
|
-
|
|
2761
|
-
|
|
3110
|
+
// Live preview while dragging a handle: the store reflows the grid to the
|
|
3111
|
+
// clamped target size without committing.
|
|
3112
|
+
onGridResizeMove(delta) {
|
|
3113
|
+
this.#store.previewGridResize(delta.deltaRows, delta.deltaColumns);
|
|
3114
|
+
}
|
|
3115
|
+
// Commit a grid resize gesture. The store clears the preview, no-ops on a
|
|
3116
|
+
// zero delta, and otherwise commits the clamped relative resize.
|
|
3117
|
+
onGridResizeEnd(delta) {
|
|
3118
|
+
const result = this.#store.endGridResize(delta.deltaRows, delta.deltaColumns);
|
|
3119
|
+
if (result)
|
|
3120
|
+
this.gridResized.emit(result);
|
|
3121
|
+
}
|
|
3122
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3123
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", 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 } }, outputs: { gridResized: "gridResized" }, host: { properties: { "style.--rows": "effectiveRows()", "style.--columns": "effectiveColumns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "effectiveColumns() + 1", "class.is-edit-mode": "true" } }, providers: [
|
|
2762
3124
|
CellContextMenuService,
|
|
2763
|
-
], viewQueries: [{ propertyName: "bottomGridRef", first: true, predicate: ["bottomGrid"], descendants: true, isSignal: true }, { propertyName: "dropZones", predicate: DropZoneComponent, descendants: true, isSignal: true }, { propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- dashboard-editor.component.html -->\n<div class=\"grid-container\">\n <!-- Bottom grid with drop zones -->\n <div class=\"grid\" id=\"bottom-grid\" #bottomGrid>\n @for (position of dropzonePositions(); track position.id) {\n <lib-drop-zone\n class=\"drop-zone\"\n [row]=\"position.row\"\n [col]=\"position.col\"\n [index]=\"position.index\"\n [highlight]=\"highlightMap().has(createCellId(position.row, position.col))\"\n [highlightInvalid]=\"\n invalidHighlightMap().has(createCellId(position.row, position.col))\n \"\n [highlightResize]=\"\n resizePreviewMap().has(createCellId(position.row, position.col))\n \"\n [editMode]=\"true\"\n (dragEnter)=\"onDragEnter($event)\"\n (dragExit)=\"onDragExit()\"\n (dragOver)=\"onDragOver($event)\"\n (dragDrop)=\"onDragDrop($event)\"\n ></lib-drop-zone>\n }\n </div>\n\n <!-- Top grid with interactive cells -->\n <div class=\"grid\" id=\"top-grid\">\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"true\"\n [draggable]=\"true\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n (dragStart)=\"onCellDragStart($event)\"\n (dragEnd)=\"dragEnd()\"\n (delete)=\"onCellDelete($event)\"\n (settings)=\"onCellSettings($event)\"\n (resizeStart)=\"onCellResizeStart($event)\"\n (resizeMove)=\"onCellResizeMove($event)\"\n (resizeEnd)=\"onCellResizeEnd($event)\"\n >\n </lib-cell>\n }\n </div>\n</div>\n\n<!-- Context menus -->\n<lib-cell-context-menu></lib-cell-context-menu>\n<lib-empty-cell-context-menu></lib-empty-cell-context-menu>\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}:host .grid{background-image:linear-gradient(to right,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px);background-size:var(--tile-size) var(--tile-size),var(--tile-size) var(--tile-size),100% 1px;background-position:var(--tile-offset) var(--tile-offset),var(--tile-offset) var(--tile-offset),bottom;background-repeat:repeat,repeat,no-repeat}.grid-container{position:relative;width:100%;height:100%}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);position:absolute;inset:0;width:100%;height:100%;box-sizing:border-box;align-items:stretch;justify-items:stretch;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}#bottom-grid{z-index:1}#top-grid{z-index:2;pointer-events:none}.grid-cell{pointer-events:auto}.grid-cell.is-dragging{pointer-events:none;opacity:.5}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }, { kind: "component", type: DropZoneComponent, selector: "lib-drop-zone", inputs: ["row", "col", "index", "highlight", "highlightInvalid", "highlightResize", "editMode"], outputs: ["dragEnter", "dragExit", "dragOver", "dragDrop"] }, { kind: "component", type: CellContextMenuComponent, selector: "lib-cell-context-menu" }, { kind: "component", type: EmptyCellContextMenuComponent, selector: "lib-empty-cell-context-menu" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3125
|
+
], 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 [highlightPreview]=\"isPreviewAdded(position.row, position.col)\"\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 <!-- Grid resize handles (right edge, bottom edge, bottom-right corner).\n Hidden during a widget drag to avoid conflicting gestures. -->\n @if (!isDragActive()) {\n @for (axis of resizeAxes; track axis) {\n <lib-grid-resize-handle\n [axis]=\"axis\"\n [cellWidth]=\"cellDimensions().width\"\n [cellHeight]=\"cellDimensions().height\"\n (resizeMove)=\"onGridResizeMove($event)\"\n (resizeEnd)=\"onGridResizeEnd($event)\"\n ></lib-grid-resize-handle>\n }\n }\n\n <!-- Live size badge shown while a resize handle is being dragged. -->\n @if (gridResizePreview(); as preview) {\n <div\n class=\"grid-resize-badge\"\n [class.grid-resize-badge--clamped]=\"preview.clamped\"\n i18n=\"@@ngx.dashboard.editor.gridResize.dimensions\"\n >\n {{ preview.columns }} \u00D7 {{ preview.rows }}\n </div>\n }\n\n <!-- Top grid with interactive cells -->\n <div class=\"grid\" id=\"top-grid\">\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"true\"\n [draggable]=\"true\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n (dragStart)=\"onCellDragStart($event)\"\n (dragEnd)=\"dragEnd()\"\n (delete)=\"onCellDelete($event)\"\n (settings)=\"onCellSettings($event)\"\n (resizeStart)=\"onCellResizeStart($event)\"\n (resizeMove)=\"onCellResizeMove($event)\"\n (resizeEnd)=\"onCellResizeEnd($event)\"\n >\n </lib-cell>\n }\n </div>\n</div>\n\n<!-- Context menus -->\n<lib-cell-context-menu></lib-cell-context-menu>\n<lib-empty-cell-context-menu></lib-empty-cell-context-menu>\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}:host .grid{background-image:linear-gradient(to right,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px);background-size:var(--tile-size) var(--tile-size),var(--tile-size) var(--tile-size),100% 1px;background-position:var(--tile-offset) var(--tile-offset),var(--tile-offset) var(--tile-offset),bottom;background-repeat:repeat,repeat,no-repeat}.grid-container{position:relative;width:100%;height:100%}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);position:absolute;inset:0;width:100%;height:100%;box-sizing:border-box;align-items:stretch;justify-items:stretch;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}#bottom-grid{z-index:1}#top-grid{z-index:2;pointer-events:none}.grid-cell{pointer-events:auto}.grid-cell.is-dragging{pointer-events:none;opacity:.5}.grid-resize-badge{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:30;padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.grid-resize-badge--clamped{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }, { kind: "component", type: DropZoneComponent, selector: "lib-drop-zone", inputs: ["row", "col", "index", "highlight", "highlightInvalid", "highlightResize", "highlightPreview", "editMode"], outputs: ["dragEnter", "dragExit", "dragOver", "dragDrop"] }, { kind: "component", type: CellContextMenuComponent, selector: "lib-cell-context-menu" }, { kind: "component", type: EmptyCellContextMenuComponent, selector: "lib-empty-cell-context-menu" }, { kind: "component", type: GridResizeHandleComponent, selector: "lib-grid-resize-handle", inputs: ["axis", "cellWidth", "cellHeight"], outputs: ["resizeMove", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2764
3126
|
}
|
|
2765
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3127
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardEditorComponent, decorators: [{
|
|
2766
3128
|
type: Component,
|
|
2767
3129
|
args: [{ selector: 'ngx-dashboard-editor', standalone: true, imports: [
|
|
2768
3130
|
CellComponent,
|
|
2769
3131
|
DropZoneComponent,
|
|
2770
3132
|
CellContextMenuComponent,
|
|
2771
|
-
EmptyCellContextMenuComponent
|
|
3133
|
+
EmptyCellContextMenuComponent,
|
|
3134
|
+
GridResizeHandleComponent
|
|
2772
3135
|
], providers: [
|
|
2773
3136
|
CellContextMenuService,
|
|
2774
3137
|
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
2775
|
-
'[style.--rows]': '
|
|
2776
|
-
'[style.--columns]': '
|
|
3138
|
+
'[style.--rows]': 'effectiveRows()',
|
|
3139
|
+
'[style.--columns]': 'effectiveColumns()',
|
|
2777
3140
|
'[style.--gutter-size]': 'gutterSize()',
|
|
2778
|
-
'[style.--gutters]': '
|
|
3141
|
+
'[style.--gutters]': 'effectiveColumns() + 1',
|
|
2779
3142
|
'[class.is-edit-mode]': 'true', // Always in edit mode
|
|
2780
|
-
}, template: "<!-- dashboard-editor.component.html -->\n<div class=\"grid-container\">\n <!-- Bottom grid with drop zones -->\n <div class=\"grid\" id=\"bottom-grid\" #bottomGrid>\n @for (position of dropzonePositions(); track position.id) {\n <lib-drop-zone\n class=\"drop-zone\"\n [row]=\"position.row\"\n [col]=\"position.col\"\n [index]=\"position.index\"\n [highlight]=\"highlightMap().has(createCellId(position.row, position.col))\"\n [highlightInvalid]=\"\n invalidHighlightMap().has(createCellId(position.row, position.col))\n \"\n [highlightResize]=\"\n resizePreviewMap().has(createCellId(position.row, position.col))\n \"\n [editMode]=\"true\"\n (dragEnter)=\"onDragEnter($event)\"\n (dragExit)=\"onDragExit()\"\n (dragOver)=\"onDragOver($event)\"\n (dragDrop)=\"onDragDrop($event)\"\n ></lib-drop-zone>\n }\n </div>\n\n <!-- Top grid with interactive cells -->\n <div class=\"grid\" id=\"top-grid\">\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"true\"\n [draggable]=\"true\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n (dragStart)=\"onCellDragStart($event)\"\n (dragEnd)=\"dragEnd()\"\n (delete)=\"onCellDelete($event)\"\n (settings)=\"onCellSettings($event)\"\n (resizeStart)=\"onCellResizeStart($event)\"\n (resizeMove)=\"onCellResizeMove($event)\"\n (resizeEnd)=\"onCellResizeEnd($event)\"\n >\n </lib-cell>\n }\n </div>\n</div>\n\n<!-- Context menus -->\n<lib-cell-context-menu></lib-cell-context-menu>\n<lib-empty-cell-context-menu></lib-empty-cell-context-menu>\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}:host .grid{background-image:linear-gradient(to right,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px);background-size:var(--tile-size) var(--tile-size),var(--tile-size) var(--tile-size),100% 1px;background-position:var(--tile-offset) var(--tile-offset),var(--tile-offset) var(--tile-offset),bottom;background-repeat:repeat,repeat,no-repeat}.grid-container{position:relative;width:100%;height:100%}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);position:absolute;inset:0;width:100%;height:100%;box-sizing:border-box;align-items:stretch;justify-items:stretch;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}#bottom-grid{z-index:1}#top-grid{z-index:2;pointer-events:none}.grid-cell{pointer-events:auto}.grid-cell.is-dragging{pointer-events:none;opacity:.5}\n"] }]
|
|
2781
|
-
}], ctorParameters: () => [], propDecorators: { bottomGridRef: [{ type: i0.ViewChild, args: ['bottomGrid', { isSignal: true }] }], dropZones: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => DropZoneComponent), { isSignal: true }] }], cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CellComponent), { isSignal: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }] } });
|
|
3143
|
+
}, 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 [highlightPreview]=\"isPreviewAdded(position.row, position.col)\"\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 <!-- Grid resize handles (right edge, bottom edge, bottom-right corner).\n Hidden during a widget drag to avoid conflicting gestures. -->\n @if (!isDragActive()) {\n @for (axis of resizeAxes; track axis) {\n <lib-grid-resize-handle\n [axis]=\"axis\"\n [cellWidth]=\"cellDimensions().width\"\n [cellHeight]=\"cellDimensions().height\"\n (resizeMove)=\"onGridResizeMove($event)\"\n (resizeEnd)=\"onGridResizeEnd($event)\"\n ></lib-grid-resize-handle>\n }\n }\n\n <!-- Live size badge shown while a resize handle is being dragged. -->\n @if (gridResizePreview(); as preview) {\n <div\n class=\"grid-resize-badge\"\n [class.grid-resize-badge--clamped]=\"preview.clamped\"\n i18n=\"@@ngx.dashboard.editor.gridResize.dimensions\"\n >\n {{ preview.columns }} \u00D7 {{ preview.rows }}\n </div>\n }\n\n <!-- Top grid with interactive cells -->\n <div class=\"grid\" id=\"top-grid\">\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"true\"\n [draggable]=\"true\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n (dragStart)=\"onCellDragStart($event)\"\n (dragEnd)=\"dragEnd()\"\n (delete)=\"onCellDelete($event)\"\n (settings)=\"onCellSettings($event)\"\n (resizeStart)=\"onCellResizeStart($event)\"\n (resizeMove)=\"onCellResizeMove($event)\"\n (resizeEnd)=\"onCellResizeEnd($event)\"\n >\n </lib-cell>\n }\n </div>\n</div>\n\n<!-- Context menus -->\n<lib-cell-context-menu></lib-cell-context-menu>\n<lib-empty-cell-context-menu></lib-empty-cell-context-menu>\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}:host .grid{background-image:linear-gradient(to right,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(100,100,100,.12) 1px,transparent 1px);background-size:var(--tile-size) var(--tile-size),var(--tile-size) var(--tile-size),100% 1px;background-position:var(--tile-offset) var(--tile-offset),var(--tile-offset) var(--tile-offset),bottom;background-repeat:repeat,repeat,no-repeat}.grid-container{position:relative;width:100%;height:100%}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);position:absolute;inset:0;width:100%;height:100%;box-sizing:border-box;align-items:stretch;justify-items:stretch;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}#bottom-grid{z-index:1}#top-grid{z-index:2;pointer-events:none}.grid-cell{pointer-events:auto}.grid-cell.is-dragging{pointer-events:none;opacity:.5}.grid-resize-badge{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:30;padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.grid-resize-badge--clamped{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}\n"] }]
|
|
3144
|
+
}], ctorParameters: () => [], propDecorators: { bottomGridRef: [{ type: i0.ViewChild, args: ['bottomGrid', { isSignal: true }] }], dropZones: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => DropZoneComponent), { isSignal: true }] }], cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CellComponent), { isSignal: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }], gridResized: [{ type: i0.Output, args: ["gridResized"] }] } });
|
|
2782
3145
|
|
|
2783
3146
|
// dashboard-bridge.service.ts
|
|
2784
3147
|
/**
|
|
@@ -2789,7 +3152,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
2789
3152
|
*/
|
|
2790
3153
|
class DashboardBridgeService {
|
|
2791
3154
|
// Map of registered dashboard instances with their reactive dimensions
|
|
2792
|
-
dashboards = signal(new Map(),
|
|
3155
|
+
dashboards = signal(new Map(), /* @ts-ignore */
|
|
3156
|
+
...(ngDevMode ? [{ debugName: "dashboards" }] : /* istanbul ignore next */ []));
|
|
2793
3157
|
/**
|
|
2794
3158
|
* Register a dashboard store instance using its dashboard ID
|
|
2795
3159
|
*/
|
|
@@ -2840,7 +3204,8 @@ class DashboardBridgeService {
|
|
|
2840
3204
|
}
|
|
2841
3205
|
// Return dimensions from first available dashboard with fallback for undefined
|
|
2842
3206
|
return dashboardEntries[0].dimensions() || { width: 100, height: 100 };
|
|
2843
|
-
},
|
|
3207
|
+
}, /* @ts-ignore */
|
|
3208
|
+
...(ngDevMode ? [{ debugName: "availableDimensions" }] : /* istanbul ignore next */ []));
|
|
2844
3209
|
/**
|
|
2845
3210
|
* Start drag operation on the first available dashboard
|
|
2846
3211
|
* (Widget lists need some dashboard to coordinate with during drag)
|
|
@@ -2863,15 +3228,18 @@ class DashboardBridgeService {
|
|
|
2863
3228
|
/**
|
|
2864
3229
|
* Get all registered dashboard IDs
|
|
2865
3230
|
*/
|
|
2866
|
-
registeredDashboards = computed(() => Array.from(this.dashboards().keys()),
|
|
3231
|
+
registeredDashboards = computed(() => Array.from(this.dashboards().keys()), /* @ts-ignore */
|
|
3232
|
+
...(ngDevMode ? [{ debugName: "registeredDashboards" }] : /* istanbul ignore next */ []));
|
|
2867
3233
|
/**
|
|
2868
3234
|
* Get the number of registered dashboards
|
|
2869
3235
|
*/
|
|
2870
|
-
dashboardCount = computed(() => this.dashboards().size,
|
|
3236
|
+
dashboardCount = computed(() => this.dashboards().size, /* @ts-ignore */
|
|
3237
|
+
...(ngDevMode ? [{ debugName: "dashboardCount" }] : /* istanbul ignore next */ []));
|
|
2871
3238
|
/**
|
|
2872
3239
|
* Check if any dashboards are registered
|
|
2873
3240
|
*/
|
|
2874
|
-
hasDashboards = computed(() => this.dashboards().size > 0,
|
|
3241
|
+
hasDashboards = computed(() => this.dashboards().size > 0, /* @ts-ignore */
|
|
3242
|
+
...(ngDevMode ? [{ debugName: "hasDashboards" }] : /* istanbul ignore next */ []));
|
|
2875
3243
|
/**
|
|
2876
3244
|
* Update registration for a dashboard store when its ID becomes available
|
|
2877
3245
|
*/
|
|
@@ -2906,10 +3274,10 @@ class DashboardBridgeService {
|
|
|
2906
3274
|
getAllDashboards() {
|
|
2907
3275
|
return this.dashboards();
|
|
2908
3276
|
}
|
|
2909
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2910
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
3277
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3278
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardBridgeService, providedIn: 'root' });
|
|
2911
3279
|
}
|
|
2912
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3280
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardBridgeService, decorators: [{
|
|
2913
3281
|
type: Injectable,
|
|
2914
3282
|
args: [{ providedIn: 'root' }]
|
|
2915
3283
|
}] });
|
|
@@ -2924,8 +3292,10 @@ class DashboardViewportService {
|
|
|
2924
3292
|
platformId = inject(PLATFORM_ID);
|
|
2925
3293
|
destroyRef = inject(DestroyRef);
|
|
2926
3294
|
store = inject(DashboardStore);
|
|
2927
|
-
viewportSize = signal({ width: 0, height: 0 },
|
|
2928
|
-
|
|
3295
|
+
viewportSize = signal({ width: 0, height: 0 }, /* @ts-ignore */
|
|
3296
|
+
...(ngDevMode ? [{ debugName: "viewportSize" }] : /* istanbul ignore next */ []));
|
|
3297
|
+
reservedSpace = signal(DEFAULT_RESERVED_SPACE, /* @ts-ignore */
|
|
3298
|
+
...(ngDevMode ? [{ debugName: "reservedSpace" }] : /* istanbul ignore next */ []));
|
|
2929
3299
|
resizeObserver = null;
|
|
2930
3300
|
constructor() {
|
|
2931
3301
|
if (isPlatformBrowser(this.platformId)) {
|
|
@@ -2983,15 +3353,17 @@ class DashboardViewportService {
|
|
|
2983
3353
|
width: Math.max(0, viewport.width - reserved.left - reserved.right),
|
|
2984
3354
|
height: Math.max(0, viewport.height - reserved.top - reserved.bottom)
|
|
2985
3355
|
};
|
|
2986
|
-
},
|
|
3356
|
+
}, /* @ts-ignore */
|
|
3357
|
+
...(ngDevMode ? [{ debugName: "availableSpace" }] : /* istanbul ignore next */ []));
|
|
2987
3358
|
/**
|
|
2988
3359
|
* Calculate dashboard constraints for this dashboard instance
|
|
2989
3360
|
*/
|
|
2990
3361
|
constraints = computed(() => {
|
|
2991
3362
|
const availableSize = this.availableSpace();
|
|
2992
|
-
//
|
|
2993
|
-
|
|
2994
|
-
const
|
|
3363
|
+
// Use the effective (preview-aware) size so the letterboxed frame reflows
|
|
3364
|
+
// to fit during a grid-resize drag instead of overflowing/scrolling.
|
|
3365
|
+
const rows = this.store.effectiveRows();
|
|
3366
|
+
const columns = this.store.effectiveColumns();
|
|
2995
3367
|
if (rows === 0 || columns === 0) {
|
|
2996
3368
|
return {
|
|
2997
3369
|
maxWidth: availableSize.width,
|
|
@@ -3024,11 +3396,12 @@ class DashboardViewportService {
|
|
|
3024
3396
|
maxHeight: Math.max(0, maxHeight),
|
|
3025
3397
|
constrainedBy
|
|
3026
3398
|
};
|
|
3027
|
-
},
|
|
3028
|
-
|
|
3029
|
-
static
|
|
3399
|
+
}, /* @ts-ignore */
|
|
3400
|
+
...(ngDevMode ? [{ debugName: "constraints" }] : /* istanbul ignore next */ []));
|
|
3401
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3402
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardViewportService });
|
|
3030
3403
|
}
|
|
3031
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3404
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardViewportService, decorators: [{
|
|
3032
3405
|
type: Injectable
|
|
3033
3406
|
}], ctorParameters: () => [] });
|
|
3034
3407
|
|
|
@@ -3046,19 +3419,28 @@ class DashboardComponent {
|
|
|
3046
3419
|
store = this.#store;
|
|
3047
3420
|
viewport = this.#viewport;
|
|
3048
3421
|
// Component inputs
|
|
3049
|
-
dashboardData = input.required(
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3422
|
+
dashboardData = input.required(/* @ts-ignore */
|
|
3423
|
+
...(ngDevMode ? [{ debugName: "dashboardData" }] : /* istanbul ignore next */ []));
|
|
3424
|
+
editMode = input(false, /* @ts-ignore */
|
|
3425
|
+
...(ngDevMode ? [{ debugName: "editMode" }] : /* istanbul ignore next */ []));
|
|
3426
|
+
reservedSpace = input(/* @ts-ignore */
|
|
3427
|
+
...(ngDevMode ? [undefined, { debugName: "reservedSpace" }] : /* istanbul ignore next */ []));
|
|
3428
|
+
enableSelection = input(false, /* @ts-ignore */
|
|
3429
|
+
...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
|
|
3430
|
+
selectionModifier = input(null, /* @ts-ignore */
|
|
3431
|
+
...(ngDevMode ? [{ debugName: "selectionModifier" }] : /* istanbul ignore next */ []));
|
|
3432
|
+
dragThreshold = input(4, /* @ts-ignore */
|
|
3433
|
+
...(ngDevMode ? [{ debugName: "dragThreshold" }] : /* istanbul ignore next */ []));
|
|
3055
3434
|
// Component outputs
|
|
3056
3435
|
selectionComplete = output();
|
|
3436
|
+
gridResized = output();
|
|
3057
3437
|
// Store signals - shared by both child components
|
|
3058
3438
|
cells = this.#store.cells;
|
|
3059
3439
|
// ViewChild references for export/import functionality
|
|
3060
|
-
dashboardEditor = viewChild(DashboardEditorComponent,
|
|
3061
|
-
|
|
3440
|
+
dashboardEditor = viewChild(DashboardEditorComponent, /* @ts-ignore */
|
|
3441
|
+
...(ngDevMode ? [{ debugName: "dashboardEditor" }] : /* istanbul ignore next */ []));
|
|
3442
|
+
dashboardViewer = viewChild(DashboardViewerComponent, /* @ts-ignore */
|
|
3443
|
+
...(ngDevMode ? [{ debugName: "dashboardViewer" }] : /* istanbul ignore next */ []));
|
|
3062
3444
|
// Track if we're in the middle of preserving states
|
|
3063
3445
|
#isPreservingStates = false;
|
|
3064
3446
|
// Track if component has been initialized
|
|
@@ -3152,6 +3534,27 @@ class DashboardComponent {
|
|
|
3152
3534
|
clearDashboard() {
|
|
3153
3535
|
this.#store.clearDashboard();
|
|
3154
3536
|
}
|
|
3537
|
+
/**
|
|
3538
|
+
* Resize the dashboard grid to the given row/column counts.
|
|
3539
|
+
*
|
|
3540
|
+
* Uses a clamp-to-content policy: a size that would push an existing widget
|
|
3541
|
+
* out of bounds is snapped up to the smallest size that still contains every
|
|
3542
|
+
* widget, so shrinking never orphans a widget. The applied size (which may
|
|
3543
|
+
* differ from the request when clamped) is returned and emitted via
|
|
3544
|
+
* `gridResized`. Values below 1 are treated as 1; fractional values are
|
|
3545
|
+
* floored.
|
|
3546
|
+
*/
|
|
3547
|
+
setGridSize(rows, columns) {
|
|
3548
|
+
const beforeRows = this.#store.rows();
|
|
3549
|
+
const beforeColumns = this.#store.columns();
|
|
3550
|
+
const result = this.#store.setGridSize(rows, columns);
|
|
3551
|
+
// Only signal a resize when the committed size actually changed, matching
|
|
3552
|
+
// the handle-drag path (store.endGridResize).
|
|
3553
|
+
if (result.rows !== beforeRows || result.columns !== beforeColumns) {
|
|
3554
|
+
this.gridResized.emit(result);
|
|
3555
|
+
}
|
|
3556
|
+
return result;
|
|
3557
|
+
}
|
|
3155
3558
|
/**
|
|
3156
3559
|
* Forwards to the active viewer. No-op in edit mode.
|
|
3157
3560
|
* See `DashboardViewerComponent.clearSelection()`.
|
|
@@ -3195,21 +3598,21 @@ class DashboardComponent {
|
|
|
3195
3598
|
this.#isPreservingStates = false;
|
|
3196
3599
|
}
|
|
3197
3600
|
}
|
|
3198
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3199
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
3601
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3602
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: DashboardComponent, isStandalone: true, selector: "ngx-dashboard", inputs: { dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: true, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, reservedSpace: { classPropertyName: "reservedSpace", publicName: "reservedSpace", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, selectionModifier: { classPropertyName: "selectionModifier", publicName: "selectionModifier", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete", gridResized: "gridResized" }, host: { properties: { "style.--rows": "store.effectiveRows()", "style.--columns": "store.effectiveColumns()", "style.--gutter-size": "store.gutterSize()", "style.--gutters": "store.effectiveColumns() + 1", "class.is-edit-mode": "editMode()", "style.max-width.px": "viewport.constraints().maxWidth", "style.max-height.px": "viewport.constraints().maxHeight" } }, providers: [DashboardStore, DashboardViewportService], viewQueries: [{ propertyName: "dashboardEditor", first: true, predicate: DashboardEditorComponent, descendants: true, isSignal: true }, { propertyName: "dashboardViewer", first: true, predicate: DashboardViewerComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n (gridResized)=\"gridResized.emit($event)\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize", "enableSelection", "selectionModifier", "dragThreshold"], outputs: ["selectionComplete"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"], outputs: ["gridResized"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3200
3603
|
}
|
|
3201
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3604
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DashboardComponent, decorators: [{
|
|
3202
3605
|
type: Component,
|
|
3203
3606
|
args: [{ selector: 'ngx-dashboard', standalone: true, imports: [DashboardViewerComponent, DashboardEditorComponent], providers: [DashboardStore, DashboardViewportService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
3204
|
-
'[style.--rows]': 'store.
|
|
3205
|
-
'[style.--columns]': 'store.
|
|
3607
|
+
'[style.--rows]': 'store.effectiveRows()',
|
|
3608
|
+
'[style.--columns]': 'store.effectiveColumns()',
|
|
3206
3609
|
'[style.--gutter-size]': 'store.gutterSize()',
|
|
3207
|
-
'[style.--gutters]': 'store.
|
|
3610
|
+
'[style.--gutters]': 'store.effectiveColumns() + 1',
|
|
3208
3611
|
'[class.is-edit-mode]': 'editMode()',
|
|
3209
3612
|
'[style.max-width.px]': 'viewport.constraints().maxWidth',
|
|
3210
3613
|
'[style.max-height.px]': 'viewport.constraints().maxHeight',
|
|
3211
|
-
}, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"] }]
|
|
3212
|
-
}], ctorParameters: () => [], propDecorators: { dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: true }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], reservedSpace: [{ type: i0.Input, args: [{ isSignal: true, alias: "reservedSpace", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionModifier", required: false }] }], dragThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragThreshold", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], dashboardEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardEditorComponent), { isSignal: true }] }], dashboardViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardViewerComponent), { isSignal: true }] }] } });
|
|
3614
|
+
}, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n (gridResized)=\"gridResized.emit($event)\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"] }]
|
|
3615
|
+
}], ctorParameters: () => [], propDecorators: { dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: true }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], reservedSpace: [{ type: i0.Input, args: [{ isSignal: true, alias: "reservedSpace", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionModifier", required: false }] }], dragThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragThreshold", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], gridResized: [{ type: i0.Output, args: ["gridResized"] }], dashboardEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardEditorComponent), { isSignal: true }] }], dashboardViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardViewerComponent), { isSignal: true }] }] } });
|
|
3213
3616
|
|
|
3214
3617
|
// widget-list.component.ts
|
|
3215
3618
|
class WidgetListComponent {
|
|
@@ -3218,14 +3621,17 @@ class WidgetListComponent {
|
|
|
3218
3621
|
#renderer = inject(Renderer2);
|
|
3219
3622
|
#bridge = inject(DashboardBridgeService);
|
|
3220
3623
|
// Input to track collapsed state for tooltip display
|
|
3221
|
-
collapsed = input(false,
|
|
3222
|
-
|
|
3624
|
+
collapsed = input(false, /* @ts-ignore */
|
|
3625
|
+
...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
3626
|
+
activeWidget = signal(null, /* @ts-ignore */
|
|
3627
|
+
...(ngDevMode ? [{ debugName: "activeWidget" }] : /* istanbul ignore next */ []));
|
|
3223
3628
|
// Get grid cell dimensions from bridge service (uses first available dashboard)
|
|
3224
3629
|
gridCellDimensions = this.#bridge.availableDimensions;
|
|
3225
3630
|
widgets = computed(() => this.#service.widgetTypes().map((w) => ({
|
|
3226
3631
|
...w.metadata,
|
|
3227
3632
|
safeSvgIcon: this.#sanitizer.bypassSecurityTrustHtml(w.metadata.svgIcon),
|
|
3228
|
-
})),
|
|
3633
|
+
})), /* @ts-ignore */
|
|
3634
|
+
...(ngDevMode ? [{ debugName: "widgets" }] : /* istanbul ignore next */ []));
|
|
3229
3635
|
onDragStart(event, widget) {
|
|
3230
3636
|
if (!event.dataTransfer)
|
|
3231
3637
|
return;
|
|
@@ -3277,10 +3683,10 @@ class WidgetListComponent {
|
|
|
3277
3683
|
// Using $localize for the template pattern
|
|
3278
3684
|
return $localize `:@@ngx.dashboard.widget.list.item.ariaLabel:${widget.name} widget: ${widget.description}`;
|
|
3279
3685
|
}
|
|
3280
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3281
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
3686
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WidgetListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3687
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: WidgetListComponent, isStandalone: true, selector: "ngx-dashboard-widget-list", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- widget-list.component.html -->\n<div\n class=\"widget-list\"\n role=\"list\"\n i18n-aria-label=\"@@ngx.dashboard.widget.list.available\"\n aria-label=\"Available widgets\"\n>\n @for (widget of widgets(); track widget.widgetTypeid) {\n <div\n class=\"widget-list-item\"\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\n draggable=\"true\"\n (dragstart)=\"onDragStart($event, widget)\"\n (dragend)=\"onDragEnd()\"\n role=\"listitem\"\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\n [attr.aria-label]=\"getWidgetAriaLabel(widget)\"\n [matTooltip]=\"widget.description\"\n [matTooltipDisabled]=\"!collapsed()\"\n matTooltipPosition=\"right\"\n tabindex=\"0\"\n >\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\n <div class=\"content\">\n <strong>{{ widget.name }}</strong>\n <small>{{ widget.description }}</small>\n </div>\n </div>\n }\n</div>\n", styles: [":host{background-color:var(--mat-sys-surface-container, #f5f5f5);container-type:inline-size}.widget-list{display:flex;flex-direction:column;gap:var(--mat-sys-spacing-2, 8px)}@container (max-width: 200px){.widget-list{gap:var(--mat-sys-spacing-1, 4px)}}@container (min-width: 400px){.widget-list{gap:var(--mat-sys-spacing-3, 12px)}}.widget-list-item{display:flex;align-items:start;gap:var(--mat-sys-spacing-3, 12px);background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);padding:var(--mat-sys-spacing-3, 12px);border-radius:var(--mat-sys-corner-small, 4px);cursor:grab;transition:background-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),border-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),box-shadow var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out);box-shadow:var(--mat-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, .05))}@container (max-width: 200px){.widget-list-item{padding:var(--mat-sys-spacing-2, 8px);gap:var(--mat-sys-spacing-2, 8px)}}@container (min-width: 400px){.widget-list-item{padding:var(--mat-sys-spacing-4, 16px);gap:var(--mat-sys-spacing-4, 16px)}}.widget-list-item .icon{width:clamp(20px,4vw,28px);height:clamp(20px,4vw,28px);flex-shrink:0;color:var(--mat-sys-on-surface-variant, #5f5f5f);transition:color var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block}.widget-list-item .content{display:flex;flex-direction:column;line-height:1.2;color:var(--mat-sys-on-surface, #1c1c1c);flex:1;min-width:0}.widget-list-item .content strong{color:var(--mat-sys-on-surface, #1c1c1c);font-weight:500;font-size:clamp(.875rem,2.5vw,1rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item .content small{color:var(--mat-sys-on-surface-variant, #5f5f5f);font-size:clamp(.75rem,2vw,.875rem);margin-top:var(--mat-sys-spacing-1, 4px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item:hover{background-color:var(--mat-sys-surface-container-low, #f0f0f0);box-shadow:var(--mat-sys-elevation-level2, 0 2px 4px rgba(0, 0, 0, .1))}.widget-list-item:hover .icon{color:var(--mat-sys-on-surface, #1c1c1c)}.widget-list-item:active{cursor:grabbing;background-color:var(--mat-sys-surface-container, #f5f5f5)}.widget-list-item.active{background-color:var(--mat-sys-primary-container, #e6f2ff);border-color:var(--mat-sys-primary, #1976d2);color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content strong{color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content small{color:var(--mat-sys-on-primary-container, #004a99);opacity:.8}.widget-list-item.active .icon{color:var(--mat-sys-on-primary-container, #004a99)}.drag-ghost{position:absolute;top:0;left:0;z-index:9999;margin:0;pointer-events:none;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);border-radius:var(--mat-sys-corner-small, 4px);box-shadow:var(--mat-sys-elevation-level3, 0 4px 6px rgba(0, 0, 0, .15));opacity:.8}.drag-ghost .icon{display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}.drag-ghost .icon ::ng-deep svg{display:block}\n"], dependencies: [{ kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3282
3688
|
}
|
|
3283
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3689
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WidgetListComponent, decorators: [{
|
|
3284
3690
|
type: Component,
|
|
3285
3691
|
args: [{ selector: 'ngx-dashboard-widget-list', standalone: true, imports: [MatTooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- widget-list.component.html -->\n<div\n class=\"widget-list\"\n role=\"list\"\n i18n-aria-label=\"@@ngx.dashboard.widget.list.available\"\n aria-label=\"Available widgets\"\n>\n @for (widget of widgets(); track widget.widgetTypeid) {\n <div\n class=\"widget-list-item\"\n [class.active]=\"activeWidget() === widget.widgetTypeid\"\n draggable=\"true\"\n (dragstart)=\"onDragStart($event, widget)\"\n (dragend)=\"onDragEnd()\"\n role=\"listitem\"\n [attr.aria-grabbed]=\"activeWidget() === widget.widgetTypeid\"\n [attr.aria-label]=\"getWidgetAriaLabel(widget)\"\n [matTooltip]=\"widget.description\"\n [matTooltipDisabled]=\"!collapsed()\"\n matTooltipPosition=\"right\"\n tabindex=\"0\"\n >\n <div class=\"icon\" [innerHTML]=\"widget.safeSvgIcon\" aria-hidden=\"true\"></div>\n <div class=\"content\">\n <strong>{{ widget.name }}</strong>\n <small>{{ widget.description }}</small>\n </div>\n </div>\n }\n</div>\n", styles: [":host{background-color:var(--mat-sys-surface-container, #f5f5f5);container-type:inline-size}.widget-list{display:flex;flex-direction:column;gap:var(--mat-sys-spacing-2, 8px)}@container (max-width: 200px){.widget-list{gap:var(--mat-sys-spacing-1, 4px)}}@container (min-width: 400px){.widget-list{gap:var(--mat-sys-spacing-3, 12px)}}.widget-list-item{display:flex;align-items:start;gap:var(--mat-sys-spacing-3, 12px);background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);padding:var(--mat-sys-spacing-3, 12px);border-radius:var(--mat-sys-corner-small, 4px);cursor:grab;transition:background-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),border-color var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out),box-shadow var(--mat-sys-motion-duration-medium2, .3s) var(--mat-sys-motion-easing-standard, ease-in-out);box-shadow:var(--mat-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, .05))}@container (max-width: 200px){.widget-list-item{padding:var(--mat-sys-spacing-2, 8px);gap:var(--mat-sys-spacing-2, 8px)}}@container (min-width: 400px){.widget-list-item{padding:var(--mat-sys-spacing-4, 16px);gap:var(--mat-sys-spacing-4, 16px)}}.widget-list-item .icon{width:clamp(20px,4vw,28px);height:clamp(20px,4vw,28px);flex-shrink:0;color:var(--mat-sys-on-surface-variant, #5f5f5f);transition:color var(--mat-sys-motion-duration-short2, .15s) var(--mat-sys-motion-easing-standard, ease-in-out)}.widget-list-item .icon ::ng-deep svg{width:100%;height:100%;display:block}.widget-list-item .content{display:flex;flex-direction:column;line-height:1.2;color:var(--mat-sys-on-surface, #1c1c1c);flex:1;min-width:0}.widget-list-item .content strong{color:var(--mat-sys-on-surface, #1c1c1c);font-weight:500;font-size:clamp(.875rem,2.5vw,1rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item .content small{color:var(--mat-sys-on-surface-variant, #5f5f5f);font-size:clamp(.75rem,2vw,.875rem);margin-top:var(--mat-sys-spacing-1, 4px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.widget-list-item:hover{background-color:var(--mat-sys-surface-container-low, #f0f0f0);box-shadow:var(--mat-sys-elevation-level2, 0 2px 4px rgba(0, 0, 0, .1))}.widget-list-item:hover .icon{color:var(--mat-sys-on-surface, #1c1c1c)}.widget-list-item:active{cursor:grabbing;background-color:var(--mat-sys-surface-container, #f5f5f5)}.widget-list-item.active{background-color:var(--mat-sys-primary-container, #e6f2ff);border-color:var(--mat-sys-primary, #1976d2);color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content strong{color:var(--mat-sys-on-primary-container, #004a99)}.widget-list-item.active .content small{color:var(--mat-sys-on-primary-container, #004a99);opacity:.8}.widget-list-item.active .icon{color:var(--mat-sys-on-primary-container, #004a99)}.drag-ghost{position:absolute;top:0;left:0;z-index:9999;margin:0;pointer-events:none;display:flex;align-items:center;justify-content:center;box-sizing:border-box;background-color:var(--mat-sys-surface, #ffffff);border:1px solid var(--mat-sys-outline-variant, #c7c7c7);border-radius:var(--mat-sys-corner-small, 4px);box-shadow:var(--mat-sys-elevation-level3, 0 4px 6px rgba(0, 0, 0, .15));opacity:.8}.drag-ghost .icon{display:flex;align-items:center;justify-content:center;color:var(--mat-sys-on-surface-variant, #5f5f5f);opacity:.6}.drag-ghost .icon ::ng-deep svg{display:block}\n"] }]
|
|
3286
3692
|
}], propDecorators: { collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });
|