@gravity-ui/dashkit 8.0.2 → 8.1.0-beta.1

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 (62) hide show
  1. package/README.md +1 -0
  2. package/build/cjs/components/ActionPanel/ActionPanel.d.ts +13 -1
  3. package/build/cjs/components/ActionPanel/ActionPanel.js +25 -6
  4. package/build/cjs/components/ActionPanel/types.d.ts +1 -0
  5. package/build/cjs/components/DashKit/DashKit.d.ts +10 -3
  6. package/build/cjs/components/DashKit/DashKit.js +2 -0
  7. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +6 -0
  8. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.js +24 -0
  9. package/build/cjs/components/GridItem/GridItem.css +7 -0
  10. package/build/cjs/components/GridItem/GridItem.d.ts +2 -2
  11. package/build/cjs/components/GridItem/GridItem.js +63 -4
  12. package/build/cjs/components/GridLayout/GridLayout.d.ts +3 -0
  13. package/build/cjs/components/GridLayout/GridLayout.js +90 -10
  14. package/build/cjs/components/Item/Item.css +1 -1
  15. package/build/cjs/components/Item/Item.d.ts +1 -0
  16. package/build/cjs/components/Item/Item.js +7 -1
  17. package/build/cjs/components/index.d.ts +1 -0
  18. package/build/cjs/components/index.js +1 -0
  19. package/build/cjs/constants/common.d.ts +2 -0
  20. package/build/cjs/constants/common.js +3 -1
  21. package/build/cjs/context/DashKitContext.d.ts +1 -0
  22. package/build/cjs/context/DashKitContext.js +3 -1
  23. package/build/cjs/hocs/prepareItem.d.ts +1 -0
  24. package/build/cjs/hocs/prepareItem.js +4 -2
  25. package/build/cjs/hocs/withContext.js +87 -6
  26. package/build/cjs/shared/constants/common.d.ts +1 -0
  27. package/build/cjs/shared/constants/common.js +2 -1
  28. package/build/cjs/typings/config.d.ts +3 -0
  29. package/build/cjs/typings/plugin.d.ts +1 -0
  30. package/build/cjs/utils/update-manager.d.ts +2 -2
  31. package/build/cjs/utils/update-manager.js +25 -7
  32. package/build/esm/components/ActionPanel/ActionPanel.d.ts +13 -1
  33. package/build/esm/components/ActionPanel/ActionPanel.js +23 -5
  34. package/build/esm/components/ActionPanel/types.d.ts +1 -0
  35. package/build/esm/components/DashKit/DashKit.d.ts +10 -3
  36. package/build/esm/components/DashKit/DashKit.js +2 -0
  37. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +6 -0
  38. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.js +19 -0
  39. package/build/esm/components/GridItem/GridItem.css +7 -0
  40. package/build/esm/components/GridItem/GridItem.d.ts +2 -2
  41. package/build/esm/components/GridItem/GridItem.js +63 -4
  42. package/build/esm/components/GridLayout/GridLayout.d.ts +3 -0
  43. package/build/esm/components/GridLayout/GridLayout.js +91 -11
  44. package/build/esm/components/Item/Item.css +1 -1
  45. package/build/esm/components/Item/Item.d.ts +1 -0
  46. package/build/esm/components/Item/Item.js +7 -1
  47. package/build/esm/components/index.d.ts +1 -0
  48. package/build/esm/components/index.js +1 -0
  49. package/build/esm/constants/common.d.ts +2 -0
  50. package/build/esm/constants/common.js +2 -0
  51. package/build/esm/context/DashKitContext.d.ts +1 -0
  52. package/build/esm/context/DashKitContext.js +2 -1
  53. package/build/esm/hocs/prepareItem.d.ts +1 -0
  54. package/build/esm/hocs/prepareItem.js +4 -2
  55. package/build/esm/hocs/withContext.js +88 -7
  56. package/build/esm/shared/constants/common.d.ts +1 -0
  57. package/build/esm/shared/constants/common.js +1 -0
  58. package/build/esm/typings/config.d.ts +3 -0
  59. package/build/esm/typings/plugin.d.ts +1 -0
  60. package/build/esm/utils/update-manager.d.ts +2 -2
  61. package/build/esm/utils/update-manager.js +25 -7
  62. package/package.json +1 -1
@@ -1,9 +1,47 @@
1
1
  import React from 'react';
2
2
  import ReactGridLayout, { WidthProvider } from 'react-grid-layout';
3
- import { OVERLAY_CONTROLS_CLASS_NAME } from '../../constants';
3
+ import { OVERLAY_CLASS_NAME, OVERLAY_CONTROLS_CLASS_NAME, TEMPORARY_ITEM_ID } from '../../constants';
4
4
  import { DashKitContext } from '../../context/DashKitContext';
5
5
  import GridItem from '../GridItem/GridItem';
6
- const Layout = WidthProvider(ReactGridLayout); // eslint-disable-line new-cap
6
+ class DragOverLayout extends ReactGridLayout {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.dragReset = () => {
10
+ if (this.dragEnterCounter) {
11
+ this.dragEnterCounter = 0;
12
+ this.removeDroppingPlaceholder();
13
+ }
14
+ };
15
+ }
16
+ componentDidMount() {
17
+ super.componentDidMount();
18
+ window.addEventListener('dragend', this.dragReset);
19
+ }
20
+ componentWillUnmount() {
21
+ window.removeEventListener('dragend', this.dragReset);
22
+ }
23
+ processGridItem(child, isDroppingItem) {
24
+ if (isDroppingItem) {
25
+ // Drop item from outside gets 0,0 droppingPosition
26
+ // centering cursor on newly creted grid item
27
+ // And cause grid-layout using it's own GridItem to make it look
28
+ // like overlay adding className
29
+ const gridItem = super.processGridItem(child, isDroppingItem);
30
+ if (!gridItem)
31
+ return null;
32
+ const { props } = gridItem;
33
+ const { containerWidth, cols, w, h, rowHeight, margin, transformScale } = props;
34
+ const leftOffset = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
35
+ const topOffset = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
36
+ return React.cloneElement(gridItem, {
37
+ className: OVERLAY_CLASS_NAME,
38
+ droppingPosition: Object.assign(Object.assign({}, props.droppingPosition), { left: props.droppingPosition.left - leftOffset, top: props.droppingPosition.top - topOffset }),
39
+ });
40
+ }
41
+ return super.processGridItem(child, isDroppingItem);
42
+ }
43
+ }
44
+ const Layout = WidthProvider(DragOverLayout); // eslint-disable-line new-cap
7
45
  class GridLayout extends React.PureComponent {
8
46
  constructor(props, context) {
9
47
  super(props, context);
@@ -29,13 +67,38 @@ class GridLayout extends React.PureComponent {
29
67
  return getItemsMeta(this.pluginsRefs);
30
68
  };
31
69
  this._onStart = () => {
70
+ if (this.temporaryLayout)
71
+ return;
32
72
  this.setState({ isDragging: true });
33
73
  };
34
74
  this._onStop = (newLayout) => {
35
- const { layoutChange } = this.context;
36
- layoutChange(newLayout);
75
+ const { layoutChange, onDrop, temporaryLayout } = this.context;
76
+ if (temporaryLayout) {
77
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(newLayout, newLayout.find(({ i }) => i === TEMPORARY_ITEM_ID));
78
+ }
79
+ else {
80
+ layoutChange(newLayout);
81
+ }
37
82
  this.setState({ isDragging: false });
38
83
  };
84
+ this._onDropDragOver = (e) => {
85
+ const { editMode, onDropDragOver, temporaryLayout } = this.context;
86
+ if (!editMode) {
87
+ return false;
88
+ }
89
+ const result = onDropDragOver(e);
90
+ if (temporaryLayout) {
91
+ return false;
92
+ }
93
+ return result;
94
+ };
95
+ this._onDrop = (layout, item, e) => {
96
+ const { editMode, temporaryLayout, onDrop } = this.context;
97
+ if (!editMode && temporaryLayout) {
98
+ return false;
99
+ }
100
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(layout, item, e);
101
+ };
39
102
  this.pluginsRefs = [];
40
103
  this.state = {
41
104
  isDragging: false,
@@ -68,16 +131,33 @@ class GridLayout extends React.PureComponent {
68
131
  this._timeout = setTimeout(() => this.reloadItems(), reloadIntervalRemains <= 0 ? autoupdateIntervalMs : reloadIntervalRemains);
69
132
  }
70
133
  }
134
+ renderTemporaryPlaceholder() {
135
+ const { temporaryLayout, dragOverPlugin, noOverlay, draggableHandleClassName } = this.context;
136
+ if (!temporaryLayout) {
137
+ return null;
138
+ }
139
+ const id = TEMPORARY_ITEM_ID;
140
+ const type = dragOverPlugin.type;
141
+ return (React.createElement(GridItem, { key: id, id: id, item: { id, type, data: {} }, layout: temporaryLayout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, isPlaceholder: true, noOverlay: noOverlay, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
142
+ }
71
143
  render() {
72
- const { layout, config, registerManager, editMode, noOverlay, draggableHandleClassName } = this.context;
144
+ const { layout, temporaryLayout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
73
145
  this.pluginsRefs.length = config.items.length;
74
- return (React.createElement(Layout, Object.assign({}, registerManager.gridLayout, { layout: layout, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: this._onStop, onResizeStart: this._onStart, onResizeStop: this._onStop }, (draggableHandleClassName
146
+ return (React.createElement(Layout, Object.assign({}, registerManager.gridLayout, { layout: temporaryLayout || layout, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: this._onStop, onResizeStart: this._onStart, onResizeStop: this._onStop }, (draggableHandleClassName
75
147
  ? { draggableHandle: `.${draggableHandleClassName}` }
76
- : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }), config.items.map((item, i) => {
77
- return (React.createElement(GridItem, { forwardedPluginRef: (pluginRef) => {
78
- this.pluginsRefs[i] = pluginRef;
79
- }, key: item.id, id: item.id, item: item, layout: layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
80
- })));
148
+ : null), (outerDnDEnable
149
+ ? {
150
+ isDroppable: true,
151
+ onDropDragOver: this._onDropDragOver,
152
+ onDrop: this._onDrop,
153
+ }
154
+ : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
155
+ config.items.map((item, i) => {
156
+ return (React.createElement(GridItem, { forwardedPluginRef: (pluginRef) => {
157
+ this.pluginsRefs[i] = pluginRef;
158
+ }, key: item.id, id: item.id, item: item, layout: temporaryLayout || layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
159
+ }),
160
+ this.renderTemporaryPlaceholder()));
81
161
  }
82
162
  }
83
163
  GridLayout.contextType = DashKitContext;
@@ -1,4 +1,4 @@
1
- .dashkit-item__renderer {
1
+ .dashkit-item__placeholder, .dashkit-item__renderer {
2
2
  position: absolute;
3
3
  inset: 0;
4
4
  }
@@ -56,6 +56,7 @@ declare const _default: {
56
56
  width: PropTypes.Requireable<number>;
57
57
  height: PropTypes.Requireable<number>;
58
58
  transform: PropTypes.Requireable<string>;
59
+ isPlaceholder: PropTypes.Requireable<boolean>;
59
60
  forwardedPluginRef: PropTypes.Requireable<any>;
60
61
  };
61
62
  contextType: React.Context<any>;
@@ -5,11 +5,16 @@ import { cn } from '../../utils/cn';
5
5
  import './Item.css';
6
6
  const b = cn('dashkit-item');
7
7
  // TODO: getDerivedStateFromError и заглушка с ошибкой
8
- const Item = ({ registerManager, rendererProps, type, forwardedPluginRef }) => {
8
+ const Item = ({ registerManager, rendererProps, type, isPlaceholder, forwardedPluginRef }) => {
9
+ var _a, _b;
9
10
  if (!registerManager.check(type)) {
10
11
  console.warn(`type [${type}] не зарегистрирован`);
11
12
  return null;
12
13
  }
14
+ if (isPlaceholder) {
15
+ return (React.createElement("div", { className: b('placeholder') }, ((_b = (_a = registerManager
16
+ .getItem(type)).placeholderRenderer) === null || _b === void 0 ? void 0 : _b.call(_a, rendererProps, forwardedPluginRef)) || null));
17
+ }
13
18
  return (React.createElement("div", { className: b('renderer') }, registerManager.getItem(type).renderer(rendererProps, forwardedPluginRef)));
14
19
  };
15
20
  Item.propTypes = {
@@ -17,5 +22,6 @@ Item.propTypes = {
17
22
  rendererProps: PropTypes.object,
18
23
  registerManager: PropTypes.object,
19
24
  type: PropTypes.string,
25
+ isPlaceholder: PropTypes.bool,
20
26
  };
21
27
  export default prepareItem(Item);
@@ -2,3 +2,4 @@ export * from './DashKit';
2
2
  export type { OverlayControlItem, PreparedCopyItemOptions } from './OverlayControls/OverlayControls';
3
3
  export * from './ActionPanel/ActionPanel';
4
4
  export type { ActionPanelItem, ActionPanelProps } from './ActionPanel/types';
5
+ export * from './DashKitDnDWrapper/DashKitDnDWrapper';
@@ -1,2 +1,3 @@
1
1
  export * from './DashKit';
2
2
  export * from './ActionPanel/ActionPanel';
3
+ export * from './DashKitDnDWrapper/DashKitDnDWrapper';
@@ -1,6 +1,8 @@
1
1
  export declare const COPIED_WIDGET_STORE_KEY = "dashCopiedItem";
2
2
  export declare const DEFAULT_NAMESPACE = "default";
3
3
  export declare const OVERLAY_CONTROLS_CLASS_NAME = "dashkit-overlay-controls";
4
+ export declare const OVERLAY_CLASS_NAME = "dashkit-grid-item__overlay";
5
+ export declare const TEMPORARY_ITEM_ID = "__dropping-elem__";
4
6
  export declare const MenuItems: {
5
7
  readonly Copy: "copy";
6
8
  readonly Delete: "delete";
@@ -1,6 +1,8 @@
1
1
  export const COPIED_WIDGET_STORE_KEY = 'dashCopiedItem';
2
2
  export const DEFAULT_NAMESPACE = 'default';
3
3
  export const OVERLAY_CONTROLS_CLASS_NAME = 'dashkit-overlay-controls';
4
+ export const OVERLAY_CLASS_NAME = 'dashkit-grid-item__overlay';
5
+ export const TEMPORARY_ITEM_ID = '__dropping-elem__';
4
6
  export const MenuItems = {
5
7
  Copy: 'copy',
6
8
  Delete: 'delete',
@@ -1,2 +1,3 @@
1
1
  export const DashKitContext: React.Context<any>;
2
+ export const DashKitDnDContext: React.Context<any>;
2
3
  import React from 'react';
@@ -1,3 +1,4 @@
1
1
  import React from 'react';
2
2
  const DashKitContext = React.createContext();
3
- export { DashKitContext };
3
+ const DashKitDnDContext = React.createContext();
4
+ export { DashKitContext, DashKitDnDContext };
@@ -56,6 +56,7 @@ export function prepareItem(Component: any): {
56
56
  width: PropTypes.Requireable<number>;
57
57
  height: PropTypes.Requireable<number>;
58
58
  transform: PropTypes.Requireable<string>;
59
+ isPlaceholder: PropTypes.Requireable<boolean>;
59
60
  forwardedPluginRef: PropTypes.Requireable<any>;
60
61
  };
61
62
  contextType: React.Context<any>;
@@ -22,7 +22,7 @@ export function prepareItem(Component) {
22
22
  return true;
23
23
  }
24
24
  render() {
25
- const { id, width, height, item, adjustWidgetLayout, layout } = this.props;
25
+ const { id, width, height, item, adjustWidgetLayout, layout, isPlaceholder } = this.props;
26
26
  const { itemsState, itemsParams, registerManager, settings, context, editMode } = this.context;
27
27
  const { type, data, defaults, namespace } = item;
28
28
  const rendererProps = {
@@ -41,8 +41,9 @@ export function prepareItem(Component) {
41
41
  layout,
42
42
  gridLayout: registerManager.gridLayout,
43
43
  adjustWidgetLayout,
44
+ isPlaceholder,
44
45
  };
45
- return (React.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: rendererProps, registerManager: registerManager, type: type }));
46
+ return (React.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: rendererProps, registerManager: registerManager, type: type, isPlaceholder: isPlaceholder }));
46
47
  }
47
48
  },
48
49
  _a.propTypes = {
@@ -54,6 +55,7 @@ export function prepareItem(Component) {
54
55
  width: PropTypes.number,
55
56
  height: PropTypes.number,
56
57
  transform: PropTypes.string,
58
+ isPlaceholder: PropTypes.bool,
57
59
  forwardedPluginRef: PropTypes.any,
58
60
  },
59
61
  _a.contextType = DashKitContext,
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import isEqual from 'lodash/isEqual';
3
- import { DashKitContext } from '../context/DashKitContext';
3
+ import { TEMPORARY_ITEM_ID } from '../constants/common';
4
+ import { DashKitContext, DashKitDnDContext } from '../context/DashKitContext';
4
5
  import { getItemsParams, getItemsState } from '../shared';
5
6
  import { UpdateManager } from '../utils';
6
7
  function useMemoStateContext(props) {
@@ -11,6 +12,10 @@ function useMemoStateContext(props) {
11
12
  // (высота) из конфига будет запоминаться в originalLayouts, новое значение высоты в adjustedLayouts
12
13
  const originalLayouts = React.useRef({});
13
14
  const adjustedLayouts = React.useRef({});
15
+ const [temporaryLayout, setTemporaryLayout] = React.useState(null);
16
+ const resetTemporaryLayout = React.useCallback(() => setTemporaryLayout(null), [setTemporaryLayout]);
17
+ const dndContext = React.useContext(DashKitDnDContext);
18
+ const outerDnDEnable = Boolean(dndContext);
14
19
  // TODO: need move originalLayouts, adjustedLayouts to state
15
20
  const [layoutUpdateCounter, forceUpdateLayout] = React.useState(0);
16
21
  const onChange = React.useCallback(({ config = props.config, itemsStateAndParams = props.itemsStateAndParams }) => {
@@ -41,12 +46,27 @@ function useMemoStateContext(props) {
41
46
  }
42
47
  }, [props.config, onChange]);
43
48
  const onItemRemove = React.useCallback((id) => {
44
- onChange(UpdateManager.removeItem({
45
- id,
46
- config: props.config,
47
- itemsStateAndParams: props.itemsStateAndParams,
48
- }));
49
- }, [props.config, props.itemsStateAndParams, onChange]);
49
+ if (id === TEMPORARY_ITEM_ID) {
50
+ resetTemporaryLayout();
51
+ }
52
+ else {
53
+ if (temporaryLayout) {
54
+ setTemporaryLayout(temporaryLayout.filter(({ i }) => i !== id));
55
+ }
56
+ onChange(UpdateManager.removeItem({
57
+ id,
58
+ config: props.config,
59
+ itemsStateAndParams: props.itemsStateAndParams,
60
+ }));
61
+ }
62
+ }, [
63
+ props.config,
64
+ props.itemsStateAndParams,
65
+ temporaryLayout,
66
+ onChange,
67
+ setTemporaryLayout,
68
+ resetTemporaryLayout,
69
+ ]);
50
70
  const onItemStateAndParamsChange = React.useCallback((id, stateAndParams, options) => {
51
71
  onChange({
52
72
  itemsStateAndParams: UpdateManager.changeStateAndParams({
@@ -120,11 +140,62 @@ function useMemoStateContext(props) {
120
140
  const reloadItems = React.useCallback((pluginsRefs, data) => {
121
141
  pluginsRefs.forEach((ref) => ref && ref.reload && ref.reload(data));
122
142
  }, []);
143
+ const draggedPluginRef = React.useRef(dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType);
144
+ React.useEffect(() => {
145
+ if (!(dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType) && !temporaryLayout) {
146
+ draggedPluginRef.current = null;
147
+ }
148
+ else if (dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType) {
149
+ draggedPluginRef.current = dndContext.dragPluginType;
150
+ }
151
+ }, [draggedPluginRef, dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType, temporaryLayout]);
152
+ const dndPluginType = draggedPluginRef.current || (dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType);
153
+ const dragOverPlugin = React.useMemo(() => {
154
+ const pluginType = dndPluginType;
155
+ if (pluginType === null && temporaryLayout === null)
156
+ return null;
157
+ if (props.registerManager.check(pluginType)) {
158
+ return props.registerManager.getItem(pluginType);
159
+ }
160
+ else {
161
+ // eslint-disable-next-line no-console
162
+ console.error(`Uknown pluginType: ${pluginType}`);
163
+ return null;
164
+ }
165
+ }, [dndPluginType, props.registerManager, temporaryLayout]);
166
+ const onDropDragOver = React.useCallback(() => {
167
+ if (temporaryLayout) {
168
+ resetTemporaryLayout();
169
+ return false;
170
+ }
171
+ if (dragOverPlugin === null || dragOverPlugin === void 0 ? void 0 : dragOverPlugin.defaultLayout) {
172
+ const { h = 3, w = 3 } = dragOverPlugin.defaultLayout;
173
+ return { h, w };
174
+ }
175
+ return false;
176
+ }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin]);
177
+ const onDrop = React.useCallback((newLayout, item) => {
178
+ setTemporaryLayout(newLayout);
179
+ const { i, w, h, x, y } = item;
180
+ props.onDrop({
181
+ newLayout: newLayout.reduce((memo, l) => {
182
+ if (l.i !== i) {
183
+ memo.push({ i: l.i, w: l.w, h: l.h, x: l.x, y: l.y });
184
+ }
185
+ return memo;
186
+ }, []),
187
+ itemLayout: { w, h, x, y },
188
+ pluginType: dndPluginType,
189
+ commit: resetTemporaryLayout,
190
+ });
191
+ }, [dndPluginType, props.onDrop]);
123
192
  return React.useMemo(() => ({
124
193
  layout: resultLayout,
194
+ temporaryLayout,
125
195
  config: props.config,
126
196
  context: props.context,
127
197
  noOverlay: props.noOverlay,
198
+ focusable: props.focusable,
128
199
  defaultGlobalParams: props.globalParams,
129
200
  globalParams: props.globalParams,
130
201
  editMode: props.editMode,
@@ -134,6 +205,8 @@ function useMemoStateContext(props) {
134
205
  registerManager: props.registerManager,
135
206
  onItemStateAndParamsChange,
136
207
  removeItem: onItemRemove,
208
+ onDrop,
209
+ onDropDragOver,
137
210
  editItem: props.onItemEdit,
138
211
  layoutChange: onLayoutChange,
139
212
  getItemsMeta,
@@ -142,11 +215,15 @@ function useMemoStateContext(props) {
142
215
  revertToOriginalLayout,
143
216
  forwardedMetaRef: props.forwardedMetaRef,
144
217
  draggableHandleClassName: props.draggableHandleClassName,
218
+ outerDnDEnable,
219
+ dragOverPlugin,
145
220
  }), [
146
221
  resultLayout,
222
+ temporaryLayout,
147
223
  props.config,
148
224
  props.context,
149
225
  props.noOverlay,
226
+ props.focusable,
150
227
  props.globalParams,
151
228
  props.editMode,
152
229
  props.settings,
@@ -155,6 +232,8 @@ function useMemoStateContext(props) {
155
232
  props.registerManager,
156
233
  onItemStateAndParamsChange,
157
234
  onItemRemove,
235
+ onDrop,
236
+ onDropDragOver,
158
237
  props.onItemEdit,
159
238
  onLayoutChange,
160
239
  getItemsMeta,
@@ -163,6 +242,8 @@ function useMemoStateContext(props) {
163
242
  revertToOriginalLayout,
164
243
  props.forwardedMetaRef,
165
244
  props.draggableHandleClassName,
245
+ outerDnDEnable,
246
+ dragOverPlugin,
166
247
  ]);
167
248
  }
168
249
  export function withContext(Component) {
@@ -1,3 +1,4 @@
1
1
  export declare const CURRENT_VERSION = 2;
2
2
  export declare const META_KEY = "__meta__";
3
3
  export declare const ACTION_PARAM_PREFIX = "_ap_";
4
+ export declare const TERMORARY_ITEM_ID = "__dropping-elem__";
@@ -1,3 +1,4 @@
1
1
  export const CURRENT_VERSION = 2;
2
2
  export const META_KEY = '__meta__';
3
3
  export const ACTION_PARAM_PREFIX = '_ap_';
4
+ export const TERMORARY_ITEM_ID = '__dropping-elem__';
@@ -8,3 +8,6 @@ export type SetConfigItem = ConfigItem | AddConfigItem;
8
8
  export type SetItemOptions = {
9
9
  excludeIds?: string[];
10
10
  };
11
+ export type SetNewItemOptions = SetItemOptions & {
12
+ updateLayout?: ConfigLayout[];
13
+ };
@@ -36,4 +36,5 @@ export interface PluginDefaultLayout {
36
36
  export interface Plugin<P extends PluginWidgetProps<T> = any, T = StringParams> extends PluginBase {
37
37
  defaultLayout?: PluginDefaultLayout;
38
38
  renderer: (props: P, forwardedRef: React.RefObject<any>) => React.ReactNode;
39
+ placeholderRenderer?: (props: P, forwardedRef: React.RefObject<any>) => React.ReactNode;
39
40
  }
@@ -1,5 +1,5 @@
1
1
  import type { Config, ConfigItem, ItemStateAndParams, ItemStateAndParamsChangeOptions, ItemsStateAndParams } from '../shared';
2
- import type { AddConfigItem, SetItemOptions, WidgetLayout } from '../typings';
2
+ import type { AddConfigItem, SetItemOptions, SetNewItemOptions, WidgetLayout } from '../typings';
3
3
  import { RegisterManagerPluginLayout } from './register-manager';
4
4
  interface RemoveItemArg {
5
5
  id: string;
@@ -19,7 +19,7 @@ export declare class UpdateManager {
19
19
  namespace: string;
20
20
  layout: RegisterManagerPluginLayout;
21
21
  config: Config;
22
- options: SetItemOptions;
22
+ options: SetNewItemOptions;
23
23
  }): Config;
24
24
  static editItem({ item, namespace, config, options, }: {
25
25
  item: ConfigItem;
@@ -212,19 +212,37 @@ function changeGroupParams({ groupItemIds, initiatorId, initiatorItem, itemsStat
212
212
  }
213
213
  export class UpdateManager {
214
214
  static addItem({ item, namespace = DEFAULT_NAMESPACE, layout, config, options, }) {
215
- const layoutY = Math.max(0, ...config.layout.map(({ h, y }) => h + y));
216
- const saveDefaultLayout = pick(layout, ['h', 'w', 'x', 'y']);
217
215
  const salt = config.salt;
218
216
  const newItemData = getNewItemData({ item, config, salt, counter: config.counter, options });
219
217
  let counter = newItemData.counter;
220
218
  const newIdData = getNewId({ config, salt, counter, excludeIds: newItemData.excludeIds });
221
219
  counter = newIdData.counter;
222
220
  const newItem = Object.assign(Object.assign({}, item), { id: newIdData.id, data: newItemData.data, namespace });
223
- return update(config, {
224
- items: { $push: [newItem] },
225
- layout: { $push: [Object.assign(Object.assign({}, saveDefaultLayout), { y: layoutY, i: newItem.id })] },
226
- counter: { $set: counter },
227
- });
221
+ const saveDefaultLayout = pick(layout, ['h', 'w', 'x', 'y']);
222
+ if (options.updateLayout) {
223
+ const byId = options.updateLayout.reduce((memo, t) => {
224
+ memo[t.i] = t;
225
+ return memo;
226
+ }, {});
227
+ const newLayout = [
228
+ ...config.layout.map((t) => (Object.assign(Object.assign({}, t), (byId[t.i] || {})))),
229
+ Object.assign(Object.assign({}, saveDefaultLayout), { i: newItem.id }),
230
+ ];
231
+ return update(config, {
232
+ items: { $push: [newItem] },
233
+ layout: { $set: newLayout },
234
+ counter: { $set: counter },
235
+ });
236
+ }
237
+ else {
238
+ const layoutY = Math.max(0, ...config.layout.map(({ h, y }) => h + y));
239
+ const newLayoutItem = Object.assign(Object.assign({}, saveDefaultLayout), { y: layoutY, i: newItem.id });
240
+ return update(config, {
241
+ items: { $push: [newItem] },
242
+ layout: { $push: [newLayoutItem] },
243
+ counter: { $set: counter },
244
+ });
245
+ }
228
246
  }
229
247
  static editItem({ item, namespace = DEFAULT_NAMESPACE, config, options, }) {
230
248
  const itemIndex = config.items.findIndex(({ id }) => item.id === id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dashkit",
3
- "version": "8.0.2",
3
+ "version": "8.1.0-beta.1",
4
4
  "description": "Library for rendering dashboard grid layout",
5
5
  "license": "MIT",
6
6
  "repository": {