@gravity-ui/dashkit 8.2.0-beta.0 → 8.3.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.
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { Config, ConfigItem, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
- import { ContextProps, Plugin, SetConfigItem, SetNewItemOptions, Settings, SettingsProps } from '../../typings';
3
+ import { ContextProps, DashKiGroup, 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 {
@@ -14,6 +14,7 @@ interface DashKitDefaultProps {
14
14
  onChange: (data: {
15
15
  config: Config;
16
16
  itemsStateAndParams: ItemsStateAndParams;
17
+ groups?: DashKiGroup[];
17
18
  }) => void;
18
19
  onDrop: (dropProps: ItemDropProps) => void;
19
20
  defaultGlobalParams: GlobalParams;
@@ -23,6 +24,7 @@ interface DashKitDefaultProps {
23
24
  context: ContextProps;
24
25
  noOverlay: boolean;
25
26
  focusable?: boolean;
27
+ groups?: DashKiGroup[];
26
28
  }
27
29
  export interface DashKitProps extends DashKitGeneralProps, Partial<DashKitDefaultProps> {
28
30
  }
@@ -44,11 +44,7 @@ class DashKit extends react_1.default.PureComponent {
44
44
  return utils_1.UpdateManager.removeItem({ id, config, itemsStateAndParams });
45
45
  }
46
46
  render() {
47
- return (react_1.default.createElement(DashKitView_1.default
48
- // @ts-ignore
49
- , Object.assign({
50
- // @ts-ignore
51
- registerManager: registerManager, ref: this.metaRef }, this.props)));
47
+ return react_1.default.createElement(DashKitView_1.default, Object.assign({ registerManager: registerManager, ref: this.metaRef }, this.props));
52
48
  }
53
49
  getItemsMeta() {
54
50
  var _a;
@@ -18,12 +18,15 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
18
18
  adjustedWidgetLayout: any;
19
19
  }) => void;
20
20
  getItemsMeta: () => any;
21
+ getActiveLayout(): any;
22
+ mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
21
23
  reloadItems(): void;
22
24
  _onStart: () => void;
23
- _onStop: (newLayout: any) => void;
25
+ _onStop: (group: any, newLayout: any) => void;
24
26
  _onDropDragOver: (e: any) => any;
25
- _onDrop: (layout: any, item: any, e: any) => false | undefined;
27
+ _onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
26
28
  renderTemporaryPlaceholder(): JSX.Element | null;
27
- render(): JSX.Element;
29
+ renderGroup(group: any, renderLayout: any, renderItems: any, offset?: number): JSX.Element;
30
+ render(): any;
28
31
  }
29
32
  import React from 'react';
@@ -35,13 +35,14 @@ class GridLayout extends react_1.default.PureComponent {
35
35
  return;
36
36
  this.setState({ isDragging: true });
37
37
  };
38
- this._onStop = (newLayout) => {
38
+ this._onStop = (group, newLayout) => {
39
39
  const { layoutChange, onDrop, temporaryLayout } = this.context;
40
+ const groupedLayout = this.mergeGroupsLayout(group, newLayout);
40
41
  if (temporaryLayout) {
41
- onDrop === null || onDrop === void 0 ? void 0 : onDrop(newLayout, newLayout.find(({ i }) => i === constants_1.TEMPORARY_ITEM_ID));
42
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, groupedLayout.find(({ i }) => i === constants_1.TEMPORARY_ITEM_ID));
42
43
  }
43
44
  else {
44
- layoutChange(newLayout);
45
+ layoutChange(groupedLayout);
45
46
  }
46
47
  this.setState({ isDragging: false });
47
48
  };
@@ -52,7 +53,7 @@ class GridLayout extends react_1.default.PureComponent {
52
53
  }
53
54
  return onDropDragOver(e);
54
55
  };
55
- this._onDrop = (layout, item, e) => {
56
+ this._onDrop = (group, newLayout, item, e) => {
56
57
  if (!item) {
57
58
  return false;
58
59
  }
@@ -60,7 +61,11 @@ class GridLayout extends react_1.default.PureComponent {
60
61
  if (!editMode) {
61
62
  return false;
62
63
  }
63
- onDrop === null || onDrop === void 0 ? void 0 : onDrop(layout, item, e);
64
+ if (group !== constants_1.DEFAULT_GROUP) {
65
+ item.parent = group;
66
+ }
67
+ const groupedLayout = this.mergeGroupsLayout(group, newLayout, item);
68
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, item, e);
64
69
  };
65
70
  this.pluginsRefs = [];
66
71
  this.state = {
@@ -80,6 +85,29 @@ class GridLayout extends react_1.default.PureComponent {
80
85
  clearTimeout(this._timeout);
81
86
  document.removeEventListener('visibilitychange', this.onVisibilityChange);
82
87
  }
88
+ getActiveLayout() {
89
+ const { layout, temporaryLayout } = this.context;
90
+ return (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout;
91
+ }
92
+ mergeGroupsLayout(group, newLayout, temporaryItem) {
93
+ const renderLayout = this.getActiveLayout();
94
+ const itemsByGroup = renderLayout.reduce((memo, item) => {
95
+ memo[item.i] = item;
96
+ return memo;
97
+ }, temporaryItem ? { [temporaryItem.i]: temporaryItem } : {});
98
+ const newItemsLayoutById = newLayout.reduce((memo, item) => {
99
+ const parent = itemsByGroup[item.i].parent;
100
+ memo[item.i] = Object.assign(Object.assign({}, item), { parent });
101
+ return memo;
102
+ }, {});
103
+ return renderLayout.map((currentItem) => {
104
+ const itemParent = itemsByGroup[currentItem.i].parent || constants_1.DEFAULT_GROUP;
105
+ if (itemParent === group) {
106
+ return newItemsLayoutById[currentItem.i];
107
+ }
108
+ return currentItem;
109
+ });
110
+ }
83
111
  reloadItems() {
84
112
  const { editMode, settings: { autoupdateInterval, silentLoading } = {}, reloadItems, } = this.context;
85
113
  const { isPageHidden } = this.state;
@@ -103,25 +131,84 @@ class GridLayout extends react_1.default.PureComponent {
103
131
  const { type } = temporaryLayout.dragProps;
104
132
  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
133
  }
106
- render() {
107
- const { layout, temporaryLayout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
108
- this.pluginsRefs.length = config.items.length;
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
134
+ renderGroup(group, renderLayout, renderItems, offset = 0) {
135
+ const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
136
+ return (react_1.default.createElement(ReactGridLayout_1.Layout, Object.assign({}, registerManager.gridLayout, { key: `group_${group}`, layout: renderLayout, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: (...args) => this._onStop(group, ...args), onResizeStart: this._onStart, onResizeStop: (...args) => this._onStop(group, ...args) }, (draggableHandleClassName
110
137
  ? { draggableHandle: `.${draggableHandleClassName}` }
111
138
  : null), (outerDnDEnable
112
139
  ? {
113
140
  isDroppable: true,
114
141
  onDropDragOver: this._onDropDragOver,
115
- onDrop: this._onDrop,
142
+ onDrop: (...args) => this._onDrop(group, ...args),
116
143
  }
117
144
  : null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }),
118
- config.items.map((item, i) => {
145
+ renderItems.map((item, i) => {
119
146
  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 }));
147
+ this.pluginsRefs[offset + i] = pluginRef;
148
+ }, key: item.id, id: item.id, item: item, layout: renderLayout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
122
149
  }),
123
150
  this.renderTemporaryPlaceholder()));
124
151
  }
152
+ render() {
153
+ const { config, groups, editMode } = this.context;
154
+ this.pluginsRefs.length = config.items.length;
155
+ const defaultRenderLayout = [];
156
+ const defaultRenderItems = [];
157
+ const layoutMap = {};
158
+ const groupedLayout = this.getActiveLayout().reduce((memo, item) => {
159
+ if (item.parent) {
160
+ if (!memo[item.parent]) {
161
+ memo[item.parent] = [];
162
+ }
163
+ memo[item.parent].push(item);
164
+ layoutMap[item.i] = item.parent;
165
+ }
166
+ else {
167
+ defaultRenderLayout.push(item);
168
+ }
169
+ return memo;
170
+ }, []);
171
+ const itemsByGroup = config.items.reduce((memo, item) => {
172
+ const group = layoutMap[item.id];
173
+ if (group) {
174
+ if (!memo[group]) {
175
+ memo[group] = [];
176
+ }
177
+ memo[group].push(item);
178
+ }
179
+ else {
180
+ defaultRenderItems.push(item);
181
+ }
182
+ return memo;
183
+ }, {});
184
+ let offset = 0;
185
+ if (groups) {
186
+ return groups.map((group) => {
187
+ const id = group.id || constants_1.DEFAULT_GROUP;
188
+ let element;
189
+ if (id === constants_1.DEFAULT_GROUP) {
190
+ element = this.renderGroup(constants_1.DEFAULT_GROUP, defaultRenderLayout, defaultRenderItems, offset);
191
+ offset += defaultRenderItems.length;
192
+ }
193
+ else {
194
+ element = this.renderGroup(id, groupedLayout[id], itemsByGroup[id], offset);
195
+ offset += itemsByGroup[id].length;
196
+ }
197
+ if (group.render) {
198
+ return group.render(id, element, {
199
+ config,
200
+ editMode,
201
+ items: itemsByGroup[id],
202
+ layout: groupedLayout[id],
203
+ });
204
+ }
205
+ return element;
206
+ });
207
+ }
208
+ else {
209
+ return this.renderGroup(constants_1.DEFAULT_GROUP, defaultRenderLayout, defaultRenderItems, offset);
210
+ }
211
+ }
125
212
  }
126
213
  GridLayout.contextType = DashKitContext_1.DashKitContext;
127
214
  exports.default = GridLayout;
@@ -6,14 +6,29 @@ const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const react_grid_layout_1 = tslib_1.__importStar(require("react-grid-layout"));
7
7
  const constants_1 = require("../../constants");
8
8
  class DragOverLayout extends react_grid_layout_1.default {
9
- constructor() {
10
- super(...arguments);
9
+ constructor(...args) {
10
+ super(...args);
11
11
  this.dragReset = () => {
12
12
  if (this.dragEnterCounter) {
13
13
  this.dragEnterCounter = 0;
14
14
  this.removeDroppingPlaceholder();
15
15
  }
16
16
  };
17
+ this.mouseLeaveHandler = (e) => {
18
+ var _a;
19
+ const rect = ((_a = this.props.innerRef) === null || _a === void 0 ? void 0 : _a.current.getBoundingClientRect()) || {};
20
+ if (rect.bottom <= e.clientY ||
21
+ rect.top >= e.clientY ||
22
+ rect.left >= e.clientX ||
23
+ rect.right <= e.clientX) {
24
+ this.dragReset();
25
+ }
26
+ };
27
+ const oldonDrag = this.onDrag;
28
+ this.onDrag = (i, x, y, sintE) => {
29
+ oldonDrag(i, x, y, sintE);
30
+ this.mouseLeaveHandler(sintE.e);
31
+ };
17
32
  }
18
33
  componentDidMount() {
19
34
  var _a;
@@ -10,3 +10,4 @@ export declare const MenuItems: {
10
10
  };
11
11
  export declare const DEFAULT_WIDGET_HEIGHT = 3;
12
12
  export declare const DEFAULT_WIDGET_WIDTH = 3;
13
+ export declare const DEFAULT_GROUP = "__default";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
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;
3
+ exports.DEFAULT_GROUP = 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';
@@ -13,3 +13,4 @@ exports.MenuItems = {
13
13
  };
14
14
  exports.DEFAULT_WIDGET_HEIGHT = 3;
15
15
  exports.DEFAULT_WIDGET_WIDTH = 3;
16
+ exports.DEFAULT_GROUP = '__default';
@@ -4,6 +4,7 @@ exports.withContext = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
7
+ const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
7
8
  const common_1 = require("../constants/common");
8
9
  const DashKitContext_1 = require("../context/DashKitContext");
9
10
  const shared_1 = require("../shared");
@@ -22,10 +23,11 @@ function useMemoStateContext(props) {
22
23
  const outerDnDEnable = Boolean(dndContext);
23
24
  // TODO: need move originalLayouts, adjustedLayouts to state
24
25
  const [layoutUpdateCounter, forceUpdateLayout] = react_1.default.useState(0);
25
- const onChange = react_1.default.useCallback(({ config = props.config, itemsStateAndParams = props.itemsStateAndParams }) => {
26
+ const onChange = react_1.default.useCallback(({ config = props.config, itemsStateAndParams = props.itemsStateAndParams, groups = props.groups, }) => {
26
27
  if (!((0, isEqual_1.default)(config, props.config) &&
27
- (0, isEqual_1.default)(itemsStateAndParams, props.itemsStateAndParams))) {
28
- props.onChange({ config, itemsStateAndParams });
28
+ (0, isEqual_1.default)(itemsStateAndParams, props.itemsStateAndParams) &&
29
+ (0, isEqual_1.default)(groups, props.groups))) {
30
+ props.onChange({ config, itemsStateAndParams, groups });
29
31
  }
30
32
  }, [props.config, props.itemsStateAndParams, props.onChange]);
31
33
  // каллбэк вызывающийся при изменение лэйаута сетки, первым аргументом приходит актуальный конфиг лэйаута,
@@ -171,6 +173,7 @@ function useMemoStateContext(props) {
171
173
  }
172
174
  return false;
173
175
  }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
176
+ const onDropProp = props.onDrop;
174
177
  const onDrop = react_1.default.useCallback((newLayout, item) => {
175
178
  if (!dragProps) {
176
179
  return;
@@ -179,23 +182,23 @@ function useMemoStateContext(props) {
179
182
  data: newLayout,
180
183
  dragProps,
181
184
  });
182
- const { i, w, h, x, y } = item;
183
- props.onDrop({
185
+ onDropProp({
184
186
  newLayout: newLayout.reduce((memo, l) => {
185
- if (l.i !== i) {
186
- memo.push({ i: l.i, w: l.w, h: l.h, x: l.x, y: l.y });
187
+ if (l.i !== item.i) {
188
+ memo.push((0, pick_1.default)(l, ['i', 'h', 'w', 'x', 'y', 'parent']));
187
189
  }
188
190
  return memo;
189
191
  }, []),
190
- itemLayout: { w, h, x, y },
192
+ itemLayout: (0, pick_1.default)(item, ['i', 'h', 'w', 'x', 'y', 'parent']),
191
193
  commit: resetTemporaryLayout,
192
194
  dragProps,
193
195
  });
194
- }, [dragProps, props.onDrop, setTemporaryLayout, resetTemporaryLayout]);
196
+ }, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
195
197
  return react_1.default.useMemo(() => ({
196
198
  layout: resultLayout,
197
199
  temporaryLayout,
198
200
  config: props.config,
201
+ groups: props.groups,
199
202
  context: props.context,
200
203
  noOverlay: props.noOverlay,
201
204
  focusable: props.focusable,
@@ -224,6 +227,7 @@ function useMemoStateContext(props) {
224
227
  resultLayout,
225
228
  temporaryLayout,
226
229
  props.config,
230
+ props.groups,
227
231
  props.context,
228
232
  props.noOverlay,
229
233
  props.focusable,
@@ -6,6 +6,7 @@ export declare const useCalcPropsLayout: (config: Config, registerManager: Regis
6
6
  w: number;
7
7
  x: number;
8
8
  y: number;
9
+ parent?: string | undefined;
9
10
  minW: number;
10
11
  minH: number;
11
12
  maxW?: number | undefined;
@@ -1,5 +1,8 @@
1
1
  import { StringParams } from './common';
2
- export interface ConfigLayout {
2
+ export interface AdditionalWidgetLayout {
3
+ parent?: string;
4
+ }
5
+ export interface ConfigLayout extends AdditionalWidgetLayout {
3
6
  i: string;
4
7
  h: number;
5
8
  w: number;
@@ -1,6 +1,7 @@
1
1
  import type ReactGridLayout from 'react-grid-layout';
2
2
  import type { OverlayCustomControlItem } from '../components/OverlayControls/OverlayControls';
3
3
  import { MenuItems } from '../constants';
4
+ import { AdditionalWidgetLayout } from '../shared';
4
5
  export interface Settings {
5
6
  gridLayout?: ReactGridLayout.ReactGridLayoutProps;
6
7
  theme?: string;
@@ -15,7 +16,7 @@ export interface SettingsProps {
15
16
  export interface ContextProps {
16
17
  [key: string]: any;
17
18
  }
18
- export interface WidgetLayout {
19
+ export interface WidgetLayout extends AdditionalWidgetLayout {
19
20
  i: string;
20
21
  w: number;
21
22
  h: number;
@@ -1,4 +1,5 @@
1
- import type { ConfigItem, ConfigLayout } from '../shared';
1
+ /// <reference types="react" />
2
+ import type { Config, ConfigItem, ConfigLayout } from '../shared';
2
3
  export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
3
4
  id?: null;
4
5
  namespace?: string;
@@ -11,3 +12,13 @@ export type SetItemOptions = {
11
12
  export type SetNewItemOptions = SetItemOptions & {
12
13
  updateLayout?: ConfigLayout[];
13
14
  };
15
+ export interface DashkitGroupRenderProps {
16
+ config: Config;
17
+ editMode: boolean;
18
+ items: ConfigItem[];
19
+ layout: ConfigLayout[];
20
+ }
21
+ export interface DashKiGroup {
22
+ id?: string;
23
+ render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
24
+ }
@@ -23,16 +23,7 @@ export interface PluginWidgetProps<T = StringParams> {
23
23
  adjustedWidgetLayout?: WidgetLayout;
24
24
  }) => void;
25
25
  }
26
- export interface PluginDefaultLayout {
27
- w?: number;
28
- h?: number;
29
- x?: number;
30
- y?: number;
31
- minW?: number;
32
- maxW?: number;
33
- minH?: number;
34
- maxH?: number;
35
- }
26
+ export type PluginDefaultLayout = Partial<Omit<WidgetLayout, 'i'>>;
36
27
  export interface Plugin<P extends PluginWidgetProps<T> = any, T = StringParams> extends PluginBase {
37
28
  defaultLayout?: PluginDefaultLayout;
38
29
  renderer: (props: P, forwardedRef: React.RefObject<any>) => React.ReactNode;
@@ -82,6 +82,7 @@ function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams, pa
82
82
  // if it's Record<string, StringParams>, then this is a group application of params
83
83
  // and checking for comparison of allowedParams and stateParamsConf is not necessary
84
84
  const isGroupParamsApply = typeof (stateParamsConf === null || stateParamsConf === void 0 ? void 0 : stateParamsConf[item.id]) === 'object' &&
85
+ (stateParamsConf === null || stateParamsConf === void 0 ? void 0 : stateParamsConf[item.id]) !== null &&
85
86
  !Array.isArray(stateParamsConf === null || stateParamsConf === void 0 ? void 0 : stateParamsConf[item.id]);
86
87
  if ((0, shared_1.isItemWithTabs)(item)) {
87
88
  let tab;
@@ -233,7 +234,7 @@ class UpdateManager {
233
234
  const newIdData = (0, get_new_id_1.getNewId)({ config, salt, counter, excludeIds: newItemData.excludeIds });
234
235
  counter = newIdData.counter;
235
236
  const newItem = Object.assign(Object.assign({}, item), { id: newIdData.id, data: newItemData.data, namespace });
236
- const saveDefaultLayout = (0, pick_1.default)(layout, ['h', 'w', 'x', 'y']);
237
+ const saveDefaultLayout = (0, pick_1.default)(layout, ['h', 'w', 'x', 'y', 'parent']);
237
238
  if (options.updateLayout) {
238
239
  const byId = options.updateLayout.reduce((memo, t) => {
239
240
  memo[t.i] = t;
@@ -314,7 +315,7 @@ class UpdateManager {
314
315
  static updateLayout({ layout, config }) {
315
316
  return (0, immutability_helper_1.default)(config, {
316
317
  layout: {
317
- $set: layout.map(({ x, y, w, h, i }) => ({ x, y, w, h, i })),
318
+ $set: layout.map((item) => (0, pick_1.default)(item, ['i', 'h', 'w', 'x', 'y', 'parent'])),
318
319
  },
319
320
  });
320
321
  }
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { Config, ConfigItem, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
- import { ContextProps, Plugin, SetConfigItem, SetNewItemOptions, Settings, SettingsProps } from '../../typings';
3
+ import { ContextProps, DashKiGroup, 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 {
@@ -14,6 +14,7 @@ interface DashKitDefaultProps {
14
14
  onChange: (data: {
15
15
  config: Config;
16
16
  itemsStateAndParams: ItemsStateAndParams;
17
+ groups?: DashKiGroup[];
17
18
  }) => void;
18
19
  onDrop: (dropProps: ItemDropProps) => void;
19
20
  defaultGlobalParams: GlobalParams;
@@ -23,6 +24,7 @@ interface DashKitDefaultProps {
23
24
  context: ContextProps;
24
25
  noOverlay: boolean;
25
26
  focusable?: boolean;
27
+ groups?: DashKiGroup[];
26
28
  }
27
29
  export interface DashKitProps extends DashKitGeneralProps, Partial<DashKitDefaultProps> {
28
30
  }
@@ -40,11 +40,7 @@ export class DashKit extends React.PureComponent {
40
40
  return UpdateManager.removeItem({ id, config, itemsStateAndParams });
41
41
  }
42
42
  render() {
43
- return (React.createElement(DashKitView
44
- // @ts-ignore
45
- , Object.assign({
46
- // @ts-ignore
47
- registerManager: registerManager, ref: this.metaRef }, this.props)));
43
+ return React.createElement(DashKitView, Object.assign({ registerManager: registerManager, ref: this.metaRef }, this.props));
48
44
  }
49
45
  getItemsMeta() {
50
46
  var _a;
@@ -18,12 +18,15 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
18
18
  adjustedWidgetLayout: any;
19
19
  }) => void;
20
20
  getItemsMeta: () => any;
21
+ getActiveLayout(): any;
22
+ mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
21
23
  reloadItems(): void;
22
24
  _onStart: () => void;
23
- _onStop: (newLayout: any) => void;
25
+ _onStop: (group: any, newLayout: any) => void;
24
26
  _onDropDragOver: (e: any) => any;
25
- _onDrop: (layout: any, item: any, e: any) => false | undefined;
27
+ _onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
26
28
  renderTemporaryPlaceholder(): JSX.Element | null;
27
- render(): JSX.Element;
29
+ renderGroup(group: any, renderLayout: any, renderItems: any, offset?: number): JSX.Element;
30
+ render(): any;
28
31
  }
29
32
  import React from 'react';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { OVERLAY_CONTROLS_CLASS_NAME, TEMPORARY_ITEM_ID } from '../../constants';
2
+ import { DEFAULT_GROUP, OVERLAY_CONTROLS_CLASS_NAME, TEMPORARY_ITEM_ID } from '../../constants';
3
3
  import { DashKitContext } from '../../context/DashKitContext';
4
4
  import GridItem from '../GridItem/GridItem';
5
5
  import { Layout } from './ReactGridLayout';
@@ -32,13 +32,14 @@ class GridLayout extends React.PureComponent {
32
32
  return;
33
33
  this.setState({ isDragging: true });
34
34
  };
35
- this._onStop = (newLayout) => {
35
+ this._onStop = (group, newLayout) => {
36
36
  const { layoutChange, onDrop, temporaryLayout } = this.context;
37
+ const groupedLayout = this.mergeGroupsLayout(group, newLayout);
37
38
  if (temporaryLayout) {
38
- onDrop === null || onDrop === void 0 ? void 0 : onDrop(newLayout, newLayout.find(({ i }) => i === TEMPORARY_ITEM_ID));
39
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, groupedLayout.find(({ i }) => i === TEMPORARY_ITEM_ID));
39
40
  }
40
41
  else {
41
- layoutChange(newLayout);
42
+ layoutChange(groupedLayout);
42
43
  }
43
44
  this.setState({ isDragging: false });
44
45
  };
@@ -49,7 +50,7 @@ class GridLayout extends React.PureComponent {
49
50
  }
50
51
  return onDropDragOver(e);
51
52
  };
52
- this._onDrop = (layout, item, e) => {
53
+ this._onDrop = (group, newLayout, item, e) => {
53
54
  if (!item) {
54
55
  return false;
55
56
  }
@@ -57,7 +58,11 @@ class GridLayout extends React.PureComponent {
57
58
  if (!editMode) {
58
59
  return false;
59
60
  }
60
- onDrop === null || onDrop === void 0 ? void 0 : onDrop(layout, item, e);
61
+ if (group !== DEFAULT_GROUP) {
62
+ item.parent = group;
63
+ }
64
+ const groupedLayout = this.mergeGroupsLayout(group, newLayout, item);
65
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, item, e);
61
66
  };
62
67
  this.pluginsRefs = [];
63
68
  this.state = {
@@ -77,6 +82,29 @@ class GridLayout extends React.PureComponent {
77
82
  clearTimeout(this._timeout);
78
83
  document.removeEventListener('visibilitychange', this.onVisibilityChange);
79
84
  }
85
+ getActiveLayout() {
86
+ const { layout, temporaryLayout } = this.context;
87
+ return (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout;
88
+ }
89
+ mergeGroupsLayout(group, newLayout, temporaryItem) {
90
+ const renderLayout = this.getActiveLayout();
91
+ const itemsByGroup = renderLayout.reduce((memo, item) => {
92
+ memo[item.i] = item;
93
+ return memo;
94
+ }, temporaryItem ? { [temporaryItem.i]: temporaryItem } : {});
95
+ const newItemsLayoutById = newLayout.reduce((memo, item) => {
96
+ const parent = itemsByGroup[item.i].parent;
97
+ memo[item.i] = Object.assign(Object.assign({}, item), { parent });
98
+ return memo;
99
+ }, {});
100
+ return renderLayout.map((currentItem) => {
101
+ const itemParent = itemsByGroup[currentItem.i].parent || DEFAULT_GROUP;
102
+ if (itemParent === group) {
103
+ return newItemsLayoutById[currentItem.i];
104
+ }
105
+ return currentItem;
106
+ });
107
+ }
80
108
  reloadItems() {
81
109
  const { editMode, settings: { autoupdateInterval, silentLoading } = {}, reloadItems, } = this.context;
82
110
  const { isPageHidden } = this.state;
@@ -100,25 +128,84 @@ class GridLayout extends React.PureComponent {
100
128
  const { type } = temporaryLayout.dragProps;
101
129
  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
130
  }
103
- render() {
104
- const { layout, temporaryLayout, config, registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
105
- this.pluginsRefs.length = config.items.length;
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
131
+ renderGroup(group, renderLayout, renderItems, offset = 0) {
132
+ const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
133
+ return (React.createElement(Layout, Object.assign({}, registerManager.gridLayout, { key: `group_${group}`, layout: renderLayout, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: (...args) => this._onStop(group, ...args), onResizeStart: this._onStart, onResizeStop: (...args) => this._onStop(group, ...args) }, (draggableHandleClassName
107
134
  ? { draggableHandle: `.${draggableHandleClassName}` }
108
135
  : null), (outerDnDEnable
109
136
  ? {
110
137
  isDroppable: true,
111
138
  onDropDragOver: this._onDropDragOver,
112
- onDrop: this._onDrop,
139
+ onDrop: (...args) => this._onDrop(group, ...args),
113
140
  }
114
141
  : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
115
- config.items.map((item, i) => {
142
+ renderItems.map((item, i) => {
116
143
  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 }));
144
+ this.pluginsRefs[offset + i] = pluginRef;
145
+ }, key: item.id, id: item.id, item: item, layout: renderLayout, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, noOverlay: noOverlay, focusable: focusable, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
119
146
  }),
120
147
  this.renderTemporaryPlaceholder()));
121
148
  }
149
+ render() {
150
+ const { config, groups, editMode } = this.context;
151
+ this.pluginsRefs.length = config.items.length;
152
+ const defaultRenderLayout = [];
153
+ const defaultRenderItems = [];
154
+ const layoutMap = {};
155
+ const groupedLayout = this.getActiveLayout().reduce((memo, item) => {
156
+ if (item.parent) {
157
+ if (!memo[item.parent]) {
158
+ memo[item.parent] = [];
159
+ }
160
+ memo[item.parent].push(item);
161
+ layoutMap[item.i] = item.parent;
162
+ }
163
+ else {
164
+ defaultRenderLayout.push(item);
165
+ }
166
+ return memo;
167
+ }, []);
168
+ const itemsByGroup = config.items.reduce((memo, item) => {
169
+ const group = layoutMap[item.id];
170
+ if (group) {
171
+ if (!memo[group]) {
172
+ memo[group] = [];
173
+ }
174
+ memo[group].push(item);
175
+ }
176
+ else {
177
+ defaultRenderItems.push(item);
178
+ }
179
+ return memo;
180
+ }, {});
181
+ let offset = 0;
182
+ if (groups) {
183
+ return groups.map((group) => {
184
+ const id = group.id || DEFAULT_GROUP;
185
+ let element;
186
+ if (id === DEFAULT_GROUP) {
187
+ element = this.renderGroup(DEFAULT_GROUP, defaultRenderLayout, defaultRenderItems, offset);
188
+ offset += defaultRenderItems.length;
189
+ }
190
+ else {
191
+ element = this.renderGroup(id, groupedLayout[id], itemsByGroup[id], offset);
192
+ offset += itemsByGroup[id].length;
193
+ }
194
+ if (group.render) {
195
+ return group.render(id, element, {
196
+ config,
197
+ editMode,
198
+ items: itemsByGroup[id],
199
+ layout: groupedLayout[id],
200
+ });
201
+ }
202
+ return element;
203
+ });
204
+ }
205
+ else {
206
+ return this.renderGroup(DEFAULT_GROUP, defaultRenderLayout, defaultRenderItems, offset);
207
+ }
208
+ }
122
209
  }
123
210
  GridLayout.contextType = DashKitContext;
124
211
  export default GridLayout;
@@ -2,14 +2,29 @@ import React from 'react';
2
2
  import ReactGridLayout, { WidthProvider } from 'react-grid-layout';
3
3
  import { OVERLAY_CLASS_NAME } from '../../constants';
4
4
  class DragOverLayout extends ReactGridLayout {
5
- constructor() {
6
- super(...arguments);
5
+ constructor(...args) {
6
+ super(...args);
7
7
  this.dragReset = () => {
8
8
  if (this.dragEnterCounter) {
9
9
  this.dragEnterCounter = 0;
10
10
  this.removeDroppingPlaceholder();
11
11
  }
12
12
  };
13
+ this.mouseLeaveHandler = (e) => {
14
+ var _a;
15
+ const rect = ((_a = this.props.innerRef) === null || _a === void 0 ? void 0 : _a.current.getBoundingClientRect()) || {};
16
+ if (rect.bottom <= e.clientY ||
17
+ rect.top >= e.clientY ||
18
+ rect.left >= e.clientX ||
19
+ rect.right <= e.clientX) {
20
+ this.dragReset();
21
+ }
22
+ };
23
+ const oldonDrag = this.onDrag;
24
+ this.onDrag = (i, x, y, sintE) => {
25
+ oldonDrag(i, x, y, sintE);
26
+ this.mouseLeaveHandler(sintE.e);
27
+ };
13
28
  }
14
29
  componentDidMount() {
15
30
  var _a;
@@ -10,3 +10,4 @@ export declare const MenuItems: {
10
10
  };
11
11
  export declare const DEFAULT_WIDGET_HEIGHT = 3;
12
12
  export declare const DEFAULT_WIDGET_WIDTH = 3;
13
+ export declare const DEFAULT_GROUP = "__default";
@@ -10,3 +10,4 @@ export const MenuItems = {
10
10
  };
11
11
  export const DEFAULT_WIDGET_HEIGHT = 3;
12
12
  export const DEFAULT_WIDGET_WIDTH = 3;
13
+ export const DEFAULT_GROUP = '__default';
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import isEqual from 'lodash/isEqual';
3
+ import pick from 'lodash/pick';
3
4
  import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, TEMPORARY_ITEM_ID } from '../constants/common';
4
5
  import { DashKitContext, DashKitDnDContext } from '../context/DashKitContext';
5
6
  import { getItemsParams, getItemsState } from '../shared';
@@ -18,10 +19,11 @@ function useMemoStateContext(props) {
18
19
  const outerDnDEnable = Boolean(dndContext);
19
20
  // TODO: need move originalLayouts, adjustedLayouts to state
20
21
  const [layoutUpdateCounter, forceUpdateLayout] = React.useState(0);
21
- const onChange = React.useCallback(({ config = props.config, itemsStateAndParams = props.itemsStateAndParams }) => {
22
+ const onChange = React.useCallback(({ config = props.config, itemsStateAndParams = props.itemsStateAndParams, groups = props.groups, }) => {
22
23
  if (!(isEqual(config, props.config) &&
23
- isEqual(itemsStateAndParams, props.itemsStateAndParams))) {
24
- props.onChange({ config, itemsStateAndParams });
24
+ isEqual(itemsStateAndParams, props.itemsStateAndParams) &&
25
+ isEqual(groups, props.groups))) {
26
+ props.onChange({ config, itemsStateAndParams, groups });
25
27
  }
26
28
  }, [props.config, props.itemsStateAndParams, props.onChange]);
27
29
  // каллбэк вызывающийся при изменение лэйаута сетки, первым аргументом приходит актуальный конфиг лэйаута,
@@ -167,6 +169,7 @@ function useMemoStateContext(props) {
167
169
  }
168
170
  return false;
169
171
  }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
172
+ const onDropProp = props.onDrop;
170
173
  const onDrop = React.useCallback((newLayout, item) => {
171
174
  if (!dragProps) {
172
175
  return;
@@ -175,23 +178,23 @@ function useMemoStateContext(props) {
175
178
  data: newLayout,
176
179
  dragProps,
177
180
  });
178
- const { i, w, h, x, y } = item;
179
- props.onDrop({
181
+ onDropProp({
180
182
  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
+ if (l.i !== item.i) {
184
+ memo.push(pick(l, ['i', 'h', 'w', 'x', 'y', 'parent']));
183
185
  }
184
186
  return memo;
185
187
  }, []),
186
- itemLayout: { w, h, x, y },
188
+ itemLayout: pick(item, ['i', 'h', 'w', 'x', 'y', 'parent']),
187
189
  commit: resetTemporaryLayout,
188
190
  dragProps,
189
191
  });
190
- }, [dragProps, props.onDrop, setTemporaryLayout, resetTemporaryLayout]);
192
+ }, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
191
193
  return React.useMemo(() => ({
192
194
  layout: resultLayout,
193
195
  temporaryLayout,
194
196
  config: props.config,
197
+ groups: props.groups,
195
198
  context: props.context,
196
199
  noOverlay: props.noOverlay,
197
200
  focusable: props.focusable,
@@ -220,6 +223,7 @@ function useMemoStateContext(props) {
220
223
  resultLayout,
221
224
  temporaryLayout,
222
225
  props.config,
226
+ props.groups,
223
227
  props.context,
224
228
  props.noOverlay,
225
229
  props.focusable,
@@ -6,6 +6,7 @@ export declare const useCalcPropsLayout: (config: Config, registerManager: Regis
6
6
  w: number;
7
7
  x: number;
8
8
  y: number;
9
+ parent?: string | undefined;
9
10
  minW: number;
10
11
  minH: number;
11
12
  maxW?: number | undefined;
@@ -1,5 +1,8 @@
1
1
  import { StringParams } from './common';
2
- export interface ConfigLayout {
2
+ export interface AdditionalWidgetLayout {
3
+ parent?: string;
4
+ }
5
+ export interface ConfigLayout extends AdditionalWidgetLayout {
3
6
  i: string;
4
7
  h: number;
5
8
  w: number;
@@ -1,6 +1,7 @@
1
1
  import type ReactGridLayout from 'react-grid-layout';
2
2
  import type { OverlayCustomControlItem } from '../components/OverlayControls/OverlayControls';
3
3
  import { MenuItems } from '../constants';
4
+ import { AdditionalWidgetLayout } from '../shared';
4
5
  export interface Settings {
5
6
  gridLayout?: ReactGridLayout.ReactGridLayoutProps;
6
7
  theme?: string;
@@ -15,7 +16,7 @@ export interface SettingsProps {
15
16
  export interface ContextProps {
16
17
  [key: string]: any;
17
18
  }
18
- export interface WidgetLayout {
19
+ export interface WidgetLayout extends AdditionalWidgetLayout {
19
20
  i: string;
20
21
  w: number;
21
22
  h: number;
@@ -1,4 +1,5 @@
1
- import type { ConfigItem, ConfigLayout } from '../shared';
1
+ /// <reference types="react" />
2
+ import type { Config, ConfigItem, ConfigLayout } from '../shared';
2
3
  export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
3
4
  id?: null;
4
5
  namespace?: string;
@@ -11,3 +12,13 @@ export type SetItemOptions = {
11
12
  export type SetNewItemOptions = SetItemOptions & {
12
13
  updateLayout?: ConfigLayout[];
13
14
  };
15
+ export interface DashkitGroupRenderProps {
16
+ config: Config;
17
+ editMode: boolean;
18
+ items: ConfigItem[];
19
+ layout: ConfigLayout[];
20
+ }
21
+ export interface DashKiGroup {
22
+ id?: string;
23
+ render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
24
+ }
@@ -23,16 +23,7 @@ export interface PluginWidgetProps<T = StringParams> {
23
23
  adjustedWidgetLayout?: WidgetLayout;
24
24
  }) => void;
25
25
  }
26
- export interface PluginDefaultLayout {
27
- w?: number;
28
- h?: number;
29
- x?: number;
30
- y?: number;
31
- minW?: number;
32
- maxW?: number;
33
- minH?: number;
34
- maxH?: number;
35
- }
26
+ export type PluginDefaultLayout = Partial<Omit<WidgetLayout, 'i'>>;
36
27
  export interface Plugin<P extends PluginWidgetProps<T> = any, T = StringParams> extends PluginBase {
37
28
  defaultLayout?: PluginDefaultLayout;
38
29
  renderer: (props: P, forwardedRef: React.RefObject<any>) => React.ReactNode;
@@ -78,6 +78,7 @@ function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams, pa
78
78
  // if it's Record<string, StringParams>, then this is a group application of params
79
79
  // and checking for comparison of allowedParams and stateParamsConf is not necessary
80
80
  const isGroupParamsApply = typeof (stateParamsConf === null || stateParamsConf === void 0 ? void 0 : stateParamsConf[item.id]) === 'object' &&
81
+ (stateParamsConf === null || stateParamsConf === void 0 ? void 0 : stateParamsConf[item.id]) !== null &&
81
82
  !Array.isArray(stateParamsConf === null || stateParamsConf === void 0 ? void 0 : stateParamsConf[item.id]);
82
83
  if (isItemWithTabs(item)) {
83
84
  let tab;
@@ -228,7 +229,7 @@ export class UpdateManager {
228
229
  const newIdData = getNewId({ config, salt, counter, excludeIds: newItemData.excludeIds });
229
230
  counter = newIdData.counter;
230
231
  const newItem = Object.assign(Object.assign({}, item), { id: newIdData.id, data: newItemData.data, namespace });
231
- const saveDefaultLayout = pick(layout, ['h', 'w', 'x', 'y']);
232
+ const saveDefaultLayout = pick(layout, ['h', 'w', 'x', 'y', 'parent']);
232
233
  if (options.updateLayout) {
233
234
  const byId = options.updateLayout.reduce((memo, t) => {
234
235
  memo[t.i] = t;
@@ -309,7 +310,7 @@ export class UpdateManager {
309
310
  static updateLayout({ layout, config }) {
310
311
  return update(config, {
311
312
  layout: {
312
- $set: layout.map(({ x, y, w, h, i }) => ({ x, y, w, h, i })),
313
+ $set: layout.map((item) => pick(item, ['i', 'h', 'w', 'x', 'y', 'parent'])),
313
314
  },
314
315
  });
315
316
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dashkit",
3
- "version": "8.2.0-beta.0",
3
+ "version": "8.3.0-beta.0",
4
4
  "description": "Library for rendering dashboard grid layout",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -60,12 +60,12 @@
60
60
  "prepublishOnly": "npm run lint && npm run test && npm run build"
61
61
  },
62
62
  "dependencies": {
63
- "@gravity-ui/icons": "^2.8.1",
64
63
  "@bem-react/classname": "^1.6.0",
64
+ "@gravity-ui/icons": "^2.8.1",
65
65
  "hashids": "^2.2.8",
66
66
  "immutability-helper": "^3.1.1",
67
67
  "prop-types": "^15.8.1",
68
- "react-grid-layout": "^1.3.4",
68
+ "react-grid-layout": "^1.4.4",
69
69
  "react-transition-group": "^4.4.5"
70
70
  },
71
71
  "peerDependencies": {
@@ -90,7 +90,7 @@
90
90
  "@types/jest": "^26.0.20",
91
91
  "@types/lodash": "^4.14.170",
92
92
  "@types/react": "^18.0.27",
93
- "@types/react-grid-layout": "^1.3.2",
93
+ "@types/react-grid-layout": "^1.3.5",
94
94
  "babel-jest": "^26.6.3",
95
95
  "copyfiles": "^2.4.1",
96
96
  "enzyme": "^3.11.0",