@gravity-ui/dashkit 8.12.1 → 8.14.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.
package/README.md CHANGED
@@ -24,6 +24,15 @@ Plugins are required to create custom widgets.
24
24
  ### Props
25
25
 
26
26
  ```ts
27
+ type ItemManipulationCallback = (eventData: {
28
+ layout: Layouts;
29
+ oldItem: Layout;
30
+ newItem: Layout;
31
+ placeholder: Layout;
32
+ e: MouseEvent;
33
+ element: HTMLElement;
34
+ }) => void;
35
+
27
36
  interface DashKitProps {
28
37
  config: Config;
29
38
  editMode: boolean;
@@ -32,6 +41,14 @@ interface DashKitProps {
32
41
  onDrop: (dropProps: ItemDropProps) => void;
33
42
  onItemMountChange: (item: ConfigItem, state: {isAsync: boolead; isMounted: boolean}) => void;
34
43
  onItemRender: (item: ConfigItem) => void;
44
+
45
+ onDragStart?: ItemManipulationCallback;
46
+ onDrag?: ItemManipulationCallback;
47
+ onDragStop?: ItemManipulationCallback;
48
+ onResizeStart?: ItemManipulationCallback;
49
+ onResize?: ItemManipulationCallback;
50
+ onResizeStop?: ItemManipulationCallback;
51
+
35
52
  defaultGlobalParams: GlobalParams;
36
53
  globalParams: GlobalParams;
37
54
  itemsStateAndParams: ItemsStateAndParams;
@@ -61,6 +78,12 @@ interface DashKitProps {
61
78
  - **noOverlay**: If `true`, overlay and controls are not displayed while editing.
62
79
  - **focusable**: If `true`, grid items will be focusable.
63
80
  - **draggableHandleClassName** : СSS class name of the element that makes the widget draggable.
81
+ - **onDragStart**: ReactGridLayout called when item drag started
82
+ - **onDrag**: ReactGridLayout called while item drag
83
+ - **onDragStop**: ReactGridLayout called when item drag stopped
84
+ - **onResizeStart**: ReactGridLayout called when item resize started
85
+ - **onResize**: ReactGridLayout called while item resizing
86
+ - **onResizeStop**: ReactGridLayout called when item resize stoped
64
87
 
65
88
  ## Usage
66
89
 
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { Config, ConfigItem, ConfigLayout, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
- import { AddNewItemOptions, ContextProps, DashKitGroup, MenuItem, Plugin, SetConfigItem, Settings, SettingsProps } from '../../typings';
3
+ import { AddNewItemOptions, ContextProps, DashKitGroup, ItemManipulationCallback, MenuItem, Plugin, SetConfigItem, Settings, SettingsProps } from '../../typings';
4
4
  import GridLayout from '../GridLayout/GridLayout';
5
5
  import { OverlayControlItem } from '../OverlayControls/OverlayControls';
6
6
  interface DashKitGeneralProps {
@@ -17,12 +17,18 @@ interface DashKitDefaultProps {
17
17
  itemsStateAndParams: ItemsStateAndParams;
18
18
  groups?: DashKitGroup[];
19
19
  }) => void;
20
- onDrop: (dropProps: ItemDropProps) => void;
20
+ onDrop?: (dropProps: ItemDropProps) => void;
21
21
  onItemMountChange?: (item: ConfigItem, state: {
22
22
  isAsync: boolean;
23
23
  isMounted: boolean;
24
24
  }) => void;
25
25
  onItemRender?: (item: ConfigItem) => void;
26
+ onDragStart?: ItemManipulationCallback;
27
+ onDrag?: ItemManipulationCallback;
28
+ onDragStop?: ItemManipulationCallback;
29
+ onResizeStart?: ItemManipulationCallback;
30
+ onResize?: ItemManipulationCallback;
31
+ onResizeStop?: ItemManipulationCallback;
26
32
  defaultGlobalParams: GlobalParams;
27
33
  globalParams: GlobalParams;
28
34
  itemsStateAndParams: ItemsStateAndParams;
@@ -54,7 +60,11 @@ export declare class DashKit extends React.PureComponent<DashKitInnerProps> {
54
60
  config: Config;
55
61
  itemsStateAndParams: ItemsStateAndParams;
56
62
  };
57
- static reflowLayout(newLayoutItem: ConfigLayout, layout: ConfigLayout[], groups?: DashKitGroup[]): ConfigLayout[];
63
+ static reflowLayout({ newLayoutItem, layout, groups, }: {
64
+ newLayoutItem?: ConfigLayout;
65
+ layout: ConfigLayout[];
66
+ groups?: DashKitGroup[];
67
+ }): ConfigLayout[];
58
68
  metaRef: React.RefObject<GridLayout>;
59
69
  render(): JSX.Element;
60
70
  getItemsMeta(): any;
@@ -66,8 +66,12 @@ class DashKit extends react_1.default.PureComponent {
66
66
  static removeItem({ id, config, itemsStateAndParams, }) {
67
67
  return utils_1.UpdateManager.removeItem({ id, config, itemsStateAndParams });
68
68
  }
69
- static reflowLayout(newLayoutItem, layout, groups) {
70
- return (0, utils_1.reflowLayout)(newLayoutItem, layout, getReflowGroupsConfig(groups));
69
+ static reflowLayout({ newLayoutItem, layout, groups, }) {
70
+ return (0, utils_1.reflowLayout)({
71
+ newLayoutItem,
72
+ layout,
73
+ reflowLayoutOptions: getReflowGroupsConfig(groups),
74
+ });
71
75
  }
72
76
  render() {
73
77
  return react_1.default.createElement(DashKitView_1.default, Object.assign({ registerManager: registerManager, ref: this.metaRef }, this.props));
@@ -25,8 +25,8 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
25
25
  }) => void;
26
26
  getItemsMeta: () => any;
27
27
  getActiveLayout(): any;
28
- getMemoGroupLayout: (group: any, layout: any) => any;
29
- getMemoGroupCallbacks: (group: any) => any;
28
+ getMemoGroupLayout(group: any, layout: any): any;
29
+ getMemoGroupCallbacks(group: any): any;
30
30
  getMemoGroupProps: (group: any, renderLayout: any, properties: any) => {
31
31
  layout: any;
32
32
  callbacks: any;
@@ -38,9 +38,23 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
38
38
  getMemoForwardRefCallback: (refIndex: any) => any;
39
39
  mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
40
40
  reloadItems(): void;
41
- _onDragStart: (group: any, _newLayout: any, layoutItem: any, _newItem: any, _placeholder: any, e: any) => void;
42
- _onResizeStart: () => void;
43
- _onTargetRestore: () => void;
41
+ prepareDefaultArguments(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): {
42
+ group: any;
43
+ layout: any;
44
+ oldItem: any;
45
+ newItem: any;
46
+ placeholder: any;
47
+ e: any;
48
+ element: any;
49
+ };
50
+ updateeDraggingElementState(group: any, layoutItem: any, e: any): void;
51
+ _onDragStart(group: any, _newLayout: any, layoutItem: any, _newItem: any, _placeholder: any, e: any, element: any): void;
52
+ _onDrag(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
53
+ _onDragStop(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
54
+ _onResizeStart(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
55
+ _onResize(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
56
+ _onResizeStop(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
57
+ _onTargetRestore(): void;
44
58
  _onStop: (group: any, newLayout: any) => void;
45
59
  _onSharedDrop: (targetGroup: any, newLayout: any, tempItem: any) => void;
46
60
  _onExternalDrop: (group: any, newLayout: any, item: any, e: any) => void;
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
5
  const constants_1 = require("../../constants");
6
6
  const DashKitContext_1 = require("../../context/DashKitContext");
7
+ const utils_1 = require("../../utils");
7
8
  const GridItem_1 = tslib_1.__importDefault(require("../GridItem/GridItem"));
8
9
  const ReactGridLayout_1 = require("./ReactGridLayout");
9
10
  class GridLayout extends react_1.default.PureComponent {
@@ -34,44 +35,6 @@ class GridLayout extends react_1.default.PureComponent {
34
35
  const { getItemsMeta } = this.context;
35
36
  return getItemsMeta(this.pluginsRefs);
36
37
  };
37
- this.getMemoGroupLayout = (group, layout) => {
38
- // fastest possible way to match json
39
- const key = JSON.stringify(layout);
40
- if (this._memoGroupsLayouts[group]) {
41
- if (this._memoGroupsLayouts[group].key === key) {
42
- return this._memoGroupsLayouts[group];
43
- }
44
- else {
45
- this._memoGroupsLayouts[group].key = key;
46
- this._memoGroupsLayouts[group].layout = layout;
47
- }
48
- }
49
- else {
50
- this._memoGroupsLayouts[group] = {
51
- key,
52
- layout,
53
- };
54
- }
55
- return this._memoGroupsLayouts[group];
56
- };
57
- this.getMemoGroupCallbacks = (group) => {
58
- if (!this._memoCallbacksForGroups[group]) {
59
- const onDragStart = this._onDragStart.bind(this, group);
60
- const onStop = this._onStop.bind(this, group);
61
- const onDrop = this._onDrop.bind(this, group);
62
- const onDropDragOver = this._onDropDragOver.bind(this, group);
63
- const onDragTargetRestore = this._onTargetRestore.bind(this, group);
64
- this._memoCallbacksForGroups[group] = {
65
- onDragStart,
66
- onDragStop: onStop,
67
- onResizeStop: onStop,
68
- onDrop,
69
- onDropDragOver,
70
- onDragTargetRestore,
71
- };
72
- }
73
- return this._memoCallbacksForGroups[group];
74
- };
75
38
  this.getMemoGroupProps = (group, renderLayout, properties) => {
76
39
  // Needed for _onDropDragOver
77
40
  this._memoGroupsProps[group] = properties;
@@ -94,45 +57,6 @@ class GridLayout extends react_1.default.PureComponent {
94
57
  }
95
58
  return this._memoForwardedPluginRef[refIndex];
96
59
  };
97
- this._onDragStart = (group, _newLayout, layoutItem, _newItem, _placeholder, e) => {
98
- if (this.temporaryLayout)
99
- return;
100
- if (this.context.dragOverPlugin) {
101
- this.setState({ isDragging: true });
102
- }
103
- else {
104
- let currentDraggingElement = this.state.currentDraggingElement;
105
- if (!currentDraggingElement) {
106
- const layoutId = layoutItem.i;
107
- const item = this.context.config.items.find(({ id }) => id === layoutId);
108
- const { offsetX, offsetY } = e.nativeEvent;
109
- currentDraggingElement = {
110
- group,
111
- layoutItem,
112
- item,
113
- cursorPosition: { offsetX, offsetY },
114
- };
115
- }
116
- this.setState({
117
- isDragging: true,
118
- currentDraggingElement,
119
- draggedOverGroup: group,
120
- });
121
- }
122
- };
123
- this._onResizeStart = () => {
124
- this.setState({
125
- isDragging: true,
126
- });
127
- };
128
- this._onTargetRestore = () => {
129
- const { currentDraggingElement } = this.state;
130
- if (currentDraggingElement) {
131
- this.setState({
132
- draggedOverGroup: currentDraggingElement.group,
133
- });
134
- }
135
- };
136
60
  this._onStop = (group, newLayout) => {
137
61
  const { layoutChange, onDrop, temporaryLayout } = this.context;
138
62
  const { draggedOverGroup, currentDraggingElement } = this.state;
@@ -180,6 +104,7 @@ class GridLayout extends react_1.default.PureComponent {
180
104
  currentDraggingElement: null,
181
105
  draggedOverGroup: null,
182
106
  });
107
+ // TODO temporaryLayout
183
108
  layoutChange(groupedLayout);
184
109
  };
185
110
  this._onExternalDrop = (group, newLayout, item, e) => {
@@ -204,8 +129,12 @@ class GridLayout extends react_1.default.PureComponent {
204
129
  }
205
130
  };
206
131
  this._onDropDragOver = (group, e) => {
207
- const { editMode, dragOverPlugin, onDropDragOver } = this.context;
132
+ const { editMode, dragOverPlugin, onDropDragOver, temporaryLayout } = this.context;
208
133
  const { currentDraggingElement } = this.state;
134
+ // TODO If temporary item is trying to change group
135
+ if (temporaryLayout && currentDraggingElement) {
136
+ return false;
137
+ }
209
138
  if (!editMode || (!dragOverPlugin && !currentDraggingElement)) {
210
139
  return false;
211
140
  }
@@ -248,6 +177,51 @@ class GridLayout extends react_1.default.PureComponent {
248
177
  const { layout, temporaryLayout } = this.context;
249
178
  return (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout;
250
179
  }
180
+ getMemoGroupLayout(group, layout) {
181
+ // fastest possible way to match json
182
+ const key = JSON.stringify(layout);
183
+ if (this._memoGroupsLayouts[group]) {
184
+ if (this._memoGroupsLayouts[group].key === key) {
185
+ return this._memoGroupsLayouts[group];
186
+ }
187
+ else {
188
+ this._memoGroupsLayouts[group].key = key;
189
+ this._memoGroupsLayouts[group].layout = layout;
190
+ }
191
+ }
192
+ else {
193
+ this._memoGroupsLayouts[group] = {
194
+ key,
195
+ layout,
196
+ };
197
+ }
198
+ return this._memoGroupsLayouts[group];
199
+ }
200
+ getMemoGroupCallbacks(group) {
201
+ if (!this._memoCallbacksForGroups[group]) {
202
+ const onDragStart = this._onDragStart.bind(this, group);
203
+ const onDrag = this._onDrag.bind(this, group);
204
+ const onDragStop = this._onDragStop.bind(this, group);
205
+ const onResizeStart = this._onResizeStart.bind(this, group);
206
+ const onResize = this._onResize.bind(this, group);
207
+ const onResizeStop = this._onResizeStop.bind(this, group);
208
+ const onDrop = this._onDrop.bind(this, group);
209
+ const onDropDragOver = this._onDropDragOver.bind(this, group);
210
+ const onDragTargetRestore = this._onTargetRestore.bind(this, group);
211
+ this._memoCallbacksForGroups[group] = {
212
+ onDragStart,
213
+ onDrag,
214
+ onDragStop,
215
+ onResizeStart,
216
+ onResize,
217
+ onResizeStop,
218
+ onDrop,
219
+ onDropDragOver,
220
+ onDragTargetRestore,
221
+ };
222
+ }
223
+ return this._memoCallbacksForGroups[group];
224
+ }
251
225
  mergeGroupsLayout(group, newLayout, temporaryItem) {
252
226
  const renderLayout = this.getActiveLayout();
253
227
  const itemsByGroup = renderLayout.reduce((memo, item) => {
@@ -263,7 +237,7 @@ class GridLayout extends react_1.default.PureComponent {
263
237
  return memo;
264
238
  }, {});
265
239
  return renderLayout.map((currentItem) => {
266
- const itemParent = itemsByGroup[currentItem.i].parent || constants_1.DEFAULT_GROUP;
240
+ const itemParent = (0, utils_1.resolveLayoutGroup)(itemsByGroup[currentItem.i]);
267
241
  if (itemParent === group) {
268
242
  return newItemsLayoutById[currentItem.i];
269
243
  }
@@ -284,6 +258,81 @@ class GridLayout extends react_1.default.PureComponent {
284
258
  this._timeout = setTimeout(() => this.reloadItems(), reloadIntervalRemains <= 0 ? autoupdateIntervalMs : reloadIntervalRemains);
285
259
  }
286
260
  }
261
+ prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element) {
262
+ return {
263
+ group,
264
+ layout,
265
+ oldItem,
266
+ newItem,
267
+ placeholder,
268
+ e,
269
+ element,
270
+ };
271
+ }
272
+ updateeDraggingElementState(group, layoutItem, e) {
273
+ let currentDraggingElement = this.state.currentDraggingElement;
274
+ if (!currentDraggingElement) {
275
+ const { temporaryLayout } = this.context;
276
+ const layoutId = layoutItem.i;
277
+ const item = temporaryLayout
278
+ ? temporaryLayout.dragProps
279
+ : this.context.config.items.find(({ id }) => id === layoutId);
280
+ const { offsetX, offsetY } = e.nativeEvent;
281
+ currentDraggingElement = {
282
+ group,
283
+ layoutItem,
284
+ item,
285
+ cursorPosition: { offsetX, offsetY },
286
+ };
287
+ }
288
+ this.setState({ currentDraggingElement, draggedOverGroup: group });
289
+ }
290
+ _onDragStart(group, _newLayout, layoutItem, _newItem, _placeholder, e, element) {
291
+ var _a;
292
+ (_a = this.context.onDragStart) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, _newLayout, layoutItem, _newItem, _placeholder, e, element));
293
+ if (this.context.dragOverPlugin) {
294
+ this.setState({ isDragging: true });
295
+ }
296
+ else {
297
+ this.updateeDraggingElementState(group, layoutItem, e);
298
+ this.setState({ isDragging: true });
299
+ }
300
+ }
301
+ _onDrag(group, layout, oldItem, newItem, placeholder, e, element) {
302
+ var _a;
303
+ (_a = this.context.onDrag) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
304
+ }
305
+ _onDragStop(group, layout, oldItem, newItem, placeholder, e, element) {
306
+ var _a;
307
+ this._onStop(group, layout);
308
+ (_a = this.context.onDragStop) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
309
+ }
310
+ _onResizeStart(group, layout, oldItem, newItem, placeholder, e, element) {
311
+ var _a;
312
+ this.setState({
313
+ isDragging: true,
314
+ });
315
+ (_a = this.context.onResizeStart) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
316
+ }
317
+ _onResize(group, layout, oldItem, newItem, placeholder, e, element) {
318
+ var _a;
319
+ (_a = this.context.onResize) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
320
+ }
321
+ _onResizeStop(group, layout, oldItem, newItem, placeholder, e, element) {
322
+ var _a;
323
+ (_a = this.context.onResizeStop) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
324
+ }
325
+ _onTargetRestore() {
326
+ if (this.context.temporaryLayout) {
327
+ return;
328
+ }
329
+ const { currentDraggingElement } = this.state;
330
+ if (currentDraggingElement) {
331
+ this.setState({
332
+ draggedOverGroup: currentDraggingElement.group,
333
+ });
334
+ }
335
+ }
287
336
  renderTemporaryPlaceholder() {
288
337
  const { temporaryLayout, noOverlay, draggableHandleClassName } = this.context;
289
338
  if (!temporaryLayout || !temporaryLayout.dragProps) {
@@ -309,13 +358,21 @@ class GridLayout extends react_1.default.PureComponent {
309
358
  group === currentDraggingElement.group &&
310
359
  draggedOverGroup !== null &&
311
360
  draggedOverGroup !== group;
312
- return (react_1.default.createElement(ReactGridLayout_1.Layout, Object.assign({}, properties, { compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onResizeStart: this._onResizeStart, onDragStart: callbacks.onDragStart, onDragStop: callbacks.onDragStop, onResizeStop: callbacks.onResizeStop, onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured }, (draggableHandleClassName
361
+ return (react_1.default.createElement(ReactGridLayout_1.Layout
362
+ // Group properties
363
+ , Object.assign({}, properties, {
364
+ // Layout props
365
+ compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }, (draggableHandleClassName
313
366
  ? { draggableHandle: `.${draggableHandleClassName}` }
314
- : null), (outerDnDEnable
367
+ : null), {
368
+ // Default callbacks
369
+ onDragStart: callbacks.onDragStart, onDrag: callbacks.onDrag, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResize: callbacks.onResize, onResizeStop: callbacks.onResizeStop,
370
+ // External Drag N Drop options
371
+ onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured }, (outerDnDEnable
315
372
  ? {
316
373
  isDroppable: true,
317
374
  }
318
- : null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }),
375
+ : null)),
319
376
  renderItems.map((item, i) => {
320
377
  return (react_1.default.createElement(GridItem_1.default, { forwardedPluginRef: this.getMemoForwardRefCallback(offset + i), key: item.id, id: item.id, item: item, layout: layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), onItemMountChange: onItemMountChange, onItemRender: onItemRender }));
321
378
  }),
@@ -154,7 +154,7 @@ function useMemoStateContext(props) {
154
154
  if (hasNowrapGroups) {
155
155
  layout.forEach((item) => {
156
156
  const widgetId = item.i;
157
- const parentId = item.parent || common_1.DEFAULT_GROUP;
157
+ const parentId = (0, utils_1.resolveLayoutGroup)(item);
158
158
  if (nowrapGroups[parentId]) {
159
159
  // Collecting nowrap elements
160
160
  nowrapGroups[parentId].items.push(item);
@@ -287,7 +287,7 @@ function useMemoStateContext(props) {
287
287
  return;
288
288
  }
289
289
  setTemporaryLayout({
290
- data: newLayout,
290
+ data: [...newLayout, item],
291
291
  dragProps,
292
292
  });
293
293
  onDropProp({
@@ -331,6 +331,13 @@ function useMemoStateContext(props) {
331
331
  draggableHandleClassName: props.draggableHandleClassName,
332
332
  outerDnDEnable,
333
333
  dragOverPlugin,
334
+ /* default bypassing handlers */
335
+ onDragStart: props.onDragStart,
336
+ onDrag: props.onDrag,
337
+ onDragStop: props.onDragStop,
338
+ onResizeStart: props.onResizeStart,
339
+ onResize: props.onResize,
340
+ onResizeStop: props.onResizeStop,
334
341
  }), [
335
342
  resultLayout,
336
343
  temporaryLayout,
@@ -359,6 +366,12 @@ function useMemoStateContext(props) {
359
366
  props.draggableHandleClassName,
360
367
  outerDnDEnable,
361
368
  dragOverPlugin,
369
+ props.onDragStart,
370
+ props.onDrag,
371
+ props.onDragStop,
372
+ props.onResizeStart,
373
+ props.onResize,
374
+ props.onResizeStop,
362
375
  ]);
363
376
  const overlayMenuItems = props.overlayMenuItems || props.registerManager.settings.menu;
364
377
  const controlsContextValue = react_1.default.useMemo(() => ({
@@ -1,5 +1,5 @@
1
- /// <reference types="react-grid-layout" />
2
1
  /// <reference types="react" />
2
+ import type { Layout, Layouts } from 'react-grid-layout';
3
3
  import type { Config, ConfigItem, ConfigLayout } from '../shared';
4
4
  export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
5
5
  id?: null;
@@ -38,3 +38,11 @@ export interface DashKitGroup {
38
38
  render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
39
39
  gridProperties?: (props: ReactGridLayoutProps) => ReactGridLayoutProps;
40
40
  }
41
+ export type ItemManipulationCallback = (eventData: {
42
+ layout: Layouts;
43
+ oldItem: Layout;
44
+ newItem: Layout;
45
+ placeholder: Layout;
46
+ e: MouseEvent;
47
+ element: HTMLElement;
48
+ }) => void;
@@ -0,0 +1,3 @@
1
+ import type { ConfigLayout } from '../shared/types';
2
+ export declare const resolveLayoutGroup: (item: ConfigLayout) => string;
3
+ export declare const isDefaultLayoutGroup: (item: ConfigLayout) => boolean;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDefaultLayoutGroup = exports.resolveLayoutGroup = void 0;
4
+ const constants_1 = require("../constants");
5
+ const resolveLayoutGroup = (item) => {
6
+ if (!item.parent) {
7
+ return constants_1.DEFAULT_GROUP;
8
+ }
9
+ return item.parent;
10
+ };
11
+ exports.resolveLayoutGroup = resolveLayoutGroup;
12
+ const isDefaultLayoutGroup = (item) => {
13
+ return item.parent === constants_1.DEFAULT_GROUP || item.parent === undefined;
14
+ };
15
+ exports.isDefaultLayoutGroup = isDefaultLayoutGroup;
@@ -1,2 +1,3 @@
1
1
  export * from './register-manager';
2
2
  export * from './update-manager';
3
+ export * from './group-helpers';
@@ -3,3 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./register-manager"), exports);
5
5
  tslib_1.__exportStar(require("./update-manager"), exports);
6
+ tslib_1.__exportStar(require("./group-helpers"), exports);
@@ -21,7 +21,11 @@ export declare const getChangedParams: ({ initiatorItem, stateAndParams, itemsSt
21
21
  }) => {
22
22
  [x: string]: string | string[];
23
23
  };
24
- export declare function reflowLayout(newLayoutItem: ConfigLayout, layout: ConfigLayout[], reflowLayoutOptions: ReflowLayoutOptions): ConfigLayout[];
24
+ export declare function reflowLayout({ newLayoutItem, layout, reflowLayoutOptions, }: {
25
+ newLayoutItem?: ConfigLayout;
26
+ layout: ConfigLayout[];
27
+ reflowLayoutOptions: ReflowLayoutOptions;
28
+ }): ConfigLayout[];
25
29
  export declare class UpdateManager {
26
30
  static addItem({ item, namespace, layout, config, options, }: {
27
31
  item: AddConfigItem;
@@ -9,6 +9,7 @@ const constants_1 = require("../constants");
9
9
  const shared_1 = require("../shared");
10
10
  const get_new_id_1 = require("./get-new-id");
11
11
  const grid_layout_1 = require("./grid-layout");
12
+ const group_helpers_1 = require("./group-helpers");
12
13
  (0, immutability_helper_1.extend)('$auto', (value, object) => (object ? (0, immutability_helper_1.default)(object, value) : (0, immutability_helper_1.default)({}, value)));
13
14
  function removeItemVersion1({ id, config, itemsStateAndParams }) {
14
15
  const itemIndex = config.items.findIndex((item) => item.id === id);
@@ -227,11 +228,11 @@ function changeGroupParams({ groupItemIds, initiatorId, initiatorItem, itemsStat
227
228
  };
228
229
  return (0, immutability_helper_1.default)(itemsStateAndParams, obj);
229
230
  }
230
- function reflowLayout(newLayoutItem, layout, reflowLayoutOptions) {
231
+ function reflowLayout({ newLayoutItem, layout, reflowLayoutOptions, }) {
231
232
  const byGroup = {};
232
233
  const reducer = (memo, item, i, _items, isNewItem) => {
233
234
  memo[item.i] = i;
234
- const parent = item.parent || constants_1.DEFAULT_GROUP;
235
+ const parent = (0, group_helpers_1.resolveLayoutGroup)(item);
235
236
  if (byGroup[parent]) {
236
237
  if (isNewItem) {
237
238
  byGroup[parent].unshift(item);
@@ -246,7 +247,9 @@ function reflowLayout(newLayoutItem, layout, reflowLayoutOptions) {
246
247
  return memo;
247
248
  };
248
249
  const orderById = layout.reduce(reducer, {});
249
- reducer(orderById, newLayoutItem, layout.length, layout, true);
250
+ if (newLayoutItem) {
251
+ reducer(orderById, newLayoutItem, layout.length, layout, true);
252
+ }
250
253
  const { defaultProps } = reflowLayoutOptions;
251
254
  return Object.entries(byGroup)
252
255
  .reduce((memo, [groupId, layoutItems]) => {
@@ -287,7 +290,11 @@ class UpdateManager {
287
290
  let newLayout;
288
291
  const newLayoutItem = Object.assign(Object.assign({}, saveDefaultLayout), { i: newItem.id });
289
292
  if (options.reflowLayoutOptions) {
290
- newLayout = reflowLayout(newLayoutItem, config.layout.map((t) => (Object.assign(Object.assign({}, t), (byId[t.i] || {})))), options.reflowLayoutOptions);
293
+ newLayout = reflowLayout({
294
+ newLayoutItem,
295
+ layout: config.layout.map((t) => (Object.assign(Object.assign({}, t), (byId[t.i] || {})))),
296
+ reflowLayoutOptions: options.reflowLayoutOptions,
297
+ });
291
298
  }
292
299
  else {
293
300
  newLayout = [
@@ -305,7 +312,11 @@ class UpdateManager {
305
312
  let newLayout;
306
313
  const newLayoutItem = Object.assign(Object.assign({}, saveDefaultLayout), { i: newItem.id });
307
314
  if (options.reflowLayoutOptions) {
308
- newLayout = reflowLayout(newLayoutItem, config.layout, options.reflowLayoutOptions);
315
+ newLayout = reflowLayout({
316
+ newLayoutItem,
317
+ layout: config.layout,
318
+ reflowLayoutOptions: options.reflowLayoutOptions,
319
+ });
309
320
  }
310
321
  else {
311
322
  newLayout = [...config.layout, newLayoutItem];
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { Config, ConfigItem, ConfigLayout, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
- import { AddNewItemOptions, ContextProps, DashKitGroup, MenuItem, Plugin, SetConfigItem, Settings, SettingsProps } from '../../typings';
3
+ import { AddNewItemOptions, ContextProps, DashKitGroup, ItemManipulationCallback, MenuItem, Plugin, SetConfigItem, Settings, SettingsProps } from '../../typings';
4
4
  import GridLayout from '../GridLayout/GridLayout';
5
5
  import { OverlayControlItem } from '../OverlayControls/OverlayControls';
6
6
  interface DashKitGeneralProps {
@@ -17,12 +17,18 @@ interface DashKitDefaultProps {
17
17
  itemsStateAndParams: ItemsStateAndParams;
18
18
  groups?: DashKitGroup[];
19
19
  }) => void;
20
- onDrop: (dropProps: ItemDropProps) => void;
20
+ onDrop?: (dropProps: ItemDropProps) => void;
21
21
  onItemMountChange?: (item: ConfigItem, state: {
22
22
  isAsync: boolean;
23
23
  isMounted: boolean;
24
24
  }) => void;
25
25
  onItemRender?: (item: ConfigItem) => void;
26
+ onDragStart?: ItemManipulationCallback;
27
+ onDrag?: ItemManipulationCallback;
28
+ onDragStop?: ItemManipulationCallback;
29
+ onResizeStart?: ItemManipulationCallback;
30
+ onResize?: ItemManipulationCallback;
31
+ onResizeStop?: ItemManipulationCallback;
26
32
  defaultGlobalParams: GlobalParams;
27
33
  globalParams: GlobalParams;
28
34
  itemsStateAndParams: ItemsStateAndParams;
@@ -54,7 +60,11 @@ export declare class DashKit extends React.PureComponent<DashKitInnerProps> {
54
60
  config: Config;
55
61
  itemsStateAndParams: ItemsStateAndParams;
56
62
  };
57
- static reflowLayout(newLayoutItem: ConfigLayout, layout: ConfigLayout[], groups?: DashKitGroup[]): ConfigLayout[];
63
+ static reflowLayout({ newLayoutItem, layout, groups, }: {
64
+ newLayoutItem?: ConfigLayout;
65
+ layout: ConfigLayout[];
66
+ groups?: DashKitGroup[];
67
+ }): ConfigLayout[];
58
68
  metaRef: React.RefObject<GridLayout>;
59
69
  render(): JSX.Element;
60
70
  getItemsMeta(): any;
@@ -62,8 +62,12 @@ export class DashKit extends React.PureComponent {
62
62
  static removeItem({ id, config, itemsStateAndParams, }) {
63
63
  return UpdateManager.removeItem({ id, config, itemsStateAndParams });
64
64
  }
65
- static reflowLayout(newLayoutItem, layout, groups) {
66
- return reflowLayout(newLayoutItem, layout, getReflowGroupsConfig(groups));
65
+ static reflowLayout({ newLayoutItem, layout, groups, }) {
66
+ return reflowLayout({
67
+ newLayoutItem,
68
+ layout,
69
+ reflowLayoutOptions: getReflowGroupsConfig(groups),
70
+ });
67
71
  }
68
72
  render() {
69
73
  return React.createElement(DashKitView, Object.assign({ registerManager: registerManager, ref: this.metaRef }, this.props));
@@ -25,8 +25,8 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
25
25
  }) => void;
26
26
  getItemsMeta: () => any;
27
27
  getActiveLayout(): any;
28
- getMemoGroupLayout: (group: any, layout: any) => any;
29
- getMemoGroupCallbacks: (group: any) => any;
28
+ getMemoGroupLayout(group: any, layout: any): any;
29
+ getMemoGroupCallbacks(group: any): any;
30
30
  getMemoGroupProps: (group: any, renderLayout: any, properties: any) => {
31
31
  layout: any;
32
32
  callbacks: any;
@@ -38,9 +38,23 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
38
38
  getMemoForwardRefCallback: (refIndex: any) => any;
39
39
  mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
40
40
  reloadItems(): void;
41
- _onDragStart: (group: any, _newLayout: any, layoutItem: any, _newItem: any, _placeholder: any, e: any) => void;
42
- _onResizeStart: () => void;
43
- _onTargetRestore: () => void;
41
+ prepareDefaultArguments(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): {
42
+ group: any;
43
+ layout: any;
44
+ oldItem: any;
45
+ newItem: any;
46
+ placeholder: any;
47
+ e: any;
48
+ element: any;
49
+ };
50
+ updateeDraggingElementState(group: any, layoutItem: any, e: any): void;
51
+ _onDragStart(group: any, _newLayout: any, layoutItem: any, _newItem: any, _placeholder: any, e: any, element: any): void;
52
+ _onDrag(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
53
+ _onDragStop(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
54
+ _onResizeStart(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
55
+ _onResize(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
56
+ _onResizeStop(group: any, layout: any, oldItem: any, newItem: any, placeholder: any, e: any, element: any): void;
57
+ _onTargetRestore(): void;
44
58
  _onStop: (group: any, newLayout: any) => void;
45
59
  _onSharedDrop: (targetGroup: any, newLayout: any, tempItem: any) => void;
46
60
  _onExternalDrop: (group: any, newLayout: any, item: any, e: any) => void;
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { COMPACT_TYPE_HORIZONTAL_NOWRAP, DEFAULT_GROUP, OVERLAY_CONTROLS_CLASS_NAME, TEMPORARY_ITEM_ID, } from '../../constants';
3
3
  import { DashKitContext } from '../../context/DashKitContext';
4
+ import { resolveLayoutGroup } from '../../utils';
4
5
  import GridItem from '../GridItem/GridItem';
5
6
  import { Layout } from './ReactGridLayout';
6
7
  class GridLayout extends React.PureComponent {
@@ -31,44 +32,6 @@ class GridLayout extends React.PureComponent {
31
32
  const { getItemsMeta } = this.context;
32
33
  return getItemsMeta(this.pluginsRefs);
33
34
  };
34
- this.getMemoGroupLayout = (group, layout) => {
35
- // fastest possible way to match json
36
- const key = JSON.stringify(layout);
37
- if (this._memoGroupsLayouts[group]) {
38
- if (this._memoGroupsLayouts[group].key === key) {
39
- return this._memoGroupsLayouts[group];
40
- }
41
- else {
42
- this._memoGroupsLayouts[group].key = key;
43
- this._memoGroupsLayouts[group].layout = layout;
44
- }
45
- }
46
- else {
47
- this._memoGroupsLayouts[group] = {
48
- key,
49
- layout,
50
- };
51
- }
52
- return this._memoGroupsLayouts[group];
53
- };
54
- this.getMemoGroupCallbacks = (group) => {
55
- if (!this._memoCallbacksForGroups[group]) {
56
- const onDragStart = this._onDragStart.bind(this, group);
57
- const onStop = this._onStop.bind(this, group);
58
- const onDrop = this._onDrop.bind(this, group);
59
- const onDropDragOver = this._onDropDragOver.bind(this, group);
60
- const onDragTargetRestore = this._onTargetRestore.bind(this, group);
61
- this._memoCallbacksForGroups[group] = {
62
- onDragStart,
63
- onDragStop: onStop,
64
- onResizeStop: onStop,
65
- onDrop,
66
- onDropDragOver,
67
- onDragTargetRestore,
68
- };
69
- }
70
- return this._memoCallbacksForGroups[group];
71
- };
72
35
  this.getMemoGroupProps = (group, renderLayout, properties) => {
73
36
  // Needed for _onDropDragOver
74
37
  this._memoGroupsProps[group] = properties;
@@ -91,45 +54,6 @@ class GridLayout extends React.PureComponent {
91
54
  }
92
55
  return this._memoForwardedPluginRef[refIndex];
93
56
  };
94
- this._onDragStart = (group, _newLayout, layoutItem, _newItem, _placeholder, e) => {
95
- if (this.temporaryLayout)
96
- return;
97
- if (this.context.dragOverPlugin) {
98
- this.setState({ isDragging: true });
99
- }
100
- else {
101
- let currentDraggingElement = this.state.currentDraggingElement;
102
- if (!currentDraggingElement) {
103
- const layoutId = layoutItem.i;
104
- const item = this.context.config.items.find(({ id }) => id === layoutId);
105
- const { offsetX, offsetY } = e.nativeEvent;
106
- currentDraggingElement = {
107
- group,
108
- layoutItem,
109
- item,
110
- cursorPosition: { offsetX, offsetY },
111
- };
112
- }
113
- this.setState({
114
- isDragging: true,
115
- currentDraggingElement,
116
- draggedOverGroup: group,
117
- });
118
- }
119
- };
120
- this._onResizeStart = () => {
121
- this.setState({
122
- isDragging: true,
123
- });
124
- };
125
- this._onTargetRestore = () => {
126
- const { currentDraggingElement } = this.state;
127
- if (currentDraggingElement) {
128
- this.setState({
129
- draggedOverGroup: currentDraggingElement.group,
130
- });
131
- }
132
- };
133
57
  this._onStop = (group, newLayout) => {
134
58
  const { layoutChange, onDrop, temporaryLayout } = this.context;
135
59
  const { draggedOverGroup, currentDraggingElement } = this.state;
@@ -177,6 +101,7 @@ class GridLayout extends React.PureComponent {
177
101
  currentDraggingElement: null,
178
102
  draggedOverGroup: null,
179
103
  });
104
+ // TODO temporaryLayout
180
105
  layoutChange(groupedLayout);
181
106
  };
182
107
  this._onExternalDrop = (group, newLayout, item, e) => {
@@ -201,8 +126,12 @@ class GridLayout extends React.PureComponent {
201
126
  }
202
127
  };
203
128
  this._onDropDragOver = (group, e) => {
204
- const { editMode, dragOverPlugin, onDropDragOver } = this.context;
129
+ const { editMode, dragOverPlugin, onDropDragOver, temporaryLayout } = this.context;
205
130
  const { currentDraggingElement } = this.state;
131
+ // TODO If temporary item is trying to change group
132
+ if (temporaryLayout && currentDraggingElement) {
133
+ return false;
134
+ }
206
135
  if (!editMode || (!dragOverPlugin && !currentDraggingElement)) {
207
136
  return false;
208
137
  }
@@ -245,6 +174,51 @@ class GridLayout extends React.PureComponent {
245
174
  const { layout, temporaryLayout } = this.context;
246
175
  return (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout;
247
176
  }
177
+ getMemoGroupLayout(group, layout) {
178
+ // fastest possible way to match json
179
+ const key = JSON.stringify(layout);
180
+ if (this._memoGroupsLayouts[group]) {
181
+ if (this._memoGroupsLayouts[group].key === key) {
182
+ return this._memoGroupsLayouts[group];
183
+ }
184
+ else {
185
+ this._memoGroupsLayouts[group].key = key;
186
+ this._memoGroupsLayouts[group].layout = layout;
187
+ }
188
+ }
189
+ else {
190
+ this._memoGroupsLayouts[group] = {
191
+ key,
192
+ layout,
193
+ };
194
+ }
195
+ return this._memoGroupsLayouts[group];
196
+ }
197
+ getMemoGroupCallbacks(group) {
198
+ if (!this._memoCallbacksForGroups[group]) {
199
+ const onDragStart = this._onDragStart.bind(this, group);
200
+ const onDrag = this._onDrag.bind(this, group);
201
+ const onDragStop = this._onDragStop.bind(this, group);
202
+ const onResizeStart = this._onResizeStart.bind(this, group);
203
+ const onResize = this._onResize.bind(this, group);
204
+ const onResizeStop = this._onResizeStop.bind(this, group);
205
+ const onDrop = this._onDrop.bind(this, group);
206
+ const onDropDragOver = this._onDropDragOver.bind(this, group);
207
+ const onDragTargetRestore = this._onTargetRestore.bind(this, group);
208
+ this._memoCallbacksForGroups[group] = {
209
+ onDragStart,
210
+ onDrag,
211
+ onDragStop,
212
+ onResizeStart,
213
+ onResize,
214
+ onResizeStop,
215
+ onDrop,
216
+ onDropDragOver,
217
+ onDragTargetRestore,
218
+ };
219
+ }
220
+ return this._memoCallbacksForGroups[group];
221
+ }
248
222
  mergeGroupsLayout(group, newLayout, temporaryItem) {
249
223
  const renderLayout = this.getActiveLayout();
250
224
  const itemsByGroup = renderLayout.reduce((memo, item) => {
@@ -260,7 +234,7 @@ class GridLayout extends React.PureComponent {
260
234
  return memo;
261
235
  }, {});
262
236
  return renderLayout.map((currentItem) => {
263
- const itemParent = itemsByGroup[currentItem.i].parent || DEFAULT_GROUP;
237
+ const itemParent = resolveLayoutGroup(itemsByGroup[currentItem.i]);
264
238
  if (itemParent === group) {
265
239
  return newItemsLayoutById[currentItem.i];
266
240
  }
@@ -281,6 +255,81 @@ class GridLayout extends React.PureComponent {
281
255
  this._timeout = setTimeout(() => this.reloadItems(), reloadIntervalRemains <= 0 ? autoupdateIntervalMs : reloadIntervalRemains);
282
256
  }
283
257
  }
258
+ prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element) {
259
+ return {
260
+ group,
261
+ layout,
262
+ oldItem,
263
+ newItem,
264
+ placeholder,
265
+ e,
266
+ element,
267
+ };
268
+ }
269
+ updateeDraggingElementState(group, layoutItem, e) {
270
+ let currentDraggingElement = this.state.currentDraggingElement;
271
+ if (!currentDraggingElement) {
272
+ const { temporaryLayout } = this.context;
273
+ const layoutId = layoutItem.i;
274
+ const item = temporaryLayout
275
+ ? temporaryLayout.dragProps
276
+ : this.context.config.items.find(({ id }) => id === layoutId);
277
+ const { offsetX, offsetY } = e.nativeEvent;
278
+ currentDraggingElement = {
279
+ group,
280
+ layoutItem,
281
+ item,
282
+ cursorPosition: { offsetX, offsetY },
283
+ };
284
+ }
285
+ this.setState({ currentDraggingElement, draggedOverGroup: group });
286
+ }
287
+ _onDragStart(group, _newLayout, layoutItem, _newItem, _placeholder, e, element) {
288
+ var _a;
289
+ (_a = this.context.onDragStart) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, _newLayout, layoutItem, _newItem, _placeholder, e, element));
290
+ if (this.context.dragOverPlugin) {
291
+ this.setState({ isDragging: true });
292
+ }
293
+ else {
294
+ this.updateeDraggingElementState(group, layoutItem, e);
295
+ this.setState({ isDragging: true });
296
+ }
297
+ }
298
+ _onDrag(group, layout, oldItem, newItem, placeholder, e, element) {
299
+ var _a;
300
+ (_a = this.context.onDrag) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
301
+ }
302
+ _onDragStop(group, layout, oldItem, newItem, placeholder, e, element) {
303
+ var _a;
304
+ this._onStop(group, layout);
305
+ (_a = this.context.onDragStop) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
306
+ }
307
+ _onResizeStart(group, layout, oldItem, newItem, placeholder, e, element) {
308
+ var _a;
309
+ this.setState({
310
+ isDragging: true,
311
+ });
312
+ (_a = this.context.onResizeStart) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
313
+ }
314
+ _onResize(group, layout, oldItem, newItem, placeholder, e, element) {
315
+ var _a;
316
+ (_a = this.context.onResize) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
317
+ }
318
+ _onResizeStop(group, layout, oldItem, newItem, placeholder, e, element) {
319
+ var _a;
320
+ (_a = this.context.onResizeStop) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
321
+ }
322
+ _onTargetRestore() {
323
+ if (this.context.temporaryLayout) {
324
+ return;
325
+ }
326
+ const { currentDraggingElement } = this.state;
327
+ if (currentDraggingElement) {
328
+ this.setState({
329
+ draggedOverGroup: currentDraggingElement.group,
330
+ });
331
+ }
332
+ }
284
333
  renderTemporaryPlaceholder() {
285
334
  const { temporaryLayout, noOverlay, draggableHandleClassName } = this.context;
286
335
  if (!temporaryLayout || !temporaryLayout.dragProps) {
@@ -306,13 +355,21 @@ class GridLayout extends React.PureComponent {
306
355
  group === currentDraggingElement.group &&
307
356
  draggedOverGroup !== null &&
308
357
  draggedOverGroup !== group;
309
- return (React.createElement(Layout, Object.assign({}, properties, { compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onResizeStart: this._onResizeStart, onDragStart: callbacks.onDragStart, onDragStop: callbacks.onDragStop, onResizeStop: callbacks.onResizeStop, onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured }, (draggableHandleClassName
358
+ return (React.createElement(Layout
359
+ // Group properties
360
+ , Object.assign({}, properties, {
361
+ // Layout props
362
+ compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }, (draggableHandleClassName
310
363
  ? { draggableHandle: `.${draggableHandleClassName}` }
311
- : null), (outerDnDEnable
364
+ : null), {
365
+ // Default callbacks
366
+ onDragStart: callbacks.onDragStart, onDrag: callbacks.onDrag, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResize: callbacks.onResize, onResizeStop: callbacks.onResizeStop,
367
+ // External Drag N Drop options
368
+ onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured }, (outerDnDEnable
312
369
  ? {
313
370
  isDroppable: true,
314
371
  }
315
- : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
372
+ : null)),
316
373
  renderItems.map((item, i) => {
317
374
  return (React.createElement(GridItem, { forwardedPluginRef: this.getMemoForwardRefCallback(offset + i), key: item.id, id: item.id, item: item, layout: layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), onItemMountChange: onItemMountChange, onItemRender: onItemRender }));
318
375
  }),
@@ -6,7 +6,7 @@ import { COMPACT_TYPE_HORIZONTAL_NOWRAP, DEFAULT_GROUP, DEFAULT_WIDGET_HEIGHT, D
6
6
  import { DashKitContext, DashKitDnDContext, DashkitOvelayControlsContext, } from '../context/DashKitContext';
7
7
  import { useDeepEqualMemo } from '../hooks/useDeepEqualMemo';
8
8
  import { getItemsParams, getItemsState } from '../shared';
9
- import { UpdateManager } from '../utils';
9
+ import { UpdateManager, resolveLayoutGroup } from '../utils';
10
10
  const ITEM_PROPS = ['i', 'h', 'w', 'x', 'y', 'parent'];
11
11
  function useMemoStateContext(props) {
12
12
  // так как мы не хотим хранить параметры виджета с активированной автовысотой в сторе и на сервере, актуальный
@@ -151,7 +151,7 @@ function useMemoStateContext(props) {
151
151
  if (hasNowrapGroups) {
152
152
  layout.forEach((item) => {
153
153
  const widgetId = item.i;
154
- const parentId = item.parent || DEFAULT_GROUP;
154
+ const parentId = resolveLayoutGroup(item);
155
155
  if (nowrapGroups[parentId]) {
156
156
  // Collecting nowrap elements
157
157
  nowrapGroups[parentId].items.push(item);
@@ -284,7 +284,7 @@ function useMemoStateContext(props) {
284
284
  return;
285
285
  }
286
286
  setTemporaryLayout({
287
- data: newLayout,
287
+ data: [...newLayout, item],
288
288
  dragProps,
289
289
  });
290
290
  onDropProp({
@@ -328,6 +328,13 @@ function useMemoStateContext(props) {
328
328
  draggableHandleClassName: props.draggableHandleClassName,
329
329
  outerDnDEnable,
330
330
  dragOverPlugin,
331
+ /* default bypassing handlers */
332
+ onDragStart: props.onDragStart,
333
+ onDrag: props.onDrag,
334
+ onDragStop: props.onDragStop,
335
+ onResizeStart: props.onResizeStart,
336
+ onResize: props.onResize,
337
+ onResizeStop: props.onResizeStop,
331
338
  }), [
332
339
  resultLayout,
333
340
  temporaryLayout,
@@ -356,6 +363,12 @@ function useMemoStateContext(props) {
356
363
  props.draggableHandleClassName,
357
364
  outerDnDEnable,
358
365
  dragOverPlugin,
366
+ props.onDragStart,
367
+ props.onDrag,
368
+ props.onDragStop,
369
+ props.onResizeStart,
370
+ props.onResize,
371
+ props.onResizeStop,
359
372
  ]);
360
373
  const overlayMenuItems = props.overlayMenuItems || props.registerManager.settings.menu;
361
374
  const controlsContextValue = React.useMemo(() => ({
@@ -1,5 +1,5 @@
1
- /// <reference types="react-grid-layout" />
2
1
  /// <reference types="react" />
2
+ import type { Layout, Layouts } from 'react-grid-layout';
3
3
  import type { Config, ConfigItem, ConfigLayout } from '../shared';
4
4
  export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
5
5
  id?: null;
@@ -38,3 +38,11 @@ export interface DashKitGroup {
38
38
  render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
39
39
  gridProperties?: (props: ReactGridLayoutProps) => ReactGridLayoutProps;
40
40
  }
41
+ export type ItemManipulationCallback = (eventData: {
42
+ layout: Layouts;
43
+ oldItem: Layout;
44
+ newItem: Layout;
45
+ placeholder: Layout;
46
+ e: MouseEvent;
47
+ element: HTMLElement;
48
+ }) => void;
@@ -0,0 +1,3 @@
1
+ import type { ConfigLayout } from '../shared/types';
2
+ export declare const resolveLayoutGroup: (item: ConfigLayout) => string;
3
+ export declare const isDefaultLayoutGroup: (item: ConfigLayout) => boolean;
@@ -0,0 +1,10 @@
1
+ import { DEFAULT_GROUP } from '../constants';
2
+ export const resolveLayoutGroup = (item) => {
3
+ if (!item.parent) {
4
+ return DEFAULT_GROUP;
5
+ }
6
+ return item.parent;
7
+ };
8
+ export const isDefaultLayoutGroup = (item) => {
9
+ return item.parent === DEFAULT_GROUP || item.parent === undefined;
10
+ };
@@ -1,2 +1,3 @@
1
1
  export * from './register-manager';
2
2
  export * from './update-manager';
3
+ export * from './group-helpers';
@@ -1,2 +1,3 @@
1
1
  export * from './register-manager';
2
2
  export * from './update-manager';
3
+ export * from './group-helpers';
@@ -21,7 +21,11 @@ export declare const getChangedParams: ({ initiatorItem, stateAndParams, itemsSt
21
21
  }) => {
22
22
  [x: string]: string | string[];
23
23
  };
24
- export declare function reflowLayout(newLayoutItem: ConfigLayout, layout: ConfigLayout[], reflowLayoutOptions: ReflowLayoutOptions): ConfigLayout[];
24
+ export declare function reflowLayout({ newLayoutItem, layout, reflowLayoutOptions, }: {
25
+ newLayoutItem?: ConfigLayout;
26
+ layout: ConfigLayout[];
27
+ reflowLayoutOptions: ReflowLayoutOptions;
28
+ }): ConfigLayout[];
25
29
  export declare class UpdateManager {
26
30
  static addItem({ item, namespace, layout, config, options, }: {
27
31
  item: AddConfigItem;
@@ -5,6 +5,7 @@ import { DEFAULT_GROUP, DEFAULT_NAMESPACE } from '../constants';
5
5
  import { META_KEY, addGroupToQueue, addToQueue, deleteFromQueue, getCurrentVersion, getInitialItemsStateAndParamsMeta, getItemsStateAndParamsMeta, isItemWithGroup, isItemWithTabs, mergeParamsWithAliases, pickActionParamsFromParams, resolveItemInnerId, transformParamsToActionParams, } from '../shared';
6
6
  import { getNewId } from './get-new-id';
7
7
  import { bottom, compact } from './grid-layout';
8
+ import { resolveLayoutGroup } from './group-helpers';
8
9
  extend('$auto', (value, object) => (object ? update(object, value) : update({}, value)));
9
10
  function removeItemVersion1({ id, config, itemsStateAndParams }) {
10
11
  const itemIndex = config.items.findIndex((item) => item.id === id);
@@ -222,11 +223,11 @@ function changeGroupParams({ groupItemIds, initiatorId, initiatorItem, itemsStat
222
223
  };
223
224
  return update(itemsStateAndParams, obj);
224
225
  }
225
- export function reflowLayout(newLayoutItem, layout, reflowLayoutOptions) {
226
+ export function reflowLayout({ newLayoutItem, layout, reflowLayoutOptions, }) {
226
227
  const byGroup = {};
227
228
  const reducer = (memo, item, i, _items, isNewItem) => {
228
229
  memo[item.i] = i;
229
- const parent = item.parent || DEFAULT_GROUP;
230
+ const parent = resolveLayoutGroup(item);
230
231
  if (byGroup[parent]) {
231
232
  if (isNewItem) {
232
233
  byGroup[parent].unshift(item);
@@ -241,7 +242,9 @@ export function reflowLayout(newLayoutItem, layout, reflowLayoutOptions) {
241
242
  return memo;
242
243
  };
243
244
  const orderById = layout.reduce(reducer, {});
244
- reducer(orderById, newLayoutItem, layout.length, layout, true);
245
+ if (newLayoutItem) {
246
+ reducer(orderById, newLayoutItem, layout.length, layout, true);
247
+ }
245
248
  const { defaultProps } = reflowLayoutOptions;
246
249
  return Object.entries(byGroup)
247
250
  .reduce((memo, [groupId, layoutItems]) => {
@@ -281,7 +284,11 @@ export class UpdateManager {
281
284
  let newLayout;
282
285
  const newLayoutItem = Object.assign(Object.assign({}, saveDefaultLayout), { i: newItem.id });
283
286
  if (options.reflowLayoutOptions) {
284
- newLayout = reflowLayout(newLayoutItem, config.layout.map((t) => (Object.assign(Object.assign({}, t), (byId[t.i] || {})))), options.reflowLayoutOptions);
287
+ newLayout = reflowLayout({
288
+ newLayoutItem,
289
+ layout: config.layout.map((t) => (Object.assign(Object.assign({}, t), (byId[t.i] || {})))),
290
+ reflowLayoutOptions: options.reflowLayoutOptions,
291
+ });
285
292
  }
286
293
  else {
287
294
  newLayout = [
@@ -299,7 +306,11 @@ export class UpdateManager {
299
306
  let newLayout;
300
307
  const newLayoutItem = Object.assign(Object.assign({}, saveDefaultLayout), { i: newItem.id });
301
308
  if (options.reflowLayoutOptions) {
302
- newLayout = reflowLayout(newLayoutItem, config.layout, options.reflowLayoutOptions);
309
+ newLayout = reflowLayout({
310
+ newLayoutItem,
311
+ layout: config.layout,
312
+ reflowLayoutOptions: options.reflowLayoutOptions,
313
+ });
303
314
  }
304
315
  else {
305
316
  newLayout = [...config.layout, newLayoutItem];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dashkit",
3
- "version": "8.12.1",
3
+ "version": "8.14.0",
4
4
  "description": "Library for rendering dashboard grid layout",
5
5
  "license": "MIT",
6
6
  "repository": {