@dragonworks/ngx-dashboard 20.2.0 → 20.3.2

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.
package/index.d.ts CHANGED
@@ -4,6 +4,8 @@ import { Type, ViewContainerRef, ComponentRef, OnChanges, SimpleChanges, Injecti
4
4
  import * as _ngrx_signals from '@ngrx/signals';
5
5
  import { SafeHtml } from '@angular/platform-browser';
6
6
 
7
+ declare const NGX_DASHBOARD_VERSION = "20.3.2";
8
+
7
9
  /**
8
10
  * Branded type for cell identifiers to ensure type safety when working with grid coordinates.
9
11
  * This prevents accidentally mixing up row/column numbers with cell IDs.
@@ -24,6 +26,7 @@ interface Widget {
24
26
  dashboardGetState?(): unknown;
25
27
  dashboardSetState?(state?: unknown): void;
26
28
  dashboardEditState?(): void;
29
+ dashboardEditSharedState?(): void;
27
30
  }
28
31
  interface WidgetMetadata {
29
32
  widgetTypeid: string;
@@ -86,6 +89,13 @@ interface DashboardDataDto {
86
89
  gutterSize: string;
87
90
  /** Array of serializable cell data */
88
91
  cells: CellDataDto[];
92
+ /**
93
+ * Shared states for widget families (optional).
94
+ * Maps widget type ID to shared state object.
95
+ * This allows widget families to share configuration across all instances.
96
+ * @since 1.1.0
97
+ */
98
+ sharedStates?: Record<string, unknown>;
89
99
  }
90
100
  /**
91
101
  * Serializable version of CellData that can be safely JSON stringified.
@@ -145,6 +155,20 @@ type DragData = {
145
155
  content: WidgetMetadata;
146
156
  };
147
157
 
158
+ /**
159
+ * Represents a rectangular selection region in the dashboard grid
160
+ */
161
+ interface GridSelection {
162
+ topLeft: {
163
+ row: number;
164
+ col: number;
165
+ };
166
+ bottomRight: {
167
+ row: number;
168
+ col: number;
169
+ };
170
+ }
171
+
148
172
  /**
149
173
  * Defines space that should be reserved around the dashboard component
150
174
  * when calculating viewport constraints.
@@ -160,6 +184,110 @@ interface ReservedSpace {
160
184
  left: number;
161
185
  }
162
186
 
187
+ /**
188
+ * Options for filtering and exporting a selection of the dashboard.
189
+ *
190
+ * Used when exporting a subset of the dashboard based on a grid selection.
191
+ * Provides control over how the selection bounds are calculated and applied.
192
+ */
193
+ interface SelectionFilterOptions {
194
+ /**
195
+ * If true, shrink the export bounds to the minimal bounding box containing all widgets.
196
+ * If false or undefined (default), use the selection bounds as-is.
197
+ *
198
+ * When enabled, the exported dashboard will be tightly cropped to only include
199
+ * the space occupied by widgets, removing any empty cells around the edges.
200
+ *
201
+ * @default false
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * // Export with minimal bounds (tight crop around widgets)
206
+ * const data = dashboard.exportDashboard(selection, { useMinimalBounds: true });
207
+ *
208
+ * // Export with full selection bounds (preserve empty space)
209
+ * const data = dashboard.exportDashboard(selection, { useMinimalBounds: false });
210
+ * ```
211
+ */
212
+ useMinimalBounds?: boolean;
213
+ /**
214
+ * Number of cells to add as padding on each side of the export bounds.
215
+ *
216
+ * Padding expands the export area by adding empty cells around the selection.
217
+ * A padding value of 1 adds 1 row above, 1 row below, 1 column to the left,
218
+ * and 1 column to the right of the bounds.
219
+ *
220
+ * When used with `useMinimalBounds: true`, padding is applied AFTER the bounds
221
+ * are shrunk to the minimal bounding box containing all widgets.
222
+ *
223
+ * The minimum row and column values are clamped to 1 (grid coordinates are 1-based),
224
+ * so padding will not extend below the grid origin.
225
+ *
226
+ * @default 0
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * // Export with 1 cell of padding on all sides
231
+ * const data = dashboard.exportDashboard(selection, { padding: 1 });
232
+ *
233
+ * // Export with minimal bounds and 2 cells of padding
234
+ * const data = dashboard.exportDashboard(selection, {
235
+ * useMinimalBounds: true,
236
+ * padding: 2
237
+ * });
238
+ * ```
239
+ */
240
+ padding?: number;
241
+ }
242
+
243
+ /**
244
+ * Interface for providing shared state across all instances of a widget type.
245
+ *
246
+ * Widget families can implement this interface to manage state that should be
247
+ * shared across all instances of that widget type (e.g., theme colors, configuration).
248
+ *
249
+ * During dashboard serialization, the framework calls getSharedState() once per
250
+ * widget type (not per instance), and during deserialization, setSharedState()
251
+ * is called to restore the shared configuration.
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * @Injectable({ providedIn: 'root' })
256
+ * export class ParkingSpaceSharedState implements WidgetSharedStateProvider<ParkingConfig> {
257
+ * private state = signal<ParkingConfig>({ color: '#4CAF50', pricePerHour: 5 });
258
+ *
259
+ * getSharedState(): ParkingConfig {
260
+ * return this.state();
261
+ * }
262
+ *
263
+ * setSharedState(state: ParkingConfig): void {
264
+ * this.state.set(state);
265
+ * }
266
+ *
267
+ * readonly config = this.state.asReadonly();
268
+ * }
269
+ *
270
+ * // Register with dashboard
271
+ * dashboardService.registerWidgetType(ParkingSpaceWidget, ParkingSpaceSharedState);
272
+ * ```
273
+ */
274
+ interface WidgetSharedStateProvider<T = unknown> {
275
+ /**
276
+ * Gets the current shared state for this widget type.
277
+ * Called during dashboard export/serialization.
278
+ *
279
+ * @returns The current shared state, or undefined if no state should be serialized
280
+ */
281
+ getSharedState(): T | undefined;
282
+ /**
283
+ * Sets the shared state for this widget type.
284
+ * Called during dashboard import/deserialization before widget instances are created.
285
+ *
286
+ * @param state The shared state to restore
287
+ */
288
+ setSharedState(state: T): void;
289
+ }
290
+
163
291
  interface ResizeData {
164
292
  cellId: CellId;
165
293
  originalRowSpan: number;
@@ -283,9 +411,8 @@ declare class DashboardComponent implements OnChanges {
283
411
  startResize: (cellId: CellId) => void;
284
412
  updateResizePreview: (direction: "horizontal" | "vertical", delta: number) => void;
285
413
  endResize: (apply: boolean) => void;
286
- exportDashboard: (getCurrentWidgetStates?: () => Map<string, unknown>) => DashboardDataDto;
414
+ exportDashboard: (getCurrentWidgetStates?: () => Map<string, unknown>, selection?: GridSelection, selectionOptions?: SelectionFilterOptions) => DashboardDataDto;
287
415
  loadDashboard: (data: DashboardDataDto) => void;
288
- initializeFromDto: (dashboardData: DashboardDataDto) => void;
289
416
  } & _ngrx_signals.StateSource<{
290
417
  dashboardId: string;
291
418
  rows: number;
@@ -308,17 +435,25 @@ declare class DashboardComponent implements OnChanges {
308
435
  dashboardData: _angular_core.InputSignal<DashboardDataDto>;
309
436
  editMode: _angular_core.InputSignal<boolean>;
310
437
  reservedSpace: _angular_core.InputSignal<ReservedSpace | undefined>;
438
+ enableSelection: _angular_core.InputSignal<boolean>;
439
+ selectionComplete: _angular_core.OutputEmitterRef<GridSelection>;
311
440
  cells: _angular_core.Signal<CellData[]>;
312
441
  private dashboardEditor;
313
442
  private dashboardViewer;
314
443
  constructor();
315
444
  ngOnChanges(changes: SimpleChanges): void;
445
+ /**
446
+ * Get current widget states from all cell components.
447
+ * Used during dashboard export to get live widget states.
448
+ */
449
+ private getCurrentWidgetStates;
316
450
  exportDashboard(): DashboardDataDto;
451
+ exportDashboard(selection: GridSelection, options?: SelectionFilterOptions): DashboardDataDto;
317
452
  loadDashboard(data: DashboardDataDto): void;
318
453
  getCurrentDashboardData(): DashboardDataDto;
319
454
  clearDashboard(): void;
320
455
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DashboardComponent, never>;
321
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DashboardComponent, "ngx-dashboard", never, { "dashboardData": { "alias": "dashboardData"; "required": true; "isSignal": true; }; "editMode": { "alias": "editMode"; "required": false; "isSignal": true; }; "reservedSpace": { "alias": "reservedSpace"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
456
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DashboardComponent, "ngx-dashboard", never, { "dashboardData": { "alias": "dashboardData"; "required": true; "isSignal": true; }; "editMode": { "alias": "editMode"; "required": false; "isSignal": true; }; "reservedSpace": { "alias": "reservedSpace"; "required": false; "isSignal": true; }; "enableSelection": { "alias": "enableSelection"; "required": false; "isSignal": true; }; }, { "selectionComplete": "selectionComplete"; }, never, never, true, never>;
322
457
  }
323
458
 
324
459
  interface WidgetDisplayItem extends WidgetMetadata {
@@ -326,6 +461,7 @@ interface WidgetDisplayItem extends WidgetMetadata {
326
461
  }
327
462
  declare class WidgetListComponent {
328
463
  #private;
464
+ collapsed: _angular_core.InputSignal<boolean>;
329
465
  activeWidget: _angular_core.WritableSignal<string | null>;
330
466
  gridCellDimensions: _angular_core.Signal<{
331
467
  width: number;
@@ -342,14 +478,36 @@ declare class WidgetListComponent {
342
478
  onDragEnd(): void;
343
479
  getWidgetAriaLabel(widget: WidgetDisplayItem): string;
344
480
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WidgetListComponent, never>;
345
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WidgetListComponent, "ngx-dashboard-widget-list", never, {}, {}, never, never, true, never>;
481
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WidgetListComponent, "ngx-dashboard-widget-list", never, { "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
346
482
  }
347
483
 
348
484
  declare class DashboardService {
349
485
  #private;
350
486
  readonly widgetTypes: _angular_core.Signal<WidgetComponentClass<_dragonworks_ngx_dashboard.Widget>[]>;
351
- registerWidgetType(widget: WidgetComponentClass): void;
487
+ registerWidgetType<T = unknown>(widget: WidgetComponentClass, sharedStateProvider?: WidgetSharedStateProvider<T> | Type<WidgetSharedStateProvider<T>>): void;
352
488
  getFactory(widgetTypeid: string): WidgetFactory;
489
+ /**
490
+ * Get the shared state provider for a specific widget type.
491
+ *
492
+ * @param widgetTypeid The widget type identifier
493
+ * @returns The shared state provider, or undefined if none is registered
494
+ */
495
+ getSharedStateProvider(widgetTypeid: string): WidgetSharedStateProvider | undefined;
496
+ /**
497
+ * Collect shared states for all widget types currently on the dashboard.
498
+ * Called during dashboard export/serialization.
499
+ *
500
+ * @param activeWidgetTypes Set of widget type IDs that are currently in use
501
+ * @returns Map of widget type IDs to their shared states
502
+ */
503
+ collectSharedStates(activeWidgetTypes: Set<string>): Map<string, unknown>;
504
+ /**
505
+ * Restore shared states for widget types.
506
+ * Called during dashboard import/deserialization, before widget instances are created.
507
+ *
508
+ * @param states Map of widget type IDs to their shared states
509
+ */
510
+ restoreSharedStates(states: Map<string, unknown>): void;
353
511
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DashboardService, never>;
354
512
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DashboardService>;
355
513
  }
@@ -390,5 +548,120 @@ declare class DefaultCellSettingsDialogProvider extends CellSettingsDialogProvid
390
548
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DefaultCellSettingsDialogProvider>;
391
549
  }
392
550
 
393
- export { CELL_SETTINGS_DIALOG_PROVIDER, CellSettingsDialogProvider, DashboardComponent, DashboardService, DefaultCellSettingsDialogProvider, WidgetListComponent, createDefaultDashboard, createEmptyDashboard };
394
- export type { CellDataDto, DashboardDataDto, ReservedSpace, Widget, WidgetMetadata };
551
+ /**
552
+ * Context information about the empty cell that was clicked
553
+ */
554
+ interface EmptyCellContext {
555
+ /** The row position in the grid (1-indexed) */
556
+ row: number;
557
+ /** The column position in the grid (1-indexed) */
558
+ col: number;
559
+ /** Total number of rows in the dashboard */
560
+ totalRows: number;
561
+ /** Total number of columns in the dashboard */
562
+ totalColumns: number;
563
+ /** The gutter size between cells (e.g., '1em') */
564
+ gutterSize: string;
565
+ /**
566
+ * Optional callback to create a widget at this position.
567
+ * When provided, allows the context provider to create widgets directly.
568
+ *
569
+ * @param widgetTypeid - The widget type identifier to create
570
+ * @returns true if widget was created successfully, false otherwise
571
+ */
572
+ createWidget?: (widgetTypeid: string) => boolean;
573
+ }
574
+ /**
575
+ * Abstract provider for handling context menu events on empty dashboard cells.
576
+ * Implement this to provide custom behavior when users right-click on unoccupied grid spaces.
577
+ *
578
+ * @example
579
+ * ```typescript
580
+ * @Injectable()
581
+ * export class CustomEmptyCellProvider extends EmptyCellContextProvider {
582
+ * handleEmptyCellContext(event: MouseEvent, context: EmptyCellContext): void {
583
+ * event.preventDefault();
584
+ * // Show custom menu, open dialog, etc.
585
+ * }
586
+ * }
587
+ * ```
588
+ */
589
+ declare abstract class EmptyCellContextProvider {
590
+ /**
591
+ * Handle context menu event on an empty dashboard cell.
592
+ *
593
+ * @param event - The mouse event from the right-click
594
+ * @param context - Information about the empty cell and dashboard
595
+ */
596
+ abstract handleEmptyCellContext(event: MouseEvent, context: EmptyCellContext): void;
597
+ }
598
+
599
+ /**
600
+ * Injection token for the empty cell context provider.
601
+ * Use this to provide your custom implementation for handling right-clicks on empty dashboard cells.
602
+ *
603
+ * @example
604
+ * ```typescript
605
+ * // Provide a custom implementation
606
+ * providers: [
607
+ * {
608
+ * provide: EMPTY_CELL_CONTEXT_PROVIDER,
609
+ * useClass: MyCustomEmptyCellProvider
610
+ * }
611
+ * ]
612
+ * ```
613
+ */
614
+ declare const EMPTY_CELL_CONTEXT_PROVIDER: InjectionToken<EmptyCellContextProvider>;
615
+
616
+ /**
617
+ * Default empty cell context provider that prevents the browser's context menu
618
+ * and performs no other action.
619
+ *
620
+ * This is the default behavior that allows users to right-click on empty dashboard
621
+ * cells without triggering the browser's default context menu.
622
+ */
623
+ declare class DefaultEmptyCellContextProvider extends EmptyCellContextProvider {
624
+ /**
625
+ * Default empty cell context handler.
626
+ * The browser context menu is already prevented by the component.
627
+ * No additional action is taken by default.
628
+ */
629
+ handleEmptyCellContext(): void;
630
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DefaultEmptyCellContextProvider, never>;
631
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<DefaultEmptyCellContextProvider>;
632
+ }
633
+
634
+ /**
635
+ * Context provider that displays a widget list menu when right-clicking on empty cells.
636
+ *
637
+ * This provider shows a Material Design context menu with all available widget types.
638
+ * When a user clicks on a widget in the menu, it's immediately added to the empty cell.
639
+ *
640
+ * @example
641
+ * ```typescript
642
+ * // In your component or app config
643
+ * providers: [
644
+ * {
645
+ * provide: EMPTY_CELL_CONTEXT_PROVIDER,
646
+ * useClass: WidgetListContextMenuProvider
647
+ * }
648
+ * ]
649
+ * ```
650
+ *
651
+ * @public
652
+ */
653
+ declare class WidgetListContextMenuProvider extends EmptyCellContextProvider {
654
+ #private;
655
+ /**
656
+ * Handle empty cell context menu by showing available widgets.
657
+ *
658
+ * @param event - The mouse event from the right-click
659
+ * @param context - Information about the empty cell and dashboard
660
+ */
661
+ handleEmptyCellContext(event: MouseEvent, context: EmptyCellContext): void;
662
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WidgetListContextMenuProvider, never>;
663
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<WidgetListContextMenuProvider>;
664
+ }
665
+
666
+ export { CELL_SETTINGS_DIALOG_PROVIDER, CellSettingsDialogProvider, DashboardComponent, DashboardService, DefaultCellSettingsDialogProvider, DefaultEmptyCellContextProvider, EMPTY_CELL_CONTEXT_PROVIDER, EmptyCellContextProvider, NGX_DASHBOARD_VERSION, WidgetListComponent, WidgetListContextMenuProvider, createDefaultDashboard, createEmptyDashboard };
667
+ export type { CellDataDto, DashboardDataDto, EmptyCellContext, GridSelection, ReservedSpace, SelectionFilterOptions, Widget, WidgetMetadata, WidgetSharedStateProvider };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dragonworks/ngx-dashboard",
3
- "version": "20.2.0",
3
+ "version": "20.3.2",
4
4
  "description": "Angular library for building drag-and-drop grid dashboards with resizable cells and customizable widgets",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^20.2.0",