@gravity-ui/dashkit 8.1.0 → 8.2.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 (72) 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/types/common.d.ts +15 -0
  33. package/build/cjs/typings/config.d.ts +3 -0
  34. package/build/cjs/typings/plugin.d.ts +1 -0
  35. package/build/cjs/utils/update-manager.d.ts +2 -2
  36. package/build/cjs/utils/update-manager.js +25 -7
  37. package/build/esm/components/ActionPanel/ActionPanel.d.ts +4 -1
  38. package/build/esm/components/ActionPanel/ActionPanel.js +8 -5
  39. package/build/esm/components/ActionPanel/types.d.ts +3 -1
  40. package/build/esm/components/DashKit/DashKit.d.ts +4 -3
  41. package/build/esm/components/DashKit/DashKit.js +1 -0
  42. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +10 -0
  43. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.js +30 -0
  44. package/build/esm/components/GridItem/GridItem.d.ts +2 -2
  45. package/build/esm/components/GridItem/GridItem.js +8 -5
  46. package/build/esm/components/GridLayout/GridLayout.d.ts +3 -0
  47. package/build/esm/components/GridLayout/GridLayout.js +52 -12
  48. package/build/esm/components/GridLayout/ReactGridLayout.d.ts +3 -0
  49. package/build/esm/components/GridLayout/ReactGridLayout.js +45 -0
  50. package/build/esm/components/Item/Item.css +1 -1
  51. package/build/esm/components/Item/Item.d.ts +1 -0
  52. package/build/esm/components/Item/Item.js +7 -1
  53. package/build/esm/components/OverlayControls/OverlayControls.js +2 -2
  54. package/build/esm/components/index.d.ts +1 -0
  55. package/build/esm/components/index.js +1 -0
  56. package/build/esm/constants/common.d.ts +4 -0
  57. package/build/esm/constants/common.js +4 -0
  58. package/build/esm/context/DashKitContext.d.ts +1 -0
  59. package/build/esm/context/DashKitContext.js +2 -1
  60. package/build/esm/hocs/prepareItem.d.ts +1 -0
  61. package/build/esm/hocs/prepareItem.js +4 -2
  62. package/build/esm/hocs/withContext.js +85 -7
  63. package/build/esm/hooks/useDnDItemProps.d.ts +10 -0
  64. package/build/esm/hooks/useDnDItemProps.js +25 -0
  65. package/build/esm/shared/constants/common.d.ts +1 -0
  66. package/build/esm/shared/constants/common.js +1 -0
  67. package/build/esm/shared/types/common.d.ts +15 -0
  68. package/build/esm/typings/config.d.ts +3 -0
  69. package/build/esm/typings/plugin.d.ts +1 -0
  70. package/build/esm/utils/update-manager.d.ts +2 -2
  71. package/build/esm/utils/update-manager.js +25 -7
  72. package/package.json +1 -1
package/README.md CHANGED
@@ -29,6 +29,7 @@ interface DashKitProps {
29
29
  editMode: boolean;
30
30
  onItemEdit: ({id}: {id: string}) => void;
31
31
  onChange: (data: {config: Config; itemsStateAndParams: ItemsStateAndParams}) => void;
32
+ onDrop: (dropProps: ItemDropProps) => void;
32
33
  defaultGlobalParams: GlobalParams;
33
34
  globalParams: GlobalParams;
34
35
  itemsStateAndParams: ItemsStateAndParams;
@@ -36,6 +37,8 @@ interface DashKitProps {
36
37
  context: ContextProps;
37
38
  overlayControls?: Record<string, OverlayControlItem[]>;
38
39
  noOverlay?: boolean;
40
+ focusable?: boolean;
41
+ draggableHandleClassName?: string;
39
42
  }
40
43
  ```
41
44
 
@@ -43,6 +46,7 @@ interface DashKitProps {
43
46
  - **editMode**: Whether edit mode is enabled.
44
47
  - **onItemEdit**: Called when you click to edit a widget.
45
48
  - **onChange**: Called when config or [itemsStateAndParams](#temsStateAndParams) are changed.
49
+ - **onDrop**: Called when item dropped from ActionPanel using (#DashKitDnDWrapper)
46
50
  - **defaultGlobalParams**, **globalParams**: [Parameters](#Params) that affect all widgets. In DataLens, `defaultGlobalParams` are global parameters set in the dashboard settings. `globalParams` are globals parameters that can be set in the url.
47
51
  - **itemsStateAndParams**: [itemsStateAndParams](#temsStateAndParams).
48
52
  - **settings**: DashKit settings.
@@ -208,6 +212,23 @@ const config: DashKitProps['config'] = {
208
212
  Add a new item to the config:
209
213
 
210
214
  ```ts
215
+ const newLayout = updateLayout: [
216
+ {
217
+ h: 6,
218
+ i: 'Ea',
219
+ w: 12,
220
+ x: 0,
221
+ y: 6,
222
+ },
223
+ {
224
+ h: 4,
225
+ i: 'Dk',
226
+ w: 8,
227
+ x: 0,
228
+ y: 12,
229
+ },
230
+ ];
231
+
211
232
  const newConfig = DashKit.setItem({
212
233
  item: {
213
234
  data: {
@@ -215,8 +236,19 @@ const newConfig = DashKit.setItem({
215
236
  },
216
237
  namespace: 'default',
217
238
  type: 'text',
239
+ // Optional. If new item needed to be inserted in current layout with predefined dimensions
240
+ layout: { // Current item inseterted before 'Ea'
241
+ h: 6,
242
+ w: 12,
243
+ x: 0,
244
+ y: 2,
245
+ },,
218
246
  },
219
247
  config: config,
248
+ options: {
249
+ // Optional. New layout values for existing items when new element is dropped from ActionPanel
250
+ updateLayout: newLayout,
251
+ },
220
252
  });
221
253
  ```
222
254
 
@@ -314,6 +346,69 @@ type MenuItem = {
314
346
  DashKit.setSettings({menu: [] as Array<MenuItem>});
315
347
  ```
316
348
 
349
+ ### Draggable items from ActionPanel
350
+
351
+ #### DashKitDnDWrapper
352
+
353
+ ```ts
354
+ interface DashKitDnDWrapperProps {
355
+ dragImageSrc?: string;
356
+ onDragStart?: (dragProps: ItemDragProps) => void;
357
+ onDragEnd?: () => void;
358
+ }
359
+ ```
360
+
361
+ - **dragImageSrc**: Drag image preview, by default used transparent 1px png base64
362
+ - **onDragStart**: Callback called when element is dragged from ActionPanel
363
+ - **onDragEnd**: Callback called when element dropped or drag canceled
364
+
365
+ ```ts
366
+ type ItemDragProps = {
367
+ type: string; // Plugin type
368
+ layout?: { // Optional. Layout item size for preview and init
369
+ w?: number;
370
+ h?: number;
371
+ };
372
+ extra?: any; // Custom user context
373
+ };
374
+ ```
375
+
376
+ ```ts
377
+ type ItemDropProps = {
378
+ commit: () => void; // Callback should be called after all config operations are made
379
+ dragProps: ItemDragProps; // Item drag props
380
+ itemLayout: ConfigLayout; // Calculated item layout dimensions
381
+ newLayout: ConfigLayout[]; // New layout after element is dropped
382
+ };
383
+ ```
384
+
385
+
386
+ #### Example:
387
+
388
+ ```jsx
389
+ const menuItems = [
390
+ {
391
+ id: 'chart',
392
+ icon: <Icon data={ChartColumn} />,
393
+ title: 'Chart',
394
+ qa: 'chart',
395
+ dragProps: { // ItemDragProps
396
+ type: 'custom', // Registered plugin type
397
+ },
398
+ }
399
+ ]
400
+
401
+ const onDrop = (dropProps: ItemDropProps) => {
402
+ // ... add element to your config
403
+ dropProps.commit();
404
+ }
405
+
406
+ <DashKitDnDWrapper>
407
+ <DashKit editMode={true} config={config} onChange={onChange} onDrop={onDrop} />
408
+ <ActionPanel items={menuItems} />
409
+ </DashKitDnDWrapper>
410
+ ```
411
+
317
412
  ### CSS API
318
413
 
319
414
  | Name | Description |
@@ -1,3 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { ActionPanelProps } from './types';
2
+ import { ActionPanelItem, ActionPanelProps } from './types';
3
+ export declare const ActionPanelItemContainer: ({ item }: {
4
+ item: ActionPanelItem;
5
+ }) => JSX.Element;
3
6
  export declare const ActionPanel: (props: ActionPanelProps) => JSX.Element | null;
@@ -1,21 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ActionPanel = void 0;
3
+ exports.ActionPanel = exports.ActionPanelItemContainer = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const react_transition_group_1 = require("react-transition-group");
7
+ const useDnDItemProps_1 = require("../../hooks/useDnDItemProps");
7
8
  const cn_1 = require("../../utils/cn");
8
9
  const b = (0, cn_1.cn)('dashkit-action-panel');
10
+ const ActionPanelItemContainer = ({ item }) => {
11
+ const dndProps = (0, useDnDItemProps_1.useDnDItemProps)(item);
12
+ return (react_1.default.createElement("div", Object.assign({ role: "button", className: b('item', { draggable: Boolean(dndProps) }, item.className), onClick: item.onClick, "data-qa": item.qa }, dndProps),
13
+ react_1.default.createElement("div", { className: b('icon') }, item.icon),
14
+ react_1.default.createElement("div", { className: b('title'), title: item.title }, item.title)));
15
+ };
16
+ exports.ActionPanelItemContainer = ActionPanelItemContainer;
9
17
  const ActionPanel = (props) => {
10
18
  var _a, _b;
11
19
  const isDisabled = (_a = props.disable) !== null && _a !== void 0 ? _a : false;
12
20
  const isAnimated = (_b = props.toggleAnimation) !== null && _b !== void 0 ? _b : false;
13
21
  const nodeRef = react_1.default.useRef(null);
14
- const content = (react_1.default.createElement("div", { ref: nodeRef, className: b(null, props.className) }, props.items.map((item) => {
15
- return (react_1.default.createElement("div", { role: "button", className: b('item', item.className), key: `dk-action-panel-${item.id}`, onClick: item.onClick, "data-qa": item.qa },
16
- react_1.default.createElement("div", { className: b('icon') }, item.icon),
17
- react_1.default.createElement("div", { className: b('title'), title: item.title }, item.title)));
18
- })));
22
+ const content = (react_1.default.createElement("div", { ref: nodeRef, className: b(null, props.className) }, props.items.map((item) => (react_1.default.createElement(exports.ActionPanelItemContainer, { key: `dk-action-panel-${item.id}`, item: item })))));
19
23
  if (isAnimated) {
20
24
  return (react_1.default.createElement(react_transition_group_1.CSSTransition, { in: !isDisabled, nodeRef: nodeRef, classNames: b(null), timeout: 300, unmountOnExit: true }, content));
21
25
  }
@@ -1,11 +1,13 @@
1
1
  import React from 'react';
2
+ import type { ItemDragProps } from '../../shared';
2
3
  export type ActionPanelItem = {
3
4
  id: string;
4
5
  icon: React.ReactNode;
5
6
  title: string;
6
- onClick?: () => void;
7
7
  className?: string;
8
8
  qa?: string;
9
+ onClick?: () => void;
10
+ dragProps?: ItemDragProps;
9
11
  };
10
12
  export type ActionPanelProps = {
11
13
  items: ActionPanelItem[];
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import type { Config, ConfigItem, GlobalParams, ItemsStateAndParams } from '../../shared';
3
- import { ContextProps, Plugin, SetConfigItem, SetItemOptions, Settings, SettingsProps } from '../../typings';
2
+ import type { Config, ConfigItem, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
+ import { ContextProps, Plugin, SetConfigItem, SetNewItemOptions, Settings, SettingsProps } from '../../typings';
4
4
  import GridLayout from '../GridLayout/GridLayout';
5
5
  import { OverlayControlItem } from '../OverlayControls/OverlayControls';
6
6
  interface DashKitGeneralProps {
@@ -15,6 +15,7 @@ interface DashKitDefaultProps {
15
15
  config: Config;
16
16
  itemsStateAndParams: ItemsStateAndParams;
17
17
  }) => void;
18
+ onDrop: (dropProps: ItemDropProps) => void;
18
19
  defaultGlobalParams: GlobalParams;
19
20
  globalParams: GlobalParams;
20
21
  itemsStateAndParams: ItemsStateAndParams;
@@ -34,7 +35,7 @@ export declare class DashKit extends React.PureComponent<DashKitInnerProps> {
34
35
  item: SetConfigItem;
35
36
  namespace?: string;
36
37
  config: Config;
37
- options?: SetItemOptions;
38
+ options?: SetNewItemOptions;
38
39
  }): Config;
39
40
  static removeItem({ id, config, itemsStateAndParams, }: {
40
41
  id: string;
@@ -59,6 +59,7 @@ exports.DashKit = DashKit;
59
59
  DashKit.defaultProps = {
60
60
  onItemEdit: noop_1.default,
61
61
  onChange: noop_1.default,
62
+ onDrop: noop_1.default,
62
63
  defaultGlobalParams: {},
63
64
  globalParams: {},
64
65
  itemsStateAndParams: {},
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { ItemDragProps } from '../../shared';
3
+ type DashKitDnDWrapperProps = {
4
+ dragImageSrc?: string;
5
+ onDragStart?: (dragProps: ItemDragProps) => void;
6
+ onDragEnd?: () => void;
7
+ children: React.ReactElement;
8
+ };
9
+ export declare const DashKitDnDWrapper: React.FC<DashKitDnDWrapperProps>;
10
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DashKitDnDWrapper = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const DashKitContext_1 = require("../../context/DashKitContext");
7
+ const defaultImageSrc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
8
+ const DashKitDnDWrapper = (props) => {
9
+ const [dragProps, setDragProps] = react_1.default.useState(null);
10
+ const dragImagePreview = react_1.default.useMemo(() => {
11
+ const img = new Image();
12
+ img.src = props.dragImageSrc || defaultImageSrc;
13
+ return img;
14
+ }, [props.dragImageSrc]);
15
+ const onDragStart = react_1.default.useCallback((_, itemDragProps) => {
16
+ var _a;
17
+ setDragProps(itemDragProps);
18
+ (_a = props.onDragStart) === null || _a === void 0 ? void 0 : _a.call(props, itemDragProps);
19
+ }, [setDragProps, props.onDragStart]);
20
+ const onDragEnd = react_1.default.useCallback((_) => {
21
+ var _a;
22
+ setDragProps(null);
23
+ (_a = props.onDragEnd) === null || _a === void 0 ? void 0 : _a.call(props);
24
+ }, [setDragProps, props.onDragEnd]);
25
+ const contextValue = react_1.default.useMemo(() => {
26
+ return {
27
+ dragProps,
28
+ dragImagePreview,
29
+ onDragStart,
30
+ onDragEnd,
31
+ };
32
+ }, [dragProps, dragImagePreview, onDragStart, onDragEnd]);
33
+ return (react_1.default.createElement(DashKitContext_1.DashKitDnDContext.Provider, { value: contextValue }, props.children));
34
+ };
35
+ exports.DashKitDnDWrapper = DashKitDnDWrapper;
@@ -1,3 +1,3 @@
1
- declare const _default: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
2
- export default _default;
1
+ export default GridItemForwarderRef;
2
+ declare const GridItemForwarderRef: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
3
3
  import React from 'react';
@@ -58,9 +58,9 @@ class GridItem extends react_1.default.PureComponent {
58
58
  };
59
59
  }
60
60
  renderOverlay() {
61
- const { overlayControls } = this.props;
61
+ const { overlayControls, isPlaceholder } = this.props;
62
62
  const { editMode } = this.context;
63
- if (!editMode || this.props.item.data._editActive) {
63
+ if (!editMode || this.props.item.data._editActive || isPlaceholder) {
64
64
  return null;
65
65
  }
66
66
  const { item } = this.props;
@@ -72,7 +72,7 @@ class GridItem extends react_1.default.PureComponent {
72
72
  render() {
73
73
  // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable
74
74
  // https://github.com/STRML/react-grid-layout/issues/721
75
- const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, } = this.props;
75
+ const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, isPlaceholder, } = this.props;
76
76
  const { editMode } = this.context;
77
77
  const width = Number.parseInt(style.width, 10);
78
78
  const height = Number.parseInt(style.height, 10);
@@ -97,7 +97,7 @@ class GridItem extends react_1.default.PureComponent {
97
97
  }
98
98
  : {})),
99
99
  react_1.default.createElement("div", { className: b('item', { editMode: editMode && !_editActive && !noOverlay }) },
100
- react_1.default.createElement(Item_1.default, { 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 })),
100
+ react_1.default.createElement(Item_1.default, { 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 })),
101
101
  !noOverlay && this.renderOverlay(),
102
102
  preparedChildren));
103
103
  }
@@ -111,6 +111,7 @@ GridItem.propTypes = {
111
111
  overlayControls: prop_types_1.default.object,
112
112
  forwardedRef: prop_types_1.default.any,
113
113
  forwardedPluginRef: prop_types_1.default.any,
114
+ isPlaceholder: prop_types_1.default.bool,
114
115
  // from react-grid-layout:
115
116
  children: prop_types_1.default.node,
116
117
  className: prop_types_1.default.string,
@@ -124,6 +125,8 @@ GridItem.propTypes = {
124
125
  onTouchStart: prop_types_1.default.func,
125
126
  };
126
127
  GridItem.contextType = DashKitContext_1.DashKitContext;
127
- exports.default = react_1.default.forwardRef((props, ref) => {
128
+ const GridItemForwarderRef = react_1.default.forwardRef((props, ref) => {
128
129
  return react_1.default.createElement(GridItem, Object.assign({}, props, { forwardedRef: ref }));
129
130
  });
131
+ GridItemForwarderRef.displayName = 'forwardRef(GridItem)';
132
+ exports.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';
@@ -2,11 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
- const react_grid_layout_1 = tslib_1.__importStar(require("react-grid-layout"));
6
5
  const constants_1 = require("../../constants");
7
6
  const DashKitContext_1 = require("../../context/DashKitContext");
8
7
  const GridItem_1 = tslib_1.__importDefault(require("../GridItem/GridItem"));
9
- const Layout = (0, react_grid_layout_1.WidthProvider)(react_grid_layout_1.default); // eslint-disable-line new-cap
8
+ const ReactGridLayout_1 = require("./ReactGridLayout");
10
9
  class GridLayout extends react_1.default.PureComponent {
11
10
  constructor(props, context) {
12
11
  super(props, context);
@@ -32,13 +31,37 @@ class GridLayout extends react_1.default.PureComponent {
32
31
  return getItemsMeta(this.pluginsRefs);
33
32
  };
34
33
  this._onStart = () => {
34
+ if (this.temporaryLayout)
35
+ return;
35
36
  this.setState({ isDragging: true });
36
37
  };
37
38
  this._onStop = (newLayout) => {
38
- const { layoutChange } = this.context;
39
- layoutChange(newLayout);
39
+ const { layoutChange, onDrop, temporaryLayout } = this.context;
40
+ if (temporaryLayout) {
41
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(newLayout, newLayout.find(({ i }) => i === constants_1.TEMPORARY_ITEM_ID));
42
+ }
43
+ else {
44
+ layoutChange(newLayout);
45
+ }
40
46
  this.setState({ isDragging: false });
41
47
  };
48
+ this._onDropDragOver = (e) => {
49
+ const { editMode, dragOverPlugin, onDropDragOver } = this.context;
50
+ if (!editMode || !dragOverPlugin) {
51
+ return false;
52
+ }
53
+ return onDropDragOver(e);
54
+ };
55
+ this._onDrop = (layout, item, e) => {
56
+ if (!item) {
57
+ return false;
58
+ }
59
+ const { editMode, onDrop } = this.context;
60
+ if (!editMode) {
61
+ return false;
62
+ }
63
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(layout, item, e);
64
+ };
42
65
  this.pluginsRefs = [];
43
66
  this.state = {
44
67
  isDragging: false,
@@ -71,16 +94,33 @@ class GridLayout extends react_1.default.PureComponent {
71
94
  this._timeout = setTimeout(() => this.reloadItems(), reloadIntervalRemains <= 0 ? autoupdateIntervalMs : reloadIntervalRemains);
72
95
  }
73
96
  }
97
+ renderTemporaryPlaceholder() {
98
+ const { temporaryLayout, noOverlay, draggableHandleClassName } = this.context;
99
+ if (!temporaryLayout || !temporaryLayout.dragProps) {
100
+ return null;
101
+ }
102
+ const id = constants_1.TEMPORARY_ITEM_ID;
103
+ const { type } = temporaryLayout.dragProps;
104
+ return (react_1.default.createElement(GridItem_1.default, { 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 }));
105
+ }
74
106
  render() {
75
- const { layout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, } = this.context;
107
+ const { layout, temporaryLayout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
76
108
  this.pluginsRefs.length = config.items.length;
77
- return (react_1.default.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
109
+ return (react_1.default.createElement(ReactGridLayout_1.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
78
110
  ? { draggableHandle: `.${draggableHandleClassName}` }
79
- : null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }), config.items.map((item, i) => {
80
- return (react_1.default.createElement(GridItem_1.default, { forwardedPluginRef: (pluginRef) => {
81
- this.pluginsRefs[i] = pluginRef;
82
- }, 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 }));
83
- })));
111
+ : null), (outerDnDEnable
112
+ ? {
113
+ isDroppable: true,
114
+ onDropDragOver: this._onDropDragOver,
115
+ onDrop: this._onDrop,
116
+ }
117
+ : null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }),
118
+ config.items.map((item, i) => {
119
+ return (react_1.default.createElement(GridItem_1.default, { forwardedPluginRef: (pluginRef) => {
120
+ this.pluginsRefs[i] = pluginRef;
121
+ }, 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 }));
122
+ }),
123
+ this.renderTemporaryPlaceholder()));
84
124
  }
85
125
  }
86
126
  GridLayout.contextType = DashKitContext_1.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,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Layout = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const react_grid_layout_1 = tslib_1.__importStar(require("react-grid-layout"));
7
+ const constants_1 = require("../../constants");
8
+ class DragOverLayout extends react_grid_layout_1.default {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.dragReset = () => {
12
+ if (this.dragEnterCounter) {
13
+ this.dragEnterCounter = 0;
14
+ this.removeDroppingPlaceholder();
15
+ }
16
+ };
17
+ }
18
+ componentDidMount() {
19
+ var _a;
20
+ (_a = super.componentDidMount) === null || _a === void 0 ? void 0 : _a.call(this);
21
+ window.addEventListener('dragend', this.dragReset);
22
+ }
23
+ componentWillUnmount() {
24
+ window.removeEventListener('dragend', this.dragReset);
25
+ }
26
+ processGridItem(child, isDroppingItem) {
27
+ var _a;
28
+ const gridItem = (_a = super.processGridItem) === null || _a === void 0 ? void 0 : _a.call(this, child, isDroppingItem);
29
+ if (isDroppingItem) {
30
+ // Drop item from outside gets 0,0 droppingPosition
31
+ // centering cursor on newly creted grid item
32
+ // And cause grid-layout using it's own GridItem to make it look
33
+ // like overlay adding className
34
+ if (!gridItem)
35
+ return null;
36
+ const { props } = gridItem;
37
+ const { containerWidth, cols, w, h, rowHeight, margin, transformScale } = props;
38
+ const leftOffset = (((containerWidth / cols) * w) / 2 || 0) * transformScale;
39
+ const topOffset = ((h * rowHeight + (h - 1) * margin[1]) / 2 || 0) * transformScale;
40
+ return react_1.default.cloneElement(gridItem, {
41
+ className: constants_1.OVERLAY_CLASS_NAME,
42
+ droppingPosition: Object.assign(Object.assign({}, props.droppingPosition), { left: props.droppingPosition.left - leftOffset, top: props.droppingPosition.top - topOffset }),
43
+ });
44
+ }
45
+ return gridItem;
46
+ }
47
+ }
48
+ // eslint-disable-next-line new-cap
49
+ exports.Layout = (0, react_grid_layout_1.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>;
@@ -7,11 +7,16 @@ const prepareItem_1 = require("../../hocs/prepareItem");
7
7
  const cn_1 = require("../../utils/cn");
8
8
  const b = (0, cn_1.cn)('dashkit-item');
9
9
  // TODO: getDerivedStateFromError и заглушка с ошибкой
10
- const Item = ({ registerManager, rendererProps, type, forwardedPluginRef }) => {
10
+ const Item = ({ registerManager, rendererProps, type, isPlaceholder, forwardedPluginRef }) => {
11
+ var _a, _b;
11
12
  if (!registerManager.check(type)) {
12
13
  console.warn(`type [${type}] не зарегистрирован`);
13
14
  return null;
14
15
  }
16
+ if (isPlaceholder) {
17
+ return (react_1.default.createElement("div", { className: b('placeholder') }, ((_b = (_a = registerManager
18
+ .getItem(type)).placeholderRenderer) === null || _b === void 0 ? void 0 : _b.call(_a, rendererProps, forwardedPluginRef)) || null));
19
+ }
15
20
  return (react_1.default.createElement("div", { className: b('renderer') }, registerManager.getItem(type).renderer(rendererProps, forwardedPluginRef)));
16
21
  };
17
22
  Item.propTypes = {
@@ -19,5 +24,6 @@ Item.propTypes = {
19
24
  rendererProps: prop_types_1.default.object,
20
25
  registerManager: prop_types_1.default.object,
21
26
  type: prop_types_1.default.string,
27
+ isPlaceholder: prop_types_1.default.bool,
22
28
  };
23
29
  exports.default = (0, prepareItem_1.prepareItem)(Item);
@@ -183,8 +183,8 @@ class OverlayControls extends react_1.default.Component {
183
183
  };
184
184
  });
185
185
  items = items.filter(Boolean);
186
- return (react_1.default.createElement(uikit_1.DropdownMenu, { items: items, switcher: react_1.default.createElement(uikit_1.Button, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" },
187
- react_1.default.createElement(uikit_1.Icon, { data: DotsIcon_1.DotsIcon, size: "16" })) }));
186
+ return (react_1.default.createElement(uikit_1.DropdownMenu, { items: items, renderSwitcher: (props) => (react_1.default.createElement(uikit_1.Button, Object.assign({}, props, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" }),
187
+ react_1.default.createElement(uikit_1.Icon, { data: DotsIcon_1.DotsIcon, size: "16" }))) }));
188
188
  }
189
189
  getControlItemPinStyle(index, itemsLength) {
190
190
  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';
@@ -3,3 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./DashKit"), exports);
5
5
  tslib_1.__exportStar(require("./ActionPanel/ActionPanel"), exports);
6
+ tslib_1.__exportStar(require("./DashKitDnDWrapper/DashKitDnDWrapper"), exports);
@@ -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,11 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MenuItems = exports.OVERLAY_CONTROLS_CLASS_NAME = exports.DEFAULT_NAMESPACE = exports.COPIED_WIDGET_STORE_KEY = void 0;
3
+ exports.DEFAULT_WIDGET_WIDTH = exports.DEFAULT_WIDGET_HEIGHT = exports.MenuItems = exports.TEMPORARY_ITEM_ID = exports.OVERLAY_CLASS_NAME = exports.OVERLAY_CONTROLS_CLASS_NAME = exports.DEFAULT_NAMESPACE = exports.COPIED_WIDGET_STORE_KEY = void 0;
4
4
  exports.COPIED_WIDGET_STORE_KEY = 'dashCopiedItem';
5
5
  exports.DEFAULT_NAMESPACE = 'default';
6
6
  exports.OVERLAY_CONTROLS_CLASS_NAME = 'dashkit-overlay-controls';
7
+ exports.OVERLAY_CLASS_NAME = 'dashkit-grid-item__overlay';
8
+ exports.TEMPORARY_ITEM_ID = '__dropping-elem__';
7
9
  exports.MenuItems = {
8
10
  Copy: 'copy',
9
11
  Delete: 'delete',
10
12
  Settings: 'settings',
11
13
  };
14
+ exports.DEFAULT_WIDGET_HEIGHT = 3;
15
+ exports.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,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DashKitContext = void 0;
3
+ exports.DashKitDnDContext = exports.DashKitContext = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const DashKitContext = react_1.default.createContext();
7
7
  exports.DashKitContext = DashKitContext;
8
+ const DashKitDnDContext = react_1.default.createContext();
9
+ exports.DashKitDnDContext = 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>;
@@ -26,7 +26,7 @@ function prepareItem(Component) {
26
26
  return true;
27
27
  }
28
28
  render() {
29
- const { id, width, height, item, adjustWidgetLayout, layout } = this.props;
29
+ const { id, width, height, item, adjustWidgetLayout, layout, isPlaceholder } = this.props;
30
30
  const { itemsState, itemsParams, registerManager, settings, context, editMode } = this.context;
31
31
  const { type, data, defaults, namespace } = item;
32
32
  const rendererProps = {
@@ -45,8 +45,9 @@ function prepareItem(Component) {
45
45
  layout,
46
46
  gridLayout: registerManager.gridLayout,
47
47
  adjustWidgetLayout,
48
+ isPlaceholder,
48
49
  };
49
- return (react_1.default.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: rendererProps, registerManager: registerManager, type: type }));
50
+ return (react_1.default.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: rendererProps, registerManager: registerManager, type: type, isPlaceholder: isPlaceholder }));
50
51
  }
51
52
  },
52
53
  _a.propTypes = {
@@ -58,6 +59,7 @@ function prepareItem(Component) {
58
59
  width: prop_types_1.default.number,
59
60
  height: prop_types_1.default.number,
60
61
  transform: prop_types_1.default.string,
62
+ isPlaceholder: prop_types_1.default.bool,
61
63
  forwardedPluginRef: prop_types_1.default.any,
62
64
  },
63
65
  _a.contextType = DashKitContext_1.DashKitContext,