@gravity-ui/dashkit 8.8.1 → 8.9.1-beta.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 (29) hide show
  1. package/build/cjs/components/DashKit/DashKit.d.ts +5 -0
  2. package/build/cjs/components/GridItem/GridItem.css +1 -0
  3. package/build/cjs/components/GridItem/GridItem.js +30 -2
  4. package/build/cjs/components/GridLayout/GridLayout.d.ts +8 -2
  5. package/build/cjs/components/GridLayout/GridLayout.js +113 -25
  6. package/build/cjs/components/GridLayout/ReactGridLayout.js +142 -24
  7. package/build/cjs/components/Item/Item.d.ts +2 -0
  8. package/build/cjs/components/Item/Item.js +13 -2
  9. package/build/cjs/hocs/prepareItem.d.ts +2 -0
  10. package/build/cjs/hocs/prepareItem.js +6 -3
  11. package/build/cjs/hocs/withContext.js +28 -6
  12. package/build/cjs/plugins/Text/Text.d.ts +1 -0
  13. package/build/cjs/plugins/Text/Text.js +2 -0
  14. package/build/cjs/typings/plugin.d.ts +1 -0
  15. package/build/esm/components/DashKit/DashKit.d.ts +5 -0
  16. package/build/esm/components/GridItem/GridItem.css +1 -0
  17. package/build/esm/components/GridItem/GridItem.js +30 -2
  18. package/build/esm/components/GridLayout/GridLayout.d.ts +8 -2
  19. package/build/esm/components/GridLayout/GridLayout.js +113 -25
  20. package/build/esm/components/GridLayout/ReactGridLayout.js +143 -25
  21. package/build/esm/components/Item/Item.d.ts +2 -0
  22. package/build/esm/components/Item/Item.js +13 -2
  23. package/build/esm/hocs/prepareItem.d.ts +2 -0
  24. package/build/esm/hocs/prepareItem.js +6 -3
  25. package/build/esm/hocs/withContext.js +28 -6
  26. package/build/esm/plugins/Text/Text.d.ts +1 -0
  27. package/build/esm/plugins/Text/Text.js +2 -0
  28. package/build/esm/typings/plugin.d.ts +1 -0
  29. package/package.json +1 -1
@@ -32,7 +32,7 @@ function useMemoStateContext(props) {
32
32
  (0, isEqual_1.default)(groups, props.groups))) {
33
33
  props.onChange({ config, itemsStateAndParams, groups });
34
34
  }
35
- }, [props.config, props.itemsStateAndParams, props.onChange]);
35
+ }, [props.config, props.groups, props.itemsStateAndParams, props.onChange]);
36
36
  // каллбэк вызывающийся при изменение лэйаута сетки, первым аргументом приходит актуальный конфиг лэйаута,
37
37
  // т.е. если на текущей сетке есть виджеты, с активированной опцией автовысоты, их параметр "h" будет
38
38
  // "подстроенный"; чтобы, для сохранения в сторе "ушли" значения без учёта подстройки (как если бы у этих
@@ -40,7 +40,17 @@ function useMemoStateContext(props) {
40
40
  const onLayoutChange = react_1.default.useCallback((layout) => {
41
41
  const currentInnerLayout = layout.map((item) => {
42
42
  if (item.i in originalLayouts.current) {
43
- return Object.assign(Object.assign({}, originalLayouts.current[item.i]), { w: item.w, x: item.x, y: item.y });
43
+ // eslint-disable-next-line no-unused-vars
44
+ const _a = originalLayouts.current[item.i], { parent } = _a, originalCopy = tslib_1.__rest(_a, ["parent"]);
45
+ // Updating original if parent has changed and saving copy as original
46
+ // or leaving default
47
+ if (item.parent) {
48
+ originalCopy.parent = item.parent;
49
+ }
50
+ originalCopy.w = item.w;
51
+ originalCopy.x = item.x;
52
+ originalCopy.y = item.y;
53
+ return originalCopy;
44
54
  }
45
55
  else {
46
56
  return Object.assign({}, item);
@@ -237,16 +247,24 @@ function useMemoStateContext(props) {
237
247
  return null;
238
248
  }
239
249
  }, [dragProps, props.registerManager]);
240
- const onDropDragOver = react_1.default.useCallback((_e, gridProps, groupLayout) => {
250
+ const onDropDragOver = react_1.default.useCallback((_e, gridProps, groupLayout, sharedItem) => {
241
251
  if (temporaryLayout) {
242
252
  resetTemporaryLayout();
243
253
  return false;
244
254
  }
245
- if (!dragOverPlugin) {
255
+ let defaultLayout;
256
+ if (sharedItem) {
257
+ const { type, h, w } = sharedItem;
258
+ const _defaults = props.registerManager.getItem(type);
259
+ defaultLayout = _defaults ? Object.assign(Object.assign({}, _defaults.defaultLayout), { h, w }) : { h, w };
260
+ }
261
+ else if (dragOverPlugin) {
262
+ defaultLayout = dragOverPlugin.defaultLayout;
263
+ }
264
+ else {
246
265
  return false;
247
266
  }
248
267
  let maxW = gridProps.cols;
249
- const { defaultLayout } = dragOverPlugin;
250
268
  const maxH = Math.min(gridProps.maxRows || Infinity, defaultLayout.maxH || Infinity);
251
269
  if (gridProps.compactType === common_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
252
270
  maxW = groupLayout.reduce((memo, item) => memo - item.w, gridProps.cols);
@@ -257,7 +275,7 @@ function useMemoStateContext(props) {
257
275
  maxH < defaultLayout.minH) {
258
276
  return false;
259
277
  }
260
- 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.layout || {};
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) || {};
261
279
  return {
262
280
  h: maxH ? Math.min(h, maxH) : h,
263
281
  w: maxW ? Math.min(w, maxW) : w,
@@ -302,6 +320,8 @@ function useMemoStateContext(props) {
302
320
  onItemStateAndParamsChange,
303
321
  onDrop,
304
322
  onDropDragOver,
323
+ onItemMountChange: props.onItemMountChange,
324
+ onItemRender: props.onItemRender,
305
325
  layoutChange: onLayoutChange,
306
326
  getItemsMeta,
307
327
  reloadItems,
@@ -329,6 +349,8 @@ function useMemoStateContext(props) {
329
349
  onDrop,
330
350
  onDropDragOver,
331
351
  onLayoutChange,
352
+ props.onItemMountChange,
353
+ props.onItemRender,
332
354
  getItemsMeta,
333
355
  reloadItems,
334
356
  memorizeOriginalLayout,
@@ -15,6 +15,7 @@ export interface PluginTextProps extends PluginWidgetProps {
15
15
  data: {
16
16
  text: string;
17
17
  } & PluginWidgetProps['data'];
18
+ onBeforeRender: () => () => void;
18
19
  }
19
20
  interface PluginTextState {
20
21
  htmlText: string;
@@ -80,6 +80,7 @@ class PluginText extends react_1.default.PureComponent {
80
80
  return;
81
81
  }
82
82
  this.setState({ status: LoadStatus.Pending });
83
+ const onLoadComplete = this.props.onBeforeLoad();
83
84
  try {
84
85
  let htmlText = '';
85
86
  if (this.state.text && this.state.text.trim()) {
@@ -100,6 +101,7 @@ class PluginText extends react_1.default.PureComponent {
100
101
  }
101
102
  this.setState({ status: LoadStatus.Fail });
102
103
  }
104
+ onLoadComplete();
103
105
  }
104
106
  get withMarkdown() {
105
107
  return typeof this.props.apiHandler === 'function';
@@ -8,6 +8,7 @@ export interface PluginWidgetProps<T = StringParams> {
8
8
  params: T;
9
9
  state: ItemState;
10
10
  onStateAndParamsChange: (stateAndParams: ItemStateAndParams, options?: ItemStateAndParamsChangeOptions) => void;
11
+ onBeforeLoad: () => () => void;
11
12
  width: number;
12
13
  height: number;
13
14
  data: ConfigItem['data'];
@@ -18,6 +18,11 @@ interface DashKitDefaultProps {
18
18
  groups?: DashKitGroup[];
19
19
  }) => void;
20
20
  onDrop: (dropProps: ItemDropProps) => void;
21
+ onItemMountChange?: (item: ConfigItem, state: {
22
+ isAsync: boolean;
23
+ isMounted: boolean;
24
+ }) => void;
25
+ onItemRender?: (item: ConfigItem) => void;
21
26
  defaultGlobalParams: GlobalParams;
22
27
  globalParams: GlobalParams;
23
28
  itemsStateAndParams: ItemsStateAndParams;
@@ -57,6 +57,7 @@
57
57
  transition: none;
58
58
  z-index: 3;
59
59
  will-change: transform;
60
+ pointer-events: none;
60
61
  }
61
62
 
62
63
  .react-grid-item.dashkit-grid-item_is-focused {
@@ -36,6 +36,7 @@ const windowFocusObserver = new WindowFocusObserver();
36
36
  class GridItem extends React.PureComponent {
37
37
  constructor() {
38
38
  super(...arguments);
39
+ this._isAsyncItem = false;
39
40
  this.state = {
40
41
  isFocused: false,
41
42
  };
@@ -54,6 +55,33 @@ class GridItem extends React.PureComponent {
54
55
  this.controller = null;
55
56
  });
56
57
  };
58
+ this.onMountChange = (isMounted) => {
59
+ var _a, _b, _c, _d, _e, _f;
60
+ if (isMounted) {
61
+ this._inited = true;
62
+ (_b = (_a = this.props).onItemMountChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.props.item, {
63
+ isAsync: this._isAsyncItem,
64
+ isMounted: isMounted,
65
+ });
66
+ if (!this._isAsyncItem) {
67
+ (_d = (_c = this.props).onItemRender) === null || _d === void 0 ? void 0 : _d.call(_c, this.props.item);
68
+ }
69
+ }
70
+ else {
71
+ (_f = (_e = this.props).onItemMountChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.props.item, {
72
+ isAsync: this._isAsyncItem,
73
+ isMounted: isMounted,
74
+ });
75
+ }
76
+ };
77
+ this.onBeforeLoad = () => {
78
+ this._isAsyncItem = true;
79
+ return this.onLoad;
80
+ };
81
+ this.onLoad = () => {
82
+ var _a, _b;
83
+ (_b = (_a = this.props).onItemRender) === null || _b === void 0 ? void 0 : _b.call(_a, this.props.item);
84
+ };
57
85
  }
58
86
  renderOverlay() {
59
87
  const { isPlaceholder } = this.props;
@@ -69,7 +97,7 @@ class GridItem extends React.PureComponent {
69
97
  render() {
70
98
  // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable
71
99
  // https://github.com/STRML/react-grid-layout/issues/721
72
- const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, isPlaceholder, } = this.props;
100
+ const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, isPlaceholder = false, } = this.props;
73
101
  const { editMode } = this.context;
74
102
  const width = Number.parseInt(style.width, 10);
75
103
  const height = Number.parseInt(style.height, 10);
@@ -94,7 +122,7 @@ class GridItem extends React.PureComponent {
94
122
  }
95
123
  : {})),
96
124
  React.createElement("div", { className: b('item', { editMode: editMode && !_editActive && !noOverlay }) },
97
- React.createElement(Item, { id: this.props.id, item: this.props.item, shouldItemUpdate: !isDragging, width: width, height: height, transform: transform, isPlaceholder: isPlaceholder, adjustWidgetLayout: this.props.adjustWidgetLayout, layout: this.props.layout, forwardedPluginRef: this.props.forwardedPluginRef })),
125
+ React.createElement(Item, { id: this.props.id, item: this.props.item, shouldItemUpdate: !isDragging, width: width, height: height, transform: transform, isPlaceholder: isPlaceholder, adjustWidgetLayout: this.props.adjustWidgetLayout, layout: this.props.layout, forwardedPluginRef: this.props.forwardedPluginRef, onMountChange: this.onMountChange, onBeforeLoad: this.onBeforeLoad })),
98
126
  !noOverlay && this.renderOverlay(),
99
127
  preparedChildren));
100
128
  }
@@ -5,6 +5,8 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
5
5
  state: {
6
6
  isDragging: boolean;
7
7
  isPageHidden: boolean;
8
+ currentDraggingElement: null;
9
+ draggedOverGroup: null;
8
10
  };
9
11
  componentDidMount(): void;
10
12
  componentDidUpdate(): void;
@@ -36,10 +38,14 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
36
38
  getMemoForwardRefCallback: (refIndex: any) => any;
37
39
  mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
38
40
  reloadItems(): void;
39
- _onStart: () => void;
41
+ _onDragStart: (group: any, _newLayout: any, layoutItem: any) => void;
42
+ _onResizeStart: () => void;
43
+ _onTargetRestore: () => void;
40
44
  _onStop: (group: any, newLayout: any) => void;
41
- _onDropDragOver: (group: any, e: any) => any;
45
+ _onSharedDrop: (targetGroup: any, newLayout: any, tempItem: any) => void;
46
+ _onExternalDrop: (group: any, newLayout: any, item: any, e: any) => void;
42
47
  _onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
48
+ _onDropDragOver: (group: any, e: any) => any;
43
49
  renderTemporaryPlaceholder(): JSX.Element | null;
44
50
  renderGroup(group: any, renderLayout: any, renderItems: any, offset: number | undefined, groupGridProperties: any): JSX.Element;
45
51
  render(): any;
@@ -53,17 +53,18 @@ class GridLayout extends React.PureComponent {
53
53
  };
54
54
  this.getMemoGroupCallbacks = (group) => {
55
55
  if (!this._memoCallbacksForGroups[group]) {
56
- const onStart = this._onStart;
56
+ const onDragStart = this._onDragStart.bind(this, group);
57
57
  const onStop = this._onStop.bind(this, group);
58
58
  const onDrop = this._onDrop.bind(this, group);
59
59
  const onDropDragOver = this._onDropDragOver.bind(this, group);
60
+ const onDragTargetRestore = this._onTargetRestore.bind(this, group);
60
61
  this._memoCallbacksForGroups[group] = {
61
- onDragStart: onStart,
62
- onResizeStart: onStart,
62
+ onDragStart,
63
63
  onDragStop: onStop,
64
64
  onResizeStop: onStop,
65
- onDrop: onDrop,
65
+ onDrop,
66
66
  onDropDragOver,
67
+ onDragTargetRestore,
67
68
  };
68
69
  }
69
70
  return this._memoCallbacksForGroups[group];
@@ -90,48 +91,131 @@ class GridLayout extends React.PureComponent {
90
91
  }
91
92
  return this._memoForwardedPluginRef[refIndex];
92
93
  };
93
- this._onStart = () => {
94
+ this._onDragStart = (group, _newLayout, layoutItem) => {
94
95
  if (this.temporaryLayout)
95
96
  return;
96
- this.setState({ isDragging: true });
97
+ if (this.context.dragOverPlugin) {
98
+ this.setState({ isDragging: true });
99
+ }
100
+ else {
101
+ let currentDraggingElement = this.state.currentDraggingElement;
102
+ if (!currentDraggingElement) {
103
+ const _id = layoutItem.i;
104
+ const item = this.context.config.items.find(({ id }) => id === _id);
105
+ currentDraggingElement = [group, layoutItem, item];
106
+ }
107
+ this.setState({
108
+ isDragging: true,
109
+ currentDraggingElement,
110
+ draggedOverGroup: group,
111
+ });
112
+ }
113
+ };
114
+ this._onResizeStart = () => {
115
+ this.setState({
116
+ isDragging: true,
117
+ });
118
+ };
119
+ this._onTargetRestore = () => {
120
+ const { currentDraggingElement } = this.state;
121
+ if (currentDraggingElement) {
122
+ this.setState({
123
+ draggedOverGroup: currentDraggingElement[0],
124
+ });
125
+ }
97
126
  };
98
127
  this._onStop = (group, newLayout) => {
99
128
  const { layoutChange, onDrop, temporaryLayout } = this.context;
129
+ const { draggedOverGroup, currentDraggingElement } = this.state;
130
+ if (currentDraggingElement &&
131
+ draggedOverGroup !== null &&
132
+ draggedOverGroup !== currentDraggingElement[0]) {
133
+ // Skipping layout update when change event called for source grid
134
+ // and waiting _onDrop
135
+ return;
136
+ }
100
137
  const groupedLayout = this.mergeGroupsLayout(group, newLayout);
138
+ this.setState({
139
+ isDragging: false,
140
+ currentDraggingElement: null,
141
+ draggedOverGroup: null,
142
+ });
101
143
  if (temporaryLayout) {
102
144
  onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, groupedLayout.find(({ i }) => i === TEMPORARY_ITEM_ID));
103
145
  }
104
146
  else {
105
147
  layoutChange(groupedLayout);
106
148
  }
107
- this.setState({ isDragging: false });
108
149
  };
109
- this._onDropDragOver = (group, e) => {
110
- const { editMode, dragOverPlugin } = this.context;
111
- if (!editMode || !dragOverPlugin) {
112
- return false;
150
+ this._onSharedDrop = (targetGroup, newLayout, tempItem) => {
151
+ const { currentDraggingElement } = this.state;
152
+ const { layoutChange } = this.context;
153
+ if (!currentDraggingElement) {
154
+ return;
113
155
  }
114
- const { properties, layout } = this.getLayoutAndPropsByGroup(group);
115
- return this.context.onDropDragOver(e, properties, layout);
156
+ const [, sourceItem] = currentDraggingElement;
157
+ const groupedLayout = this.mergeGroupsLayout(targetGroup, newLayout, tempItem).map((item) => {
158
+ if (item.i === sourceItem.i) {
159
+ const copy = Object.assign({}, tempItem);
160
+ delete copy.parent;
161
+ if (targetGroup !== DEFAULT_GROUP) {
162
+ copy.parent = targetGroup;
163
+ }
164
+ copy.i = sourceItem.i;
165
+ return copy;
166
+ }
167
+ return item;
168
+ });
169
+ this.setState({
170
+ isDragging: false,
171
+ currentDraggingElement: null,
172
+ draggedOverGroup: null,
173
+ });
174
+ layoutChange(groupedLayout);
175
+ };
176
+ this._onExternalDrop = (group, newLayout, item, e) => {
177
+ const { onDrop } = this.context;
178
+ if (group !== DEFAULT_GROUP) {
179
+ item.parent = group;
180
+ }
181
+ const groupedLayout = this.mergeGroupsLayout(group, newLayout, item);
182
+ this.setState({ isDragging: false });
183
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, item, e);
116
184
  };
117
185
  this._onDrop = (group, newLayout, item, e) => {
118
- if (!item) {
186
+ if (!item || !this.context.editMode) {
119
187
  return false;
120
188
  }
121
- const { editMode, onDrop } = this.context;
122
- if (!editMode) {
189
+ const { draggedOverGroup, currentDraggingElement } = this.state;
190
+ if (currentDraggingElement && draggedOverGroup === group) {
191
+ this._onSharedDrop(group, newLayout, item);
192
+ }
193
+ else {
194
+ this._onExternalDrop(group, newLayout, item, e);
195
+ }
196
+ };
197
+ this._onDropDragOver = (group, e) => {
198
+ const { editMode, dragOverPlugin, onDropDragOver } = this.context;
199
+ const { currentDraggingElement } = this.state;
200
+ if (!editMode || (!dragOverPlugin && !currentDraggingElement)) {
123
201
  return false;
124
202
  }
125
- if (group !== DEFAULT_GROUP) {
126
- item.parent = group;
203
+ const { properties, layout } = this.getLayoutAndPropsByGroup(group);
204
+ if (currentDraggingElement) {
205
+ const [, { h, w, i }, { type }] = currentDraggingElement;
206
+ return onDropDragOver(e, properties, layout, { h, w, i, type });
127
207
  }
128
- const groupedLayout = this.mergeGroupsLayout(group, newLayout, item);
129
- onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, item, e);
208
+ if (dragOverPlugin) {
209
+ return onDropDragOver(e, properties, layout);
210
+ }
211
+ return false;
130
212
  };
131
213
  this.pluginsRefs = [];
132
214
  this.state = {
133
215
  isDragging: false,
134
216
  isPageHidden: false,
217
+ currentDraggingElement: null,
218
+ draggedOverGroup: null,
135
219
  };
136
220
  }
137
221
  componentDidMount() {
@@ -200,7 +284,8 @@ class GridLayout extends React.PureComponent {
200
284
  return (React.createElement(GridItem, { key: id, id: id, item: { id, type, data: {} }, layout: temporaryLayout.data, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, isPlaceholder: true, noOverlay: noOverlay, withCustomHandle: Boolean(draggableHandleClassName) }));
201
285
  }
202
286
  renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
203
- const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
287
+ const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, onItemMountChange, onItemRender, } = this.context;
288
+ const { currentDraggingElement, draggedOverGroup } = this.state;
204
289
  const properties = groupGridProperties
205
290
  ? groupGridProperties(Object.assign({}, registerManager.gridLayout))
206
291
  : registerManager.gridLayout;
@@ -209,17 +294,20 @@ class GridLayout extends React.PureComponent {
209
294
  compactType = 'horizontal';
210
295
  }
211
296
  const { callbacks, layout } = this.getMemoGroupProps(group, renderLayout, properties);
212
- return (React.createElement(Layout, Object.assign({}, properties, { compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onDragStart: callbacks.onDragStart, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResizeStop: callbacks.onResizeStop }, (draggableHandleClassName
297
+ const hasSharedDragItem = Boolean(currentDraggingElement && currentDraggingElement[0] !== group);
298
+ const isDragCaptured = currentDraggingElement &&
299
+ group === currentDraggingElement[0] &&
300
+ draggedOverGroup !== null &&
301
+ draggedOverGroup !== group;
302
+ 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, isDragCaptured: isDragCaptured }, (draggableHandleClassName
213
303
  ? { draggableHandle: `.${draggableHandleClassName}` }
214
304
  : null), (outerDnDEnable
215
305
  ? {
216
306
  isDroppable: true,
217
- onDropDragOver: callbacks.onDropDragOver,
218
- onDrop: callbacks.onDrop,
219
307
  }
220
308
  : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
221
309
  renderItems.map((item, i) => {
222
- 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) }));
310
+ 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 }));
223
311
  }),
224
312
  this.renderTemporaryPlaceholder()));
225
313
  }
@@ -1,62 +1,180 @@
1
1
  import React from 'react';
2
- import ReactGridLayout, { WidthProvider } from 'react-grid-layout';
2
+ import ReactGridLayout, { WidthProvider, utils } from 'react-grid-layout';
3
3
  import { OVERLAY_CLASS_NAME } from '../../constants';
4
4
  class DragOverLayout extends ReactGridLayout {
5
5
  constructor(...args) {
6
6
  super(...args);
7
- this.dragReset = () => {
7
+ this._savedDraggedOutLayout = null;
8
+ // Reset placeholder when item dragged from outside
9
+ this.resetExternalPlaceholder = () => {
8
10
  if (this.dragEnterCounter) {
9
11
  this.dragEnterCounter = 0;
10
12
  this.removeDroppingPlaceholder();
11
13
  }
12
14
  };
15
+ // Hide placeholder when element is dragged out
16
+ this.hideLocalPlaceholder = (i) => {
17
+ const { layout } = this.state;
18
+ const { cols } = this.props;
19
+ const savedLayout = layout.map((item) => (Object.assign({}, item)));
20
+ let hiddenElement;
21
+ const newLayout = utils.compact(layout.filter((item) => {
22
+ if (item.i === i) {
23
+ hiddenElement = item;
24
+ return false;
25
+ }
26
+ return true;
27
+ }), utils.compactType(this.props), cols);
28
+ if (hiddenElement) {
29
+ newLayout.push(hiddenElement);
30
+ }
31
+ this.setState({
32
+ activeDrag: null,
33
+ layout: newLayout,
34
+ });
35
+ return savedLayout;
36
+ };
37
+ this.extendedOnDrag = (i, x, y, sintEv) => {
38
+ if (this.props.isDragCaptured) {
39
+ if (!this._savedDraggedOutLayout) {
40
+ this._savedDraggedOutLayout = this.hideLocalPlaceholder(i);
41
+ }
42
+ return;
43
+ }
44
+ this._savedDraggedOutLayout = null;
45
+ // parent onDrag will show new placeholder again
46
+ this.parentOnDrag(i, x, y, sintEv);
47
+ };
48
+ this.extendedOnDragStop = (i, x, y, sintEv) => {
49
+ // Restoring layout if item was dropped outside of the grid
50
+ if (this._savedDraggedOutLayout) {
51
+ const savedLayout = this._savedDraggedOutLayout;
52
+ const l = utils.getLayoutItem(savedLayout, i);
53
+ // Create placeholder (display only)
54
+ const placeholder = {
55
+ w: l.w,
56
+ h: l.h,
57
+ x: l.x,
58
+ y: l.y,
59
+ placeholder: true,
60
+ i: i,
61
+ };
62
+ this.setState({
63
+ layout: savedLayout,
64
+ activeDrag: placeholder,
65
+ }, () => {
66
+ this.parentOnDragStop(i, x, y, sintEv);
67
+ });
68
+ this._savedDraggedOutLayout = null;
69
+ }
70
+ else {
71
+ this.parentOnDragStop(i, x, y, sintEv);
72
+ }
73
+ };
74
+ // Proxy mouse events -> drag methods for dnd between groups
75
+ this.mouseEnterHandler = (e) => {
76
+ var _a, _b;
77
+ if (this.props.hasSharedDragItem) {
78
+ this.onDragEnter(e);
79
+ }
80
+ else if (this.props.isDragCaptured) {
81
+ (_b = (_a = this.props).onDragTargetRestore) === null || _b === void 0 ? void 0 : _b.call(_a);
82
+ }
83
+ };
13
84
  this.mouseLeaveHandler = (e) => {
14
- var _a;
15
- const rect = ((_a = this.props.innerRef) === null || _a === void 0 ? void 0 : _a.current.getBoundingClientRect()) || {};
16
- if (rect.bottom <= e.clientY ||
17
- rect.top >= e.clientY ||
18
- rect.left >= e.clientX ||
19
- rect.right <= e.clientX) {
20
- this.dragReset();
85
+ var _a, _b;
86
+ if (this.props.hasSharedDragItem) {
87
+ this.onDragLeave(e);
88
+ (_b = (_a = this.props).onDragTargetRestore) === null || _b === void 0 ? void 0 : _b.call(_a);
21
89
  }
22
90
  };
23
- this.parentOnDrag = this.onDrag;
24
- this.onDrag = (i, x, y, sintE) => {
25
- this.parentOnDrag(i, x, y, sintE);
26
- this.mouseLeaveHandler(sintE.e);
91
+ this.mouseMoveHandler = (e) => {
92
+ if (this.props.hasSharedDragItem) {
93
+ this.onDragOver(e);
94
+ }
27
95
  };
96
+ this.mouseUpHandler = (e) => {
97
+ var _a, _b;
98
+ if (this.props.hasSharedDragItem) {
99
+ e.preventDefault();
100
+ const { droppingItem } = this.props;
101
+ const { layout } = this.state;
102
+ const item = layout.find((l) => l.i === droppingItem.i);
103
+ // reset dragEnter counter on drop
104
+ this.resetExternalPlaceholder();
105
+ (_b = (_a = this.props).onDrop) === null || _b === void 0 ? void 0 : _b.call(_a, layout, item, e);
106
+ }
107
+ };
108
+ this.parentOnDrag = this.onDrag;
109
+ this.onDrag = this.extendedOnDrag;
110
+ this.parentOnDragStop = this.onDragStop;
111
+ this.onDragStop = this.extendedOnDragStop;
28
112
  }
29
113
  componentDidMount() {
30
114
  var _a;
31
115
  (_a = super.componentDidMount) === null || _a === void 0 ? void 0 : _a.call(this);
32
- window.addEventListener('dragend', this.dragReset);
116
+ // If cursor is moved out of the window there is a bug
117
+ // which leaves placeholder element in grid, this action needed to reset this state
118
+ window.addEventListener('dragend', this.resetExternalPlaceholder);
119
+ const innerElement = this.getInnerElement();
120
+ if (innerElement) {
121
+ innerElement.addEventListener('mouseup', this.mouseUpHandler);
122
+ innerElement.addEventListener('mouseenter', this.mouseEnterHandler);
123
+ innerElement.addEventListener('mouseleave', this.mouseLeaveHandler);
124
+ innerElement.addEventListener('mousemove', this.mouseMoveHandler);
125
+ }
33
126
  }
34
127
  componentWillUnmount() {
35
- window.removeEventListener('dragend', this.dragReset);
128
+ window.removeEventListener('dragend', this.resetExternalPlaceholder);
129
+ const innerElement = this.getInnerElement();
130
+ if (innerElement) {
131
+ innerElement.removeEventListener('mouseup', this.mouseUpHandler);
132
+ innerElement.removeEventListener('mouseenter', this.mouseEnterHandler);
133
+ innerElement.removeEventListener('mouseleave', this.mouseLeaveHandler);
134
+ innerElement.removeEventListener('mousemove', this.mouseMoveHandler);
135
+ }
36
136
  }
137
+ // react-grid-layout doens't calculate it's height when last element is removed
138
+ // and just keeps the previous value
139
+ // so for autosize to work in that case we are resetting it's height value
37
140
  containerHeight() {
38
141
  if (this.props.autoSize && this.state.layout.length === 0) {
39
- return 'unset';
142
+ return;
40
143
  }
144
+ // eslint-disable-next-line consistent-return
41
145
  return super.containerHeight();
42
146
  }
147
+ // innerRef is passed by WithProvider without this wrapper there are only
148
+ // * findDOMNode - deprecated
149
+ // * rewrite whole ReactGridLayout.render method
150
+ // so in that case don't try to use this class on it's own
151
+ // or pass innerRef: React.MutableRef as it's not optional prop
152
+ getInnerElement() {
153
+ var _a;
154
+ return ((_a = this.props.innerRef) === null || _a === void 0 ? void 0 : _a.current) || null;
155
+ }
156
+ // Drop item from outside gets 0,0 droppingPosition
157
+ // centering cursor on newly creted grid item
158
+ // And cause grid-layout using it's own GridItem to make it look
159
+ // like overlay adding className
43
160
  processGridItem(child, isDroppingItem) {
44
161
  var _a;
45
162
  const gridItem = (_a = super.processGridItem) === null || _a === void 0 ? void 0 : _a.call(this, child, isDroppingItem);
163
+ if (!gridItem) {
164
+ return gridItem;
165
+ }
166
+ const { props: itemProps } = gridItem;
46
167
  if (isDroppingItem) {
47
- // Drop item from outside gets 0,0 droppingPosition
48
- // centering cursor on newly creted grid item
49
- // And cause grid-layout using it's own GridItem to make it look
50
- // like overlay adding className
51
- if (!gridItem)
52
- return null;
53
- const { props } = gridItem;
54
- const { containerWidth, cols, w, h, rowHeight, margin, transformScale } = props;
168
+ const { containerWidth, cols, w, h, rowHeight, margin, transformScale, droppingPosition, } = itemProps;
55
169
  const leftOffset = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
56
170
  const topOffset = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
171
+ const style = gridItem.props.style || null;
172
+ // React.cloneElement is just cleaner then copy-paste whole processGridItem method
57
173
  return React.cloneElement(gridItem, {
174
+ // hiding previre if dragging shared item
175
+ style: this.props.hasSharedDragItem ? Object.assign(Object.assign({}, style), { opacity: 0 }) : style,
58
176
  className: OVERLAY_CLASS_NAME,
59
- droppingPosition: Object.assign(Object.assign({}, props.droppingPosition), { left: props.droppingPosition.left - leftOffset, top: props.droppingPosition.top - topOffset }),
177
+ droppingPosition: Object.assign(Object.assign({}, droppingPosition), { left: droppingPosition.left - leftOffset, top: droppingPosition.top - topOffset }),
60
178
  });
61
179
  }
62
180
  return gridItem;
@@ -61,7 +61,9 @@ declare const _default: {
61
61
  height: PropTypes.Requireable<number>;
62
62
  transform: PropTypes.Requireable<string>;
63
63
  isPlaceholder: PropTypes.Requireable<boolean>;
64
+ onBeforeLoad: PropTypes.Requireable<(...args: any[]) => any>;
64
65
  forwardedPluginRef: PropTypes.Requireable<any>;
66
+ onMountChange: PropTypes.Requireable<(...args: any[]) => any>;
65
67
  };
66
68
  contextType: React.Context<any>;
67
69
  };