@xh/hoist 79.0.0-SNAPSHOT.1766100504431 → 79.0.0-SNAPSHOT.1766101107851

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
@@ -20,10 +20,6 @@
20
20
  * `TabContainerConfig.switcher` has been repurposed to accept a `TabSwitcherConfig`. To pass
21
21
  `TabSwitcherProps` via a parent `TabContainer`, use `TabContainerProps.switcher`.
22
22
 
23
- ### 🎁 New Features
24
-
25
- * DashCanvas component now supports dragging and dropping widgets in from an external container.
26
-
27
23
  ### 🐞 Bug Fixes
28
24
 
29
25
  * Fixed column chooser to display columns in the same order as they appear in the grid.
@@ -38,10 +34,6 @@
38
34
  * `GroupingChooserProps.popoverTitle` - use `editorTitle`
39
35
  * `RelativeTimestampProps.options` - provide directly as top-level props
40
36
 
41
- ### 📚 Libraries
42
-
43
- * react-grid-layout `1.5.0 → 2.1.0`
44
-
45
37
  ## 78.1.4 - 2025-12-05
46
38
 
47
39
  ### 🐞 Bug Fixes
@@ -1,6 +1,6 @@
1
1
  import { TEST_ID } from '@xh/hoist/utils/js';
2
2
  import { ComponentType, JSX, Key, ReactElement, ReactNode } from 'react';
3
- import { PlainObject, Thunkable } from './types/Types';
3
+ import { PlainObject, Some, Thunkable } from './types/Types';
4
4
  /**
5
5
  * Alternative format for specifying React Elements in render functions. This type is designed to
6
6
  * provide a well-formatted, declarative, native javascript approach to configuring Elements and
@@ -26,9 +26,9 @@ import { PlainObject, Thunkable } from './types/Types';
26
26
  */
27
27
  export type ElementSpec<P> = Omit<P, 'items' | 'item' | 'omit'> & {
28
28
  /** Child Element(s). Equivalent provided as Rest Arguments to React.createElement.*/
29
- items?: ReactNode;
29
+ items?: Some<ReactNode>;
30
30
  /** Equivalent to `items`, offered for code clarity when only one child is needed. */
31
- item?: ReactNode;
31
+ item?: Some<ReactNode>;
32
32
  /** True to exclude the Element. */
33
33
  omit?: Thunkable<boolean>;
34
34
  /** React key for this component. */
@@ -1,9 +1,8 @@
1
- import { type GridLayoutProps } from 'react-grid-layout';
2
1
  import { HoistProps, TestSupportProps } from '@xh/hoist/core';
3
2
  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
- import 'react-resizable/css/styles.css';
7
6
  import './DashCanvas.scss';
8
7
  export interface DashCanvasProps extends HoistProps<DashCanvasModel>, TestSupportProps {
9
8
  /**
@@ -12,7 +11,7 @@ export interface DashCanvasProps extends HoistProps<DashCanvasModel>, TestSuppor
12
11
  * {@link https://www.npmjs.com/package/react-grid-layout#grid-layout-props}
13
12
  * Note that some ReactGridLayout props are managed directly by DashCanvas and will be overridden if provided here.
14
13
  */
15
- rglOptions?: GridLayoutProps;
14
+ rglOptions?: ReactGridLayoutProps;
16
15
  }
17
16
  /**
18
17
  * Dashboard-style container that allows users to drag-and-drop child widgets into flexible layouts.
@@ -1,5 +1,3 @@
1
- import { DragEvent } from 'react';
2
- import type { LayoutItem } from 'react-grid-layout';
3
1
  import { Persistable, PersistableState } from '@xh/hoist/core';
4
2
  import { DashCanvasViewModel, DashCanvasViewSpec, DashConfig, DashViewState, DashModel } from '../';
5
3
  import '@xh/hoist/desktop/register';
@@ -20,35 +18,8 @@ export interface DashCanvasConfig extends DashConfig<DashCanvasViewSpec, DashCan
20
18
  margin?: [number, number];
21
19
  /** Maximum number of rows permitted for this container. Default `Infinity`. */
22
20
  maxRows?: number;
23
- /** Padding inside the container [x, y] in pixels. Default `[0, 0]`. */
21
+ /** Padding inside the container [x, y] in pixels. Defaults to same as `margin`. */
24
22
  containerPadding?: [number, number];
25
- /**
26
- * Whether the canvas should accept drag-and-drop of views from outside
27
- * the canvas. Default false.
28
- */
29
- droppable?: boolean;
30
- /**
31
- * Optional Callback to invoke after a view is successfully dropped onto the canvas.
32
- */
33
- onDropDone?: (viewModel: DashCanvasViewModel) => void;
34
- /**
35
- * Optional callback to invoke when an item is dragged over the canvas. This may be used to
36
- * customize how the size of the dropping placeholder is calculated. The callback should
37
- * return an object with optional properties indicating the desired width, height (in grid units),
38
- * and offset (in pixels) of the dropping placeholder.
39
- * If not provided, Hoist's own default logic will be used.
40
- */
41
- onDropDragOver?: (e: DragEvent) => {
42
- w?: number;
43
- h?: number;
44
- dragOffsetX?: number;
45
- dragOffsetY?: number;
46
- } | false | void;
47
- /**
48
- * Whether an overlay with an Add View button should be rendered
49
- * when the canvas is empty. Default true.
50
- */
51
- showAddViewButtonWhenEmpty?: boolean;
52
23
  }
53
24
  export interface DashCanvasItemState {
54
25
  layout: DashCanvasItemLayout;
@@ -74,12 +45,7 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
74
45
  compact: boolean;
75
46
  margin: [number, number];
76
47
  containerPadding: [number, number];
77
- showAddViewButtonWhenEmpty: boolean;
78
- DROPPING_ELEM_ID: string;
79
48
  maxRows: number;
80
- droppable: boolean;
81
- onDropDone: (viewModel: DashCanvasViewModel) => void;
82
- draggedInView: DashCanvasItemState;
83
49
  /** Current number of rows in canvas */
84
50
  get rows(): number;
85
51
  get isEmpty(): boolean;
@@ -88,7 +54,7 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
88
54
  isResizing: boolean;
89
55
  private isLoadingState;
90
56
  get rglLayout(): any[];
91
- constructor({ viewSpecs, viewSpecDefaults, initialState, layoutLocked, contentLocked, renameLocked, persistWith, emptyText, addViewButtonText, columns, rowHeight, compact, margin, maxRows, containerPadding, extraMenuItems, showAddViewButtonWhenEmpty, droppable, onDropDone, onDropDragOver }: DashCanvasConfig);
57
+ constructor({ viewSpecs, viewSpecDefaults, initialState, layoutLocked, contentLocked, renameLocked, persistWith, emptyText, addViewButtonText, columns, rowHeight, compact, margin, maxRows, containerPadding, extraMenuItems }: DashCanvasConfig);
92
58
  /** Removes all views from the canvas */
93
59
  clear(): void;
94
60
  /**
@@ -126,14 +92,6 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
126
92
  renameView(id: string): void;
127
93
  /** Scrolls a DashCanvasView into view. */
128
94
  ensureViewVisible(id: string): void;
129
- onDrop(rglLayout: LayoutItem[], layoutItem: LayoutItem, evt: Event): void;
130
- setDraggedInView(view?: DashCanvasItemState): void;
131
- onDropDragOver(evt: DragEvent): {
132
- w?: number;
133
- h?: number;
134
- dragOffsetX?: number;
135
- dragOffsetY?: number;
136
- } | false | void;
137
95
  getPersistableState(): PersistableState<{
138
96
  state: DashCanvasItemState[];
139
97
  }>;
@@ -142,7 +100,7 @@ export declare class DashCanvasModel extends DashModel<DashCanvasViewSpec, DashC
142
100
  }>): void;
143
101
  private getLayoutFromPosition;
144
102
  private addViewInternal;
145
- onRglLayoutChange(rglLayout: LayoutItem[]): void;
103
+ onRglLayoutChange(rglLayout: any): void;
146
104
  private setLayout;
147
105
  private loadState;
148
106
  private buildState;
@@ -42,12 +42,12 @@ export interface PanelProps extends HoistProps<PanelModel>, Omit<BoxProps, 'titl
42
42
  * A toolbar to be docked at the top of the panel.
43
43
  * If specified as an array, items will be passed as children to a Toolbar component.
44
44
  */
45
- tbar?: ReactNode;
45
+ tbar?: Some<ReactNode>;
46
46
  /**
47
47
  * A toolbar to be docked at the bottom of the panel.
48
48
  * If specified as an array, items will be passed as children to a Toolbar component.
49
49
  */
50
- bbar?: ReactNode;
50
+ bbar?: Some<ReactNode>;
51
51
  /** Title text added to the panel's header. */
52
52
  title?: ReactNode;
53
53
  /** Title to be used when the panel is collapsed. Defaults to `title`. */
@@ -1,4 +1,4 @@
1
- import { HoistProps, PlainObject } from '@xh/hoist/core';
1
+ import { HoistProps, PlainObject, Some } from '@xh/hoist/core';
2
2
  import { PanelProps } from '@xh/hoist/desktop/cmp/panel';
3
3
  import '@xh/hoist/desktop/register';
4
4
  import { ReactElement, ReactNode } from 'react';
@@ -14,7 +14,7 @@ export interface RestGridProps extends HoistProps<RestGridModel>, Omit<PanelProp
14
14
  * Optional components rendered adjacent to the top toolbar's action buttons.
15
15
  * See also {@link tbar} to take full control of the toolbar.
16
16
  */
17
- extraToolbarItems?: ReactNode | (() => ReactNode);
17
+ extraToolbarItems?: Some<ReactNode> | (() => Some<ReactNode>);
18
18
  /** Classname to be passed to RestForm. */
19
19
  formClassName?: string;
20
20
  /**
@@ -28,6 +28,6 @@ export interface RestGridProps extends HoistProps<RestGridModel>, Omit<PanelProp
28
28
  * configs `toolbarActions`, `filterFields`, and `showRefreshButton`. If specified as an array,
29
29
  * will be passed as children to a Toolbar component.
30
30
  */
31
- tbar?: ReactNode;
31
+ tbar?: Some<ReactNode>;
32
32
  }
33
33
  export declare const RestGrid: import("react").FC<RestGridProps>, restGrid: import("@xh/hoist/core").ElementFactory<RestGridProps>;
@@ -4,7 +4,7 @@ import { ReactNode, ReactElement } from 'react';
4
4
  import './Panel.scss';
5
5
  export interface PanelProps extends HoistProps, Omit<BoxProps, 'title'> {
6
6
  /** A toolbar to be docked at the bottom of the panel. */
7
- bbar?: ReactNode;
7
+ bbar?: Some<ReactNode>;
8
8
  /** CSS class name specific to the panel's header. */
9
9
  headerClassName?: string;
10
10
  /** Items to be added to the right-side of the panel's header. */
@@ -30,7 +30,7 @@ export interface PanelProps extends HoistProps, Omit<BoxProps, 'title'> {
30
30
  /** Allow the panel to scroll vertically */
31
31
  scrollable?: boolean;
32
32
  /** A toolbar to be docked at the top of the panel. */
33
- tbar?: ReactNode;
33
+ tbar?: Some<ReactNode>;
34
34
  /** Title text added to the panel's header. */
35
35
  title?: ReactNode;
36
36
  }
package/core/elem.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  ReactElement,
16
16
  ReactNode
17
17
  } from 'react';
18
- import {PlainObject, Thunkable} from './types/Types';
18
+ import {PlainObject, Some, Thunkable} from './types/Types';
19
19
 
20
20
  /**
21
21
  * Alternative format for specifying React Elements in render functions. This type is designed to
@@ -45,10 +45,10 @@ export type ElementSpec<P> = Omit<P, 'items' | 'item' | 'omit'> & {
45
45
  // Enhanced attributes to support element factory
46
46
  //---------------------------------------------
47
47
  /** Child Element(s). Equivalent provided as Rest Arguments to React.createElement.*/
48
- items?: ReactNode;
48
+ items?: Some<ReactNode>;
49
49
 
50
50
  /** Equivalent to `items`, offered for code clarity when only one child is needed. */
51
- item?: ReactNode;
51
+ item?: Some<ReactNode>;
52
52
 
53
53
  /** True to exclude the Element. */
54
54
  omit?: Thunkable<boolean>;
@@ -126,7 +126,7 @@ export function elementFactory<C extends ReactComponent>(component: C): ElementF
126
126
  export function elementFactory<P extends PlainObject>(component: ReactComponent): ElementFactory<P>;
127
127
  export function elementFactory(component: ReactComponent): ElementFactory {
128
128
  const ret = function (...args) {
129
- return createElement(component, normalizeArgs(args));
129
+ return createElement(component, normalizeArgs(args, component));
130
130
  };
131
131
  ret.isElementFactory = true;
132
132
  return ret;
@@ -135,7 +135,7 @@ export function elementFactory(component: ReactComponent): ElementFactory {
135
135
  //------------------------
136
136
  // Implementation
137
137
  //------------------------
138
- function normalizeArgs(args: any[]) {
138
+ function normalizeArgs(args: any[], type: any) {
139
139
  const len = args.length;
140
140
  if (len === 0) return {};
141
141
  if (len === 1) {
@@ -4,16 +4,6 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {omit} from 'lodash';
8
- import {DragEvent} from 'react';
9
- import ReactGridLayout, {
10
- type LayoutItem,
11
- type GridLayoutProps,
12
- useContainerWidth,
13
- noCompactor,
14
- verticalCompactor
15
- } from 'react-grid-layout';
16
-
17
7
  import {showContextMenu} from '@xh/hoist/kit/blueprint';
18
8
  import composeRefs from '@seznam/compose-react-refs';
19
9
  import {div, vbox, vspacer} from '@xh/hoist/cmp/layout';
@@ -30,12 +20,13 @@ import '@xh/hoist/desktop/register';
30
20
  import {Classes, overlay} from '@xh/hoist/kit/blueprint';
31
21
  import {consumeEvent, TEST_ID} from '@xh/hoist/utils/js';
32
22
  import classNames from 'classnames';
23
+ import ReactGridLayout, {WidthProvider} from 'react-grid-layout';
24
+ import type {ReactGridLayoutProps} from 'react-grid-layout';
33
25
  import {DashCanvasModel} from './DashCanvasModel';
34
26
  import {dashCanvasContextMenu} from './impl/DashCanvasContextMenu';
35
27
  import {dashCanvasView} from './impl/DashCanvasView';
36
28
 
37
29
  import 'react-grid-layout/css/styles.css';
38
- import 'react-resizable/css/styles.css';
39
30
  import './DashCanvas.scss';
40
31
 
41
32
  export interface DashCanvasProps extends HoistProps<DashCanvasModel>, TestSupportProps {
@@ -45,7 +36,7 @@ export interface DashCanvasProps extends HoistProps<DashCanvasModel>, TestSuppor
45
36
  * {@link https://www.npmjs.com/package/react-grid-layout#grid-layout-props}
46
37
  * Note that some ReactGridLayout props are managed directly by DashCanvas and will be overridden if provided here.
47
38
  */
48
- rglOptions?: GridLayoutProps;
39
+ rglOptions?: ReactGridLayoutProps;
49
40
  }
50
41
 
51
42
  /**
@@ -67,14 +58,7 @@ export const [DashCanvas, dashCanvas] = hoistCmp.withFactory<DashCanvasProps>({
67
58
  render({className, model, rglOptions, testId}, ref) {
68
59
  const isDraggable = !model.layoutLocked,
69
60
  isResizable = !model.layoutLocked,
70
- [padX, padY] = model.containerPadding,
71
- topLevelRglOptions: Partial<GridLayoutProps> = omit(rglOptions ?? {}, [
72
- 'gridConfig',
73
- 'dragConfig',
74
- 'resizeConfig',
75
- 'dropConfig'
76
- ]),
77
- {width, containerRef, mounted} = useContainerWidth();
61
+ [padX, padY] = model.containerPadding;
78
62
 
79
63
  return refreshContextView({
80
64
  model: model.refreshContextModel,
@@ -85,55 +69,37 @@ export const [DashCanvas, dashCanvas] = hoistCmp.withFactory<DashCanvasProps>({
85
69
  isResizable ? `${className}--resizable` : null
86
70
  ),
87
71
  style: {padding: `${padY}px ${padX}px`},
88
- ref: composeRefs(ref, model.ref, containerRef),
72
+ ref: composeRefs(ref, model.ref),
89
73
  onContextMenu: e => onContextMenu(e, model),
90
- items: mounted
91
- ? [
92
- reactGridLayout({
93
- layout: model.rglLayout,
94
- width,
95
- gridConfig: {
96
- cols: model.columns,
97
- rowHeight: model.rowHeight,
98
- margin: model.margin,
99
- maxRows: model.maxRows,
100
- ...(rglOptions?.gridConfig ?? {})
101
- },
102
- dragConfig: {
103
- enabled: isDraggable,
104
- handle: '.xh-dash-tab.xh-panel > .xh-panel__content > .xh-panel-header',
105
- cancel: '.xh-button',
106
- bounded: true,
107
- ...(rglOptions?.dragConfig ?? {})
108
- },
109
- resizeConfig: {
110
- enabled: isResizable,
111
- ...(rglOptions?.resizeConfig ?? {})
112
- },
113
- dropConfig: {
114
- enabled: model.contentLocked ? false : model.droppable,
115
- defaultItem: {w: 6, h: 6},
116
- ...(rglOptions?.dropConfig ?? {})
117
- },
118
- compactor: model.compact ? verticalCompactor : noCompactor,
119
- onLayoutChange: (layout: LayoutItem[]) =>
120
- model.onRglLayoutChange(layout),
121
- onResizeStart: () => (model.isResizing = true),
122
- onResizeStop: () => (model.isResizing = false),
123
- children: model.viewModels.map(vm =>
124
- div({
125
- key: vm.id,
126
- item: dashCanvasView({model: vm})
127
- })
128
- ),
129
- onDropDragOver: (evt: DragEvent) => model.onDropDragOver(evt),
130
- onDrop: (layout: LayoutItem[], layoutItem: LayoutItem, evt: Event) =>
131
- model.onDrop(layout, layoutItem, evt),
132
- ...topLevelRglOptions
133
- }),
134
- emptyContainerOverlay({omit: !model.showAddViewButtonWhenEmpty})
135
- ]
136
- : [],
74
+ items: [
75
+ reactGridLayout({
76
+ layout: model.rglLayout,
77
+ cols: model.columns,
78
+ rowHeight: model.rowHeight,
79
+ isDraggable,
80
+ isResizable,
81
+ compactType: model.compact ? 'vertical' : null,
82
+ margin: model.margin,
83
+ maxRows: model.maxRows,
84
+ containerPadding: [0, 0], // Workaround for https://github.com/react-grid-layout/react-grid-layout/issues/1990
85
+ autoSize: true,
86
+ isBounded: true,
87
+ draggableHandle:
88
+ '.xh-dash-tab.xh-panel > .xh-panel__content > .xh-panel-header',
89
+ draggableCancel: '.xh-button',
90
+ onLayoutChange: layout => model.onRglLayoutChange(layout),
91
+ onResizeStart: () => (model.isResizing = true),
92
+ onResizeStop: () => (model.isResizing = false),
93
+ items: model.viewModels.map(vm =>
94
+ div({
95
+ key: vm.id,
96
+ item: dashCanvasView({model: vm})
97
+ })
98
+ ),
99
+ ...rglOptions
100
+ }),
101
+ emptyContainerOverlay()
102
+ ],
137
103
  [TEST_ID]: testId
138
104
  })
139
105
  });
@@ -181,4 +147,4 @@ const onContextMenu = (e, model) => {
181
147
  }
182
148
  };
183
149
 
184
- const reactGridLayout = elementFactory<GridLayoutProps>(ReactGridLayout);
150
+ const reactGridLayout = elementFactory(WidthProvider(ReactGridLayout));
@@ -4,9 +4,6 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {wait} from '@xh/hoist/promise';
8
- import {DragEvent} from 'react';
9
- import type {LayoutItem} from 'react-grid-layout';
10
7
  import {Persistable, PersistableState, PersistenceProvider, XH} from '@xh/hoist/core';
11
8
  import {required} from '@xh/hoist/data';
12
9
  import {DashCanvasViewModel, DashCanvasViewSpec, DashConfig, DashViewState, DashModel} from '../';
@@ -19,7 +16,6 @@ import {createObservableRef} from '@xh/hoist/utils/react';
19
16
  import {
20
17
  defaultsDeep,
21
18
  find,
22
- omit,
23
19
  uniqBy,
24
20
  times,
25
21
  without,
@@ -52,42 +48,8 @@ export interface DashCanvasConfig extends DashConfig<DashCanvasViewSpec, DashCan
52
48
  /** Maximum number of rows permitted for this container. Default `Infinity`. */
53
49
  maxRows?: number;
54
50
 
55
- /** Padding inside the container [x, y] in pixels. Default `[0, 0]`. */
51
+ /** Padding inside the container [x, y] in pixels. Defaults to same as `margin`. */
56
52
  containerPadding?: [number, number];
57
-
58
- /**
59
- * Whether the canvas should accept drag-and-drop of views from outside
60
- * the canvas. Default false.
61
- */
62
- droppable?: boolean;
63
-
64
- /**
65
- * Optional Callback to invoke after a view is successfully dropped onto the canvas.
66
- */
67
- onDropDone?: (viewModel: DashCanvasViewModel) => void;
68
-
69
- /**
70
- * Optional callback to invoke when an item is dragged over the canvas. This may be used to
71
- * customize how the size of the dropping placeholder is calculated. The callback should
72
- * return an object with optional properties indicating the desired width, height (in grid units),
73
- * and offset (in pixels) of the dropping placeholder.
74
- * If not provided, Hoist's own default logic will be used.
75
- */
76
- onDropDragOver?: (e: DragEvent) =>
77
- | {
78
- w?: number;
79
- h?: number;
80
- dragOffsetX?: number;
81
- dragOffsetY?: number;
82
- }
83
- | false
84
- | void;
85
-
86
- /**
87
- * Whether an overlay with an Add View button should be rendered
88
- * when the canvas is empty. Default true.
89
- */
90
- showAddViewButtonWhenEmpty?: boolean;
91
53
  }
92
54
 
93
55
  export interface DashCanvasItemState {
@@ -120,16 +82,11 @@ export class DashCanvasModel
120
82
  @bindable compact: boolean;
121
83
  @bindable.ref margin: [number, number]; // [x, y]
122
84
  @bindable.ref containerPadding: [number, number]; // [x, y]
123
- @bindable showAddViewButtonWhenEmpty: boolean;
124
85
 
125
86
  //-----------------------------
126
87
  // Public properties
127
88
  //-----------------------------
128
- DROPPING_ELEM_ID = '__dropping-elem__';
129
89
  maxRows: number;
130
- droppable: boolean;
131
- onDropDone: (viewModel: DashCanvasViewModel) => void;
132
- draggedInView: DashCanvasItemState;
133
90
 
134
91
  /** Current number of rows in canvas */
135
92
  get rows(): number {
@@ -149,27 +106,21 @@ export class DashCanvasModel
149
106
  private isLoadingState: boolean;
150
107
 
151
108
  get rglLayout() {
152
- return this.layout
153
- .map(it => {
154
- const dashCanvasView = this.getView(it.i);
155
-
156
- // `dashCanvasView` will not be found if `it` is a dropping element.
157
- if (!dashCanvasView) return null;
158
-
159
- const {autoHeight, viewSpec} = dashCanvasView;
160
-
161
- return {
162
- ...it,
163
- resizeHandles: autoHeight
164
- ? ['w', 'e']
165
- : ['s', 'w', 'e', 'n', 'sw', 'nw', 'se', 'ne'],
166
- maxH: viewSpec.maxHeight,
167
- minH: viewSpec.minHeight,
168
- maxW: viewSpec.maxWidth,
169
- minW: viewSpec.minWidth
170
- };
171
- })
172
- .filter(Boolean);
109
+ return this.layout.map(it => {
110
+ const dashCanvasView = this.getView(it.i),
111
+ {autoHeight, viewSpec} = dashCanvasView;
112
+
113
+ return {
114
+ ...it,
115
+ resizeHandles: autoHeight
116
+ ? ['w', 'e']
117
+ : ['s', 'w', 'e', 'n', 'sw', 'nw', 'se', 'ne'],
118
+ maxH: viewSpec.maxHeight,
119
+ minH: viewSpec.minHeight,
120
+ maxW: viewSpec.maxWidth,
121
+ minW: viewSpec.minWidth
122
+ };
123
+ });
173
124
  }
174
125
 
175
126
  constructor({
@@ -187,12 +138,8 @@ export class DashCanvasModel
187
138
  compact = true,
188
139
  margin = [10, 10],
189
140
  maxRows = Infinity,
190
- containerPadding = [0, 0],
191
- extraMenuItems,
192
- showAddViewButtonWhenEmpty = true,
193
- droppable = false,
194
- onDropDone,
195
- onDropDragOver
141
+ containerPadding = margin,
142
+ extraMenuItems
196
143
  }: DashCanvasConfig) {
197
144
  super();
198
145
  makeObservable(this);
@@ -235,15 +182,11 @@ export class DashCanvasModel
235
182
  this.maxRows = maxRows;
236
183
  this.containerPadding = containerPadding;
237
184
  this.margin = margin;
185
+ this.containerPadding = containerPadding;
238
186
  this.compact = compact;
239
187
  this.emptyText = emptyText;
240
188
  this.addViewButtonText = addViewButtonText;
241
189
  this.extraMenuItems = extraMenuItems;
242
- this.showAddViewButtonWhenEmpty = showAddViewButtonWhenEmpty;
243
- this.droppable = droppable;
244
- this.onDropDone = onDropDone;
245
- // Override default onDropDragOver if provided
246
- if (onDropDragOver) this.onDropDragOver = onDropDragOver;
247
190
 
248
191
  this.loadState(initialState);
249
192
  this.state = this.buildState();
@@ -369,56 +312,6 @@ export class DashCanvasModel
369
312
  this.getView(id)?.ensureVisible();
370
313
  }
371
314
 
372
- onDrop(rglLayout: LayoutItem[], layoutItem: LayoutItem, evt: Event) {
373
- throwIf(
374
- !this.draggedInView,
375
- `No draggedInView set on DashCanvasModel prior to onDrop operation.
376
- Typically a developer would set this in response to dragstart events from
377
- a DashViewTray or similar component.`
378
- );
379
-
380
- const {viewSpecId, title, state} = this.draggedInView,
381
- layout = omit(layoutItem, 'i'),
382
- newViewModel: DashCanvasViewModel = this.addViewInternal(viewSpecId, {
383
- title,
384
- state,
385
- layout
386
- }),
387
- droppingItem: any = rglLayout.find(it => it.i === this.DROPPING_ELEM_ID);
388
-
389
- // Change ID of dropping item to the new view's id
390
- // so that the new view goes where the dropping item is.
391
- droppingItem.i = newViewModel.id;
392
-
393
- // must wait a tick for RGL to settle
394
- wait().then(() => {
395
- this.draggedInView = null;
396
- this.onRglLayoutChange(rglLayout);
397
- this.onDropDone?.(newViewModel);
398
- });
399
- }
400
-
401
- setDraggedInView(view?: DashCanvasItemState) {
402
- this.draggedInView = view;
403
- }
404
-
405
- onDropDragOver(evt: DragEvent):
406
- | {
407
- w?: number;
408
- h?: number;
409
- dragOffsetX?: number;
410
- dragOffsetY?: number;
411
- }
412
- | false
413
- | void {
414
- if (!this.draggedInView) return false;
415
-
416
- return {
417
- w: this.draggedInView.layout.w,
418
- h: this.draggedInView.layout.h
419
- };
420
- }
421
-
422
315
  //------------------------
423
316
  // Persistable Interface
424
317
  //------------------------
@@ -491,19 +384,13 @@ export class DashCanvasModel
491
384
  return model;
492
385
  }
493
386
 
494
- onRglLayoutChange(rglLayout: LayoutItem[]) {
387
+ onRglLayoutChange(rglLayout) {
495
388
  rglLayout = rglLayout.map(it => pick(it, ['i', 'x', 'y', 'w', 'h']));
496
-
497
- // Early out if RGL is changing layout as user is dragging droppable
498
- // item around the canvas. This will be called again once dragging
499
- // has stopped and user has dropped the item onto the canvas.
500
- if (rglLayout.some(it => it.i === this.DROPPING_ELEM_ID)) return;
501
-
502
389
  this.setLayout(rglLayout);
503
390
  }
504
391
 
505
392
  @action
506
- private setLayout(layout: LayoutItem[]) {
393
+ private setLayout(layout) {
507
394
  layout = sortBy(layout, 'i');
508
395
  const layoutChanged = !isEqual(layout, this.layout);
509
396
  if (!layoutChanged) return;
@@ -605,7 +492,6 @@ export class DashCanvasModel
605
492
  }
606
493
  }
607
494
  }
608
-
609
495
  const checkPosition = (originX, originY) => {
610
496
  for (let y = originY; y < originY + height; y++) {
611
497
  for (let x = originX; x < originX + width; x++) {
@@ -81,13 +81,13 @@ export interface PanelProps extends HoistProps<PanelModel>, Omit<BoxProps, 'titl
81
81
  * A toolbar to be docked at the top of the panel.
82
82
  * If specified as an array, items will be passed as children to a Toolbar component.
83
83
  */
84
- tbar?: ReactNode;
84
+ tbar?: Some<ReactNode>;
85
85
 
86
86
  /**
87
87
  * A toolbar to be docked at the bottom of the panel.
88
88
  * If specified as an array, items will be passed as children to a Toolbar component.
89
89
  */
90
- bbar?: ReactNode;
90
+ bbar?: Some<ReactNode>;
91
91
 
92
92
  /** Title text added to the panel's header. */
93
93
  title?: ReactNode;