@gravity-ui/dashkit 8.17.4 → 8.18.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.
Files changed (28) hide show
  1. package/README.md +9 -0
  2. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +2 -1
  3. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.js +8 -7
  4. package/build/cjs/components/GridItem/GridItem.css +5 -0
  5. package/build/cjs/components/GridLayout/GridLayout.d.ts +1 -1
  6. package/build/cjs/components/GridLayout/GridLayout.js +38 -30
  7. package/build/cjs/components/GridLayout/ReactGridLayout.js +19 -17
  8. package/build/cjs/components/OverlayControls/OverlayControls.js +4 -5
  9. package/build/cjs/constants/common.d.ts +1 -0
  10. package/build/cjs/constants/common.js +2 -1
  11. package/build/cjs/hocs/withContext.js +23 -12
  12. package/build/cjs/shared/types/common.d.ts +4 -0
  13. package/build/cjs/typings/common.d.ts +4 -1
  14. package/build/cjs/typings/config.d.ts +2 -1
  15. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +2 -1
  16. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.js +8 -7
  17. package/build/esm/components/GridItem/GridItem.css +5 -0
  18. package/build/esm/components/GridLayout/GridLayout.d.ts +1 -1
  19. package/build/esm/components/GridLayout/GridLayout.js +38 -30
  20. package/build/esm/components/GridLayout/ReactGridLayout.js +20 -18
  21. package/build/esm/components/OverlayControls/OverlayControls.js +4 -5
  22. package/build/esm/constants/common.d.ts +1 -0
  23. package/build/esm/constants/common.js +1 -0
  24. package/build/esm/hocs/withContext.js +23 -12
  25. package/build/esm/shared/types/common.d.ts +4 -0
  26. package/build/esm/typings/common.d.ts +4 -1
  27. package/build/esm/typings/config.d.ts +2 -1
  28. package/package.json +1 -1
package/README.md CHANGED
@@ -384,10 +384,19 @@ DashKit.setSettings({menu: [] as Array<MenuItem>});
384
384
  #### DashKitDnDWrapper
385
385
 
386
386
  ```ts
387
+ type DraggedOverItem = {
388
+ h: number;
389
+ w: number;
390
+ type: string;
391
+ parent: string;
392
+ i?: number;
393
+ };
394
+
387
395
  interface DashKitDnDWrapperProps {
388
396
  dragImageSrc?: string;
389
397
  onDragStart?: (dragProps: ItemDragProps) => void;
390
398
  onDragEnd?: () => void;
399
+ onDropDragOver?: (draggedItem: DraggedOverItem, sharedItem: DraggedOverItem | null) => void | boolean;
391
400
  }
392
401
  ```
393
402
 
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import type { ItemDragProps } from '../../shared';
2
+ import type { DraggedOverItem, ItemDragProps } from '../../shared';
3
3
  type DashKitDnDWrapperProps = {
4
4
  dragImageSrc?: string;
5
+ onDropDragOver?: (draggedItem: DraggedOverItem, sharedItem: DraggedOverItem | null) => void | boolean;
5
6
  onDragStart?: (dragProps: ItemDragProps) => void;
6
7
  onDragEnd?: () => void;
7
8
  children: React.ReactElement;
@@ -12,24 +12,25 @@ const DashKitDnDWrapper = (props) => {
12
12
  img.src = props.dragImageSrc || defaultImageSrc;
13
13
  return img;
14
14
  }, [props.dragImageSrc]);
15
+ const onDragStartProp = props.onDragStart;
15
16
  const onDragStart = react_1.default.useCallback((_, itemDragProps) => {
16
- var _a;
17
17
  setDragProps(itemDragProps);
18
- (_a = props.onDragStart) === null || _a === void 0 ? void 0 : _a.call(props, itemDragProps);
19
- }, [setDragProps, props.onDragStart]);
18
+ onDragStartProp === null || onDragStartProp === void 0 ? void 0 : onDragStartProp(itemDragProps);
19
+ }, [setDragProps, onDragStartProp]);
20
+ const onDragEndProp = props.onDragEnd;
20
21
  const onDragEnd = react_1.default.useCallback((_) => {
21
- var _a;
22
22
  setDragProps(null);
23
- (_a = props.onDragEnd) === null || _a === void 0 ? void 0 : _a.call(props);
24
- }, [setDragProps, props.onDragEnd]);
23
+ onDragEndProp === null || onDragEndProp === void 0 ? void 0 : onDragEndProp();
24
+ }, [setDragProps, onDragEndProp]);
25
25
  const contextValue = react_1.default.useMemo(() => {
26
26
  return {
27
27
  dragProps,
28
28
  dragImagePreview,
29
29
  onDragStart,
30
30
  onDragEnd,
31
+ onDropDragOver: props.onDropDragOver,
31
32
  };
32
- }, [dragProps, dragImagePreview, onDragStart, onDragEnd]);
33
+ }, [dragProps, dragImagePreview, onDragStart, onDragEnd, props.onDropDragOver]);
33
34
  return (react_1.default.createElement(DashKitContext_1.DashKitDnDContext.Provider, { value: contextValue }, props.children));
34
35
  };
35
36
  exports.DashKitDnDWrapper = DashKitDnDWrapper;
@@ -38,6 +38,11 @@
38
38
  pointer-events: none;
39
39
  }
40
40
 
41
+ .react-grid-item.dropping {
42
+ user-select: none;
43
+ pointer-events: none;
44
+ }
45
+
41
46
  .react-grid-layout {
42
47
  position: relative;
43
48
  transition: height 200ms ease;
@@ -4,10 +4,10 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
4
4
  pluginsRefs: any[];
5
5
  state: {
6
6
  isDragging: boolean;
7
+ isDraggedOut: boolean;
7
8
  isPageHidden: boolean;
8
9
  currentDraggingElement: null;
9
10
  draggedOverGroup: null;
10
- draggedOut: boolean;
11
11
  };
12
12
  componentDidMount(): void;
13
13
  componentDidUpdate(): void;
@@ -142,20 +142,27 @@ class GridLayout extends react_1.default.PureComponent {
142
142
  if (currentDraggingElement) {
143
143
  const { h, w, i } = currentDraggingElement.layoutItem;
144
144
  const { type } = currentDraggingElement.item;
145
- return onDropDragOver(e, properties, layout, { h, w, i, type });
145
+ const sharedItem = {
146
+ h,
147
+ w,
148
+ i,
149
+ type,
150
+ parent: currentDraggingElement.group,
151
+ };
152
+ return onDropDragOver(e, group, properties, layout, sharedItem);
146
153
  }
147
154
  if (dragOverPlugin) {
148
- return onDropDragOver(e, properties, layout);
155
+ return onDropDragOver(e, group, properties, layout);
149
156
  }
150
157
  return false;
151
158
  };
152
159
  this.pluginsRefs = [];
153
160
  this.state = {
154
161
  isDragging: false,
162
+ isDraggedOut: false,
155
163
  isPageHidden: false,
156
164
  currentDraggingElement: null,
157
165
  draggedOverGroup: null,
158
- draggedOut: false,
159
166
  };
160
167
  }
161
168
  componentDidMount() {
@@ -291,7 +298,7 @@ class GridLayout extends react_1.default.PureComponent {
291
298
  _initDragCoordinatesWatcher(element) {
292
299
  if (!this._parendDragNode) {
293
300
  this._parendDragNode = element.parentElement;
294
- this.setState({ draggedOut: false });
301
+ this.setState({ isDraggedOut: false });
295
302
  }
296
303
  }
297
304
  // When element is going back and prointer-event: none is removed mouse enter event is not fired
@@ -317,19 +324,19 @@ class GridLayout extends react_1.default.PureComponent {
317
324
  const parent = this._parendDragNode;
318
325
  const parentRect = parent.getBoundingClientRect();
319
326
  const { clientX, clientY } = e;
320
- let draggedOut = this.state.draggedOut;
327
+ let isDraggedOut = this.state.isDraggedOut;
321
328
  if (clientX < parentRect.left ||
322
329
  clientX > parentRect.right ||
323
330
  clientY < parentRect.top ||
324
331
  clientY > parentRect.bottom) {
325
- draggedOut = true;
332
+ isDraggedOut = true;
326
333
  }
327
334
  else {
328
- draggedOut = false;
335
+ isDraggedOut = false;
329
336
  }
330
- if (draggedOut !== this.state.draggedOut) {
331
- this.setState({ draggedOut });
332
- if (!draggedOut) {
337
+ if (isDraggedOut !== this.state.isDraggedOut) {
338
+ this.setState({ isDraggedOut });
339
+ if (!isDraggedOut) {
333
340
  this._forceCursorCapture(parent, {
334
341
  top: clientY - parentRect.top,
335
342
  left: clientX - parentRect.left,
@@ -339,23 +346,25 @@ class GridLayout extends react_1.default.PureComponent {
339
346
  }
340
347
  _resetDragWatcher() {
341
348
  this._parendDragNode = null;
342
- this.setState({ draggedOut: false });
349
+ this.setState({ isDraggedOut: false });
343
350
  }
344
351
  _onDragStart(group, _newLayout, layoutItem, _newItem, _placeholder, e, element) {
345
352
  var _a;
346
353
  (_a = this.context.onDragStart) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, _newLayout, layoutItem, _newItem, _placeholder, e, element));
347
- this._initDragCoordinatesWatcher(element);
348
354
  if (this.context.dragOverPlugin) {
349
355
  this.setState({ isDragging: true });
350
356
  }
351
357
  else {
358
+ this._initDragCoordinatesWatcher(element);
352
359
  this.updateDraggingElementState(group, layoutItem, e);
353
360
  this.setState({ isDragging: true });
354
361
  }
355
362
  }
356
363
  _onDrag(group, layout, oldItem, newItem, placeholder, e, element) {
357
364
  var _a;
358
- this._updateDragCoordinates(e);
365
+ if (!this.context.dragOverPlugin) {
366
+ this._updateDragCoordinates(e);
367
+ }
359
368
  (_a = this.context.onDrag) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
360
369
  }
361
370
  _onDragStop(group, layout, oldItem, newItem, placeholder, e, element) {
@@ -403,7 +412,8 @@ class GridLayout extends react_1.default.PureComponent {
403
412
  renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
404
413
  const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, onItemMountChange, onItemRender, } = this.context;
405
414
  const { currentDraggingElement, draggedOverGroup } = this.state;
406
- const properties = groupGridProperties
415
+ const hasOwnGroupProperties = typeof groupGridProperties === 'function';
416
+ const properties = hasOwnGroupProperties
407
417
  ? groupGridProperties(Object.assign({}, registerManager.gridLayout))
408
418
  : registerManager.gridLayout;
409
419
  let { compactType } = properties;
@@ -416,25 +426,22 @@ class GridLayout extends react_1.default.PureComponent {
416
426
  group === currentDraggingElement.group &&
417
427
  draggedOverGroup !== null &&
418
428
  draggedOverGroup !== group;
419
- return (react_1.default.createElement(ReactGridLayout_1.Layout
420
- // Group properties
421
- , Object.assign({}, properties, {
429
+ return (react_1.default.createElement(ReactGridLayout_1.Layout, Object.assign({ isDraggable: editMode, isResizable: editMode }, properties, { key: `group_${group}`,
422
430
  // Layout props
423
- compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, draggableCancel: `.${constants_1.DRAGGABLE_CANCEL_CLASS_NAME}` }, (draggableHandleClassName
424
- ? { draggableHandle: `.${draggableHandleClassName}` }
425
- : null), {
431
+ compactType: compactType, layout: layout, draggableCancel: `.${constants_1.DRAGGABLE_CANCEL_CLASS_NAME}`, draggableHandle: draggableHandleClassName ? `.${draggableHandleClassName}` : null,
426
432
  // Default callbacks
427
433
  onDragStart: callbacks.onDragStart, onDrag: callbacks.onDrag, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResize: callbacks.onResize, onResizeStop: callbacks.onResizeStop,
428
434
  // External Drag N Drop options
429
- onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured }, (outerDnDEnable
430
- ? {
431
- isDroppable: true,
432
- }
433
- : null)),
435
+ onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured, isDroppable: Boolean(outerDnDEnable) && editMode }),
434
436
  renderItems.map((item, i) => {
435
- const isCurrentItem = (currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.item.id) === item.id;
436
- const isDraggedOut = isCurrentItem && this.state.draggedOut;
437
- 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, isDraggedOut: isDraggedOut, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), onItemMountChange: onItemMountChange, onItemRender: onItemRender }));
437
+ const keyId = item.id;
438
+ const isDragging = this.state.isDragging;
439
+ const isCurrentDraggedItem = (currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.item.id) === keyId;
440
+ const isDraggedOut = isCurrentDraggedItem && this.state.isDraggedOut;
441
+ const itemNoOverlay = hasOwnGroupProperties && 'noOverlay' in properties
442
+ ? properties.noOverlay
443
+ : noOverlay;
444
+ return (react_1.default.createElement(GridItem_1.default, { forwardedPluginRef: this.getMemoForwardRefCallback(offset + i), key: keyId, id: keyId, item: item, layout: layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: isDragging, isDraggedOut: isDraggedOut, noOverlay: itemNoOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), onItemMountChange: onItemMountChange, onItemRender: onItemRender }));
438
445
  }),
439
446
  this.renderTemporaryPlaceholder()));
440
447
  }
@@ -486,13 +493,14 @@ class GridLayout extends react_1.default.PureComponent {
486
493
  const element = this.renderGroup(id, layout, items, offset, group.gridProperties);
487
494
  offset += items.length;
488
495
  if (group.render) {
489
- return group.render(id, element, {
496
+ const groupContext = {
490
497
  config,
491
498
  editMode,
492
499
  items,
493
500
  layout,
494
501
  context,
495
- });
502
+ };
503
+ return group.render(id, element, groupContext);
496
504
  }
497
505
  return element;
498
506
  });
@@ -157,6 +157,20 @@ class DragOverLayout extends react_grid_layout_1.default {
157
157
  var _a;
158
158
  return ((_a = this.props.innerRef) === null || _a === void 0 ? void 0 : _a.current) || null;
159
159
  }
160
+ calculateDroppingPosition(itemProps) {
161
+ const { containerWidth, cols, w, h, rowHeight, margin, transformScale, droppingPosition } = itemProps;
162
+ const { sharedDragPosition } = this.props;
163
+ let offsetX, offsetY;
164
+ if (sharedDragPosition) {
165
+ offsetX = sharedDragPosition.offsetX;
166
+ offsetY = sharedDragPosition.offsetY;
167
+ }
168
+ else {
169
+ offsetX = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
170
+ offsetY = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
171
+ }
172
+ return Object.assign(Object.assign({}, droppingPosition), { left: droppingPosition.left - offsetX, top: droppingPosition.top - offsetY });
173
+ }
160
174
  // Drop item from outside gets 0,0 droppingPosition
161
175
  // centering cursor on newly creted grid item
162
176
  // And cause grid-layout using it's own GridItem to make it look
@@ -167,26 +181,14 @@ class DragOverLayout extends react_grid_layout_1.default {
167
181
  if (!gridItem) {
168
182
  return gridItem;
169
183
  }
170
- const { props: itemProps } = gridItem;
171
184
  if (isDroppingItem) {
172
- const { containerWidth, cols, w, h, rowHeight, margin, transformScale, droppingPosition, } = itemProps;
173
- const { sharedDragPosition, hasSharedDragItem } = this.props;
174
- let offsetX, offsetY;
175
- if (sharedDragPosition) {
176
- offsetX = sharedDragPosition.offsetX;
177
- offsetY = sharedDragPosition.offsetY;
178
- }
179
- else {
180
- offsetX = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
181
- offsetY = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
182
- }
183
- const style = gridItem.props.style || null;
184
185
  // React.cloneElement is just cleaner then copy-paste whole processGridItem method
185
186
  return react_1.default.cloneElement(gridItem, {
186
- // hiding previre if dragging shared item
187
- style: hasSharedDragItem ? Object.assign(Object.assign({}, style), { opacity: 0 }) : style,
188
- className: constants_1.OVERLAY_CLASS_NAME,
189
- droppingPosition: Object.assign(Object.assign({}, droppingPosition), { left: droppingPosition.left - offsetX, top: droppingPosition.top - offsetY }),
187
+ // hiding preview if dragging shared item
188
+ style: this.props.hasSharedDragItem
189
+ ? Object.assign(Object.assign({}, gridItem.props.style), { opacity: 0 }) : gridItem.props.style,
190
+ className: `${constants_1.OVERLAY_CLASS_NAME} ${constants_1.DROPPING_ELEMENT_CLASS_NAME}`,
191
+ droppingPosition: this.calculateDroppingPosition(gridItem.props),
190
192
  });
191
193
  }
192
194
  return gridItem;
@@ -32,7 +32,7 @@ class OverlayControls extends react_1.default.Component {
32
32
  const { view, size, onItemClick } = this.props;
33
33
  const { title, handler, icon, iconSize, qa } = item;
34
34
  const onItemClickHandler = typeof handler === 'function' ? handler : noop_1.default;
35
- return (react_1.default.createElement(uikit_1.Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => {
35
+ return (react_1.default.createElement(uikit_1.Button, { key: `control_${index}`, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => {
36
36
  onItemClickHandler(this.props.configItem);
37
37
  onItemClick === null || onItemClick === void 0 ? void 0 : onItemClick();
38
38
  }, qa: qa },
@@ -43,7 +43,7 @@ class OverlayControls extends react_1.default.Component {
43
43
  if (this.context.overlayControls === null) {
44
44
  return null;
45
45
  }
46
- return (react_1.default.createElement(uikit_1.Button, { view: view, size: size, title: (0, i18n_1.i18n)('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
46
+ return (react_1.default.createElement(uikit_1.Button, { key: 'control_default', view: view, size: size, title: (0, i18n_1.i18n)('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
47
47
  react_1.default.createElement(uikit_1.Icon, { data: icons_1.Gear, size: constants_1.OVERLAY_ICON_SIZE })));
48
48
  };
49
49
  this.getCustomLeftOverlayControls = () => {
@@ -161,10 +161,9 @@ class OverlayControls extends react_1.default.Component {
161
161
  renderControls() {
162
162
  const customLeftControls = this.getCustomLeftOverlayControls();
163
163
  const hasCustomOverlayLeftControls = Boolean(customLeftControls.length);
164
- const defaultControl = this.getDefaultControls();
165
164
  const controls = hasCustomOverlayLeftControls
166
165
  ? customLeftControls.map((item, index, items) => this.renderControlsItem(item, index, items.length + 1))
167
- : defaultControl;
166
+ : this.getDefaultControls();
168
167
  const menu = this.renderMenu(controls === null);
169
168
  return (react_1.default.createElement("div", { className: b('default-controls', {
170
169
  'with-custom-left': hasCustomOverlayLeftControls,
@@ -231,7 +230,7 @@ class OverlayControls extends react_1.default.Component {
231
230
  if (items.length === 0) {
232
231
  return null;
233
232
  }
234
- return (react_1.default.createElement(uikit_1.DropdownMenu, { items: items, renderSwitcher: (props) => (react_1.default.createElement(uikit_1.Button, Object.assign({}, props, { view: view, size: size, pin: isOnlyOneItem ? 'round-round' : 'brick-round', qa: "dashkit-overlay-control-menu" }),
233
+ return (react_1.default.createElement(uikit_1.DropdownMenu, { key: 'controls_dropdown', items: items, renderSwitcher: (props) => (react_1.default.createElement(uikit_1.Button, Object.assign({}, props, { view: view, size: size, pin: isOnlyOneItem ? 'round-round' : 'brick-round', qa: "dashkit-overlay-control-menu" }),
235
234
  react_1.default.createElement(uikit_1.Icon, { data: icons_1.Ellipsis, size: constants_1.OVERLAY_ICON_SIZE }))), popupProps: {
236
235
  contentClassName: constants_1.DRAGGABLE_CANCEL_CLASS_NAME,
237
236
  } }));
@@ -15,3 +15,4 @@ export declare const DEFAULT_GROUP = "__default";
15
15
  export declare const COMPACT_TYPE_HORIZONTAL_NOWRAP = "horizontal-nowrap";
16
16
  export declare const DRAGGABLE_CANCEL_CLASS_NAME = "dashkit_draggable_cancel";
17
17
  export declare const FOCUSED_CLASS_NAME = "dashkit_focused";
18
+ export declare const DROPPING_ELEMENT_CLASS_NAME = "dropping";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FOCUSED_CLASS_NAME = exports.DRAGGABLE_CANCEL_CLASS_NAME = exports.COMPACT_TYPE_HORIZONTAL_NOWRAP = exports.DEFAULT_GROUP = exports.DEFAULT_WIDGET_WIDTH = exports.DEFAULT_WIDGET_HEIGHT = exports.MenuItems = exports.TEMPORARY_ITEM_ID = exports.OVERLAY_ICON_SIZE = exports.OVERLAY_CLASS_NAME = exports.OVERLAY_CONTROLS_CLASS_NAME = exports.DEFAULT_NAMESPACE = exports.COPIED_WIDGET_STORE_KEY = void 0;
3
+ exports.DROPPING_ELEMENT_CLASS_NAME = exports.FOCUSED_CLASS_NAME = exports.DRAGGABLE_CANCEL_CLASS_NAME = exports.COMPACT_TYPE_HORIZONTAL_NOWRAP = exports.DEFAULT_GROUP = exports.DEFAULT_WIDGET_WIDTH = exports.DEFAULT_WIDGET_HEIGHT = exports.MenuItems = exports.TEMPORARY_ITEM_ID = exports.OVERLAY_ICON_SIZE = exports.OVERLAY_CLASS_NAME = exports.OVERLAY_CONTROLS_CLASS_NAME = exports.DEFAULT_NAMESPACE = exports.COPIED_WIDGET_STORE_KEY = void 0;
4
4
  exports.COPIED_WIDGET_STORE_KEY = 'dashCopiedItem';
5
5
  exports.DEFAULT_NAMESPACE = 'default';
6
6
  exports.OVERLAY_CONTROLS_CLASS_NAME = 'dashkit-overlay-controls';
@@ -18,3 +18,4 @@ exports.DEFAULT_GROUP = '__default';
18
18
  exports.COMPACT_TYPE_HORIZONTAL_NOWRAP = 'horizontal-nowrap';
19
19
  exports.DRAGGABLE_CANCEL_CLASS_NAME = 'dashkit_draggable_cancel';
20
20
  exports.FOCUSED_CLASS_NAME = 'dashkit_focused';
21
+ exports.DROPPING_ELEMENT_CLASS_NAME = 'dropping';
@@ -232,12 +232,13 @@ function useMemoStateContext(props) {
232
232
  const reloadItems = react_1.default.useCallback((pluginsRefs, data) => {
233
233
  pluginsRefs.forEach((ref) => ref && ref.reload && ref.reload(data));
234
234
  }, []);
235
- const dragProps = dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragProps;
235
+ const dragPropsContext = dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragProps;
236
+ const onDropDragOverContext = dndContext === null || dndContext === void 0 ? void 0 : dndContext.onDropDragOver;
236
237
  const dragOverPlugin = react_1.default.useMemo(() => {
237
- if (!dragProps) {
238
+ if (!dragPropsContext) {
238
239
  return null;
239
240
  }
240
- const pluginType = dragProps.type;
241
+ const pluginType = dragPropsContext.type;
241
242
  if (props.registerManager.check(pluginType)) {
242
243
  return props.registerManager.getItem(pluginType);
243
244
  }
@@ -246,8 +247,8 @@ function useMemoStateContext(props) {
246
247
  console.error(`Uknown pluginType: ${pluginType}`);
247
248
  return null;
248
249
  }
249
- }, [dragProps, props.registerManager]);
250
- const onDropDragOver = react_1.default.useCallback((_e, gridProps, groupLayout, sharedItem) => {
250
+ }, [dragPropsContext, props.registerManager]);
251
+ const onDropDragOver = react_1.default.useCallback((_e, group, gridProps, groupLayout, sharedItem) => {
251
252
  if (temporaryLayout) {
252
253
  resetTemporaryLayout();
253
254
  return false;
@@ -275,20 +276,30 @@ function useMemoStateContext(props) {
275
276
  maxH < defaultLayout.minH) {
276
277
  return false;
277
278
  }
278
- const { h = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.h) || common_1.DEFAULT_WIDGET_HEIGHT, w = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.w) || common_1.DEFAULT_WIDGET_WIDTH, } = (dragProps === null || dragProps === void 0 ? void 0 : dragProps.layout) || {};
279
- return {
279
+ const { h = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.h) || common_1.DEFAULT_WIDGET_HEIGHT, w = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.w) || common_1.DEFAULT_WIDGET_WIDTH, } = (dragPropsContext === null || dragPropsContext === void 0 ? void 0 : dragPropsContext.layout) || {};
280
+ const itemLayout = {
280
281
  h: maxH ? Math.min(h, maxH) : h,
281
282
  w: maxW ? Math.min(w, maxW) : w,
282
283
  };
283
- }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
284
+ if ((onDropDragOverContext === null || onDropDragOverContext === void 0 ? void 0 : onDropDragOverContext(Object.assign(Object.assign(Object.assign({}, sharedItem), itemLayout), { parent: group }), sharedItem !== null && sharedItem !== void 0 ? sharedItem : null)) === false) {
285
+ return false;
286
+ }
287
+ return itemLayout;
288
+ }, [
289
+ resetTemporaryLayout,
290
+ temporaryLayout,
291
+ dragOverPlugin,
292
+ dragPropsContext,
293
+ onDropDragOverContext,
294
+ ]);
284
295
  const onDropProp = props.onDrop;
285
296
  const onDrop = react_1.default.useCallback((newLayout, item) => {
286
- if (!dragProps) {
297
+ if (!dragPropsContext) {
287
298
  return;
288
299
  }
289
300
  setTemporaryLayout({
290
301
  data: [...newLayout, item],
291
- dragProps,
302
+ dragProps: dragPropsContext,
292
303
  });
293
304
  onDropProp({
294
305
  newLayout: newLayout.reduce((memo, l) => {
@@ -299,9 +310,9 @@ function useMemoStateContext(props) {
299
310
  }, []),
300
311
  itemLayout: (0, pick_1.default)(item, ITEM_PROPS),
301
312
  commit: resetTemporaryLayout,
302
- dragProps,
313
+ dragProps: dragPropsContext,
303
314
  });
304
- }, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
315
+ }, [dragPropsContext, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
305
316
  const dashkitContextValue = react_1.default.useMemo(() => ({
306
317
  layout: resultLayout,
307
318
  temporaryLayout,
@@ -12,6 +12,10 @@ export type ItemDragProps = {
12
12
  };
13
13
  extra?: any;
14
14
  };
15
+ export type DraggedOverItem = Omit<ConfigLayout, 'x' | 'y' | 'i'> & {
16
+ type: string;
17
+ i?: ConfigLayout['i'];
18
+ };
15
19
  export type ItemDropProps = {
16
20
  commit: () => void;
17
21
  dragProps: ItemDragProps;
@@ -2,8 +2,11 @@ import type ReactGridLayout from 'react-grid-layout';
2
2
  import type { OverlayCustomControlItem } from '../components/OverlayControls/OverlayControls';
3
3
  import { MenuItems } from '../constants';
4
4
  import { AdditionalWidgetLayout } from '../shared';
5
+ export type GridLayoutSettings = ReactGridLayout.ReactGridLayoutProps & {
6
+ noOverlay?: boolean;
7
+ };
5
8
  export interface Settings {
6
- gridLayout?: ReactGridLayout.ReactGridLayoutProps;
9
+ gridLayout?: GridLayoutSettings;
7
10
  theme?: string;
8
11
  isMobile?: boolean;
9
12
  menu?: Array<MenuItem>;
@@ -1,6 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import type { Layout, Layouts } from 'react-grid-layout';
3
3
  import type { Config, ConfigItem, ConfigLayout } from '../shared';
4
+ import { GridLayoutSettings } from './common';
4
5
  export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
5
6
  id?: null;
6
7
  namespace?: string;
@@ -31,7 +32,7 @@ export interface DashkitGroupRenderProps {
31
32
  layout: ConfigLayout[];
32
33
  context: any;
33
34
  }
34
- export type ReactGridLayoutProps = Omit<ReactGridLayout.ReactGridLayoutProps, 'children' | 'compactType' | 'innerRef' | 'key' | 'layout' | 'isDraggable' | 'isResizable' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'> & {
35
+ export type ReactGridLayoutProps = Omit<GridLayoutSettings, 'children' | 'compactType' | 'innerRef' | 'key' | 'layout' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'> & {
35
36
  compactType?: CompactType;
36
37
  };
37
38
  export interface DashKitGroup {
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import type { ItemDragProps } from '../../shared';
2
+ import type { DraggedOverItem, ItemDragProps } from '../../shared';
3
3
  type DashKitDnDWrapperProps = {
4
4
  dragImageSrc?: string;
5
+ onDropDragOver?: (draggedItem: DraggedOverItem, sharedItem: DraggedOverItem | null) => void | boolean;
5
6
  onDragStart?: (dragProps: ItemDragProps) => void;
6
7
  onDragEnd?: () => void;
7
8
  children: React.ReactElement;
@@ -8,23 +8,24 @@ export const DashKitDnDWrapper = (props) => {
8
8
  img.src = props.dragImageSrc || defaultImageSrc;
9
9
  return img;
10
10
  }, [props.dragImageSrc]);
11
+ const onDragStartProp = props.onDragStart;
11
12
  const onDragStart = React.useCallback((_, itemDragProps) => {
12
- var _a;
13
13
  setDragProps(itemDragProps);
14
- (_a = props.onDragStart) === null || _a === void 0 ? void 0 : _a.call(props, itemDragProps);
15
- }, [setDragProps, props.onDragStart]);
14
+ onDragStartProp === null || onDragStartProp === void 0 ? void 0 : onDragStartProp(itemDragProps);
15
+ }, [setDragProps, onDragStartProp]);
16
+ const onDragEndProp = props.onDragEnd;
16
17
  const onDragEnd = React.useCallback((_) => {
17
- var _a;
18
18
  setDragProps(null);
19
- (_a = props.onDragEnd) === null || _a === void 0 ? void 0 : _a.call(props);
20
- }, [setDragProps, props.onDragEnd]);
19
+ onDragEndProp === null || onDragEndProp === void 0 ? void 0 : onDragEndProp();
20
+ }, [setDragProps, onDragEndProp]);
21
21
  const contextValue = React.useMemo(() => {
22
22
  return {
23
23
  dragProps,
24
24
  dragImagePreview,
25
25
  onDragStart,
26
26
  onDragEnd,
27
+ onDropDragOver: props.onDropDragOver,
27
28
  };
28
- }, [dragProps, dragImagePreview, onDragStart, onDragEnd]);
29
+ }, [dragProps, dragImagePreview, onDragStart, onDragEnd, props.onDropDragOver]);
29
30
  return (React.createElement(DashKitDnDContext.Provider, { value: contextValue }, props.children));
30
31
  };
@@ -38,6 +38,11 @@
38
38
  pointer-events: none;
39
39
  }
40
40
 
41
+ .react-grid-item.dropping {
42
+ user-select: none;
43
+ pointer-events: none;
44
+ }
45
+
41
46
  .react-grid-layout {
42
47
  position: relative;
43
48
  transition: height 200ms ease;
@@ -4,10 +4,10 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
4
4
  pluginsRefs: any[];
5
5
  state: {
6
6
  isDragging: boolean;
7
+ isDraggedOut: boolean;
7
8
  isPageHidden: boolean;
8
9
  currentDraggingElement: null;
9
10
  draggedOverGroup: null;
10
- draggedOut: boolean;
11
11
  };
12
12
  componentDidMount(): void;
13
13
  componentDidUpdate(): void;
@@ -139,20 +139,27 @@ class GridLayout extends React.PureComponent {
139
139
  if (currentDraggingElement) {
140
140
  const { h, w, i } = currentDraggingElement.layoutItem;
141
141
  const { type } = currentDraggingElement.item;
142
- return onDropDragOver(e, properties, layout, { h, w, i, type });
142
+ const sharedItem = {
143
+ h,
144
+ w,
145
+ i,
146
+ type,
147
+ parent: currentDraggingElement.group,
148
+ };
149
+ return onDropDragOver(e, group, properties, layout, sharedItem);
143
150
  }
144
151
  if (dragOverPlugin) {
145
- return onDropDragOver(e, properties, layout);
152
+ return onDropDragOver(e, group, properties, layout);
146
153
  }
147
154
  return false;
148
155
  };
149
156
  this.pluginsRefs = [];
150
157
  this.state = {
151
158
  isDragging: false,
159
+ isDraggedOut: false,
152
160
  isPageHidden: false,
153
161
  currentDraggingElement: null,
154
162
  draggedOverGroup: null,
155
- draggedOut: false,
156
163
  };
157
164
  }
158
165
  componentDidMount() {
@@ -288,7 +295,7 @@ class GridLayout extends React.PureComponent {
288
295
  _initDragCoordinatesWatcher(element) {
289
296
  if (!this._parendDragNode) {
290
297
  this._parendDragNode = element.parentElement;
291
- this.setState({ draggedOut: false });
298
+ this.setState({ isDraggedOut: false });
292
299
  }
293
300
  }
294
301
  // When element is going back and prointer-event: none is removed mouse enter event is not fired
@@ -314,19 +321,19 @@ class GridLayout extends React.PureComponent {
314
321
  const parent = this._parendDragNode;
315
322
  const parentRect = parent.getBoundingClientRect();
316
323
  const { clientX, clientY } = e;
317
- let draggedOut = this.state.draggedOut;
324
+ let isDraggedOut = this.state.isDraggedOut;
318
325
  if (clientX < parentRect.left ||
319
326
  clientX > parentRect.right ||
320
327
  clientY < parentRect.top ||
321
328
  clientY > parentRect.bottom) {
322
- draggedOut = true;
329
+ isDraggedOut = true;
323
330
  }
324
331
  else {
325
- draggedOut = false;
332
+ isDraggedOut = false;
326
333
  }
327
- if (draggedOut !== this.state.draggedOut) {
328
- this.setState({ draggedOut });
329
- if (!draggedOut) {
334
+ if (isDraggedOut !== this.state.isDraggedOut) {
335
+ this.setState({ isDraggedOut });
336
+ if (!isDraggedOut) {
330
337
  this._forceCursorCapture(parent, {
331
338
  top: clientY - parentRect.top,
332
339
  left: clientX - parentRect.left,
@@ -336,23 +343,25 @@ class GridLayout extends React.PureComponent {
336
343
  }
337
344
  _resetDragWatcher() {
338
345
  this._parendDragNode = null;
339
- this.setState({ draggedOut: false });
346
+ this.setState({ isDraggedOut: false });
340
347
  }
341
348
  _onDragStart(group, _newLayout, layoutItem, _newItem, _placeholder, e, element) {
342
349
  var _a;
343
350
  (_a = this.context.onDragStart) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, _newLayout, layoutItem, _newItem, _placeholder, e, element));
344
- this._initDragCoordinatesWatcher(element);
345
351
  if (this.context.dragOverPlugin) {
346
352
  this.setState({ isDragging: true });
347
353
  }
348
354
  else {
355
+ this._initDragCoordinatesWatcher(element);
349
356
  this.updateDraggingElementState(group, layoutItem, e);
350
357
  this.setState({ isDragging: true });
351
358
  }
352
359
  }
353
360
  _onDrag(group, layout, oldItem, newItem, placeholder, e, element) {
354
361
  var _a;
355
- this._updateDragCoordinates(e);
362
+ if (!this.context.dragOverPlugin) {
363
+ this._updateDragCoordinates(e);
364
+ }
356
365
  (_a = this.context.onDrag) === null || _a === void 0 ? void 0 : _a.call(this, this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element));
357
366
  }
358
367
  _onDragStop(group, layout, oldItem, newItem, placeholder, e, element) {
@@ -400,7 +409,8 @@ class GridLayout extends React.PureComponent {
400
409
  renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
401
410
  const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, onItemMountChange, onItemRender, } = this.context;
402
411
  const { currentDraggingElement, draggedOverGroup } = this.state;
403
- const properties = groupGridProperties
412
+ const hasOwnGroupProperties = typeof groupGridProperties === 'function';
413
+ const properties = hasOwnGroupProperties
404
414
  ? groupGridProperties(Object.assign({}, registerManager.gridLayout))
405
415
  : registerManager.gridLayout;
406
416
  let { compactType } = properties;
@@ -413,25 +423,22 @@ class GridLayout extends React.PureComponent {
413
423
  group === currentDraggingElement.group &&
414
424
  draggedOverGroup !== null &&
415
425
  draggedOverGroup !== group;
416
- return (React.createElement(Layout
417
- // Group properties
418
- , Object.assign({}, properties, {
426
+ return (React.createElement(Layout, Object.assign({ isDraggable: editMode, isResizable: editMode }, properties, { key: `group_${group}`,
419
427
  // Layout props
420
- compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, draggableCancel: `.${DRAGGABLE_CANCEL_CLASS_NAME}` }, (draggableHandleClassName
421
- ? { draggableHandle: `.${draggableHandleClassName}` }
422
- : null), {
428
+ compactType: compactType, layout: layout, draggableCancel: `.${DRAGGABLE_CANCEL_CLASS_NAME}`, draggableHandle: draggableHandleClassName ? `.${draggableHandleClassName}` : null,
423
429
  // Default callbacks
424
430
  onDragStart: callbacks.onDragStart, onDrag: callbacks.onDrag, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResize: callbacks.onResize, onResizeStop: callbacks.onResizeStop,
425
431
  // External Drag N Drop options
426
- onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured }, (outerDnDEnable
427
- ? {
428
- isDroppable: true,
429
- }
430
- : null)),
432
+ onDragTargetRestore: callbacks.onDragTargetRestore, onDropDragOver: callbacks.onDropDragOver, onDrop: callbacks.onDrop, hasSharedDragItem: hasSharedDragItem, sharedDragPosition: currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.cursorPosition, isDragCaptured: isDragCaptured, isDroppable: Boolean(outerDnDEnable) && editMode }),
431
433
  renderItems.map((item, i) => {
432
- const isCurrentItem = (currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.item.id) === item.id;
433
- const isDraggedOut = isCurrentItem && this.state.draggedOut;
434
- 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, isDraggedOut: isDraggedOut, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), onItemMountChange: onItemMountChange, onItemRender: onItemRender }));
434
+ const keyId = item.id;
435
+ const isDragging = this.state.isDragging;
436
+ const isCurrentDraggedItem = (currentDraggingElement === null || currentDraggingElement === void 0 ? void 0 : currentDraggingElement.item.id) === keyId;
437
+ const isDraggedOut = isCurrentDraggedItem && this.state.isDraggedOut;
438
+ const itemNoOverlay = hasOwnGroupProperties && 'noOverlay' in properties
439
+ ? properties.noOverlay
440
+ : noOverlay;
441
+ return (React.createElement(GridItem, { forwardedPluginRef: this.getMemoForwardRefCallback(offset + i), key: keyId, id: keyId, item: item, layout: layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: isDragging, isDraggedOut: isDraggedOut, noOverlay: itemNoOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), onItemMountChange: onItemMountChange, onItemRender: onItemRender }));
435
442
  }),
436
443
  this.renderTemporaryPlaceholder()));
437
444
  }
@@ -483,13 +490,14 @@ class GridLayout extends React.PureComponent {
483
490
  const element = this.renderGroup(id, layout, items, offset, group.gridProperties);
484
491
  offset += items.length;
485
492
  if (group.render) {
486
- return group.render(id, element, {
493
+ const groupContext = {
487
494
  config,
488
495
  editMode,
489
496
  items,
490
497
  layout,
491
498
  context,
492
- });
499
+ };
500
+ return group.render(id, element, groupContext);
493
501
  }
494
502
  return element;
495
503
  });
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import ReactGridLayout, { WidthProvider, utils } from 'react-grid-layout';
3
- import { OVERLAY_CLASS_NAME } from '../../constants';
3
+ import { DROPPING_ELEMENT_CLASS_NAME, OVERLAY_CLASS_NAME } from '../../constants';
4
4
  class DragOverLayout extends ReactGridLayout {
5
5
  constructor(...args) {
6
6
  super(...args);
@@ -153,6 +153,20 @@ class DragOverLayout extends ReactGridLayout {
153
153
  var _a;
154
154
  return ((_a = this.props.innerRef) === null || _a === void 0 ? void 0 : _a.current) || null;
155
155
  }
156
+ calculateDroppingPosition(itemProps) {
157
+ const { containerWidth, cols, w, h, rowHeight, margin, transformScale, droppingPosition } = itemProps;
158
+ const { sharedDragPosition } = this.props;
159
+ let offsetX, offsetY;
160
+ if (sharedDragPosition) {
161
+ offsetX = sharedDragPosition.offsetX;
162
+ offsetY = sharedDragPosition.offsetY;
163
+ }
164
+ else {
165
+ offsetX = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
166
+ offsetY = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
167
+ }
168
+ return Object.assign(Object.assign({}, droppingPosition), { left: droppingPosition.left - offsetX, top: droppingPosition.top - offsetY });
169
+ }
156
170
  // Drop item from outside gets 0,0 droppingPosition
157
171
  // centering cursor on newly creted grid item
158
172
  // And cause grid-layout using it's own GridItem to make it look
@@ -163,26 +177,14 @@ class DragOverLayout extends ReactGridLayout {
163
177
  if (!gridItem) {
164
178
  return gridItem;
165
179
  }
166
- const { props: itemProps } = gridItem;
167
180
  if (isDroppingItem) {
168
- const { containerWidth, cols, w, h, rowHeight, margin, transformScale, droppingPosition, } = itemProps;
169
- const { sharedDragPosition, hasSharedDragItem } = this.props;
170
- let offsetX, offsetY;
171
- if (sharedDragPosition) {
172
- offsetX = sharedDragPosition.offsetX;
173
- offsetY = sharedDragPosition.offsetY;
174
- }
175
- else {
176
- offsetX = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
177
- offsetY = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
178
- }
179
- const style = gridItem.props.style || null;
180
181
  // React.cloneElement is just cleaner then copy-paste whole processGridItem method
181
182
  return React.cloneElement(gridItem, {
182
- // hiding previre if dragging shared item
183
- style: hasSharedDragItem ? Object.assign(Object.assign({}, style), { opacity: 0 }) : style,
184
- className: OVERLAY_CLASS_NAME,
185
- droppingPosition: Object.assign(Object.assign({}, droppingPosition), { left: droppingPosition.left - offsetX, top: droppingPosition.top - offsetY }),
183
+ // hiding preview if dragging shared item
184
+ style: this.props.hasSharedDragItem
185
+ ? Object.assign(Object.assign({}, gridItem.props.style), { opacity: 0 }) : gridItem.props.style,
186
+ className: `${OVERLAY_CLASS_NAME} ${DROPPING_ELEMENT_CLASS_NAME}`,
187
+ droppingPosition: this.calculateDroppingPosition(gridItem.props),
186
188
  });
187
189
  }
188
190
  return gridItem;
@@ -29,7 +29,7 @@ class OverlayControls extends React.Component {
29
29
  const { view, size, onItemClick } = this.props;
30
30
  const { title, handler, icon, iconSize, qa } = item;
31
31
  const onItemClickHandler = typeof handler === 'function' ? handler : noop;
32
- return (React.createElement(Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => {
32
+ return (React.createElement(Button, { key: `control_${index}`, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => {
33
33
  onItemClickHandler(this.props.configItem);
34
34
  onItemClick === null || onItemClick === void 0 ? void 0 : onItemClick();
35
35
  }, qa: qa },
@@ -40,7 +40,7 @@ class OverlayControls extends React.Component {
40
40
  if (this.context.overlayControls === null) {
41
41
  return null;
42
42
  }
43
- return (React.createElement(Button, { view: view, size: size, title: i18n('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
43
+ return (React.createElement(Button, { key: 'control_default', view: view, size: size, title: i18n('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
44
44
  React.createElement(Icon, { data: Gear, size: OVERLAY_ICON_SIZE })));
45
45
  };
46
46
  this.getCustomLeftOverlayControls = () => {
@@ -158,10 +158,9 @@ class OverlayControls extends React.Component {
158
158
  renderControls() {
159
159
  const customLeftControls = this.getCustomLeftOverlayControls();
160
160
  const hasCustomOverlayLeftControls = Boolean(customLeftControls.length);
161
- const defaultControl = this.getDefaultControls();
162
161
  const controls = hasCustomOverlayLeftControls
163
162
  ? customLeftControls.map((item, index, items) => this.renderControlsItem(item, index, items.length + 1))
164
- : defaultControl;
163
+ : this.getDefaultControls();
165
164
  const menu = this.renderMenu(controls === null);
166
165
  return (React.createElement("div", { className: b('default-controls', {
167
166
  'with-custom-left': hasCustomOverlayLeftControls,
@@ -228,7 +227,7 @@ class OverlayControls extends React.Component {
228
227
  if (items.length === 0) {
229
228
  return null;
230
229
  }
231
- return (React.createElement(DropdownMenu, { items: items, renderSwitcher: (props) => (React.createElement(Button, Object.assign({}, props, { view: view, size: size, pin: isOnlyOneItem ? 'round-round' : 'brick-round', qa: "dashkit-overlay-control-menu" }),
230
+ return (React.createElement(DropdownMenu, { key: 'controls_dropdown', items: items, renderSwitcher: (props) => (React.createElement(Button, Object.assign({}, props, { view: view, size: size, pin: isOnlyOneItem ? 'round-round' : 'brick-round', qa: "dashkit-overlay-control-menu" }),
232
231
  React.createElement(Icon, { data: Ellipsis, size: OVERLAY_ICON_SIZE }))), popupProps: {
233
232
  contentClassName: DRAGGABLE_CANCEL_CLASS_NAME,
234
233
  } }));
@@ -15,3 +15,4 @@ export declare const DEFAULT_GROUP = "__default";
15
15
  export declare const COMPACT_TYPE_HORIZONTAL_NOWRAP = "horizontal-nowrap";
16
16
  export declare const DRAGGABLE_CANCEL_CLASS_NAME = "dashkit_draggable_cancel";
17
17
  export declare const FOCUSED_CLASS_NAME = "dashkit_focused";
18
+ export declare const DROPPING_ELEMENT_CLASS_NAME = "dropping";
@@ -15,3 +15,4 @@ export const DEFAULT_GROUP = '__default';
15
15
  export const COMPACT_TYPE_HORIZONTAL_NOWRAP = 'horizontal-nowrap';
16
16
  export const DRAGGABLE_CANCEL_CLASS_NAME = 'dashkit_draggable_cancel';
17
17
  export const FOCUSED_CLASS_NAME = 'dashkit_focused';
18
+ export const DROPPING_ELEMENT_CLASS_NAME = 'dropping';
@@ -229,12 +229,13 @@ function useMemoStateContext(props) {
229
229
  const reloadItems = React.useCallback((pluginsRefs, data) => {
230
230
  pluginsRefs.forEach((ref) => ref && ref.reload && ref.reload(data));
231
231
  }, []);
232
- const dragProps = dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragProps;
232
+ const dragPropsContext = dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragProps;
233
+ const onDropDragOverContext = dndContext === null || dndContext === void 0 ? void 0 : dndContext.onDropDragOver;
233
234
  const dragOverPlugin = React.useMemo(() => {
234
- if (!dragProps) {
235
+ if (!dragPropsContext) {
235
236
  return null;
236
237
  }
237
- const pluginType = dragProps.type;
238
+ const pluginType = dragPropsContext.type;
238
239
  if (props.registerManager.check(pluginType)) {
239
240
  return props.registerManager.getItem(pluginType);
240
241
  }
@@ -243,8 +244,8 @@ function useMemoStateContext(props) {
243
244
  console.error(`Uknown pluginType: ${pluginType}`);
244
245
  return null;
245
246
  }
246
- }, [dragProps, props.registerManager]);
247
- const onDropDragOver = React.useCallback((_e, gridProps, groupLayout, sharedItem) => {
247
+ }, [dragPropsContext, props.registerManager]);
248
+ const onDropDragOver = React.useCallback((_e, group, gridProps, groupLayout, sharedItem) => {
248
249
  if (temporaryLayout) {
249
250
  resetTemporaryLayout();
250
251
  return false;
@@ -272,20 +273,30 @@ function useMemoStateContext(props) {
272
273
  maxH < defaultLayout.minH) {
273
274
  return false;
274
275
  }
275
- const { h = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.h) || DEFAULT_WIDGET_HEIGHT, w = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.w) || DEFAULT_WIDGET_WIDTH, } = (dragProps === null || dragProps === void 0 ? void 0 : dragProps.layout) || {};
276
- return {
276
+ const { h = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.h) || DEFAULT_WIDGET_HEIGHT, w = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.w) || DEFAULT_WIDGET_WIDTH, } = (dragPropsContext === null || dragPropsContext === void 0 ? void 0 : dragPropsContext.layout) || {};
277
+ const itemLayout = {
277
278
  h: maxH ? Math.min(h, maxH) : h,
278
279
  w: maxW ? Math.min(w, maxW) : w,
279
280
  };
280
- }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
281
+ if ((onDropDragOverContext === null || onDropDragOverContext === void 0 ? void 0 : onDropDragOverContext(Object.assign(Object.assign(Object.assign({}, sharedItem), itemLayout), { parent: group }), sharedItem !== null && sharedItem !== void 0 ? sharedItem : null)) === false) {
282
+ return false;
283
+ }
284
+ return itemLayout;
285
+ }, [
286
+ resetTemporaryLayout,
287
+ temporaryLayout,
288
+ dragOverPlugin,
289
+ dragPropsContext,
290
+ onDropDragOverContext,
291
+ ]);
281
292
  const onDropProp = props.onDrop;
282
293
  const onDrop = React.useCallback((newLayout, item) => {
283
- if (!dragProps) {
294
+ if (!dragPropsContext) {
284
295
  return;
285
296
  }
286
297
  setTemporaryLayout({
287
298
  data: [...newLayout, item],
288
- dragProps,
299
+ dragProps: dragPropsContext,
289
300
  });
290
301
  onDropProp({
291
302
  newLayout: newLayout.reduce((memo, l) => {
@@ -296,9 +307,9 @@ function useMemoStateContext(props) {
296
307
  }, []),
297
308
  itemLayout: pick(item, ITEM_PROPS),
298
309
  commit: resetTemporaryLayout,
299
- dragProps,
310
+ dragProps: dragPropsContext,
300
311
  });
301
- }, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
312
+ }, [dragPropsContext, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
302
313
  const dashkitContextValue = React.useMemo(() => ({
303
314
  layout: resultLayout,
304
315
  temporaryLayout,
@@ -12,6 +12,10 @@ export type ItemDragProps = {
12
12
  };
13
13
  extra?: any;
14
14
  };
15
+ export type DraggedOverItem = Omit<ConfigLayout, 'x' | 'y' | 'i'> & {
16
+ type: string;
17
+ i?: ConfigLayout['i'];
18
+ };
15
19
  export type ItemDropProps = {
16
20
  commit: () => void;
17
21
  dragProps: ItemDragProps;
@@ -2,8 +2,11 @@ import type ReactGridLayout from 'react-grid-layout';
2
2
  import type { OverlayCustomControlItem } from '../components/OverlayControls/OverlayControls';
3
3
  import { MenuItems } from '../constants';
4
4
  import { AdditionalWidgetLayout } from '../shared';
5
+ export type GridLayoutSettings = ReactGridLayout.ReactGridLayoutProps & {
6
+ noOverlay?: boolean;
7
+ };
5
8
  export interface Settings {
6
- gridLayout?: ReactGridLayout.ReactGridLayoutProps;
9
+ gridLayout?: GridLayoutSettings;
7
10
  theme?: string;
8
11
  isMobile?: boolean;
9
12
  menu?: Array<MenuItem>;
@@ -1,6 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import type { Layout, Layouts } from 'react-grid-layout';
3
3
  import type { Config, ConfigItem, ConfigLayout } from '../shared';
4
+ import { GridLayoutSettings } from './common';
4
5
  export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
5
6
  id?: null;
6
7
  namespace?: string;
@@ -31,7 +32,7 @@ export interface DashkitGroupRenderProps {
31
32
  layout: ConfigLayout[];
32
33
  context: any;
33
34
  }
34
- export type ReactGridLayoutProps = Omit<ReactGridLayout.ReactGridLayoutProps, 'children' | 'compactType' | 'innerRef' | 'key' | 'layout' | 'isDraggable' | 'isResizable' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'> & {
35
+ export type ReactGridLayoutProps = Omit<GridLayoutSettings, 'children' | 'compactType' | 'innerRef' | 'key' | 'layout' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'> & {
35
36
  compactType?: CompactType;
36
37
  };
37
38
  export interface DashKitGroup {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dashkit",
3
- "version": "8.17.4",
3
+ "version": "8.18.0",
4
4
  "description": "Library for rendering dashboard grid layout",
5
5
  "license": "MIT",
6
6
  "repository": {