@gravity-ui/dashkit 8.1.0 → 8.2.0-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 (76) hide show
  1. package/README.md +95 -0
  2. package/build/cjs/components/ActionPanel/ActionPanel.d.ts +4 -1
  3. package/build/cjs/components/ActionPanel/ActionPanel.js +10 -6
  4. package/build/cjs/components/ActionPanel/types.d.ts +3 -1
  5. package/build/cjs/components/DashKit/DashKit.d.ts +4 -3
  6. package/build/cjs/components/DashKit/DashKit.js +1 -0
  7. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +10 -0
  8. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.js +35 -0
  9. package/build/cjs/components/GridItem/GridItem.d.ts +2 -2
  10. package/build/cjs/components/GridItem/GridItem.js +8 -5
  11. package/build/cjs/components/GridLayout/GridLayout.d.ts +3 -0
  12. package/build/cjs/components/GridLayout/GridLayout.js +51 -11
  13. package/build/cjs/components/GridLayout/ReactGridLayout.d.ts +3 -0
  14. package/build/cjs/components/GridLayout/ReactGridLayout.js +49 -0
  15. package/build/cjs/components/Item/Item.css +1 -1
  16. package/build/cjs/components/Item/Item.d.ts +1 -0
  17. package/build/cjs/components/Item/Item.js +7 -1
  18. package/build/cjs/components/OverlayControls/OverlayControls.js +2 -2
  19. package/build/cjs/components/index.d.ts +1 -0
  20. package/build/cjs/components/index.js +1 -0
  21. package/build/cjs/constants/common.d.ts +4 -0
  22. package/build/cjs/constants/common.js +5 -1
  23. package/build/cjs/context/DashKitContext.d.ts +1 -0
  24. package/build/cjs/context/DashKitContext.js +3 -1
  25. package/build/cjs/hocs/prepareItem.d.ts +1 -0
  26. package/build/cjs/hocs/prepareItem.js +4 -2
  27. package/build/cjs/hocs/withContext.js +84 -6
  28. package/build/cjs/hooks/useDnDItemProps.d.ts +10 -0
  29. package/build/cjs/hooks/useDnDItemProps.js +30 -0
  30. package/build/cjs/shared/constants/common.d.ts +1 -0
  31. package/build/cjs/shared/constants/common.js +2 -1
  32. package/build/cjs/shared/modules/state-and-params.d.ts +2 -1
  33. package/build/cjs/shared/modules/state-and-params.js +18 -4
  34. package/build/cjs/shared/types/common.d.ts +15 -0
  35. package/build/cjs/typings/config.d.ts +3 -0
  36. package/build/cjs/typings/plugin.d.ts +1 -0
  37. package/build/cjs/utils/update-manager.d.ts +10 -3
  38. package/build/cjs/utils/update-manager.js +52 -20
  39. package/build/esm/components/ActionPanel/ActionPanel.d.ts +4 -1
  40. package/build/esm/components/ActionPanel/ActionPanel.js +8 -5
  41. package/build/esm/components/ActionPanel/types.d.ts +3 -1
  42. package/build/esm/components/DashKit/DashKit.d.ts +4 -3
  43. package/build/esm/components/DashKit/DashKit.js +1 -0
  44. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +10 -0
  45. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.js +30 -0
  46. package/build/esm/components/GridItem/GridItem.d.ts +2 -2
  47. package/build/esm/components/GridItem/GridItem.js +8 -5
  48. package/build/esm/components/GridLayout/GridLayout.d.ts +3 -0
  49. package/build/esm/components/GridLayout/GridLayout.js +52 -12
  50. package/build/esm/components/GridLayout/ReactGridLayout.d.ts +3 -0
  51. package/build/esm/components/GridLayout/ReactGridLayout.js +45 -0
  52. package/build/esm/components/Item/Item.css +1 -1
  53. package/build/esm/components/Item/Item.d.ts +1 -0
  54. package/build/esm/components/Item/Item.js +7 -1
  55. package/build/esm/components/OverlayControls/OverlayControls.js +2 -2
  56. package/build/esm/components/index.d.ts +1 -0
  57. package/build/esm/components/index.js +1 -0
  58. package/build/esm/constants/common.d.ts +4 -0
  59. package/build/esm/constants/common.js +4 -0
  60. package/build/esm/context/DashKitContext.d.ts +1 -0
  61. package/build/esm/context/DashKitContext.js +2 -1
  62. package/build/esm/hocs/prepareItem.d.ts +1 -0
  63. package/build/esm/hocs/prepareItem.js +4 -2
  64. package/build/esm/hocs/withContext.js +85 -7
  65. package/build/esm/hooks/useDnDItemProps.d.ts +10 -0
  66. package/build/esm/hooks/useDnDItemProps.js +25 -0
  67. package/build/esm/shared/constants/common.d.ts +1 -0
  68. package/build/esm/shared/constants/common.js +1 -0
  69. package/build/esm/shared/modules/state-and-params.d.ts +2 -1
  70. package/build/esm/shared/modules/state-and-params.js +18 -4
  71. package/build/esm/shared/types/common.d.ts +15 -0
  72. package/build/esm/typings/config.d.ts +3 -0
  73. package/build/esm/typings/plugin.d.ts +1 -0
  74. package/build/esm/utils/update-manager.d.ts +10 -3
  75. package/build/esm/utils/update-manager.js +50 -19
  76. package/package.json +1 -1
@@ -56,9 +56,9 @@ class GridItem extends React.PureComponent {
56
56
  };
57
57
  }
58
58
  renderOverlay() {
59
- const { overlayControls } = this.props;
59
+ const { overlayControls, isPlaceholder } = this.props;
60
60
  const { editMode } = this.context;
61
- if (!editMode || this.props.item.data._editActive) {
61
+ if (!editMode || this.props.item.data._editActive || isPlaceholder) {
62
62
  return null;
63
63
  }
64
64
  const { item } = this.props;
@@ -70,7 +70,7 @@ class GridItem extends React.PureComponent {
70
70
  render() {
71
71
  // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable
72
72
  // https://github.com/STRML/react-grid-layout/issues/721
73
- const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, } = this.props;
73
+ const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, isPlaceholder, } = this.props;
74
74
  const { editMode } = this.context;
75
75
  const width = Number.parseInt(style.width, 10);
76
76
  const height = Number.parseInt(style.height, 10);
@@ -95,7 +95,7 @@ class GridItem extends React.PureComponent {
95
95
  }
96
96
  : {})),
97
97
  React.createElement("div", { className: b('item', { editMode: editMode && !_editActive && !noOverlay }) },
98
- React.createElement(Item, { id: this.props.id, item: this.props.item, shouldItemUpdate: !isDragging, width: width, height: height, transform: transform, adjustWidgetLayout: this.props.adjustWidgetLayout, layout: this.props.layout, forwardedPluginRef: this.props.forwardedPluginRef })),
98
+ 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 })),
99
99
  !noOverlay && this.renderOverlay(),
100
100
  preparedChildren));
101
101
  }
@@ -109,6 +109,7 @@ GridItem.propTypes = {
109
109
  overlayControls: PropTypes.object,
110
110
  forwardedRef: PropTypes.any,
111
111
  forwardedPluginRef: PropTypes.any,
112
+ isPlaceholder: PropTypes.bool,
112
113
  // from react-grid-layout:
113
114
  children: PropTypes.node,
114
115
  className: PropTypes.string,
@@ -122,6 +123,8 @@ GridItem.propTypes = {
122
123
  onTouchStart: PropTypes.func,
123
124
  };
124
125
  GridItem.contextType = DashKitContext;
125
- export default React.forwardRef((props, ref) => {
126
+ const GridItemForwarderRef = React.forwardRef((props, ref) => {
126
127
  return React.createElement(GridItem, Object.assign({}, props, { forwardedRef: ref }));
127
128
  });
129
+ GridItemForwarderRef.displayName = 'forwardRef(GridItem)';
130
+ export default GridItemForwarderRef;
@@ -21,6 +21,9 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
21
21
  reloadItems(): void;
22
22
  _onStart: () => void;
23
23
  _onStop: (newLayout: any) => void;
24
+ _onDropDragOver: (e: any) => any;
25
+ _onDrop: (layout: any, item: any, e: any) => false | undefined;
26
+ renderTemporaryPlaceholder(): JSX.Element | null;
24
27
  render(): JSX.Element;
25
28
  }
26
29
  import React from 'react';
@@ -1,9 +1,8 @@
1
1
  import React from 'react';
2
- import ReactGridLayout, { WidthProvider } from 'react-grid-layout';
3
- import { OVERLAY_CONTROLS_CLASS_NAME } from '../../constants';
2
+ import { OVERLAY_CONTROLS_CLASS_NAME, TEMPORARY_ITEM_ID } from '../../constants';
4
3
  import { DashKitContext } from '../../context/DashKitContext';
5
4
  import GridItem from '../GridItem/GridItem';
6
- const Layout = WidthProvider(ReactGridLayout); // eslint-disable-line new-cap
5
+ import { Layout } from './ReactGridLayout';
7
6
  class GridLayout extends React.PureComponent {
8
7
  constructor(props, context) {
9
8
  super(props, context);
@@ -29,13 +28,37 @@ class GridLayout extends React.PureComponent {
29
28
  return getItemsMeta(this.pluginsRefs);
30
29
  };
31
30
  this._onStart = () => {
31
+ if (this.temporaryLayout)
32
+ return;
32
33
  this.setState({ isDragging: true });
33
34
  };
34
35
  this._onStop = (newLayout) => {
35
- const { layoutChange } = this.context;
36
- layoutChange(newLayout);
36
+ const { layoutChange, onDrop, temporaryLayout } = this.context;
37
+ if (temporaryLayout) {
38
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(newLayout, newLayout.find(({ i }) => i === TEMPORARY_ITEM_ID));
39
+ }
40
+ else {
41
+ layoutChange(newLayout);
42
+ }
37
43
  this.setState({ isDragging: false });
38
44
  };
45
+ this._onDropDragOver = (e) => {
46
+ const { editMode, dragOverPlugin, onDropDragOver } = this.context;
47
+ if (!editMode || !dragOverPlugin) {
48
+ return false;
49
+ }
50
+ return onDropDragOver(e);
51
+ };
52
+ this._onDrop = (layout, item, e) => {
53
+ if (!item) {
54
+ return false;
55
+ }
56
+ const { editMode, onDrop } = this.context;
57
+ if (!editMode) {
58
+ return false;
59
+ }
60
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(layout, item, e);
61
+ };
39
62
  this.pluginsRefs = [];
40
63
  this.state = {
41
64
  isDragging: false,
@@ -68,16 +91,33 @@ class GridLayout extends React.PureComponent {
68
91
  this._timeout = setTimeout(() => this.reloadItems(), reloadIntervalRemains <= 0 ? autoupdateIntervalMs : reloadIntervalRemains);
69
92
  }
70
93
  }
94
+ renderTemporaryPlaceholder() {
95
+ const { temporaryLayout, noOverlay, draggableHandleClassName } = this.context;
96
+ if (!temporaryLayout || !temporaryLayout.dragProps) {
97
+ return null;
98
+ }
99
+ const id = TEMPORARY_ITEM_ID;
100
+ const { type } = temporaryLayout.dragProps;
101
+ 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), overlayControls: this.props.overlayControls }));
102
+ }
71
103
  render() {
72
- const { layout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, } = this.context;
104
+ const { layout, temporaryLayout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
73
105
  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
106
+ return (React.createElement(Layout, Object.assign({}, registerManager.gridLayout, { layout: (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: this._onStop, onResizeStart: this._onStart, onResizeStop: this._onStop }, (draggableHandleClassName
75
107
  ? { 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, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
80
- })));
108
+ : null), (outerDnDEnable
109
+ ? {
110
+ isDroppable: true,
111
+ onDropDragOver: this._onDropDragOver,
112
+ onDrop: this._onDrop,
113
+ }
114
+ : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
115
+ config.items.map((item, i) => {
116
+ return (React.createElement(GridItem, { forwardedPluginRef: (pluginRef) => {
117
+ this.pluginsRefs[i] = pluginRef;
118
+ }, key: item.id, id: item.id, item: item, layout: (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
119
+ }),
120
+ this.renderTemporaryPlaceholder()));
81
121
  }
82
122
  }
83
123
  GridLayout.contextType = DashKitContext;
@@ -0,0 +1,3 @@
1
+ export const Layout: React.ComponentClass<ReactGridLayout.ReactGridLayoutProps & ReactGridLayout.WidthProviderProps, any>;
2
+ import ReactGridLayout from 'react-grid-layout';
3
+ import React from 'react';
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import ReactGridLayout, { WidthProvider } from 'react-grid-layout';
3
+ import { OVERLAY_CLASS_NAME } from '../../constants';
4
+ class DragOverLayout extends ReactGridLayout {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.dragReset = () => {
8
+ if (this.dragEnterCounter) {
9
+ this.dragEnterCounter = 0;
10
+ this.removeDroppingPlaceholder();
11
+ }
12
+ };
13
+ }
14
+ componentDidMount() {
15
+ var _a;
16
+ (_a = super.componentDidMount) === null || _a === void 0 ? void 0 : _a.call(this);
17
+ window.addEventListener('dragend', this.dragReset);
18
+ }
19
+ componentWillUnmount() {
20
+ window.removeEventListener('dragend', this.dragReset);
21
+ }
22
+ processGridItem(child, isDroppingItem) {
23
+ var _a;
24
+ const gridItem = (_a = super.processGridItem) === null || _a === void 0 ? void 0 : _a.call(this, child, isDroppingItem);
25
+ if (isDroppingItem) {
26
+ // Drop item from outside gets 0,0 droppingPosition
27
+ // centering cursor on newly creted grid item
28
+ // And cause grid-layout using it's own GridItem to make it look
29
+ // like overlay adding className
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 gridItem;
42
+ }
43
+ }
44
+ // eslint-disable-next-line new-cap
45
+ export const Layout = WidthProvider(DragOverLayout);
@@ -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);
@@ -180,8 +180,8 @@ class OverlayControls extends React.Component {
180
180
  };
181
181
  });
182
182
  items = items.filter(Boolean);
183
- return (React.createElement(DropdownMenu, { items: items, switcher: React.createElement(Button, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" },
184
- React.createElement(Icon, { data: DotsIcon, size: "16" })) }));
183
+ return (React.createElement(DropdownMenu, { items: items, renderSwitcher: (props) => (React.createElement(Button, Object.assign({}, props, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" }),
184
+ React.createElement(Icon, { data: DotsIcon, size: "16" }))) }));
185
185
  }
186
186
  getControlItemPinStyle(index, itemsLength) {
187
187
  const isOnlyOneItem = itemsLength === 1;
@@ -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,8 +1,12 @@
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";
7
9
  readonly Settings: "settings";
8
10
  };
11
+ export declare const DEFAULT_WIDGET_HEIGHT = 3;
12
+ export declare const DEFAULT_WIDGET_WIDTH = 3;
@@ -1,8 +1,12 @@
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',
7
9
  Settings: 'settings',
8
10
  };
11
+ export const DEFAULT_WIDGET_HEIGHT = 3;
12
+ export const DEFAULT_WIDGET_WIDTH = 3;
@@ -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 { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, 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(Object.assign(Object.assign({}, temporaryLayout), { data: temporaryLayout.data.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,8 +140,57 @@ 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 dragProps = dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragProps;
144
+ const dragOverPlugin = React.useMemo(() => {
145
+ if (!dragProps) {
146
+ return null;
147
+ }
148
+ const pluginType = dragProps.type;
149
+ if (props.registerManager.check(pluginType)) {
150
+ return props.registerManager.getItem(pluginType);
151
+ }
152
+ else {
153
+ // eslint-disable-next-line no-console
154
+ console.error(`Uknown pluginType: ${pluginType}`);
155
+ return null;
156
+ }
157
+ }, [dragProps, props.registerManager]);
158
+ const onDropDragOver = React.useCallback(() => {
159
+ if (temporaryLayout) {
160
+ resetTemporaryLayout();
161
+ return false;
162
+ }
163
+ if (dragOverPlugin) {
164
+ const { defaultLayout } = dragOverPlugin;
165
+ 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.layout || {};
166
+ return { h, w };
167
+ }
168
+ return false;
169
+ }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
170
+ const onDrop = React.useCallback((newLayout, item) => {
171
+ if (!dragProps) {
172
+ return;
173
+ }
174
+ setTemporaryLayout({
175
+ data: newLayout,
176
+ dragProps,
177
+ });
178
+ const { i, w, h, x, y } = item;
179
+ props.onDrop({
180
+ newLayout: newLayout.reduce((memo, l) => {
181
+ if (l.i !== i) {
182
+ memo.push({ i: l.i, w: l.w, h: l.h, x: l.x, y: l.y });
183
+ }
184
+ return memo;
185
+ }, []),
186
+ itemLayout: { w, h, x, y },
187
+ commit: resetTemporaryLayout,
188
+ dragProps,
189
+ });
190
+ }, [dragProps, props.onDrop, setTemporaryLayout, resetTemporaryLayout]);
123
191
  return React.useMemo(() => ({
124
192
  layout: resultLayout,
193
+ temporaryLayout,
125
194
  config: props.config,
126
195
  context: props.context,
127
196
  noOverlay: props.noOverlay,
@@ -135,6 +204,8 @@ function useMemoStateContext(props) {
135
204
  registerManager: props.registerManager,
136
205
  onItemStateAndParamsChange,
137
206
  removeItem: onItemRemove,
207
+ onDrop,
208
+ onDropDragOver,
138
209
  editItem: props.onItemEdit,
139
210
  layoutChange: onLayoutChange,
140
211
  getItemsMeta,
@@ -143,8 +214,11 @@ function useMemoStateContext(props) {
143
214
  revertToOriginalLayout,
144
215
  forwardedMetaRef: props.forwardedMetaRef,
145
216
  draggableHandleClassName: props.draggableHandleClassName,
217
+ outerDnDEnable,
218
+ dragOverPlugin,
146
219
  }), [
147
220
  resultLayout,
221
+ temporaryLayout,
148
222
  props.config,
149
223
  props.context,
150
224
  props.noOverlay,
@@ -157,6 +231,8 @@ function useMemoStateContext(props) {
157
231
  props.registerManager,
158
232
  onItemStateAndParamsChange,
159
233
  onItemRemove,
234
+ onDrop,
235
+ onDropDragOver,
160
236
  props.onItemEdit,
161
237
  onLayoutChange,
162
238
  getItemsMeta,
@@ -165,6 +241,8 @@ function useMemoStateContext(props) {
165
241
  revertToOriginalLayout,
166
242
  props.forwardedMetaRef,
167
243
  props.draggableHandleClassName,
244
+ outerDnDEnable,
245
+ dragOverPlugin,
168
246
  ]);
169
247
  }
170
248
  export function withContext(Component) {
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { ActionPanelItem } from '../components';
3
+ type DndProps = null | {
4
+ draggable: true;
5
+ unselectable: 'on';
6
+ onDragStart: React.DragEventHandler<HTMLDivElement>;
7
+ onDragEnd: React.DragEventHandler<HTMLDivElement>;
8
+ };
9
+ export declare const useDnDItemProps: (item: ActionPanelItem) => DndProps;
10
+ export {};
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { DashKitDnDContext } from '../context/DashKitContext';
3
+ export const useDnDItemProps = (item) => {
4
+ const dragContext = React.useContext(DashKitDnDContext);
5
+ const onDragStart = React.useCallback((e) => {
6
+ if (dragContext && item.dragProps) {
7
+ dragContext.onDragStart(e, item.dragProps);
8
+ e.dataTransfer.setDragImage(dragContext.dragImagePreview, 0, 0);
9
+ }
10
+ }, [dragContext, item.dragProps]);
11
+ const onDragEnd = React.useCallback((e) => {
12
+ if (dragContext) {
13
+ dragContext.onDragEnd(e);
14
+ }
15
+ }, [dragContext]);
16
+ if (dragContext && item.dragProps) {
17
+ return {
18
+ draggable: true,
19
+ unselectable: 'on',
20
+ onDragStart,
21
+ onDragEnd,
22
+ };
23
+ }
24
+ return null;
25
+ };
@@ -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__';
@@ -5,9 +5,10 @@ export interface GetItemsParamsArg {
5
5
  config: Config;
6
6
  itemsStateAndParams: ItemsStateAndParams;
7
7
  plugins: PluginBase[];
8
+ useStateAsInitial?: boolean;
8
9
  }
9
10
  type GetItemsParamsReturn = Record<string, StringParams | Record<string, StringParams>>;
10
- export declare function getItemsParams({ defaultGlobalParams, globalParams, config, itemsStateAndParams, plugins, }: GetItemsParamsArg): GetItemsParamsReturn;
11
+ export declare function getItemsParams({ defaultGlobalParams, globalParams, config, itemsStateAndParams, plugins, useStateAsInitial, }: GetItemsParamsArg): GetItemsParamsReturn;
11
12
  export declare function getItemsState({ config, itemsStateAndParams, }: {
12
13
  config: Config;
13
14
  itemsStateAndParams: ItemsStateAndParams;
@@ -1,7 +1,18 @@
1
1
  import groupBy from 'lodash/groupBy';
2
2
  import { META_KEY } from '../constants';
3
3
  import { formQueueData, getCurrentVersion, getMapItemsIgnores, hasActionParam, isItemWithGroup, isItemWithTabs, mergeParamsWithAliases, pickActionParamsFromParams, pickExceptActionParamsFromParams, prerenderItems, resolveItemInnerId, } from './helpers';
4
- function getItemParams({ item, itemsStateAndParams, mapItemsIgnores, itemsWithDefaultsByNamespace, getMergedParams, defaultGlobalParams, globalParams, isFirstVersion, queueData, }) {
4
+ const getParamsFromStateAndParams = ({ itemsStateAndParams, parentItemId, item, }) => {
5
+ const widgetId = parentItemId || item.id;
6
+ if (!(widgetId in itemsStateAndParams)) {
7
+ return {};
8
+ }
9
+ const stateAndParams = itemsStateAndParams;
10
+ const itemParams = parentItemId
11
+ ? Object.assign({}, stateAndParams[widgetId].params[item.id])
12
+ : Object.assign({}, stateAndParams[widgetId].params);
13
+ return itemParams;
14
+ };
15
+ function getItemParams({ item, itemsStateAndParams, mapItemsIgnores, itemsWithDefaultsByNamespace, getMergedParams, defaultGlobalParams, globalParams, isFirstVersion, queueData, parentItemId, useStateAsInitial, }) {
5
16
  var _a, _b;
6
17
  const { id, namespace } = item;
7
18
  let defaultWidgetParams = {};
@@ -20,7 +31,9 @@ function getItemParams({ item, itemsStateAndParams, mapItemsIgnores, itemsWithDe
20
31
  // default parameters to begin with
21
32
  affectingItemsWithDefaults.reduceRight((defaultParams, itemWithDefaults) => {
22
33
  return Object.assign(Object.assign({}, defaultParams), getMergedParams(itemWithDefaults.defaults || {}));
23
- }, {}), getMergedParams(globalParams));
34
+ }, {}), getMergedParams(globalParams), useStateAsInitial
35
+ ? getParamsFromStateAndParams({ parentItemId, item, itemsStateAndParams })
36
+ : {});
24
37
  if (isFirstVersion) {
25
38
  itemParams = Object.assign(itemParams, ((_b = itemsStateAndParams === null || itemsStateAndParams === void 0 ? void 0 : itemsStateAndParams[id]) === null || _b === void 0 ? void 0 : _b.params) || {});
26
39
  }
@@ -45,7 +58,7 @@ function getItemParams({ item, itemsStateAndParams, mapItemsIgnores, itemsWithDe
45
58
  }
46
59
  return Object.assign(Object.assign({}, defaultWidgetParams), itemParams);
47
60
  }
48
- export function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, config, itemsStateAndParams, plugins, }) {
61
+ export function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, config, itemsStateAndParams, plugins, useStateAsInitial, }) {
49
62
  const { aliases, connections } = config;
50
63
  const items = prerenderItems({ items: config.items, plugins });
51
64
  const isFirstVersion = getCurrentVersion(itemsStateAndParams) === 1;
@@ -88,10 +101,11 @@ export function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, co
88
101
  globalParams,
89
102
  isFirstVersion,
90
103
  queueData,
104
+ useStateAsInitial,
91
105
  };
92
106
  if (isItemWithGroup(item)) {
93
107
  const groupParams = item.data.group.reduce((groupItemParams, groupItem) => {
94
- groupItemParams[groupItem.id] = getItemParams(Object.assign({ item: groupItem }, paramsOptions));
108
+ groupItemParams[groupItem.id] = getItemParams(Object.assign({ item: groupItem, parentItemId: item.id }, paramsOptions));
95
109
  return groupItemParams;
96
110
  }, {});
97
111
  return Object.assign(Object.assign({}, itemsParams), { [id]: groupParams });
@@ -1,5 +1,20 @@
1
+ import { ConfigLayout } from './config';
1
2
  export type Dictionary<T = unknown> = Record<string, T>;
2
3
  export interface StringParams extends Dictionary<string | string[]> {
3
4
  }
4
5
  export interface GlobalParams extends StringParams {
5
6
  }
7
+ export type ItemDragProps = {
8
+ type: string;
9
+ layout?: {
10
+ w?: number;
11
+ h?: number;
12
+ };
13
+ extra?: any;
14
+ };
15
+ export type ItemDropProps = {
16
+ commit: () => void;
17
+ dragProps: ItemDragProps;
18
+ itemLayout: ConfigLayout;
19
+ newLayout: ConfigLayout[];
20
+ };
@@ -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
  }