@dragonworks/ngx-dashboard 20.0.6 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/fesm2022/dragonworks-ngx-dashboard.mjs +2250 -0
  2. package/fesm2022/dragonworks-ngx-dashboard.mjs.map +1 -0
  3. package/index.d.ts +727 -0
  4. package/package.json +45 -34
  5. package/ng-package.json +0 -7
  6. package/src/lib/__tests__/dashboard-component-widget-state-integration.spec.ts +0 -537
  7. package/src/lib/cell/__tests__/cell-resize.component.spec.ts +0 -442
  8. package/src/lib/cell/__tests__/cell.component.spec.ts +0 -541
  9. package/src/lib/cell/cell-context-menu.component.ts +0 -138
  10. package/src/lib/cell/cell-context-menu.service.ts +0 -36
  11. package/src/lib/cell/cell.component.html +0 -37
  12. package/src/lib/cell/cell.component.scss +0 -198
  13. package/src/lib/cell/cell.component.ts +0 -375
  14. package/src/lib/dashboard/dashboard.component.html +0 -18
  15. package/src/lib/dashboard/dashboard.component.scss +0 -17
  16. package/src/lib/dashboard/dashboard.component.ts +0 -187
  17. package/src/lib/dashboard-editor/dashboard-editor.component.html +0 -57
  18. package/src/lib/dashboard-editor/dashboard-editor.component.scss +0 -87
  19. package/src/lib/dashboard-editor/dashboard-editor.component.ts +0 -219
  20. package/src/lib/dashboard-viewer/__tests__/dashboard-viewer.component.spec.ts +0 -258
  21. package/src/lib/dashboard-viewer/dashboard-viewer.component.html +0 -20
  22. package/src/lib/dashboard-viewer/dashboard-viewer.component.scss +0 -50
  23. package/src/lib/dashboard-viewer/dashboard-viewer.component.ts +0 -70
  24. package/src/lib/drop-zone/__tests__/drop-zone.component.spec.ts +0 -465
  25. package/src/lib/drop-zone/drop-zone.component.html +0 -20
  26. package/src/lib/drop-zone/drop-zone.component.scss +0 -67
  27. package/src/lib/drop-zone/drop-zone.component.ts +0 -122
  28. package/src/lib/internal-widgets/unknown-widget/unknown-widget.component.ts +0 -72
  29. package/src/lib/models/cell-data.ts +0 -13
  30. package/src/lib/models/cell-dialog.ts +0 -7
  31. package/src/lib/models/cell-id.ts +0 -85
  32. package/src/lib/models/cell-position.ts +0 -15
  33. package/src/lib/models/dashboard-data.dto.ts +0 -44
  34. package/src/lib/models/dashboard-data.utils.ts +0 -49
  35. package/src/lib/models/drag-data.ts +0 -6
  36. package/src/lib/models/index.ts +0 -11
  37. package/src/lib/models/reserved-space.ts +0 -24
  38. package/src/lib/models/widget-factory.ts +0 -33
  39. package/src/lib/models/widget-id.ts +0 -70
  40. package/src/lib/models/widget.ts +0 -21
  41. package/src/lib/providers/cell-settings-dialog/cell-settings-dialog.component.ts +0 -127
  42. package/src/lib/providers/cell-settings-dialog/cell-settings-dialog.provider.ts +0 -15
  43. package/src/lib/providers/cell-settings-dialog/cell-settings-dialog.tokens.ts +0 -20
  44. package/src/lib/providers/cell-settings-dialog/default-cell-settings-dialog.provider.ts +0 -32
  45. package/src/lib/providers/cell-settings-dialog/index.ts +0 -3
  46. package/src/lib/providers/index.ts +0 -1
  47. package/src/lib/services/__tests__/dashboard-bridge.service.spec.ts +0 -220
  48. package/src/lib/services/__tests__/dashboard-viewport.service.spec.ts +0 -362
  49. package/src/lib/services/dashboard-bridge.service.ts +0 -155
  50. package/src/lib/services/dashboard-viewport.service.ts +0 -148
  51. package/src/lib/services/dashboard.service.ts +0 -62
  52. package/src/lib/store/__tests__/dashboard-store-collision-detection.spec.ts +0 -756
  53. package/src/lib/store/__tests__/dashboard-store-computed-properties.spec.ts +0 -974
  54. package/src/lib/store/__tests__/dashboard-store-drag-drop.spec.ts +0 -279
  55. package/src/lib/store/__tests__/dashboard-store-export-import.spec.ts +0 -780
  56. package/src/lib/store/__tests__/dashboard-store-grid-config.spec.ts +0 -128
  57. package/src/lib/store/__tests__/dashboard-store-query-methods.spec.ts +0 -229
  58. package/src/lib/store/__tests__/dashboard-store-resize-operations.spec.ts +0 -652
  59. package/src/lib/store/__tests__/dashboard-store-widget-management.spec.ts +0 -461
  60. package/src/lib/store/__tests__/dashboard-store-widget-state-preservation.spec.ts +0 -369
  61. package/src/lib/store/dashboard-store.ts +0 -239
  62. package/src/lib/store/features/drag-drop.feature.ts +0 -140
  63. package/src/lib/store/features/grid-config.feature.ts +0 -43
  64. package/src/lib/store/features/resize.feature.ts +0 -140
  65. package/src/lib/store/features/utils/collision.utils.ts +0 -89
  66. package/src/lib/store/features/utils/grid-query-internal.utils.ts +0 -37
  67. package/src/lib/store/features/utils/resize.utils.ts +0 -165
  68. package/src/lib/store/features/widget-management.feature.ts +0 -158
  69. package/src/lib/styles/_dashboard-grid-vars.scss +0 -11
  70. package/src/lib/widget-list/__tests__/widget-list-bridge-integration.spec.ts +0 -137
  71. package/src/lib/widget-list/widget-list.component.html +0 -22
  72. package/src/lib/widget-list/widget-list.component.scss +0 -154
  73. package/src/lib/widget-list/widget-list.component.ts +0 -106
  74. package/src/public-api.ts +0 -21
  75. package/src/test-setup.ts +0 -10
  76. package/tsconfig.lib.json +0 -15
  77. package/tsconfig.lib.prod.json +0 -11
  78. package/tsconfig.spec.json +0 -14
@@ -1,187 +0,0 @@
1
- // dashboard.component.ts
2
- //
3
- // A performant, modular, and fully reactive Angular dashboard container that orchestrates between
4
- // editing and viewing modes — with clean component separation and no external dependencies.
5
-
6
- import { CommonModule } from '@angular/common';
7
- import {
8
- ChangeDetectionStrategy,
9
- Component,
10
- effect,
11
- inject,
12
- input,
13
- viewChild,
14
- DestroyRef,
15
- OnChanges,
16
- SimpleChanges,
17
- untracked,
18
- computed,
19
- } from '@angular/core';
20
- import { DashboardViewerComponent } from '../dashboard-viewer/dashboard-viewer.component';
21
- import { DashboardEditorComponent } from '../dashboard-editor/dashboard-editor.component';
22
- import { DashboardStore } from '../store/dashboard-store';
23
- import { DashboardDataDto } from '../models/dashboard-data.dto';
24
- import { DashboardBridgeService } from '../services/dashboard-bridge.service';
25
- import { DashboardViewportService } from '../services/dashboard-viewport.service';
26
- import { ReservedSpace } from '../models/reserved-space';
27
-
28
- @Component({
29
- selector: 'ngx-dashboard',
30
- standalone: true,
31
- imports: [CommonModule, DashboardViewerComponent, DashboardEditorComponent],
32
- providers: [DashboardStore, DashboardViewportService],
33
- changeDetection: ChangeDetectionStrategy.OnPush,
34
- templateUrl: './dashboard.component.html',
35
- styleUrl: './dashboard.component.scss',
36
- host: {
37
- '[style.--rows]': 'store.rows()',
38
- '[style.--columns]': 'store.columns()',
39
- '[style.--gutter-size]': 'store.gutterSize()',
40
- '[style.--gutters]': 'store.columns() + 1',
41
- '[class.is-edit-mode]': 'editMode()',
42
- '[style.max-width.px]': 'viewport.constraints().maxWidth',
43
- '[style.max-height.px]': 'viewport.constraints().maxHeight',
44
- },
45
- })
46
- export class DashboardComponent implements OnChanges {
47
- #store = inject(DashboardStore);
48
- #bridge = inject(DashboardBridgeService);
49
- #viewport = inject(DashboardViewportService);
50
- #destroyRef = inject(DestroyRef);
51
-
52
- // Public accessors for template
53
- protected readonly store = this.#store;
54
- protected readonly viewport = this.#viewport;
55
-
56
- // Component inputs
57
- dashboardData = input.required<DashboardDataDto>();
58
- editMode = input<boolean>(false);
59
- reservedSpace = input<ReservedSpace>();
60
-
61
- // Store signals - shared by both child components
62
- cells = this.#store.cells;
63
-
64
- // ViewChild references for export/import functionality
65
- private dashboardEditor = viewChild(DashboardEditorComponent);
66
- private dashboardViewer = viewChild(DashboardViewerComponent);
67
-
68
- // Track if we're in the middle of preserving states
69
- #isPreservingStates = false;
70
- // Track if component has been initialized
71
- #isInitialized = false;
72
-
73
- constructor() {
74
- // Cleanup registration when component is destroyed
75
- this.#destroyRef.onDestroy(() => {
76
- this.#bridge.unregisterDashboard(this.#store);
77
- });
78
-
79
- // Initialize from dashboardData
80
- effect(() => {
81
- const data = this.dashboardData();
82
- if (data) {
83
- this.#store.initializeFromDto(data);
84
- // Register with bridge service after dashboard ID is set
85
- this.#bridge.updateDashboardRegistration(this.#store);
86
- this.#isInitialized = true;
87
- }
88
- });
89
-
90
- // Sync edit mode with store (without triggering state preservation)
91
- effect(() => {
92
- const editMode = this.editMode();
93
- untracked(() => {
94
- this.#store.setEditMode(editMode);
95
- });
96
- });
97
-
98
- // Sync reserved space input with viewport service
99
- effect(() => {
100
- const reserved = this.reservedSpace();
101
- if (reserved) {
102
- this.#viewport.setReservedSpace(reserved);
103
- }
104
- });
105
- }
106
-
107
- ngOnChanges(changes: SimpleChanges): void {
108
- // Handle edit mode changes after initialization
109
- if (
110
- changes['editMode'] &&
111
- !changes['editMode'].firstChange &&
112
- this.#isInitialized
113
- ) {
114
- const previousValue = changes['editMode'].previousValue;
115
- const currentValue = changes['editMode'].currentValue;
116
-
117
- if (previousValue !== currentValue) {
118
- // Preserve widget states before the mode switch
119
- this.#preserveWidgetStatesBeforeModeSwitch(previousValue);
120
- }
121
- }
122
- }
123
-
124
- // Public export/import methods
125
- exportDashboard(): DashboardDataDto {
126
- // Delegate to the active child component
127
- if (this.editMode()) {
128
- const editor = this.dashboardEditor();
129
- return editor ? editor.exportDashboard() : this.#store.exportDashboard();
130
- } else {
131
- const viewer = this.dashboardViewer();
132
- return viewer ? viewer.exportDashboard() : this.#store.exportDashboard();
133
- }
134
- }
135
-
136
- loadDashboard(data: DashboardDataDto): void {
137
- this.#store.loadDashboard(data);
138
- }
139
-
140
- getCurrentDashboardData(): DashboardDataDto {
141
- return this.exportDashboard();
142
- }
143
-
144
- clearDashboard(): void {
145
- this.#store.clearDashboard();
146
- }
147
-
148
- /**
149
- * Preserve widget states before switching modes by collecting live states
150
- * from the currently active component and updating the store.
151
- */
152
- #preserveWidgetStatesBeforeModeSwitch(previousEditMode: boolean): void {
153
- // Prevent re-entrant calls
154
- if (this.#isPreservingStates) {
155
- return;
156
- }
157
-
158
- this.#isPreservingStates = true;
159
-
160
- try {
161
- let currentWidgetStates: Map<string, unknown> | null = null;
162
-
163
- if (previousEditMode) {
164
- // Previously in edit mode, collect states from editor
165
- const editor = this.dashboardEditor();
166
- if (editor) {
167
- currentWidgetStates = editor.getCurrentWidgetStates();
168
- }
169
- } else {
170
- // Previously in view mode, collect states from viewer
171
- const viewer = this.dashboardViewer();
172
- if (viewer) {
173
- currentWidgetStates = viewer.getCurrentWidgetStates();
174
- }
175
- }
176
-
177
- // Update the store with the live widget states using untracked to avoid triggering effects
178
- if (currentWidgetStates && currentWidgetStates.size > 0) {
179
- untracked(() => {
180
- this.#store.updateAllWidgetStates(currentWidgetStates);
181
- });
182
- }
183
- } finally {
184
- this.#isPreservingStates = false;
185
- }
186
- }
187
- }
@@ -1,57 +0,0 @@
1
- <!-- dashboard-editor.component.html -->
2
- <div class="grid-container">
3
- <!-- Bottom grid with drop zones -->
4
- <div class="grid" id="bottom-grid" #bottomGrid>
5
- @for (position of dropzonePositions(); track position.id) {
6
- <lib-drop-zone
7
- class="drop-zone"
8
- [row]="position.row"
9
- [col]="position.col"
10
- [index]="position.index"
11
- [highlight]="highlightMap().has(createCellId(position.row, position.col))"
12
- [highlightInvalid]="
13
- invalidHighlightMap().has(createCellId(position.row, position.col))
14
- "
15
- [highlightResize]="
16
- resizePreviewMap().has(createCellId(position.row, position.col))
17
- "
18
- [editMode]="true"
19
- (dragEnter)="onDragEnter($event)"
20
- (dragExit)="onDragExit()"
21
- (dragOver)="onDragOver($event)"
22
- (dragDrop)="onDragDrop($event)"
23
- ></lib-drop-zone>
24
- }
25
- </div>
26
-
27
- <!-- Top grid with interactive cells -->
28
- <div class="grid" id="top-grid">
29
- @for (cell of cells(); track cell.widgetId) {
30
- <lib-cell
31
- class="grid-cell"
32
- [widgetId]="cell.widgetId"
33
- [cellId]="cell.cellId"
34
- [isEditMode]="true"
35
- [draggable]="true"
36
- [row]="cell.row"
37
- [column]="cell.col"
38
- [rowSpan]="cell.rowSpan"
39
- [colSpan]="cell.colSpan"
40
- [flat]="cell.flat"
41
- [widgetFactory]="cell.widgetFactory"
42
- [widgetState]="cell.widgetState"
43
- (dragStart)="onCellDragStart($event)"
44
- (dragEnd)="dragEnd()"
45
- (delete)="onCellDelete($event)"
46
- (settings)="onCellSettings($event)"
47
- (resizeStart)="onCellResizeStart($event)"
48
- (resizeMove)="onCellResizeMove($event)"
49
- (resizeEnd)="onCellResizeEnd($event)"
50
- >
51
- </lib-cell>
52
- }
53
- </div>
54
- </div>
55
-
56
- <!-- Context menu -->
57
- <lib-cell-context-menu></lib-cell-context-menu>
@@ -1,87 +0,0 @@
1
- /* dashboard-editor.component.scss */
2
- @use "../styles/dashboard-grid-vars" as *;
3
-
4
- :host {
5
- @include dashboard-grid-vars;
6
-
7
- display: block;
8
- container-type: inline-size;
9
- box-sizing: border-box;
10
- aspect-ratio: var(--columns) / var(--rows);
11
- width: 100%;
12
- height: auto;
13
- }
14
-
15
- /* ── Grid-line overlay (visual only) ──────────────────────────────── */
16
- :host .grid {
17
- /* Three layers:
18
- 1) vertical hair-lines (repeat)
19
- 2) horizontal centred hair-lines (repeat)
20
- 3) *single* horizontal hair-line flush with the bottom edge (no-repeat) */
21
- background-image: linear-gradient(
22
- to right,
23
- rgba(100 100 100 / 0.12) 1px,
24
- transparent 1px
25
- ),
26
- linear-gradient(to bottom, rgba(100 100 100 / 0.12) 1px, transparent 1px),
27
- linear-gradient(to bottom, rgba(100 100 100 / 0.12) 1px, transparent 1px);
28
-
29
- background-size: var(--tile-size) var(--tile-size),
30
- /* vertical lines tile */ var(--tile-size) var(--tile-size),
31
- /* horizontal centred lines tile */ 100% 1px; /* bottom edge only */
32
-
33
- background-position: var(--tile-offset) var(--tile-offset),
34
- /* vertical-line grid */ var(--tile-offset) var(--tile-offset),
35
- /* horizontal centred */ bottom; /* bottom hair-line */
36
-
37
- background-repeat: repeat, repeat, no-repeat;
38
-
39
- // background-color: rgba(245 245 245 / 0.5);
40
- //border: 1px solid rgba(245 245 245 / 0.1);
41
- }
42
- /* ── Structural wrappers ─────────────────────────────────────────── */
43
- .grid-container {
44
- position: relative;
45
- width: 100%;
46
- height: 100%;
47
- // background-color: var(--grid-background-color);
48
- }
49
-
50
- /* Real CSS Grid that holds widgets */
51
- .grid {
52
- display: grid;
53
- gap: var(--gutter-size);
54
- padding: var(--gutter-size);
55
-
56
- position: absolute;
57
- inset: 0; /* top/right/bottom/left: 0 */
58
-
59
- width: 100%;
60
- height: 100%;
61
- box-sizing: border-box;
62
-
63
- align-items: stretch;
64
- justify-items: stretch;
65
-
66
- grid-template-columns: repeat(var(--columns), var(--cell-size));
67
- grid-template-rows: repeat(var(--rows), var(--cell-size));
68
- }
69
-
70
- /* ── Layering & DnD helpers ──────────────────────────────────────── */
71
- #bottom-grid {
72
- z-index: 1;
73
- }
74
-
75
- #top-grid {
76
- z-index: 2;
77
- pointer-events: none; /* overlay shouldn’t block interactions */
78
- }
79
-
80
- .grid-cell {
81
- pointer-events: auto; /* re-enable for actual content */
82
- }
83
-
84
- .grid-cell.is-dragging {
85
- pointer-events: none; /* don’t block drop zones while lifted */
86
- opacity: 0.5;
87
- }
@@ -1,219 +0,0 @@
1
- // dashboard-editor.component.ts
2
- import { CommonModule } from '@angular/common';
3
- import {
4
- ChangeDetectionStrategy,
5
- Component,
6
- computed,
7
- DestroyRef,
8
- effect,
9
- ElementRef,
10
- inject,
11
- input,
12
- output,
13
- viewChild,
14
- viewChildren,
15
- afterNextRender,
16
- } from '@angular/core';
17
- import { CellComponent } from '../cell/cell.component';
18
- import { CellContextMenuComponent } from '../cell/cell-context-menu.component';
19
- import { CellContextMenuService } from '../cell/cell-context-menu.service';
20
- import { DropZoneComponent } from '../drop-zone/drop-zone.component';
21
- import { CellId, CellIdUtils, WidgetId, WidgetIdUtils, DragData, CellData } from '../models';
22
- import { DashboardStore } from '../store/dashboard-store';
23
-
24
- @Component({
25
- selector: 'ngx-dashboard-editor',
26
- standalone: true,
27
- imports: [
28
- CellComponent,
29
- CommonModule,
30
- DropZoneComponent,
31
- CellContextMenuComponent,
32
- ],
33
- providers: [
34
- CellContextMenuService,
35
- ],
36
- changeDetection: ChangeDetectionStrategy.OnPush,
37
- templateUrl: './dashboard-editor.component.html',
38
- styleUrl: './dashboard-editor.component.scss',
39
- host: {
40
- '[style.--rows]': 'rows()',
41
- '[style.--columns]': 'columns()',
42
- '[style.--gutter-size]': 'gutterSize()',
43
- '[style.--gutters]': 'gutters()',
44
- '[class.is-edit-mode]': 'true', // Always in edit mode
45
- },
46
- })
47
- export class DashboardEditorComponent {
48
- bottomGridRef = viewChild.required<ElementRef<HTMLDivElement>>('bottomGrid');
49
- dropZones = viewChildren(DropZoneComponent);
50
- cellComponents = viewChildren(CellComponent);
51
-
52
- #store = inject(DashboardStore);
53
- #destroyRef = inject(DestroyRef);
54
- #resizeObserver?: ResizeObserver;
55
-
56
- rows = input.required<number>();
57
- columns = input.required<number>();
58
- gutterSize = input<string>('1em');
59
- gutters = computed(() => this.columns() + 1);
60
-
61
- // store signals
62
- cells = this.#store.cells;
63
- highlightedZones = this.#store.highlightedZones;
64
- highlightMap = this.#store.highlightMap;
65
- invalidHighlightMap = this.#store.invalidHighlightMap;
66
- hoveredDropZone = this.#store.hoveredDropZone;
67
- resizePreviewMap = this.#store.resizePreviewMap;
68
-
69
- // Generate all possible cell positions for the grid
70
- dropzonePositions = computed(() => {
71
- const positions = [];
72
- for (let row = 1; row <= this.rows(); row++) {
73
- for (let col = 1; col <= this.columns(); col++) {
74
- positions.push({
75
- row,
76
- col,
77
- id: `dropzone-${row}-${col}`,
78
- index: (row - 1) * this.columns() + col,
79
- });
80
- }
81
- }
82
- return positions;
83
- });
84
-
85
- // Helper method for template
86
- createCellId(row: number, col: number): CellId {
87
- return CellIdUtils.create(row, col);
88
- }
89
-
90
- constructor() {
91
- // Sync grid configuration with store when inputs change
92
- effect(() => {
93
- this.#store.setGridConfig({
94
- rows: this.rows(),
95
- columns: this.columns(),
96
- gutterSize: this.gutterSize(),
97
- });
98
- });
99
-
100
- // Observe grid size after rendering
101
- afterNextRender(() => {
102
- this.#observeGridSize();
103
- });
104
-
105
- // Always set edit mode to true
106
- effect(() => {
107
- this.#store.setEditMode(true);
108
- });
109
- }
110
-
111
- #observeGridSize(): void {
112
- const gridEl = this.bottomGridRef()?.nativeElement;
113
- if (!gridEl || this.#resizeObserver) return;
114
-
115
- this.#resizeObserver = new ResizeObserver(() => {
116
- const dropZonesList = this.dropZones();
117
- const firstDropZone = dropZonesList[0];
118
- if (!firstDropZone) return;
119
- const el: HTMLElement = firstDropZone.nativeElement;
120
- if (!el) return;
121
- const rect = el.getBoundingClientRect();
122
-
123
- const width = rect.width;
124
- const height = rect.height;
125
-
126
- this.#store.setGridCellDimensions(width, height);
127
- });
128
-
129
- this.#resizeObserver.observe(gridEl);
130
-
131
- // Register cleanup with DestroyRef for automatic memory management
132
- this.#destroyRef.onDestroy(() => {
133
- this.#resizeObserver?.disconnect();
134
- this.#resizeObserver = undefined;
135
- });
136
- }
137
-
138
- // Pure delegation methods - no business logic in component
139
- addWidget = (cellData: CellData) => this.#store.addWidget(cellData);
140
-
141
- updateCellPosition = (id: WidgetId, row: number, column: number) =>
142
- this.#store.updateWidgetPosition(id, row, column);
143
-
144
- updateCellSpan = (id: WidgetId, colSpan: number, rowSpan: number) =>
145
- this.#store.updateWidgetSpan(id, rowSpan, colSpan);
146
-
147
- updateCellSettings = (id: WidgetId, flat: boolean) =>
148
- this.#store.updateCellSettings(id, flat);
149
-
150
- // Pure delegation - drag and drop event handlers
151
- onDragOver = (event: { row: number; col: number }) =>
152
- this.#store.setHoveredDropZone(event);
153
-
154
- onDragEnter = (event: { row: number; col: number }) => this.onDragOver(event);
155
-
156
- onDragExit = () => this.#store.setHoveredDropZone(null);
157
-
158
- dragEnd = () => this.#store.endDrag();
159
-
160
- // Pure delegation - cell event handlers
161
- onCellDelete = (id: WidgetId) => this.#store.removeWidget(id);
162
-
163
- onCellSettings = (event: { id: WidgetId; flat: boolean }) =>
164
- this.updateCellSettings(event.id, event.flat);
165
-
166
- onCellResize = (event: { id: WidgetId; rowSpan: number; colSpan: number }) =>
167
- this.updateCellSpan(event.id, event.colSpan, event.rowSpan);
168
-
169
- // Handle drag events from cell component
170
- onCellDragStart = (dragData: DragData) => this.#store.startDrag(dragData);
171
-
172
- // Handle resize events from cell component
173
- onCellResizeStart = (event: {
174
- cellId: CellId;
175
- direction: 'horizontal' | 'vertical';
176
- }) => this.#store.startResize(event.cellId);
177
-
178
- onCellResizeMove = (event: {
179
- cellId: CellId;
180
- direction: 'horizontal' | 'vertical';
181
- delta: number;
182
- }) => this.#store.updateResizePreview(event.direction, event.delta);
183
-
184
- onCellResizeEnd = (event: { cellId: CellId; apply: boolean }) =>
185
- this.#store.endResize(event.apply);
186
-
187
- // Handle drop events by delegating to store's business logic
188
- onDragDrop(event: { data: DragData; target: { row: number; col: number } }) {
189
- this.#store.handleDrop(event.data, event.target);
190
- // Note: Store handles all validation and error handling internally
191
- }
192
-
193
- /**
194
- * Get current widget states from all cell components.
195
- * Used during dashboard export to get live widget states.
196
- */
197
- getCurrentWidgetStates(): Map<string, unknown> {
198
- const stateMap = new Map<string, unknown>();
199
-
200
- const cells = this.cellComponents();
201
- for (const cell of cells) {
202
- const cellId = cell.cellId();
203
- const currentState = cell.getCurrentWidgetState();
204
- if (currentState !== undefined) {
205
- stateMap.set(CellIdUtils.toString(cellId), currentState);
206
- }
207
- }
208
-
209
- return stateMap;
210
- }
211
-
212
- /**
213
- * Export dashboard with live widget states from current component instances.
214
- * This ensures the most up-to-date widget states are captured.
215
- */
216
- exportDashboard() {
217
- return this.#store.exportDashboard(() => this.getCurrentWidgetStates());
218
- }
219
- }