@xh/hoist 79.0.0-SNAPSHOT.1765207715965 → 79.0.0-SNAPSHOT.1765213676051

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/CHANGELOG.md CHANGED
@@ -2,24 +2,9 @@
2
2
 
3
3
  ## 79.0.0-SNAPSHOT - unreleased
4
4
 
5
- ### 💥 Breaking Changes
6
-
7
- * Renamed `GridModel.applyColumnStateChanges()` to `updateColumnState()` for clarity and better
8
- symmetry with `setColumnState()`. The prior method remains as an alias but is now deprecated and
9
- scheduled for removal in v82.
10
-
11
5
  ### 🐞 Bug Fixes
12
6
 
13
- * Fixed column chooser to display columns in the same order as they appear in the grid.
14
7
  * Defaulted Highcharts font to Hoist default (--xh-font-family)
15
- * Tweaked `GridFindField` to forward a provided `ref` to its underlying `TextInput`.
16
-
17
- ### ⚙️ Technical
18
-
19
- * Removed the following previously deprecated configs as planned:
20
- * `AppSpec.websocketsEnabled` - enabled by default, disable via `disableWebSockets`
21
- * `GroupingChooserProps.popoverTitle` - use `editorTitle`
22
- * `RelativeTimestampProps.options` - provide directly as top-level props
23
8
 
24
9
  ## 78.1.4 - 2025-12-05
25
10
 
@@ -1,9 +1,9 @@
1
+ import { CellClickedEvent, CellContextMenuEvent, CellDoubleClickedEvent, CellEditingStartedEvent, CellEditingStoppedEvent, AgColumnState, RowClickedEvent, RowDoubleClickedEvent } from '@xh/hoist/kit/ag-grid';
1
2
  import { AgGridModel } from '@xh/hoist/cmp/ag-grid';
2
3
  import { Column, ColumnGroup, ColumnGroupSpec, ColumnSpec, GridAutosizeMode, GridFilterModelConfig, GridGroupSortFn, TreeStyle } from '@xh/hoist/cmp/grid';
3
4
  import { GridFilterModel } from '@xh/hoist/cmp/grid/filter/GridFilterModel';
4
5
  import { Awaitable, HoistModel, HSide, PlainObject, SizingMode, Some, TaskObserver, Thunkable, VSide } from '@xh/hoist/core';
5
6
  import { Store, StoreConfig, StoreRecord, StoreRecordId, StoreRecordOrId, StoreSelectionConfig, StoreSelectionModel, StoreTransaction } from '@xh/hoist/data';
6
- import { AgColumnState, CellClickedEvent, CellContextMenuEvent, CellDoubleClickedEvent, CellEditingStartedEvent, CellEditingStoppedEvent, RowClickedEvent, RowDoubleClickedEvent } from '@xh/hoist/kit/ag-grid';
7
7
  import { ExportOptions } from '@xh/hoist/svc/GridExportService';
8
8
  import { ReactNode, RefObject } from 'react';
9
9
  import { GridAutosizeOptions } from './GridAutosizeOptions';
@@ -483,8 +483,6 @@ export declare class GridModel extends HoistModel {
483
483
  * @param colStateChanges - changes to apply to the columns. If all leaf
484
484
  * columns are represented in these changes then the sort order will be applied as well.
485
485
  */
486
- updateColumnState(colStateChanges: Partial<ColumnState>[]): void;
487
- /** @deprecated - use {@link updateColumnState} instead. */
488
486
  applyColumnStateChanges(colStateChanges: Partial<ColumnState>[]): void;
489
487
  getColumn(colId: string): Column;
490
488
  getColumnGroup(groupId: string): ColumnGroup;
@@ -7,6 +7,12 @@ interface RelativeTimestampProps extends HoistProps, BoxProps, RelativeTimestamp
7
7
  bind?: string;
8
8
  /** Date or milliseconds representing the starting time / time to compare. See also `bind`. */
9
9
  timestamp?: Date | number;
10
+ /**
11
+ * Formatting options.
12
+ *
13
+ * @deprecated - these options should be spread into this object directly.
14
+ */
15
+ options?: RelativeTimestampOptions;
10
16
  }
11
17
  export interface RelativeTimestampOptions {
12
18
  /** Allow dates greater than Date.now().*/
@@ -116,7 +116,9 @@ export declare class AppSpec<T extends HoistAppModel = HoistAppModel> {
116
116
  * initialized, including a breakdown of elapsed time throughout the init process.
117
117
  */
118
118
  trackAppLoad?: boolean;
119
- constructor({ authModelClass, checkAccess, clientAppCode, clientAppName, componentClass, containerClass, disableWebSockets, enableXssProtection, enableLoginForm, enableLogout, idlePanel, isMobileApp, lockoutMessage, lockoutPanel, loginMessage, modelClass, showBrowserContextMenu, trackAppLoad }: {
119
+ /** @deprecated - use {@link AppSpec.disableWebSockets} instead. */
120
+ webSocketsEnabled?: boolean;
121
+ constructor({ authModelClass, checkAccess, clientAppCode, clientAppName, componentClass, containerClass, disableWebSockets, enableXssProtection, enableLoginForm, enableLogout, idlePanel, isMobileApp, lockoutMessage, lockoutPanel, loginMessage, modelClass, showBrowserContextMenu, trackAppLoad, webSocketsEnabled }: {
120
122
  authModelClass?: typeof HoistAuthModel;
121
123
  checkAccess: any;
122
124
  clientAppCode?: string;
@@ -135,5 +137,6 @@ export declare class AppSpec<T extends HoistAppModel = HoistAppModel> {
135
137
  modelClass: any;
136
138
  showBrowserContextMenu?: boolean;
137
139
  trackAppLoad?: boolean;
140
+ webSocketsEnabled: any;
138
141
  });
139
142
  }
@@ -1,6 +1,6 @@
1
+ import { type ReactGridLayoutProps } from 'react-grid-layout';
1
2
  import { HoistProps, TestSupportProps } from '@xh/hoist/core';
2
3
  import '@xh/hoist/desktop/register';
3
- import type { ReactGridLayoutProps } from 'react-grid-layout';
4
4
  import { DashCanvasModel } from './DashCanvasModel';
5
5
  import 'react-grid-layout/css/styles.css';
6
6
  import './DashCanvas.scss';
@@ -1,3 +1,4 @@
1
+ import type { DragOverEvent, Layout } from 'react-grid-layout';
1
2
  import { Persistable, PersistableState } from '@xh/hoist/core';
2
3
  import { DashCanvasViewModel, DashCanvasViewSpec, DashConfig, DashViewState, DashModel } from '../';
3
4
  import '@xh/hoist/desktop/register';
@@ -20,6 +21,30 @@ export interface DashCanvasConfig extends DashConfig<DashCanvasViewSpec, DashCan
20
21
  maxRows?: number;
21
22
  /** Padding inside the container [x, y] in pixels. Defaults to same as `margin`. */
22
23
  containerPadding?: [number, number];
24
+ /**
25
+ * Whether the canvas should accept drag-and-drop of views from outside
26
+ * the canvas. Default false.
27
+ */
28
+ droppable?: boolean;
29
+ /**
30
+ * Optional Callback to invoke after a view is successfully dropped onto the canvas.
31
+ */
32
+ onDropDone?: (viewModel: DashCanvasViewModel) => void;
33
+ /**
34
+ * Optional callback to invoke when an item is dragged over the canvas. This may be used to
35
+ * customize how the size of the dropping placeholder is calculated. The callback should
36
+ * return an object with optional 'w' and 'h' properties indicating the desired width and height
37
+ * (in grid units) of the dropping placeholder. If not provided, Hoist's own default logic will be used.
38
+ */
39
+ onDropDragOver?: (e: DragOverEvent) => {
40
+ w?: number;
41
+ h?: number;
42
+ } | false | undefined;
43
+ /**
44
+ * Whether an overlay with an Add View button should be rendered
45
+ * when the canvas is empty. Default true.
46
+ */
47
+ showAddViewButtonWhenEmpty?: boolean;
23
48
  }
24
49
  export interface DashCanvasItemState {
25
50
  layout: DashCanvasItemLayout;
@@ -45,7 +70,12 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
45
70
  compact: boolean;
46
71
  margin: [number, number];
47
72
  containerPadding: [number, number];
73
+ DROPPING_ELEM_ID: string;
48
74
  maxRows: number;
75
+ showAddViewButtonWhenEmpty: boolean;
76
+ droppable: boolean;
77
+ onDropDone: (viewModel: DashCanvasViewModel) => void;
78
+ draggedInView: DashCanvasItemState;
49
79
  /** Current number of rows in canvas */
50
80
  get rows(): number;
51
81
  get isEmpty(): boolean;
@@ -54,7 +84,7 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
54
84
  isResizing: boolean;
55
85
  private isLoadingState;
56
86
  get rglLayout(): any[];
57
- constructor({ viewSpecs, viewSpecDefaults, initialState, layoutLocked, contentLocked, renameLocked, persistWith, emptyText, addViewButtonText, columns, rowHeight, compact, margin, maxRows, containerPadding, extraMenuItems }: DashCanvasConfig);
87
+ constructor({ viewSpecs, viewSpecDefaults, initialState, layoutLocked, contentLocked, renameLocked, persistWith, emptyText, addViewButtonText, columns, rowHeight, compact, margin, maxRows, containerPadding, extraMenuItems, showAddViewButtonWhenEmpty, droppable, onDropDone, onDropDragOver }: DashCanvasConfig);
58
88
  /** Removes all views from the canvas */
59
89
  clear(): void;
60
90
  /**
@@ -92,15 +122,22 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
92
122
  renameView(id: string): void;
93
123
  /** Scrolls a DashCanvasView into view. */
94
124
  ensureViewVisible(id: string): void;
125
+ onDrop(rglLayout: Layout[], layoutItem: Layout, evt: Event): void;
126
+ setDraggedInView(view?: DashCanvasItemState): void;
127
+ onDropDragOver(e: DragOverEvent): {
128
+ w?: number;
129
+ h?: number;
130
+ } | false | undefined;
95
131
  getPersistableState(): PersistableState<{
96
132
  state: DashCanvasItemState[];
97
133
  }>;
98
134
  setPersistableState(persistableState: PersistableState<{
99
135
  state: DashCanvasItemState[];
100
136
  }>): void;
137
+ private doDrop;
101
138
  private getLayoutFromPosition;
102
139
  private addViewInternal;
103
- onRglLayoutChange(rglLayout: any): void;
140
+ onRglLayoutChange(rglLayout: Layout[]): void;
104
141
  private setLayout;
105
142
  private loadState;
106
143
  private buildState;
@@ -20,6 +20,8 @@ export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel>
20
20
  popoverMinHeight?: number;
21
21
  /** Position of popover relative to target button. */
22
22
  popoverPosition?: 'bottom' | 'top';
23
+ /** @deprecated - use `editorTitle` instead */
24
+ popoverTitle?: ReactNode;
23
25
  /**
24
26
  * Width in pixels of the popover menu itself.
25
27
  * If unspecified, will default based on favorites enabled status + side.
@@ -1,5 +1,5 @@
1
- import { GridModel, GridSorterLike } from '@xh/hoist/cmp/grid';
2
- import { HoistModel, HSide, Some } from '@xh/hoist/core';
1
+ import { GridModel } from '@xh/hoist/cmp/grid';
2
+ import { HoistModel, HSide } from '@xh/hoist/core';
3
3
  import '@xh/hoist/desktop/register';
4
4
  import { FilterTestFn, StoreRecord } from '@xh/hoist/data';
5
5
  export interface LeftRightChooserConfig {
@@ -14,13 +14,11 @@ export interface LeftRightChooserConfig {
14
14
  showCounts?: boolean;
15
15
  leftTitle?: string;
16
16
  leftSorted?: boolean;
17
- leftSortBy?: Some<GridSorterLike>;
18
17
  leftGroupingEnabled?: boolean;
19
18
  leftGroupingExpanded?: boolean;
20
19
  leftEmptyText?: string;
21
20
  rightTitle?: string;
22
21
  rightSorted?: boolean;
23
- rightSortBy?: Some<GridSorterLike>;
24
22
  rightGroupingEnabled?: boolean;
25
23
  rightGroupingExpanded?: boolean;
26
24
  rightEmptyText?: string;
@@ -41,7 +39,6 @@ export interface LeftRightChooserItem {
41
39
  /** True to prevent the user from moving the item between sides. */
42
40
  locked?: boolean;
43
41
  exclude?: boolean;
44
- sortValue?: any;
45
42
  }
46
43
  /**
47
44
  * A Model for managing the state of a LeftRightChooser.
@@ -75,7 +72,7 @@ export declare class LeftRightChooserModel extends HoistModel {
75
72
  get rightValues(): any[];
76
73
  /** Currently 'selected' values on the left hand side. */
77
74
  get leftValues(): any[];
78
- constructor({ data, onChange, ungroupedName, leftTitle, leftSorted, leftSortBy, leftGroupingEnabled, leftGroupingExpanded, leftEmptyText, readonly, rightTitle, rightSorted, rightSortBy, rightGroupingEnabled, rightGroupingExpanded, rightEmptyText, showCounts, xhImpl }: LeftRightChooserConfig);
75
+ constructor({ data, onChange, ungroupedName, leftTitle, leftSorted, leftGroupingEnabled, leftGroupingExpanded, leftEmptyText, readonly, rightTitle, rightSorted, rightGroupingEnabled, rightGroupingExpanded, rightEmptyText, showCounts, xhImpl }: LeftRightChooserConfig);
79
76
  setData(data: LeftRightChooserItem[]): void;
80
77
  moveRows(rows: StoreRecord[]): void;
81
78
  private getTextColRenderer;
@@ -4,6 +4,17 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
+ import {
8
+ CellClickedEvent,
9
+ CellContextMenuEvent,
10
+ CellDoubleClickedEvent,
11
+ CellEditingStartedEvent,
12
+ CellEditingStoppedEvent,
13
+ ColumnEvent,
14
+ AgColumnState,
15
+ RowClickedEvent,
16
+ RowDoubleClickedEvent
17
+ } from '@xh/hoist/kit/ag-grid';
7
18
  import {AgGridModel} from '@xh/hoist/cmp/ag-grid';
8
19
  import {
9
20
  Column,
@@ -45,27 +56,15 @@ import {
45
56
  import {ColChooserModel as DesktopColChooserModel} from '@xh/hoist/dynamics/desktop';
46
57
  import {ColChooserModel as MobileColChooserModel} from '@xh/hoist/dynamics/mobile';
47
58
  import {Icon} from '@xh/hoist/icon';
48
- import {
49
- AgColumnState,
50
- CellClickedEvent,
51
- CellContextMenuEvent,
52
- CellDoubleClickedEvent,
53
- CellEditingStartedEvent,
54
- CellEditingStoppedEvent,
55
- ColumnEvent,
56
- RowClickedEvent,
57
- RowDoubleClickedEvent
58
- } from '@xh/hoist/kit/ag-grid';
59
59
  import {action, bindable, makeObservable, observable, when} from '@xh/hoist/mobx';
60
60
  import {wait, waitFor} from '@xh/hoist/promise';
61
61
  import {ExportOptions} from '@xh/hoist/svc/GridExportService';
62
62
  import {SECONDS} from '@xh/hoist/utils/datetime';
63
63
  import {
64
- apiDeprecated,
64
+ sharePendingPromise,
65
65
  deepFreeze,
66
66
  executeIfFunction,
67
67
  logWithDebug,
68
- sharePendingPromise,
69
68
  throwIf,
70
69
  warnIf,
71
70
  withDefault
@@ -1184,7 +1183,7 @@ export class GridModel extends HoistModel {
1184
1183
  );
1185
1184
 
1186
1185
  pull(colStateChanges, null);
1187
- this.updateColumnState(colStateChanges);
1186
+ this.applyColumnStateChanges(colStateChanges);
1188
1187
  }
1189
1188
 
1190
1189
  @action
@@ -1215,7 +1214,7 @@ export class GridModel extends HoistModel {
1215
1214
  const col = this.findColumn(this.columns, colId);
1216
1215
  if (!width || !col || col.flex) return;
1217
1216
  const colStateChanges = [{colId, width, manuallySized: true}];
1218
- this.updateColumnState(colStateChanges);
1217
+ this.applyColumnStateChanges(colStateChanges);
1219
1218
  }
1220
1219
 
1221
1220
  /**
@@ -1231,7 +1230,7 @@ export class GridModel extends HoistModel {
1231
1230
  * columns are represented in these changes then the sort order will be applied as well.
1232
1231
  */
1233
1232
  @action
1234
- updateColumnState(colStateChanges: Partial<ColumnState>[]): void {
1233
+ applyColumnStateChanges(colStateChanges: Partial<ColumnState>[]) {
1235
1234
  if (isEmpty(colStateChanges)) return;
1236
1235
 
1237
1236
  let columnState = cloneDeep(this.columnState);
@@ -1261,16 +1260,6 @@ export class GridModel extends HoistModel {
1261
1260
  }
1262
1261
  }
1263
1262
 
1264
- /** @deprecated - use {@link updateColumnState} instead. */
1265
- applyColumnStateChanges(colStateChanges: Partial<ColumnState>[]): void {
1266
- apiDeprecated('GridModel.applyColumnStateChanges()', {
1267
- msg: 'Use updateColumnState() instead.',
1268
- v: '82',
1269
- source: GridModel
1270
- });
1271
- this.updateColumnState(colStateChanges);
1272
- }
1273
-
1274
1263
  getColumn(colId: string): Column {
1275
1264
  return this.findColumn(this.columns, colId);
1276
1265
  }
@@ -1306,7 +1295,7 @@ export class GridModel extends HoistModel {
1306
1295
  }
1307
1296
 
1308
1297
  setColumnVisible(colId: string, visible: boolean) {
1309
- this.updateColumnState([{colId, hidden: !visible}]);
1298
+ this.applyColumnStateChanges([{colId, hidden: !visible}]);
1310
1299
  }
1311
1300
 
1312
1301
  showColumn(colId: string) {
@@ -1318,7 +1307,7 @@ export class GridModel extends HoistModel {
1318
1307
  }
1319
1308
 
1320
1309
  setColumnGroupVisible(groupId: string, visible: boolean) {
1321
- this.updateColumnState(
1310
+ this.applyColumnStateChanges(
1322
1311
  this.getColumnGroup(groupId)
1323
1312
  .getLeafColumns()
1324
1313
  .map(({colId}) => ({colId, hidden: !visible}))
@@ -4,6 +4,9 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
+ import {getLayoutProps} from '@xh/hoist/utils/react';
8
+ import {inRange, isNil} from 'lodash';
9
+ import moment from 'moment';
7
10
  import {box, span} from '@xh/hoist/cmp/layout';
8
11
  import {
9
12
  BoxProps,
@@ -18,10 +21,7 @@ import {fmtCompactDate, fmtDateTime} from '@xh/hoist/format';
18
21
  import {action, computed, makeObservable, observable} from '@xh/hoist/mobx';
19
22
  import {Timer} from '@xh/hoist/utils/async';
20
23
  import {DAYS, HOURS, LocalDate, SECONDS} from '@xh/hoist/utils/datetime';
21
- import {logWarn, withDefault} from '@xh/hoist/utils/js';
22
- import {getLayoutProps} from '@xh/hoist/utils/react';
23
- import {inRange, isNil} from 'lodash';
24
- import moment from 'moment';
24
+ import {apiDeprecated, logWarn, withDefault} from '@xh/hoist/utils/js';
25
25
 
26
26
  interface RelativeTimestampProps extends HoistProps, BoxProps, RelativeTimestampOptions {
27
27
  /**
@@ -32,6 +32,13 @@ interface RelativeTimestampProps extends HoistProps, BoxProps, RelativeTimestamp
32
32
 
33
33
  /** Date or milliseconds representing the starting time / time to compare. See also `bind`. */
34
34
  timestamp?: Date | number;
35
+
36
+ /**
37
+ * Formatting options.
38
+ *
39
+ * @deprecated - these options should be spread into this object directly.
40
+ */
41
+ options?: RelativeTimestampOptions;
35
42
  }
36
43
 
37
44
  export interface RelativeTimestampOptions {
@@ -126,7 +133,16 @@ class RelativeTimestampLocalModel extends HoistModel {
126
133
 
127
134
  @computed.struct
128
135
  get options(): RelativeTimestampOptions {
129
- return this.componentProps as RelativeTimestampProps;
136
+ const {componentProps} = this;
137
+
138
+ apiDeprecated('options', {
139
+ test: componentProps.options,
140
+ msg: 'Spread options directly in this object instead',
141
+ v: `v78`,
142
+ source: RelativeTimestamp
143
+ });
144
+
145
+ return componentProps.options ?? componentProps;
130
146
  }
131
147
 
132
148
  constructor() {
package/core/AppSpec.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
  import {ElementFactory, HoistAppModel, HoistAuthModel, HoistProps, XH} from '@xh/hoist/core';
8
- import {throwIf} from '@xh/hoist/utils/js';
9
- import {isFunction, isNil, isString} from 'lodash';
8
+ import {apiDeprecated, throwIf} from '@xh/hoist/utils/js';
9
+ import {isFunction, isNil, isString, isUndefined} from 'lodash';
10
10
  import {Component, ComponentClass, FunctionComponent} from 'react';
11
11
 
12
12
  /**
@@ -140,6 +140,9 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
140
140
  */
141
141
  trackAppLoad?: boolean;
142
142
 
143
+ /** @deprecated - use {@link AppSpec.disableWebSockets} instead. */
144
+ webSocketsEnabled?: boolean;
145
+
143
146
  constructor({
144
147
  authModelClass = HoistAuthModel,
145
148
  checkAccess,
@@ -158,7 +161,8 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
158
161
  loginMessage = null,
159
162
  modelClass,
160
163
  showBrowserContextMenu = false,
161
- trackAppLoad = true
164
+ trackAppLoad = true,
165
+ webSocketsEnabled
162
166
  }) {
163
167
  throwIf(!componentClass, 'A Hoist App must define a componentClass');
164
168
 
@@ -176,6 +180,17 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
176
180
  'A Hoist App must specify a required role string or a function for checkAccess.'
177
181
  );
178
182
 
183
+ if (!isUndefined(webSocketsEnabled)) {
184
+ let msg: string;
185
+ if (webSocketsEnabled === false) {
186
+ disableWebSockets = true;
187
+ msg = `Specify disableWebSockets: true to continue actively disabling WebSockets if required.`;
188
+ } else {
189
+ msg = `WebSockets are now enabled by default - this property can be safely removed from your appSpec.`;
190
+ }
191
+ apiDeprecated('webSocketsEnabled', {msg, v: 'v78'});
192
+ }
193
+
179
194
  this.authModelClass = authModelClass;
180
195
  this.checkAccess = checkAccess;
181
196
  this.clientAppCode = clientAppCode;
@@ -194,5 +209,6 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
194
209
  this.modelClass = modelClass;
195
210
  this.showBrowserContextMenu = showBrowserContextMenu;
196
211
  this.trackAppLoad = trackAppLoad;
212
+ this.webSocketsEnabled = !disableWebSockets;
197
213
  }
198
214
  }
@@ -4,6 +4,12 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
+ import ReactGridLayout, {
8
+ type ReactGridLayoutProps,
9
+ type DragOverEvent,
10
+ type Layout,
11
+ WidthProvider
12
+ } from 'react-grid-layout';
7
13
  import {showContextMenu} from '@xh/hoist/kit/blueprint';
8
14
  import composeRefs from '@seznam/compose-react-refs';
9
15
  import {div, vbox, vspacer} from '@xh/hoist/cmp/layout';
@@ -20,8 +26,6 @@ import '@xh/hoist/desktop/register';
20
26
  import {Classes, overlay} from '@xh/hoist/kit/blueprint';
21
27
  import {consumeEvent, TEST_ID} from '@xh/hoist/utils/js';
22
28
  import classNames from 'classnames';
23
- import ReactGridLayout, {WidthProvider} from 'react-grid-layout';
24
- import type {ReactGridLayoutProps} from 'react-grid-layout';
25
29
  import {DashCanvasModel} from './DashCanvasModel';
26
30
  import {dashCanvasContextMenu} from './impl/DashCanvasContextMenu';
27
31
  import {dashCanvasView} from './impl/DashCanvasView';
@@ -87,7 +91,7 @@ export const [DashCanvas, dashCanvas] = hoistCmp.withFactory<DashCanvasProps>({
87
91
  draggableHandle:
88
92
  '.xh-dash-tab.xh-panel > .xh-panel__content > .xh-panel-header',
89
93
  draggableCancel: '.xh-button',
90
- onLayoutChange: layout => model.onRglLayoutChange(layout),
94
+ onLayoutChange: (layout: Layout[]) => model.onRglLayoutChange(layout),
91
95
  onResizeStart: () => (model.isResizing = true),
92
96
  onResizeStop: () => (model.isResizing = false),
93
97
  items: model.viewModels.map(vm =>
@@ -96,9 +100,13 @@ export const [DashCanvas, dashCanvas] = hoistCmp.withFactory<DashCanvasProps>({
96
100
  item: dashCanvasView({model: vm})
97
101
  })
98
102
  ),
103
+ isDroppable: model.droppable,
104
+ onDrop: (layout: Layout[], layoutItem: Layout, evt: Event) =>
105
+ model.onDrop(layout, layoutItem, evt),
106
+ onDropDragOver: (evt: DragOverEvent) => model.onDropDragOver(evt),
99
107
  ...rglOptions
100
108
  }),
101
- emptyContainerOverlay()
109
+ emptyContainerOverlay({omit: !model.showAddViewButtonWhenEmpty})
102
110
  ],
103
111
  [TEST_ID]: testId
104
112
  })