@gravity-ui/dashkit 8.3.0 → 8.5.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.
- package/build/cjs/components/DashKit/DashKit.d.ts +3 -1
- package/build/cjs/components/DashKit/DashKit.js +1 -5
- package/build/cjs/components/GridLayout/GridLayout.d.ts +9 -4
- package/build/cjs/components/GridLayout/GridLayout.js +132 -16
- package/build/cjs/components/GridLayout/ReactGridLayout.js +23 -2
- package/build/cjs/constants/common.d.ts +2 -0
- package/build/cjs/constants/common.js +3 -1
- package/build/cjs/hocs/withContext.js +18 -11
- package/build/cjs/hooks/useCalcLayout.d.ts +1 -0
- package/build/cjs/shared/types/config.d.ts +4 -1
- package/build/cjs/typings/common.d.ts +2 -1
- package/build/cjs/typings/config.d.ts +17 -1
- package/build/cjs/typings/plugin.d.ts +1 -10
- package/build/cjs/utils/update-manager.js +2 -2
- package/build/esm/components/DashKit/DashKit.d.ts +3 -1
- package/build/esm/components/DashKit/DashKit.js +1 -5
- package/build/esm/components/GridLayout/GridLayout.d.ts +9 -4
- package/build/esm/components/GridLayout/GridLayout.js +133 -17
- package/build/esm/components/GridLayout/ReactGridLayout.js +23 -2
- package/build/esm/constants/common.d.ts +2 -0
- package/build/esm/constants/common.js +2 -0
- package/build/esm/hocs/withContext.js +18 -11
- package/build/esm/hooks/useCalcLayout.d.ts +1 -0
- package/build/esm/shared/types/config.d.ts +4 -1
- package/build/esm/typings/common.d.ts +2 -1
- package/build/esm/typings/config.d.ts +17 -1
- package/build/esm/typings/plugin.d.ts +1 -10
- package/build/esm/utils/update-manager.js +2 -2
- package/package.json +4 -4
|
@@ -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, DashKitGroup, 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?: DashKitGroup[];
|
|
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?: DashKitGroup[];
|
|
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
|
|
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,17 @@ 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;
|
|
24
|
-
_onDropDragOver: (e: any) => any;
|
|
25
|
-
_onDrop: (
|
|
25
|
+
_onStop: (group: any, newLayout: any) => void;
|
|
26
|
+
_onDropDragOver: (e: any, gridProperties: any, layout: any) => any;
|
|
27
|
+
_onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
|
|
26
28
|
renderTemporaryPlaceholder(): JSX.Element | null;
|
|
27
|
-
|
|
29
|
+
caclculateEmptyHorizontalSpace(layout: any, cols: any): any;
|
|
30
|
+
getElementLayout(layout: any, properties: any): any;
|
|
31
|
+
renderGroup(group: any, renderLayout: any, renderItems: any, offset: number | undefined, groupGridProperties: any): JSX.Element;
|
|
32
|
+
render(): any;
|
|
28
33
|
}
|
|
29
34
|
import React from 'react';
|
|
@@ -35,24 +35,33 @@ 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(
|
|
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(
|
|
45
|
+
layoutChange(groupedLayout);
|
|
45
46
|
}
|
|
46
47
|
this.setState({ isDragging: false });
|
|
47
48
|
};
|
|
48
|
-
this._onDropDragOver = (e) => {
|
|
49
|
+
this._onDropDragOver = (e, gridProperties, layout) => {
|
|
49
50
|
const { editMode, dragOverPlugin, onDropDragOver } = this.context;
|
|
50
51
|
if (!editMode || !dragOverPlugin) {
|
|
51
52
|
return false;
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
+
let maxW = gridProperties.cols;
|
|
55
|
+
const maxH = gridProperties.maxRows;
|
|
56
|
+
if (gridProperties.compactType === constants_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
57
|
+
maxW = this.caclculateEmptyHorizontalSpace(layout, gridProperties.cols);
|
|
58
|
+
}
|
|
59
|
+
if (maxW === 0 || maxH === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return onDropDragOver(e, { maxH, maxW });
|
|
54
63
|
};
|
|
55
|
-
this._onDrop = (
|
|
64
|
+
this._onDrop = (group, newLayout, item, e) => {
|
|
56
65
|
if (!item) {
|
|
57
66
|
return false;
|
|
58
67
|
}
|
|
@@ -60,7 +69,11 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
60
69
|
if (!editMode) {
|
|
61
70
|
return false;
|
|
62
71
|
}
|
|
63
|
-
|
|
72
|
+
if (group !== constants_1.DEFAULT_GROUP) {
|
|
73
|
+
item.parent = group;
|
|
74
|
+
}
|
|
75
|
+
const groupedLayout = this.mergeGroupsLayout(group, newLayout, item);
|
|
76
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, item, e);
|
|
64
77
|
};
|
|
65
78
|
this.pluginsRefs = [];
|
|
66
79
|
this.state = {
|
|
@@ -80,6 +93,29 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
80
93
|
clearTimeout(this._timeout);
|
|
81
94
|
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
82
95
|
}
|
|
96
|
+
getActiveLayout() {
|
|
97
|
+
const { layout, temporaryLayout } = this.context;
|
|
98
|
+
return (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout;
|
|
99
|
+
}
|
|
100
|
+
mergeGroupsLayout(group, newLayout, temporaryItem) {
|
|
101
|
+
const renderLayout = this.getActiveLayout();
|
|
102
|
+
const itemsByGroup = renderLayout.reduce((memo, item) => {
|
|
103
|
+
memo[item.i] = item;
|
|
104
|
+
return memo;
|
|
105
|
+
}, temporaryItem ? { [temporaryItem.i]: temporaryItem } : {});
|
|
106
|
+
const newItemsLayoutById = newLayout.reduce((memo, item) => {
|
|
107
|
+
const parent = itemsByGroup[item.i].parent;
|
|
108
|
+
memo[item.i] = Object.assign(Object.assign({}, item), { parent });
|
|
109
|
+
return memo;
|
|
110
|
+
}, {});
|
|
111
|
+
return renderLayout.map((currentItem) => {
|
|
112
|
+
const itemParent = itemsByGroup[currentItem.i].parent || constants_1.DEFAULT_GROUP;
|
|
113
|
+
if (itemParent === group) {
|
|
114
|
+
return newItemsLayoutById[currentItem.i];
|
|
115
|
+
}
|
|
116
|
+
return currentItem;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
83
119
|
reloadItems() {
|
|
84
120
|
const { editMode, settings: { autoupdateInterval, silentLoading } = {}, reloadItems, } = this.context;
|
|
85
121
|
const { isPageHidden } = this.state;
|
|
@@ -103,25 +139,105 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
103
139
|
const { type } = temporaryLayout.dragProps;
|
|
104
140
|
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
141
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
142
|
+
caclculateEmptyHorizontalSpace(layout, cols) {
|
|
143
|
+
return layout.reduce((memo, item) => memo - item.w, cols);
|
|
144
|
+
}
|
|
145
|
+
getElementLayout(layout, properties) {
|
|
146
|
+
let maxH;
|
|
147
|
+
if (properties.maxRows) {
|
|
148
|
+
maxH = properties.maxRows;
|
|
149
|
+
}
|
|
150
|
+
const leftSpace = this.caclculateEmptyHorizontalSpace(layout, properties.cols);
|
|
151
|
+
return layout.map((item) => (Object.assign(Object.assign({}, item), { maxW: item.w + leftSpace, maxH })));
|
|
152
|
+
}
|
|
153
|
+
renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
|
|
154
|
+
const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
|
|
155
|
+
const properties = groupGridProperties
|
|
156
|
+
? groupGridProperties(Object.assign({}, registerManager.gridLayout))
|
|
157
|
+
: registerManager.gridLayout;
|
|
158
|
+
let { compactType } = properties;
|
|
159
|
+
if (compactType === constants_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
160
|
+
renderLayout = this.getElementLayout(renderLayout, properties);
|
|
161
|
+
compactType = 'horizontal';
|
|
162
|
+
}
|
|
163
|
+
return (react_1.default.createElement(ReactGridLayout_1.Layout, Object.assign({}, properties, { compactType: compactType, layout: renderLayout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: (...args) => this._onStop(group, ...args), onResizeStart: this._onStart, onResizeStop: (...args) => this._onStop(group, ...args) }, (draggableHandleClassName
|
|
110
164
|
? { draggableHandle: `.${draggableHandleClassName}` }
|
|
111
165
|
: null), (outerDnDEnable
|
|
112
166
|
? {
|
|
113
167
|
isDroppable: true,
|
|
114
|
-
onDropDragOver: this._onDropDragOver,
|
|
115
|
-
onDrop: this._onDrop,
|
|
168
|
+
onDropDragOver: (e) => this._onDropDragOver(e, properties, renderLayout),
|
|
169
|
+
onDrop: (...args) => this._onDrop(group, ...args),
|
|
116
170
|
}
|
|
117
171
|
: null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }),
|
|
118
|
-
|
|
172
|
+
renderItems.map((item, i) => {
|
|
119
173
|
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:
|
|
174
|
+
this.pluginsRefs[offset + i] = pluginRef;
|
|
175
|
+
}, 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
176
|
}),
|
|
123
177
|
this.renderTemporaryPlaceholder()));
|
|
124
178
|
}
|
|
179
|
+
render() {
|
|
180
|
+
const { config, groups, editMode } = this.context;
|
|
181
|
+
this.pluginsRefs.length = config.items.length;
|
|
182
|
+
const defaultRenderLayout = [];
|
|
183
|
+
const defaultRenderItems = [];
|
|
184
|
+
const layoutMap = {};
|
|
185
|
+
const groupedLayout = this.getActiveLayout().reduce((memo, item) => {
|
|
186
|
+
if (item.parent) {
|
|
187
|
+
if (!memo[item.parent]) {
|
|
188
|
+
memo[item.parent] = [];
|
|
189
|
+
}
|
|
190
|
+
memo[item.parent].push(item);
|
|
191
|
+
layoutMap[item.i] = item.parent;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
defaultRenderLayout.push(item);
|
|
195
|
+
}
|
|
196
|
+
return memo;
|
|
197
|
+
}, []);
|
|
198
|
+
const itemsByGroup = config.items.reduce((memo, item) => {
|
|
199
|
+
const group = layoutMap[item.id];
|
|
200
|
+
if (group) {
|
|
201
|
+
if (!memo[group]) {
|
|
202
|
+
memo[group] = [];
|
|
203
|
+
}
|
|
204
|
+
memo[group].push(item);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
defaultRenderItems.push(item);
|
|
208
|
+
}
|
|
209
|
+
return memo;
|
|
210
|
+
}, {});
|
|
211
|
+
let offset = 0;
|
|
212
|
+
if (groups) {
|
|
213
|
+
return groups.map((group) => {
|
|
214
|
+
const id = group.id || constants_1.DEFAULT_GROUP;
|
|
215
|
+
let layout, items;
|
|
216
|
+
if (id === constants_1.DEFAULT_GROUP) {
|
|
217
|
+
layout = defaultRenderLayout;
|
|
218
|
+
items = defaultRenderItems;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
layout = groupedLayout[id] || [];
|
|
222
|
+
items = itemsByGroup[id] || [];
|
|
223
|
+
}
|
|
224
|
+
const element = this.renderGroup(id, layout, items, offset, group.gridProperties);
|
|
225
|
+
offset += items.length;
|
|
226
|
+
if (group.render) {
|
|
227
|
+
return group.render(id, element, {
|
|
228
|
+
config,
|
|
229
|
+
editMode,
|
|
230
|
+
items,
|
|
231
|
+
layout,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return element;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
return this.renderGroup(constants_1.DEFAULT_GROUP, defaultRenderLayout, defaultRenderItems, offset);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
125
241
|
}
|
|
126
242
|
GridLayout.contextType = DashKitContext_1.DashKitContext;
|
|
127
243
|
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(...
|
|
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
|
+
this.parentOnDrag = this.onDrag;
|
|
28
|
+
this.onDrag = (i, x, y, sintE) => {
|
|
29
|
+
this.parentOnDrag(i, x, y, sintE);
|
|
30
|
+
this.mouseLeaveHandler(sintE.e);
|
|
31
|
+
};
|
|
17
32
|
}
|
|
18
33
|
componentDidMount() {
|
|
19
34
|
var _a;
|
|
@@ -23,6 +38,12 @@ class DragOverLayout extends react_grid_layout_1.default {
|
|
|
23
38
|
componentWillUnmount() {
|
|
24
39
|
window.removeEventListener('dragend', this.dragReset);
|
|
25
40
|
}
|
|
41
|
+
containerHeight() {
|
|
42
|
+
if (this.props.autoSize && this.state.layout.length === 0) {
|
|
43
|
+
return 'unset';
|
|
44
|
+
}
|
|
45
|
+
return super.containerHeight();
|
|
46
|
+
}
|
|
26
47
|
processGridItem(child, isDroppingItem) {
|
|
27
48
|
var _a;
|
|
28
49
|
const gridItem = (_a = super.processGridItem) === null || _a === void 0 ? void 0 : _a.call(this, child, isDroppingItem);
|
|
@@ -10,3 +10,5 @@ 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";
|
|
14
|
+
export declare const COMPACT_TYPE_HORIZONTAL_NOWRAP = "horizontal-nowrap";
|
|
@@ -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.COMPACT_TYPE_HORIZONTAL_NOWRAP = 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,5 @@ exports.MenuItems = {
|
|
|
13
13
|
};
|
|
14
14
|
exports.DEFAULT_WIDGET_HEIGHT = 3;
|
|
15
15
|
exports.DEFAULT_WIDGET_WIDTH = 3;
|
|
16
|
+
exports.DEFAULT_GROUP = '__default';
|
|
17
|
+
exports.COMPACT_TYPE_HORIZONTAL_NOWRAP = 'horizontal-nowrap';
|
|
@@ -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
|
-
|
|
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
|
// каллбэк вызывающийся при изменение лэйаута сетки, первым аргументом приходит актуальный конфиг лэйаута,
|
|
@@ -159,7 +161,7 @@ function useMemoStateContext(props) {
|
|
|
159
161
|
return null;
|
|
160
162
|
}
|
|
161
163
|
}, [dragProps, props.registerManager]);
|
|
162
|
-
const onDropDragOver = react_1.default.useCallback(() => {
|
|
164
|
+
const onDropDragOver = react_1.default.useCallback((_e, gridProps = {}) => {
|
|
163
165
|
if (temporaryLayout) {
|
|
164
166
|
resetTemporaryLayout();
|
|
165
167
|
return false;
|
|
@@ -167,10 +169,14 @@ function useMemoStateContext(props) {
|
|
|
167
169
|
if (dragOverPlugin) {
|
|
168
170
|
const { defaultLayout } = dragOverPlugin;
|
|
169
171
|
const { h = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.h) || common_1.DEFAULT_WIDGET_HEIGHT, w = (defaultLayout === null || defaultLayout === void 0 ? void 0 : defaultLayout.w) || common_1.DEFAULT_WIDGET_WIDTH, } = dragProps.layout || {};
|
|
170
|
-
return {
|
|
172
|
+
return {
|
|
173
|
+
h: gridProps.maxH ? Math.min(h, gridProps.maxH) : h,
|
|
174
|
+
w: gridProps.maxW ? Math.min(w, gridProps.maxW) : w,
|
|
175
|
+
};
|
|
171
176
|
}
|
|
172
177
|
return false;
|
|
173
178
|
}, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
|
|
179
|
+
const onDropProp = props.onDrop;
|
|
174
180
|
const onDrop = react_1.default.useCallback((newLayout, item) => {
|
|
175
181
|
if (!dragProps) {
|
|
176
182
|
return;
|
|
@@ -179,23 +185,23 @@ function useMemoStateContext(props) {
|
|
|
179
185
|
data: newLayout,
|
|
180
186
|
dragProps,
|
|
181
187
|
});
|
|
182
|
-
|
|
183
|
-
props.onDrop({
|
|
188
|
+
onDropProp({
|
|
184
189
|
newLayout: newLayout.reduce((memo, l) => {
|
|
185
|
-
if (l.i !== i) {
|
|
186
|
-
memo.push(
|
|
190
|
+
if (l.i !== item.i) {
|
|
191
|
+
memo.push((0, pick_1.default)(l, ['i', 'h', 'w', 'x', 'y', 'parent']));
|
|
187
192
|
}
|
|
188
193
|
return memo;
|
|
189
194
|
}, []),
|
|
190
|
-
itemLayout:
|
|
195
|
+
itemLayout: (0, pick_1.default)(item, ['i', 'h', 'w', 'x', 'y', 'parent']),
|
|
191
196
|
commit: resetTemporaryLayout,
|
|
192
197
|
dragProps,
|
|
193
198
|
});
|
|
194
|
-
}, [dragProps,
|
|
199
|
+
}, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
|
|
195
200
|
return react_1.default.useMemo(() => ({
|
|
196
201
|
layout: resultLayout,
|
|
197
202
|
temporaryLayout,
|
|
198
203
|
config: props.config,
|
|
204
|
+
groups: props.groups,
|
|
199
205
|
context: props.context,
|
|
200
206
|
noOverlay: props.noOverlay,
|
|
201
207
|
focusable: props.focusable,
|
|
@@ -224,6 +230,7 @@ function useMemoStateContext(props) {
|
|
|
224
230
|
resultLayout,
|
|
225
231
|
temporaryLayout,
|
|
226
232
|
props.config,
|
|
233
|
+
props.groups,
|
|
227
234
|
props.context,
|
|
228
235
|
props.noOverlay,
|
|
229
236
|
props.focusable,
|
|
@@ -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,6 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react-grid-layout" />
|
|
2
|
+
/// <reference types="react" />
|
|
3
|
+
import type { Config, ConfigItem, ConfigLayout } from '../shared';
|
|
2
4
|
export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
|
|
3
5
|
id?: null;
|
|
4
6
|
namespace?: string;
|
|
@@ -11,3 +13,17 @@ export type SetItemOptions = {
|
|
|
11
13
|
export type SetNewItemOptions = SetItemOptions & {
|
|
12
14
|
updateLayout?: ConfigLayout[];
|
|
13
15
|
};
|
|
16
|
+
export interface DashkitGroupRenderProps {
|
|
17
|
+
config: Config;
|
|
18
|
+
editMode: boolean;
|
|
19
|
+
items: ConfigItem[];
|
|
20
|
+
layout: ConfigLayout[];
|
|
21
|
+
}
|
|
22
|
+
export type ReactGridLayoutProps = Omit<ReactGridLayout.ReactGridLayoutProps, 'children' | 'compactType' | 'innerRef' | 'key' | 'layout' | 'isDraggable' | 'isResizable' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'> & {
|
|
23
|
+
compactType?: ReactGridLayout.ReactGridLayoutProps['compactType'] | 'horizontal-nowrap';
|
|
24
|
+
};
|
|
25
|
+
export interface DashKitGroup {
|
|
26
|
+
id?: string;
|
|
27
|
+
render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
|
|
28
|
+
gridProperties?: (props: ReactGridLayoutProps) => ReactGridLayoutProps;
|
|
29
|
+
}
|
|
@@ -23,16 +23,7 @@ export interface PluginWidgetProps<T = StringParams> {
|
|
|
23
23
|
adjustedWidgetLayout?: WidgetLayout;
|
|
24
24
|
}) => void;
|
|
25
25
|
}
|
|
26
|
-
export
|
|
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;
|
|
@@ -234,7 +234,7 @@ class UpdateManager {
|
|
|
234
234
|
const newIdData = (0, get_new_id_1.getNewId)({ config, salt, counter, excludeIds: newItemData.excludeIds });
|
|
235
235
|
counter = newIdData.counter;
|
|
236
236
|
const newItem = Object.assign(Object.assign({}, item), { id: newIdData.id, data: newItemData.data, namespace });
|
|
237
|
-
const saveDefaultLayout = (0, pick_1.default)(layout, ['h', 'w', 'x', 'y']);
|
|
237
|
+
const saveDefaultLayout = (0, pick_1.default)(layout, ['h', 'w', 'x', 'y', 'parent']);
|
|
238
238
|
if (options.updateLayout) {
|
|
239
239
|
const byId = options.updateLayout.reduce((memo, t) => {
|
|
240
240
|
memo[t.i] = t;
|
|
@@ -315,7 +315,7 @@ class UpdateManager {
|
|
|
315
315
|
static updateLayout({ layout, config }) {
|
|
316
316
|
return (0, immutability_helper_1.default)(config, {
|
|
317
317
|
layout: {
|
|
318
|
-
$set: layout.map((
|
|
318
|
+
$set: layout.map((item) => (0, pick_1.default)(item, ['i', 'h', 'w', 'x', 'y', 'parent'])),
|
|
319
319
|
},
|
|
320
320
|
});
|
|
321
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, DashKitGroup, 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?: DashKitGroup[];
|
|
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?: DashKitGroup[];
|
|
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
|
|
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,17 @@ 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;
|
|
24
|
-
_onDropDragOver: (e: any) => any;
|
|
25
|
-
_onDrop: (
|
|
25
|
+
_onStop: (group: any, newLayout: any) => void;
|
|
26
|
+
_onDropDragOver: (e: any, gridProperties: any, layout: any) => any;
|
|
27
|
+
_onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
|
|
26
28
|
renderTemporaryPlaceholder(): JSX.Element | null;
|
|
27
|
-
|
|
29
|
+
caclculateEmptyHorizontalSpace(layout: any, cols: any): any;
|
|
30
|
+
getElementLayout(layout: any, properties: any): any;
|
|
31
|
+
renderGroup(group: any, renderLayout: any, renderItems: any, offset: number | undefined, groupGridProperties: any): JSX.Element;
|
|
32
|
+
render(): any;
|
|
28
33
|
}
|
|
29
34
|
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 { COMPACT_TYPE_HORIZONTAL_NOWRAP, 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,24 +32,33 @@ 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(
|
|
39
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, groupedLayout.find(({ i }) => i === TEMPORARY_ITEM_ID));
|
|
39
40
|
}
|
|
40
41
|
else {
|
|
41
|
-
layoutChange(
|
|
42
|
+
layoutChange(groupedLayout);
|
|
42
43
|
}
|
|
43
44
|
this.setState({ isDragging: false });
|
|
44
45
|
};
|
|
45
|
-
this._onDropDragOver = (e) => {
|
|
46
|
+
this._onDropDragOver = (e, gridProperties, layout) => {
|
|
46
47
|
const { editMode, dragOverPlugin, onDropDragOver } = this.context;
|
|
47
48
|
if (!editMode || !dragOverPlugin) {
|
|
48
49
|
return false;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
let maxW = gridProperties.cols;
|
|
52
|
+
const maxH = gridProperties.maxRows;
|
|
53
|
+
if (gridProperties.compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
54
|
+
maxW = this.caclculateEmptyHorizontalSpace(layout, gridProperties.cols);
|
|
55
|
+
}
|
|
56
|
+
if (maxW === 0 || maxH === 0) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return onDropDragOver(e, { maxH, maxW });
|
|
51
60
|
};
|
|
52
|
-
this._onDrop = (
|
|
61
|
+
this._onDrop = (group, newLayout, item, e) => {
|
|
53
62
|
if (!item) {
|
|
54
63
|
return false;
|
|
55
64
|
}
|
|
@@ -57,7 +66,11 @@ class GridLayout extends React.PureComponent {
|
|
|
57
66
|
if (!editMode) {
|
|
58
67
|
return false;
|
|
59
68
|
}
|
|
60
|
-
|
|
69
|
+
if (group !== DEFAULT_GROUP) {
|
|
70
|
+
item.parent = group;
|
|
71
|
+
}
|
|
72
|
+
const groupedLayout = this.mergeGroupsLayout(group, newLayout, item);
|
|
73
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(groupedLayout, item, e);
|
|
61
74
|
};
|
|
62
75
|
this.pluginsRefs = [];
|
|
63
76
|
this.state = {
|
|
@@ -77,6 +90,29 @@ class GridLayout extends React.PureComponent {
|
|
|
77
90
|
clearTimeout(this._timeout);
|
|
78
91
|
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
79
92
|
}
|
|
93
|
+
getActiveLayout() {
|
|
94
|
+
const { layout, temporaryLayout } = this.context;
|
|
95
|
+
return (temporaryLayout === null || temporaryLayout === void 0 ? void 0 : temporaryLayout.data) || layout;
|
|
96
|
+
}
|
|
97
|
+
mergeGroupsLayout(group, newLayout, temporaryItem) {
|
|
98
|
+
const renderLayout = this.getActiveLayout();
|
|
99
|
+
const itemsByGroup = renderLayout.reduce((memo, item) => {
|
|
100
|
+
memo[item.i] = item;
|
|
101
|
+
return memo;
|
|
102
|
+
}, temporaryItem ? { [temporaryItem.i]: temporaryItem } : {});
|
|
103
|
+
const newItemsLayoutById = newLayout.reduce((memo, item) => {
|
|
104
|
+
const parent = itemsByGroup[item.i].parent;
|
|
105
|
+
memo[item.i] = Object.assign(Object.assign({}, item), { parent });
|
|
106
|
+
return memo;
|
|
107
|
+
}, {});
|
|
108
|
+
return renderLayout.map((currentItem) => {
|
|
109
|
+
const itemParent = itemsByGroup[currentItem.i].parent || DEFAULT_GROUP;
|
|
110
|
+
if (itemParent === group) {
|
|
111
|
+
return newItemsLayoutById[currentItem.i];
|
|
112
|
+
}
|
|
113
|
+
return currentItem;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
80
116
|
reloadItems() {
|
|
81
117
|
const { editMode, settings: { autoupdateInterval, silentLoading } = {}, reloadItems, } = this.context;
|
|
82
118
|
const { isPageHidden } = this.state;
|
|
@@ -100,25 +136,105 @@ class GridLayout extends React.PureComponent {
|
|
|
100
136
|
const { type } = temporaryLayout.dragProps;
|
|
101
137
|
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
138
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
caclculateEmptyHorizontalSpace(layout, cols) {
|
|
140
|
+
return layout.reduce((memo, item) => memo - item.w, cols);
|
|
141
|
+
}
|
|
142
|
+
getElementLayout(layout, properties) {
|
|
143
|
+
let maxH;
|
|
144
|
+
if (properties.maxRows) {
|
|
145
|
+
maxH = properties.maxRows;
|
|
146
|
+
}
|
|
147
|
+
const leftSpace = this.caclculateEmptyHorizontalSpace(layout, properties.cols);
|
|
148
|
+
return layout.map((item) => (Object.assign(Object.assign({}, item), { maxW: item.w + leftSpace, maxH })));
|
|
149
|
+
}
|
|
150
|
+
renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
|
|
151
|
+
const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
|
|
152
|
+
const properties = groupGridProperties
|
|
153
|
+
? groupGridProperties(Object.assign({}, registerManager.gridLayout))
|
|
154
|
+
: registerManager.gridLayout;
|
|
155
|
+
let { compactType } = properties;
|
|
156
|
+
if (compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
157
|
+
renderLayout = this.getElementLayout(renderLayout, properties);
|
|
158
|
+
compactType = 'horizontal';
|
|
159
|
+
}
|
|
160
|
+
return (React.createElement(Layout, Object.assign({}, properties, { compactType: compactType, layout: renderLayout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: (...args) => this._onStop(group, ...args), onResizeStart: this._onStart, onResizeStop: (...args) => this._onStop(group, ...args) }, (draggableHandleClassName
|
|
107
161
|
? { draggableHandle: `.${draggableHandleClassName}` }
|
|
108
162
|
: null), (outerDnDEnable
|
|
109
163
|
? {
|
|
110
164
|
isDroppable: true,
|
|
111
|
-
onDropDragOver: this._onDropDragOver,
|
|
112
|
-
onDrop: this._onDrop,
|
|
165
|
+
onDropDragOver: (e) => this._onDropDragOver(e, properties, renderLayout),
|
|
166
|
+
onDrop: (...args) => this._onDrop(group, ...args),
|
|
113
167
|
}
|
|
114
168
|
: null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
|
|
115
|
-
|
|
169
|
+
renderItems.map((item, i) => {
|
|
116
170
|
return (React.createElement(GridItem, { forwardedPluginRef: (pluginRef) => {
|
|
117
|
-
this.pluginsRefs[i] = pluginRef;
|
|
118
|
-
}, key: item.id, id: item.id, item: item, layout:
|
|
171
|
+
this.pluginsRefs[offset + i] = pluginRef;
|
|
172
|
+
}, 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
173
|
}),
|
|
120
174
|
this.renderTemporaryPlaceholder()));
|
|
121
175
|
}
|
|
176
|
+
render() {
|
|
177
|
+
const { config, groups, editMode } = this.context;
|
|
178
|
+
this.pluginsRefs.length = config.items.length;
|
|
179
|
+
const defaultRenderLayout = [];
|
|
180
|
+
const defaultRenderItems = [];
|
|
181
|
+
const layoutMap = {};
|
|
182
|
+
const groupedLayout = this.getActiveLayout().reduce((memo, item) => {
|
|
183
|
+
if (item.parent) {
|
|
184
|
+
if (!memo[item.parent]) {
|
|
185
|
+
memo[item.parent] = [];
|
|
186
|
+
}
|
|
187
|
+
memo[item.parent].push(item);
|
|
188
|
+
layoutMap[item.i] = item.parent;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
defaultRenderLayout.push(item);
|
|
192
|
+
}
|
|
193
|
+
return memo;
|
|
194
|
+
}, []);
|
|
195
|
+
const itemsByGroup = config.items.reduce((memo, item) => {
|
|
196
|
+
const group = layoutMap[item.id];
|
|
197
|
+
if (group) {
|
|
198
|
+
if (!memo[group]) {
|
|
199
|
+
memo[group] = [];
|
|
200
|
+
}
|
|
201
|
+
memo[group].push(item);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
defaultRenderItems.push(item);
|
|
205
|
+
}
|
|
206
|
+
return memo;
|
|
207
|
+
}, {});
|
|
208
|
+
let offset = 0;
|
|
209
|
+
if (groups) {
|
|
210
|
+
return groups.map((group) => {
|
|
211
|
+
const id = group.id || DEFAULT_GROUP;
|
|
212
|
+
let layout, items;
|
|
213
|
+
if (id === DEFAULT_GROUP) {
|
|
214
|
+
layout = defaultRenderLayout;
|
|
215
|
+
items = defaultRenderItems;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
layout = groupedLayout[id] || [];
|
|
219
|
+
items = itemsByGroup[id] || [];
|
|
220
|
+
}
|
|
221
|
+
const element = this.renderGroup(id, layout, items, offset, group.gridProperties);
|
|
222
|
+
offset += items.length;
|
|
223
|
+
if (group.render) {
|
|
224
|
+
return group.render(id, element, {
|
|
225
|
+
config,
|
|
226
|
+
editMode,
|
|
227
|
+
items,
|
|
228
|
+
layout,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return element;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
return this.renderGroup(DEFAULT_GROUP, defaultRenderLayout, defaultRenderItems, offset);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
122
238
|
}
|
|
123
239
|
GridLayout.contextType = DashKitContext;
|
|
124
240
|
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(...
|
|
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
|
+
this.parentOnDrag = this.onDrag;
|
|
24
|
+
this.onDrag = (i, x, y, sintE) => {
|
|
25
|
+
this.parentOnDrag(i, x, y, sintE);
|
|
26
|
+
this.mouseLeaveHandler(sintE.e);
|
|
27
|
+
};
|
|
13
28
|
}
|
|
14
29
|
componentDidMount() {
|
|
15
30
|
var _a;
|
|
@@ -19,6 +34,12 @@ class DragOverLayout extends ReactGridLayout {
|
|
|
19
34
|
componentWillUnmount() {
|
|
20
35
|
window.removeEventListener('dragend', this.dragReset);
|
|
21
36
|
}
|
|
37
|
+
containerHeight() {
|
|
38
|
+
if (this.props.autoSize && this.state.layout.length === 0) {
|
|
39
|
+
return 'unset';
|
|
40
|
+
}
|
|
41
|
+
return super.containerHeight();
|
|
42
|
+
}
|
|
22
43
|
processGridItem(child, isDroppingItem) {
|
|
23
44
|
var _a;
|
|
24
45
|
const gridItem = (_a = super.processGridItem) === null || _a === void 0 ? void 0 : _a.call(this, child, isDroppingItem);
|
|
@@ -10,3 +10,5 @@ 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";
|
|
14
|
+
export declare const COMPACT_TYPE_HORIZONTAL_NOWRAP = "horizontal-nowrap";
|
|
@@ -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
|
-
|
|
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
|
// каллбэк вызывающийся при изменение лэйаута сетки, первым аргументом приходит актуальный конфиг лэйаута,
|
|
@@ -155,7 +157,7 @@ function useMemoStateContext(props) {
|
|
|
155
157
|
return null;
|
|
156
158
|
}
|
|
157
159
|
}, [dragProps, props.registerManager]);
|
|
158
|
-
const onDropDragOver = React.useCallback(() => {
|
|
160
|
+
const onDropDragOver = React.useCallback((_e, gridProps = {}) => {
|
|
159
161
|
if (temporaryLayout) {
|
|
160
162
|
resetTemporaryLayout();
|
|
161
163
|
return false;
|
|
@@ -163,10 +165,14 @@ function useMemoStateContext(props) {
|
|
|
163
165
|
if (dragOverPlugin) {
|
|
164
166
|
const { defaultLayout } = dragOverPlugin;
|
|
165
167
|
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 {
|
|
168
|
+
return {
|
|
169
|
+
h: gridProps.maxH ? Math.min(h, gridProps.maxH) : h,
|
|
170
|
+
w: gridProps.maxW ? Math.min(w, gridProps.maxW) : w,
|
|
171
|
+
};
|
|
167
172
|
}
|
|
168
173
|
return false;
|
|
169
174
|
}, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
|
|
175
|
+
const onDropProp = props.onDrop;
|
|
170
176
|
const onDrop = React.useCallback((newLayout, item) => {
|
|
171
177
|
if (!dragProps) {
|
|
172
178
|
return;
|
|
@@ -175,23 +181,23 @@ function useMemoStateContext(props) {
|
|
|
175
181
|
data: newLayout,
|
|
176
182
|
dragProps,
|
|
177
183
|
});
|
|
178
|
-
|
|
179
|
-
props.onDrop({
|
|
184
|
+
onDropProp({
|
|
180
185
|
newLayout: newLayout.reduce((memo, l) => {
|
|
181
|
-
if (l.i !== i) {
|
|
182
|
-
memo.push(
|
|
186
|
+
if (l.i !== item.i) {
|
|
187
|
+
memo.push(pick(l, ['i', 'h', 'w', 'x', 'y', 'parent']));
|
|
183
188
|
}
|
|
184
189
|
return memo;
|
|
185
190
|
}, []),
|
|
186
|
-
itemLayout:
|
|
191
|
+
itemLayout: pick(item, ['i', 'h', 'w', 'x', 'y', 'parent']),
|
|
187
192
|
commit: resetTemporaryLayout,
|
|
188
193
|
dragProps,
|
|
189
194
|
});
|
|
190
|
-
}, [dragProps,
|
|
195
|
+
}, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
|
|
191
196
|
return React.useMemo(() => ({
|
|
192
197
|
layout: resultLayout,
|
|
193
198
|
temporaryLayout,
|
|
194
199
|
config: props.config,
|
|
200
|
+
groups: props.groups,
|
|
195
201
|
context: props.context,
|
|
196
202
|
noOverlay: props.noOverlay,
|
|
197
203
|
focusable: props.focusable,
|
|
@@ -220,6 +226,7 @@ function useMemoStateContext(props) {
|
|
|
220
226
|
resultLayout,
|
|
221
227
|
temporaryLayout,
|
|
222
228
|
props.config,
|
|
229
|
+
props.groups,
|
|
223
230
|
props.context,
|
|
224
231
|
props.noOverlay,
|
|
225
232
|
props.focusable,
|
|
@@ -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,6 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react-grid-layout" />
|
|
2
|
+
/// <reference types="react" />
|
|
3
|
+
import type { Config, ConfigItem, ConfigLayout } from '../shared';
|
|
2
4
|
export interface AddConfigItem extends Omit<ConfigItem, 'id' | 'namespace'> {
|
|
3
5
|
id?: null;
|
|
4
6
|
namespace?: string;
|
|
@@ -11,3 +13,17 @@ export type SetItemOptions = {
|
|
|
11
13
|
export type SetNewItemOptions = SetItemOptions & {
|
|
12
14
|
updateLayout?: ConfigLayout[];
|
|
13
15
|
};
|
|
16
|
+
export interface DashkitGroupRenderProps {
|
|
17
|
+
config: Config;
|
|
18
|
+
editMode: boolean;
|
|
19
|
+
items: ConfigItem[];
|
|
20
|
+
layout: ConfigLayout[];
|
|
21
|
+
}
|
|
22
|
+
export type ReactGridLayoutProps = Omit<ReactGridLayout.ReactGridLayoutProps, 'children' | 'compactType' | 'innerRef' | 'key' | 'layout' | 'isDraggable' | 'isResizable' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'> & {
|
|
23
|
+
compactType?: ReactGridLayout.ReactGridLayoutProps['compactType'] | 'horizontal-nowrap';
|
|
24
|
+
};
|
|
25
|
+
export interface DashKitGroup {
|
|
26
|
+
id?: string;
|
|
27
|
+
render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
|
|
28
|
+
gridProperties?: (props: ReactGridLayoutProps) => ReactGridLayoutProps;
|
|
29
|
+
}
|
|
@@ -23,16 +23,7 @@ export interface PluginWidgetProps<T = StringParams> {
|
|
|
23
23
|
adjustedWidgetLayout?: WidgetLayout;
|
|
24
24
|
}) => void;
|
|
25
25
|
}
|
|
26
|
-
export
|
|
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;
|
|
@@ -229,7 +229,7 @@ export class UpdateManager {
|
|
|
229
229
|
const newIdData = getNewId({ config, salt, counter, excludeIds: newItemData.excludeIds });
|
|
230
230
|
counter = newIdData.counter;
|
|
231
231
|
const newItem = Object.assign(Object.assign({}, item), { id: newIdData.id, data: newItemData.data, namespace });
|
|
232
|
-
const saveDefaultLayout = pick(layout, ['h', 'w', 'x', 'y']);
|
|
232
|
+
const saveDefaultLayout = pick(layout, ['h', 'w', 'x', 'y', 'parent']);
|
|
233
233
|
if (options.updateLayout) {
|
|
234
234
|
const byId = options.updateLayout.reduce((memo, t) => {
|
|
235
235
|
memo[t.i] = t;
|
|
@@ -310,7 +310,7 @@ export class UpdateManager {
|
|
|
310
310
|
static updateLayout({ layout, config }) {
|
|
311
311
|
return update(config, {
|
|
312
312
|
layout: {
|
|
313
|
-
$set: layout.map((
|
|
313
|
+
$set: layout.map((item) => pick(item, ['i', 'h', 'w', 'x', 'y', 'parent'])),
|
|
314
314
|
},
|
|
315
315
|
});
|
|
316
316
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/dashkit",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.5.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.
|
|
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.
|
|
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",
|