@dragonworks/ngx-dashboard 20.2.0 → 20.3.1

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