@gravity-ui/dashkit 8.5.0 → 8.6.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/README.md +1 -0
- package/build/cjs/components/GridLayout/GridLayout.d.ts +16 -1
- package/build/cjs/components/GridLayout/GridLayout.js +80 -9
- package/build/cjs/components/Item/Item.d.ts +4 -0
- package/build/cjs/constants/common.d.ts +1 -0
- package/build/cjs/constants/common.js +2 -1
- package/build/cjs/hocs/prepareItem.d.ts +4 -0
- package/build/cjs/hocs/prepareItem.js +33 -22
- package/build/cjs/hocs/withContext.js +102 -13
- package/build/cjs/hooks/useDeepEqualMemo.d.ts +2 -0
- package/build/cjs/hooks/useDeepEqualMemo.js +17 -0
- package/build/cjs/typings/config.d.ts +3 -1
- package/build/esm/components/GridLayout/GridLayout.d.ts +16 -1
- package/build/esm/components/GridLayout/GridLayout.js +81 -10
- package/build/esm/components/Item/Item.d.ts +4 -0
- package/build/esm/constants/common.d.ts +1 -0
- package/build/esm/constants/common.js +1 -0
- package/build/esm/hocs/prepareItem.d.ts +4 -0
- package/build/esm/hocs/prepareItem.js +33 -22
- package/build/esm/hocs/withContext.js +104 -14
- package/build/esm/hooks/useDeepEqualMemo.d.ts +2 -0
- package/build/esm/hooks/useDeepEqualMemo.js +12 -0
- package/build/esm/typings/config.d.ts +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -475,6 +475,7 @@ const CustomThemeWrapper = (props: {
|
|
|
475
475
|
By default, storybook runs on `http://localhost:7120/`.
|
|
476
476
|
New changes from a project aren't always picked up when storybook is running, so it's better to rebuild a project manually and restart storybook.
|
|
477
477
|
|
|
478
|
+
|
|
478
479
|
### Example of an nginx config for development on a dev machine
|
|
479
480
|
|
|
480
481
|
```bash
|
|
@@ -9,6 +9,10 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
|
|
|
9
9
|
componentDidMount(): void;
|
|
10
10
|
componentDidUpdate(): void;
|
|
11
11
|
componentWillUnmount(): void;
|
|
12
|
+
_memoCallbacksForGroups: {};
|
|
13
|
+
_memoGroupsProps: {};
|
|
14
|
+
_memoGroupsLayouts: {};
|
|
15
|
+
_memoForwardedPluginRef: any[];
|
|
12
16
|
_timeout: any;
|
|
13
17
|
_lastReloadAt: any;
|
|
14
18
|
onVisibilityChange: () => void;
|
|
@@ -19,11 +23,22 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
|
|
|
19
23
|
}) => void;
|
|
20
24
|
getItemsMeta: () => any;
|
|
21
25
|
getActiveLayout(): any;
|
|
26
|
+
getMemoGroupLayout: (group: any, layout: any) => any;
|
|
27
|
+
getMemoGroupCallbacks: (group: any) => any;
|
|
28
|
+
getMemoGroupProps: (group: any, renderLayout: any, properties: any) => {
|
|
29
|
+
layout: any;
|
|
30
|
+
callbacks: any;
|
|
31
|
+
};
|
|
32
|
+
getLayoutAndPropsByGroup: (group: any) => {
|
|
33
|
+
properties: any;
|
|
34
|
+
layout: any;
|
|
35
|
+
};
|
|
36
|
+
getMemoForwardRefCallback: (refIndex: any) => any;
|
|
22
37
|
mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
|
|
23
38
|
reloadItems(): void;
|
|
24
39
|
_onStart: () => void;
|
|
25
40
|
_onStop: (group: any, newLayout: any) => void;
|
|
26
|
-
_onDropDragOver: (e: any) => any;
|
|
41
|
+
_onDropDragOver: (group: any, e: any) => any;
|
|
27
42
|
_onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
|
|
28
43
|
renderTemporaryPlaceholder(): JSX.Element | null;
|
|
29
44
|
renderGroup(group: any, renderLayout: any, renderItems: any, offset: number | undefined, groupGridProperties: any): JSX.Element;
|
|
@@ -9,6 +9,10 @@ const ReactGridLayout_1 = require("./ReactGridLayout");
|
|
|
9
9
|
class GridLayout extends react_1.default.PureComponent {
|
|
10
10
|
constructor(props, context) {
|
|
11
11
|
super(props, context);
|
|
12
|
+
this._memoForwardedPluginRef = [];
|
|
13
|
+
this._memoGroupsProps = {};
|
|
14
|
+
this._memoGroupsLayouts = {};
|
|
15
|
+
this._memoCallbacksForGroups = {};
|
|
12
16
|
this.onVisibilityChange = () => {
|
|
13
17
|
this.setState({
|
|
14
18
|
isPageHidden: document.hidden,
|
|
@@ -30,6 +34,65 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
30
34
|
const { getItemsMeta } = this.context;
|
|
31
35
|
return getItemsMeta(this.pluginsRefs);
|
|
32
36
|
};
|
|
37
|
+
this.getMemoGroupLayout = (group, layout) => {
|
|
38
|
+
// fastest possible way to match json
|
|
39
|
+
const key = JSON.stringify(layout);
|
|
40
|
+
if (this._memoGroupsLayouts[group]) {
|
|
41
|
+
if (this._memoGroupsLayouts[group].key === key) {
|
|
42
|
+
return this._memoGroupsLayouts[group];
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this._memoGroupsLayouts[group].key = key;
|
|
46
|
+
this._memoGroupsLayouts[group].layout = layout;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this._memoGroupsLayouts[group] = {
|
|
51
|
+
key,
|
|
52
|
+
layout,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return this._memoGroupsLayouts[group];
|
|
56
|
+
};
|
|
57
|
+
this.getMemoGroupCallbacks = (group) => {
|
|
58
|
+
if (!this._memoCallbacksForGroups[group]) {
|
|
59
|
+
const onStart = this._onStart;
|
|
60
|
+
const onStop = this._onStop.bind(this, group);
|
|
61
|
+
const onDrop = this._onDrop.bind(this, group);
|
|
62
|
+
const onDropDragOver = this._onDropDragOver.bind(this, group);
|
|
63
|
+
this._memoCallbacksForGroups[group] = {
|
|
64
|
+
onDragStart: onStart,
|
|
65
|
+
onResizeStart: onStart,
|
|
66
|
+
onDragStop: onStop,
|
|
67
|
+
onResizeStop: onStop,
|
|
68
|
+
onDrop: onDrop,
|
|
69
|
+
onDropDragOver,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return this._memoCallbacksForGroups[group];
|
|
73
|
+
};
|
|
74
|
+
this.getMemoGroupProps = (group, renderLayout, properties) => {
|
|
75
|
+
// Needed for _onDropDragOver
|
|
76
|
+
this._memoGroupsProps[group] = properties;
|
|
77
|
+
return {
|
|
78
|
+
layout: this.getMemoGroupLayout(group, renderLayout).layout,
|
|
79
|
+
callbacks: this.getMemoGroupCallbacks(group),
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
this.getLayoutAndPropsByGroup = (group) => {
|
|
83
|
+
return {
|
|
84
|
+
properties: this._memoGroupsProps[group],
|
|
85
|
+
layout: this._memoGroupsLayouts[group].layout,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
this.getMemoForwardRefCallback = (refIndex) => {
|
|
89
|
+
if (!this._memoForwardedPluginRef[refIndex]) {
|
|
90
|
+
this._memoForwardedPluginRef[refIndex] = (pluginRef) => {
|
|
91
|
+
this.pluginsRefs[refIndex] = pluginRef;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return this._memoForwardedPluginRef[refIndex];
|
|
95
|
+
};
|
|
33
96
|
this._onStart = () => {
|
|
34
97
|
if (this.temporaryLayout)
|
|
35
98
|
return;
|
|
@@ -46,12 +109,13 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
46
109
|
}
|
|
47
110
|
this.setState({ isDragging: false });
|
|
48
111
|
};
|
|
49
|
-
this._onDropDragOver = (e) => {
|
|
50
|
-
const { editMode, dragOverPlugin
|
|
112
|
+
this._onDropDragOver = (group, e) => {
|
|
113
|
+
const { editMode, dragOverPlugin } = this.context;
|
|
51
114
|
if (!editMode || !dragOverPlugin) {
|
|
52
115
|
return false;
|
|
53
116
|
}
|
|
54
|
-
|
|
117
|
+
const { properties, layout } = this.getLayoutAndPropsByGroup(group);
|
|
118
|
+
return this.context.onDropDragOver(e, properties, layout);
|
|
55
119
|
};
|
|
56
120
|
this._onDrop = (group, newLayout, item, e) => {
|
|
57
121
|
if (!item) {
|
|
@@ -84,6 +148,10 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
84
148
|
componentWillUnmount() {
|
|
85
149
|
clearTimeout(this._timeout);
|
|
86
150
|
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
151
|
+
this._memoCallbacksForGroups = {};
|
|
152
|
+
this._memoGroupsProps = {};
|
|
153
|
+
this._memoGroupsLayouts = {};
|
|
154
|
+
this._memoForwardedPluginRef = [];
|
|
87
155
|
}
|
|
88
156
|
getActiveLayout() {
|
|
89
157
|
const { layout, temporaryLayout } = this.context;
|
|
@@ -136,19 +204,22 @@ class GridLayout extends react_1.default.PureComponent {
|
|
|
136
204
|
const properties = groupGridProperties
|
|
137
205
|
? groupGridProperties(Object.assign({}, registerManager.gridLayout))
|
|
138
206
|
: registerManager.gridLayout;
|
|
139
|
-
|
|
207
|
+
let { compactType } = properties;
|
|
208
|
+
if (compactType === constants_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
209
|
+
compactType = 'horizontal';
|
|
210
|
+
}
|
|
211
|
+
const { callbacks, layout } = this.getMemoGroupProps(group, renderLayout, properties);
|
|
212
|
+
return (react_1.default.createElement(ReactGridLayout_1.Layout, Object.assign({}, properties, { compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onDragStart: callbacks.onDragStart, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResizeStop: callbacks.onResizeStop }, (draggableHandleClassName
|
|
140
213
|
? { draggableHandle: `.${draggableHandleClassName}` }
|
|
141
214
|
: null), (outerDnDEnable
|
|
142
215
|
? {
|
|
143
216
|
isDroppable: true,
|
|
144
|
-
onDropDragOver:
|
|
145
|
-
onDrop:
|
|
217
|
+
onDropDragOver: callbacks.onDropDragOver,
|
|
218
|
+
onDrop: callbacks.onDrop,
|
|
146
219
|
}
|
|
147
220
|
: null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }),
|
|
148
221
|
renderItems.map((item, i) => {
|
|
149
|
-
return (react_1.default.createElement(GridItem_1.default, { forwardedPluginRef: (
|
|
150
|
-
this.pluginsRefs[offset + i] = pluginRef;
|
|
151
|
-
}, 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 }));
|
|
222
|
+
return (react_1.default.createElement(GridItem_1.default, { forwardedPluginRef: this.getMemoForwardRefCallback(offset + i), 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 }));
|
|
152
223
|
}),
|
|
153
224
|
this.renderTemporaryPlaceholder()));
|
|
154
225
|
}
|
|
@@ -2,6 +2,8 @@ declare const _default: {
|
|
|
2
2
|
new (props: any): {
|
|
3
3
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
4
4
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
5
|
+
_currentRenderProps: {};
|
|
6
|
+
getRenderProps: () => {};
|
|
5
7
|
render(): JSX.Element;
|
|
6
8
|
context: unknown;
|
|
7
9
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -26,6 +28,8 @@ declare const _default: {
|
|
|
26
28
|
new (props: any, context: any): {
|
|
27
29
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
28
30
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
31
|
+
_currentRenderProps: {};
|
|
32
|
+
getRenderProps: () => {};
|
|
29
33
|
render(): JSX.Element;
|
|
30
34
|
context: unknown;
|
|
31
35
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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;
|
|
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';
|
|
@@ -14,3 +14,4 @@ exports.MenuItems = {
|
|
|
14
14
|
exports.DEFAULT_WIDGET_HEIGHT = 3;
|
|
15
15
|
exports.DEFAULT_WIDGET_WIDTH = 3;
|
|
16
16
|
exports.DEFAULT_GROUP = '__default';
|
|
17
|
+
exports.COMPACT_TYPE_HORIZONTAL_NOWRAP = 'horizontal-nowrap';
|
|
@@ -2,6 +2,8 @@ export function prepareItem(Component: any): {
|
|
|
2
2
|
new (props: any): {
|
|
3
3
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
4
4
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
5
|
+
_currentRenderProps: {};
|
|
6
|
+
getRenderProps: () => {};
|
|
5
7
|
render(): JSX.Element;
|
|
6
8
|
context: unknown;
|
|
7
9
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -26,6 +28,8 @@ export function prepareItem(Component: any): {
|
|
|
26
28
|
new (props: any, context: any): {
|
|
27
29
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
28
30
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
31
|
+
_currentRenderProps: {};
|
|
32
|
+
getRenderProps: () => {};
|
|
29
33
|
render(): JSX.Element;
|
|
30
34
|
context: unknown;
|
|
31
35
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -13,6 +13,35 @@ function prepareItem(Component) {
|
|
|
13
13
|
this._onStateAndParamsChange = (stateAndParams, options) => {
|
|
14
14
|
this.context.onItemStateAndParamsChange(this.props.id, stateAndParams, options);
|
|
15
15
|
};
|
|
16
|
+
this._currentRenderProps = {};
|
|
17
|
+
this.getRenderProps = () => {
|
|
18
|
+
const { id, width, height, item, adjustWidgetLayout, layout, isPlaceholder } = this.props;
|
|
19
|
+
const { itemsState, itemsParams, registerManager, settings, context, editMode } = this.context;
|
|
20
|
+
const { data, defaults, namespace } = item;
|
|
21
|
+
const rendererProps = {
|
|
22
|
+
data,
|
|
23
|
+
editMode,
|
|
24
|
+
params: itemsParams[id],
|
|
25
|
+
state: itemsState[id],
|
|
26
|
+
onStateAndParamsChange: this._onStateAndParamsChange,
|
|
27
|
+
width,
|
|
28
|
+
height,
|
|
29
|
+
id,
|
|
30
|
+
defaults,
|
|
31
|
+
namespace,
|
|
32
|
+
settings,
|
|
33
|
+
context,
|
|
34
|
+
layout,
|
|
35
|
+
gridLayout: registerManager.gridLayout,
|
|
36
|
+
adjustWidgetLayout,
|
|
37
|
+
isPlaceholder,
|
|
38
|
+
};
|
|
39
|
+
const changedProp = Object.entries(rendererProps).find(([key, value]) => this._currentRenderProps[key] !== value);
|
|
40
|
+
if (changedProp) {
|
|
41
|
+
this._currentRenderProps = rendererProps;
|
|
42
|
+
}
|
|
43
|
+
return this._currentRenderProps;
|
|
44
|
+
};
|
|
16
45
|
}
|
|
17
46
|
shouldComponentUpdate(nextProps) {
|
|
18
47
|
const { width, height, transform } = this.props;
|
|
@@ -26,28 +55,10 @@ function prepareItem(Component) {
|
|
|
26
55
|
return true;
|
|
27
56
|
}
|
|
28
57
|
render() {
|
|
29
|
-
const {
|
|
30
|
-
const {
|
|
31
|
-
const { type
|
|
32
|
-
|
|
33
|
-
data,
|
|
34
|
-
editMode,
|
|
35
|
-
params: itemsParams[id],
|
|
36
|
-
state: itemsState[id],
|
|
37
|
-
onStateAndParamsChange: this._onStateAndParamsChange,
|
|
38
|
-
width,
|
|
39
|
-
height,
|
|
40
|
-
id,
|
|
41
|
-
defaults,
|
|
42
|
-
namespace,
|
|
43
|
-
settings,
|
|
44
|
-
context,
|
|
45
|
-
layout,
|
|
46
|
-
gridLayout: registerManager.gridLayout,
|
|
47
|
-
adjustWidgetLayout,
|
|
48
|
-
isPlaceholder,
|
|
49
|
-
};
|
|
50
|
-
return (react_1.default.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: rendererProps, registerManager: registerManager, type: type, isPlaceholder: isPlaceholder }));
|
|
58
|
+
const { item, isPlaceholder } = this.props;
|
|
59
|
+
const { registerManager } = this.context;
|
|
60
|
+
const { type } = item;
|
|
61
|
+
return (react_1.default.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: this.getRenderProps(), registerManager: registerManager, type: type, isPlaceholder: isPlaceholder }));
|
|
51
62
|
}
|
|
52
63
|
},
|
|
53
64
|
_a.propTypes = {
|
|
@@ -7,8 +7,10 @@ const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
|
|
|
7
7
|
const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
|
|
8
8
|
const common_1 = require("../constants/common");
|
|
9
9
|
const DashKitContext_1 = require("../context/DashKitContext");
|
|
10
|
+
const useDeepEqualMemo_1 = require("../hooks/useDeepEqualMemo");
|
|
10
11
|
const shared_1 = require("../shared");
|
|
11
12
|
const utils_1 = require("../utils");
|
|
13
|
+
const ITEM_PROPS = ['i', 'h', 'w', 'x', 'y', 'parent'];
|
|
12
14
|
function useMemoStateContext(props) {
|
|
13
15
|
// так как мы не хотим хранить параметры виджета с активированной автовысотой в сторе и на сервере, актуальный
|
|
14
16
|
// (видимый юзером в конкретный момент времени) лэйаут (массив объектов с данными о ширине, высоте,
|
|
@@ -17,6 +19,7 @@ function useMemoStateContext(props) {
|
|
|
17
19
|
// (высота) из конфига будет запоминаться в originalLayouts, новое значение высоты в adjustedLayouts
|
|
18
20
|
const originalLayouts = react_1.default.useRef({});
|
|
19
21
|
const adjustedLayouts = react_1.default.useRef({});
|
|
22
|
+
const nowrapAdjustedLayouts = react_1.default.useRef({});
|
|
20
23
|
const [temporaryLayout, setTemporaryLayout] = react_1.default.useState(null);
|
|
21
24
|
const resetTemporaryLayout = react_1.default.useCallback(() => setTemporaryLayout(null), [setTemporaryLayout]);
|
|
22
25
|
const dndContext = react_1.default.useContext(DashKitContext_1.DashKitDnDContext);
|
|
@@ -52,6 +55,11 @@ function useMemoStateContext(props) {
|
|
|
52
55
|
}
|
|
53
56
|
}, [props.config, onChange]);
|
|
54
57
|
const onItemRemove = react_1.default.useCallback((id) => {
|
|
58
|
+
if (nowrapAdjustedLayouts.current[id]) {
|
|
59
|
+
delete nowrapAdjustedLayouts.current[id];
|
|
60
|
+
delete adjustedLayouts.current[id];
|
|
61
|
+
delete originalLayouts.current[id];
|
|
62
|
+
}
|
|
55
63
|
if (id === common_1.TEMPORARY_ITEM_ID) {
|
|
56
64
|
resetTemporaryLayout();
|
|
57
65
|
}
|
|
@@ -106,7 +114,55 @@ function useMemoStateContext(props) {
|
|
|
106
114
|
forceUpdateLayout((prev) => prev + 1);
|
|
107
115
|
}
|
|
108
116
|
}, []);
|
|
109
|
-
|
|
117
|
+
react_1.default.useMemo(() => {
|
|
118
|
+
const groups = props.groups;
|
|
119
|
+
const layout = props.layout;
|
|
120
|
+
const defaultProps = props.registerManager._gridLayout || {};
|
|
121
|
+
const nowrapGroups = {};
|
|
122
|
+
let hasNowrapGroups = false;
|
|
123
|
+
if (defaultProps.compactType === common_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
124
|
+
nowrapGroups[common_1.DEFAULT_GROUP] = {
|
|
125
|
+
items: [],
|
|
126
|
+
leftSpace: defaultProps.cols,
|
|
127
|
+
};
|
|
128
|
+
hasNowrapGroups = true;
|
|
129
|
+
}
|
|
130
|
+
if (groups) {
|
|
131
|
+
groups.forEach((group) => {
|
|
132
|
+
var _a;
|
|
133
|
+
const resultProps = ((_a = group.gridProperties) === null || _a === void 0 ? void 0 : _a.call(group, defaultProps)) || {};
|
|
134
|
+
if (resultProps.compactType === common_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
135
|
+
nowrapGroups[group.id] = {
|
|
136
|
+
items: [],
|
|
137
|
+
leftSpace: resultProps.cols,
|
|
138
|
+
};
|
|
139
|
+
hasNowrapGroups = true;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (hasNowrapGroups) {
|
|
144
|
+
layout.forEach((item) => {
|
|
145
|
+
const widgetId = item.i;
|
|
146
|
+
const parentId = item.parent || common_1.DEFAULT_GROUP;
|
|
147
|
+
if (nowrapGroups[parentId]) {
|
|
148
|
+
// Collecting nowrap elements
|
|
149
|
+
nowrapGroups[parentId].items.push(item);
|
|
150
|
+
nowrapGroups[parentId].leftSpace -= item.w;
|
|
151
|
+
}
|
|
152
|
+
else if (nowrapAdjustedLayouts.current[widgetId]) {
|
|
153
|
+
// If element is not in horizontal-nowrap cleaning up and reverting adjustLayout values
|
|
154
|
+
delete nowrapAdjustedLayouts.current[widgetId];
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
Object.entries(nowrapGroups).forEach(([, { items, leftSpace }]) => {
|
|
158
|
+
items.forEach((item) => {
|
|
159
|
+
// setting maxW with adjustLayout fields and saving previous
|
|
160
|
+
nowrapAdjustedLayouts.current[item.i] = item.w + leftSpace;
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}, [props.registerManager, props.groups, props.layout]);
|
|
165
|
+
const itemsParams = (0, useDeepEqualMemo_1.useDeepEqualMemo)(() => (0, shared_1.getItemsParams)({
|
|
110
166
|
defaultGlobalParams: props.defaultGlobalParams,
|
|
111
167
|
globalParams: props.globalParams,
|
|
112
168
|
config: props.config,
|
|
@@ -119,7 +175,7 @@ function useMemoStateContext(props) {
|
|
|
119
175
|
props.itemsStateAndParams,
|
|
120
176
|
props.registerManager,
|
|
121
177
|
]);
|
|
122
|
-
const itemsState =
|
|
178
|
+
const itemsState = (0, useDeepEqualMemo_1.useDeepEqualMemo)(() => (0, shared_1.getItemsState)({
|
|
123
179
|
config: props.config,
|
|
124
180
|
itemsStateAndParams: props.itemsStateAndParams,
|
|
125
181
|
}), [props.config, props.itemsStateAndParams]);
|
|
@@ -134,12 +190,31 @@ function useMemoStateContext(props) {
|
|
|
134
190
|
.filter(Boolean);
|
|
135
191
|
}, []);
|
|
136
192
|
const resultLayout = react_1.default.useMemo(() => {
|
|
193
|
+
const adjusted = adjustedLayouts.current;
|
|
194
|
+
const original = originalLayouts.current;
|
|
195
|
+
const nowrapAdjust = nowrapAdjustedLayouts.current;
|
|
137
196
|
return props.layout.map((item) => {
|
|
138
|
-
|
|
139
|
-
|
|
197
|
+
const widgetId = item.i;
|
|
198
|
+
if (adjusted[widgetId] || nowrapAdjust[widgetId]) {
|
|
199
|
+
original[widgetId] = item;
|
|
200
|
+
// eslint-disable-next-line no-unused-vars
|
|
201
|
+
const _a = adjusted[widgetId] || item, { parent } = _a, adjustedItem = tslib_1.__rest(_a, ["parent"]);
|
|
202
|
+
adjustedItem.w = item.w;
|
|
203
|
+
adjustedItem.x = item.x;
|
|
204
|
+
adjustedItem.y = item.y;
|
|
205
|
+
if (item.parent) {
|
|
206
|
+
adjustedItem.parent = item.parent;
|
|
207
|
+
}
|
|
208
|
+
if (nowrapAdjust[widgetId]) {
|
|
209
|
+
adjustedItem.maxW = nowrapAdjust[widgetId];
|
|
210
|
+
}
|
|
211
|
+
return adjustedItem;
|
|
140
212
|
}
|
|
141
213
|
else {
|
|
142
|
-
|
|
214
|
+
if (original[widgetId]) {
|
|
215
|
+
delete original[widgetId];
|
|
216
|
+
}
|
|
217
|
+
return item;
|
|
143
218
|
}
|
|
144
219
|
});
|
|
145
220
|
}, [props.layout, layoutUpdateCounter]);
|
|
@@ -161,17 +236,31 @@ function useMemoStateContext(props) {
|
|
|
161
236
|
return null;
|
|
162
237
|
}
|
|
163
238
|
}, [dragProps, props.registerManager]);
|
|
164
|
-
const onDropDragOver = react_1.default.useCallback(() => {
|
|
239
|
+
const onDropDragOver = react_1.default.useCallback((_e, gridProps, groupLayout) => {
|
|
165
240
|
if (temporaryLayout) {
|
|
166
241
|
resetTemporaryLayout();
|
|
167
242
|
return false;
|
|
168
243
|
}
|
|
169
|
-
if (dragOverPlugin) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
244
|
+
if (!dragOverPlugin) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
let maxW = gridProps.cols;
|
|
248
|
+
const { defaultLayout } = dragOverPlugin;
|
|
249
|
+
const maxH = Math.min(gridProps.maxRows || Infinity, defaultLayout.maxH || Infinity);
|
|
250
|
+
if (gridProps.compactType === common_1.COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
251
|
+
maxW = groupLayout.reduce((memo, item) => memo - item.w, gridProps.cols);
|
|
252
|
+
}
|
|
253
|
+
if (maxW === 0 ||
|
|
254
|
+
maxH === 0 ||
|
|
255
|
+
maxW < defaultLayout.minW ||
|
|
256
|
+
maxH < defaultLayout.minH) {
|
|
257
|
+
return false;
|
|
173
258
|
}
|
|
174
|
-
|
|
259
|
+
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 || {};
|
|
260
|
+
return {
|
|
261
|
+
h: maxH ? Math.min(h, maxH) : h,
|
|
262
|
+
w: maxW ? Math.min(w, maxW) : w,
|
|
263
|
+
};
|
|
175
264
|
}, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
|
|
176
265
|
const onDropProp = props.onDrop;
|
|
177
266
|
const onDrop = react_1.default.useCallback((newLayout, item) => {
|
|
@@ -185,11 +274,11 @@ function useMemoStateContext(props) {
|
|
|
185
274
|
onDropProp({
|
|
186
275
|
newLayout: newLayout.reduce((memo, l) => {
|
|
187
276
|
if (l.i !== item.i) {
|
|
188
|
-
memo.push((0, pick_1.default)(l,
|
|
277
|
+
memo.push((0, pick_1.default)(l, ITEM_PROPS));
|
|
189
278
|
}
|
|
190
279
|
return memo;
|
|
191
280
|
}, []),
|
|
192
|
-
itemLayout: (0, pick_1.default)(item,
|
|
281
|
+
itemLayout: (0, pick_1.default)(item, ITEM_PROPS),
|
|
193
282
|
commit: resetTemporaryLayout,
|
|
194
283
|
dragProps,
|
|
195
284
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDeepEqualMemo = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
+
const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
|
|
7
|
+
const useDeepEqualMemo = (predicate, deps) => {
|
|
8
|
+
const previousValueRef = react_1.default.useRef({});
|
|
9
|
+
return react_1.default.useMemo(() => {
|
|
10
|
+
const value = predicate();
|
|
11
|
+
if (!(0, isEqual_1.default)(previousValueRef.current, value)) {
|
|
12
|
+
previousValueRef.current = value;
|
|
13
|
+
}
|
|
14
|
+
return previousValueRef.current;
|
|
15
|
+
}, [previousValueRef, ...deps]);
|
|
16
|
+
};
|
|
17
|
+
exports.useDeepEqualMemo = useDeepEqualMemo;
|
|
@@ -19,7 +19,9 @@ export interface DashkitGroupRenderProps {
|
|
|
19
19
|
items: ConfigItem[];
|
|
20
20
|
layout: ConfigLayout[];
|
|
21
21
|
}
|
|
22
|
-
export type ReactGridLayoutProps = Omit<ReactGridLayout.ReactGridLayoutProps, 'children' | 'innerRef' | 'key' | 'layout' | 'isDraggable' | 'isResizable' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'
|
|
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
|
+
};
|
|
23
25
|
export interface DashKitGroup {
|
|
24
26
|
id?: string;
|
|
25
27
|
render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
|
|
@@ -9,6 +9,10 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
|
|
|
9
9
|
componentDidMount(): void;
|
|
10
10
|
componentDidUpdate(): void;
|
|
11
11
|
componentWillUnmount(): void;
|
|
12
|
+
_memoCallbacksForGroups: {};
|
|
13
|
+
_memoGroupsProps: {};
|
|
14
|
+
_memoGroupsLayouts: {};
|
|
15
|
+
_memoForwardedPluginRef: any[];
|
|
12
16
|
_timeout: any;
|
|
13
17
|
_lastReloadAt: any;
|
|
14
18
|
onVisibilityChange: () => void;
|
|
@@ -19,11 +23,22 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
|
|
|
19
23
|
}) => void;
|
|
20
24
|
getItemsMeta: () => any;
|
|
21
25
|
getActiveLayout(): any;
|
|
26
|
+
getMemoGroupLayout: (group: any, layout: any) => any;
|
|
27
|
+
getMemoGroupCallbacks: (group: any) => any;
|
|
28
|
+
getMemoGroupProps: (group: any, renderLayout: any, properties: any) => {
|
|
29
|
+
layout: any;
|
|
30
|
+
callbacks: any;
|
|
31
|
+
};
|
|
32
|
+
getLayoutAndPropsByGroup: (group: any) => {
|
|
33
|
+
properties: any;
|
|
34
|
+
layout: any;
|
|
35
|
+
};
|
|
36
|
+
getMemoForwardRefCallback: (refIndex: any) => any;
|
|
22
37
|
mergeGroupsLayout(group: any, newLayout: any, temporaryItem: any): any;
|
|
23
38
|
reloadItems(): void;
|
|
24
39
|
_onStart: () => void;
|
|
25
40
|
_onStop: (group: any, newLayout: any) => void;
|
|
26
|
-
_onDropDragOver: (e: any) => any;
|
|
41
|
+
_onDropDragOver: (group: any, e: any) => any;
|
|
27
42
|
_onDrop: (group: any, newLayout: any, item: any, e: any) => false | undefined;
|
|
28
43
|
renderTemporaryPlaceholder(): JSX.Element | null;
|
|
29
44
|
renderGroup(group: any, renderLayout: any, renderItems: any, offset: number | undefined, groupGridProperties: any): JSX.Element;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { DEFAULT_GROUP, 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';
|
|
6
6
|
class GridLayout extends React.PureComponent {
|
|
7
7
|
constructor(props, context) {
|
|
8
8
|
super(props, context);
|
|
9
|
+
this._memoForwardedPluginRef = [];
|
|
10
|
+
this._memoGroupsProps = {};
|
|
11
|
+
this._memoGroupsLayouts = {};
|
|
12
|
+
this._memoCallbacksForGroups = {};
|
|
9
13
|
this.onVisibilityChange = () => {
|
|
10
14
|
this.setState({
|
|
11
15
|
isPageHidden: document.hidden,
|
|
@@ -27,6 +31,65 @@ class GridLayout extends React.PureComponent {
|
|
|
27
31
|
const { getItemsMeta } = this.context;
|
|
28
32
|
return getItemsMeta(this.pluginsRefs);
|
|
29
33
|
};
|
|
34
|
+
this.getMemoGroupLayout = (group, layout) => {
|
|
35
|
+
// fastest possible way to match json
|
|
36
|
+
const key = JSON.stringify(layout);
|
|
37
|
+
if (this._memoGroupsLayouts[group]) {
|
|
38
|
+
if (this._memoGroupsLayouts[group].key === key) {
|
|
39
|
+
return this._memoGroupsLayouts[group];
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this._memoGroupsLayouts[group].key = key;
|
|
43
|
+
this._memoGroupsLayouts[group].layout = layout;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this._memoGroupsLayouts[group] = {
|
|
48
|
+
key,
|
|
49
|
+
layout,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return this._memoGroupsLayouts[group];
|
|
53
|
+
};
|
|
54
|
+
this.getMemoGroupCallbacks = (group) => {
|
|
55
|
+
if (!this._memoCallbacksForGroups[group]) {
|
|
56
|
+
const onStart = this._onStart;
|
|
57
|
+
const onStop = this._onStop.bind(this, group);
|
|
58
|
+
const onDrop = this._onDrop.bind(this, group);
|
|
59
|
+
const onDropDragOver = this._onDropDragOver.bind(this, group);
|
|
60
|
+
this._memoCallbacksForGroups[group] = {
|
|
61
|
+
onDragStart: onStart,
|
|
62
|
+
onResizeStart: onStart,
|
|
63
|
+
onDragStop: onStop,
|
|
64
|
+
onResizeStop: onStop,
|
|
65
|
+
onDrop: onDrop,
|
|
66
|
+
onDropDragOver,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return this._memoCallbacksForGroups[group];
|
|
70
|
+
};
|
|
71
|
+
this.getMemoGroupProps = (group, renderLayout, properties) => {
|
|
72
|
+
// Needed for _onDropDragOver
|
|
73
|
+
this._memoGroupsProps[group] = properties;
|
|
74
|
+
return {
|
|
75
|
+
layout: this.getMemoGroupLayout(group, renderLayout).layout,
|
|
76
|
+
callbacks: this.getMemoGroupCallbacks(group),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
this.getLayoutAndPropsByGroup = (group) => {
|
|
80
|
+
return {
|
|
81
|
+
properties: this._memoGroupsProps[group],
|
|
82
|
+
layout: this._memoGroupsLayouts[group].layout,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
this.getMemoForwardRefCallback = (refIndex) => {
|
|
86
|
+
if (!this._memoForwardedPluginRef[refIndex]) {
|
|
87
|
+
this._memoForwardedPluginRef[refIndex] = (pluginRef) => {
|
|
88
|
+
this.pluginsRefs[refIndex] = pluginRef;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return this._memoForwardedPluginRef[refIndex];
|
|
92
|
+
};
|
|
30
93
|
this._onStart = () => {
|
|
31
94
|
if (this.temporaryLayout)
|
|
32
95
|
return;
|
|
@@ -43,12 +106,13 @@ class GridLayout extends React.PureComponent {
|
|
|
43
106
|
}
|
|
44
107
|
this.setState({ isDragging: false });
|
|
45
108
|
};
|
|
46
|
-
this._onDropDragOver = (e) => {
|
|
47
|
-
const { editMode, dragOverPlugin
|
|
109
|
+
this._onDropDragOver = (group, e) => {
|
|
110
|
+
const { editMode, dragOverPlugin } = this.context;
|
|
48
111
|
if (!editMode || !dragOverPlugin) {
|
|
49
112
|
return false;
|
|
50
113
|
}
|
|
51
|
-
|
|
114
|
+
const { properties, layout } = this.getLayoutAndPropsByGroup(group);
|
|
115
|
+
return this.context.onDropDragOver(e, properties, layout);
|
|
52
116
|
};
|
|
53
117
|
this._onDrop = (group, newLayout, item, e) => {
|
|
54
118
|
if (!item) {
|
|
@@ -81,6 +145,10 @@ class GridLayout extends React.PureComponent {
|
|
|
81
145
|
componentWillUnmount() {
|
|
82
146
|
clearTimeout(this._timeout);
|
|
83
147
|
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
148
|
+
this._memoCallbacksForGroups = {};
|
|
149
|
+
this._memoGroupsProps = {};
|
|
150
|
+
this._memoGroupsLayouts = {};
|
|
151
|
+
this._memoForwardedPluginRef = [];
|
|
84
152
|
}
|
|
85
153
|
getActiveLayout() {
|
|
86
154
|
const { layout, temporaryLayout } = this.context;
|
|
@@ -133,19 +201,22 @@ class GridLayout extends React.PureComponent {
|
|
|
133
201
|
const properties = groupGridProperties
|
|
134
202
|
? groupGridProperties(Object.assign({}, registerManager.gridLayout))
|
|
135
203
|
: registerManager.gridLayout;
|
|
136
|
-
|
|
204
|
+
let { compactType } = properties;
|
|
205
|
+
if (compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
206
|
+
compactType = 'horizontal';
|
|
207
|
+
}
|
|
208
|
+
const { callbacks, layout } = this.getMemoGroupProps(group, renderLayout, properties);
|
|
209
|
+
return (React.createElement(Layout, Object.assign({}, properties, { compactType: compactType, layout: layout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onDragStart: callbacks.onDragStart, onDragStop: callbacks.onDragStop, onResizeStart: callbacks.onResizeStart, onResizeStop: callbacks.onResizeStop }, (draggableHandleClassName
|
|
137
210
|
? { draggableHandle: `.${draggableHandleClassName}` }
|
|
138
211
|
: null), (outerDnDEnable
|
|
139
212
|
? {
|
|
140
213
|
isDroppable: true,
|
|
141
|
-
onDropDragOver:
|
|
142
|
-
onDrop:
|
|
214
|
+
onDropDragOver: callbacks.onDropDragOver,
|
|
215
|
+
onDrop: callbacks.onDrop,
|
|
143
216
|
}
|
|
144
217
|
: null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
|
|
145
218
|
renderItems.map((item, i) => {
|
|
146
|
-
return (React.createElement(GridItem, { forwardedPluginRef: (
|
|
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 }));
|
|
219
|
+
return (React.createElement(GridItem, { forwardedPluginRef: this.getMemoForwardRefCallback(offset + i), 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 }));
|
|
149
220
|
}),
|
|
150
221
|
this.renderTemporaryPlaceholder()));
|
|
151
222
|
}
|
|
@@ -2,6 +2,8 @@ declare const _default: {
|
|
|
2
2
|
new (props: any): {
|
|
3
3
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
4
4
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
5
|
+
_currentRenderProps: {};
|
|
6
|
+
getRenderProps: () => {};
|
|
5
7
|
render(): JSX.Element;
|
|
6
8
|
context: unknown;
|
|
7
9
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -26,6 +28,8 @@ declare const _default: {
|
|
|
26
28
|
new (props: any, context: any): {
|
|
27
29
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
28
30
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
31
|
+
_currentRenderProps: {};
|
|
32
|
+
getRenderProps: () => {};
|
|
29
33
|
render(): JSX.Element;
|
|
30
34
|
context: unknown;
|
|
31
35
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -2,6 +2,8 @@ export function prepareItem(Component: any): {
|
|
|
2
2
|
new (props: any): {
|
|
3
3
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
4
4
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
5
|
+
_currentRenderProps: {};
|
|
6
|
+
getRenderProps: () => {};
|
|
5
7
|
render(): JSX.Element;
|
|
6
8
|
context: unknown;
|
|
7
9
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -26,6 +28,8 @@ export function prepareItem(Component: any): {
|
|
|
26
28
|
new (props: any, context: any): {
|
|
27
29
|
shouldComponentUpdate(nextProps: any): boolean;
|
|
28
30
|
_onStateAndParamsChange: (stateAndParams: any, options: any) => void;
|
|
31
|
+
_currentRenderProps: {};
|
|
32
|
+
getRenderProps: () => {};
|
|
29
33
|
render(): JSX.Element;
|
|
30
34
|
context: unknown;
|
|
31
35
|
setState<K extends string | number | symbol>(state: any, callback?: (() => void) | undefined): void;
|
|
@@ -9,6 +9,35 @@ export function prepareItem(Component) {
|
|
|
9
9
|
this._onStateAndParamsChange = (stateAndParams, options) => {
|
|
10
10
|
this.context.onItemStateAndParamsChange(this.props.id, stateAndParams, options);
|
|
11
11
|
};
|
|
12
|
+
this._currentRenderProps = {};
|
|
13
|
+
this.getRenderProps = () => {
|
|
14
|
+
const { id, width, height, item, adjustWidgetLayout, layout, isPlaceholder } = this.props;
|
|
15
|
+
const { itemsState, itemsParams, registerManager, settings, context, editMode } = this.context;
|
|
16
|
+
const { data, defaults, namespace } = item;
|
|
17
|
+
const rendererProps = {
|
|
18
|
+
data,
|
|
19
|
+
editMode,
|
|
20
|
+
params: itemsParams[id],
|
|
21
|
+
state: itemsState[id],
|
|
22
|
+
onStateAndParamsChange: this._onStateAndParamsChange,
|
|
23
|
+
width,
|
|
24
|
+
height,
|
|
25
|
+
id,
|
|
26
|
+
defaults,
|
|
27
|
+
namespace,
|
|
28
|
+
settings,
|
|
29
|
+
context,
|
|
30
|
+
layout,
|
|
31
|
+
gridLayout: registerManager.gridLayout,
|
|
32
|
+
adjustWidgetLayout,
|
|
33
|
+
isPlaceholder,
|
|
34
|
+
};
|
|
35
|
+
const changedProp = Object.entries(rendererProps).find(([key, value]) => this._currentRenderProps[key] !== value);
|
|
36
|
+
if (changedProp) {
|
|
37
|
+
this._currentRenderProps = rendererProps;
|
|
38
|
+
}
|
|
39
|
+
return this._currentRenderProps;
|
|
40
|
+
};
|
|
12
41
|
}
|
|
13
42
|
shouldComponentUpdate(nextProps) {
|
|
14
43
|
const { width, height, transform } = this.props;
|
|
@@ -22,28 +51,10 @@ export function prepareItem(Component) {
|
|
|
22
51
|
return true;
|
|
23
52
|
}
|
|
24
53
|
render() {
|
|
25
|
-
const {
|
|
26
|
-
const {
|
|
27
|
-
const { type
|
|
28
|
-
|
|
29
|
-
data,
|
|
30
|
-
editMode,
|
|
31
|
-
params: itemsParams[id],
|
|
32
|
-
state: itemsState[id],
|
|
33
|
-
onStateAndParamsChange: this._onStateAndParamsChange,
|
|
34
|
-
width,
|
|
35
|
-
height,
|
|
36
|
-
id,
|
|
37
|
-
defaults,
|
|
38
|
-
namespace,
|
|
39
|
-
settings,
|
|
40
|
-
context,
|
|
41
|
-
layout,
|
|
42
|
-
gridLayout: registerManager.gridLayout,
|
|
43
|
-
adjustWidgetLayout,
|
|
44
|
-
isPlaceholder,
|
|
45
|
-
};
|
|
46
|
-
return (React.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: rendererProps, registerManager: registerManager, type: type, isPlaceholder: isPlaceholder }));
|
|
54
|
+
const { item, isPlaceholder } = this.props;
|
|
55
|
+
const { registerManager } = this.context;
|
|
56
|
+
const { type } = item;
|
|
57
|
+
return (React.createElement(Component, { forwardedPluginRef: this.props.forwardedPluginRef, rendererProps: this.getRenderProps(), registerManager: registerManager, type: type, isPlaceholder: isPlaceholder }));
|
|
47
58
|
}
|
|
48
59
|
},
|
|
49
60
|
_a.propTypes = {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import isEqual from 'lodash/isEqual';
|
|
3
4
|
import pick from 'lodash/pick';
|
|
4
|
-
import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, TEMPORARY_ITEM_ID } from '../constants/common';
|
|
5
|
+
import { COMPACT_TYPE_HORIZONTAL_NOWRAP, DEFAULT_GROUP, DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, TEMPORARY_ITEM_ID, } from '../constants/common';
|
|
5
6
|
import { DashKitContext, DashKitDnDContext } from '../context/DashKitContext';
|
|
7
|
+
import { useDeepEqualMemo } from '../hooks/useDeepEqualMemo';
|
|
6
8
|
import { getItemsParams, getItemsState } from '../shared';
|
|
7
9
|
import { UpdateManager } from '../utils';
|
|
10
|
+
const ITEM_PROPS = ['i', 'h', 'w', 'x', 'y', 'parent'];
|
|
8
11
|
function useMemoStateContext(props) {
|
|
9
12
|
// так как мы не хотим хранить параметры виджета с активированной автовысотой в сторе и на сервере, актуальный
|
|
10
13
|
// (видимый юзером в конкретный момент времени) лэйаут (массив объектов с данными о ширине, высоте,
|
|
@@ -13,6 +16,7 @@ function useMemoStateContext(props) {
|
|
|
13
16
|
// (высота) из конфига будет запоминаться в originalLayouts, новое значение высоты в adjustedLayouts
|
|
14
17
|
const originalLayouts = React.useRef({});
|
|
15
18
|
const adjustedLayouts = React.useRef({});
|
|
19
|
+
const nowrapAdjustedLayouts = React.useRef({});
|
|
16
20
|
const [temporaryLayout, setTemporaryLayout] = React.useState(null);
|
|
17
21
|
const resetTemporaryLayout = React.useCallback(() => setTemporaryLayout(null), [setTemporaryLayout]);
|
|
18
22
|
const dndContext = React.useContext(DashKitDnDContext);
|
|
@@ -48,6 +52,11 @@ function useMemoStateContext(props) {
|
|
|
48
52
|
}
|
|
49
53
|
}, [props.config, onChange]);
|
|
50
54
|
const onItemRemove = React.useCallback((id) => {
|
|
55
|
+
if (nowrapAdjustedLayouts.current[id]) {
|
|
56
|
+
delete nowrapAdjustedLayouts.current[id];
|
|
57
|
+
delete adjustedLayouts.current[id];
|
|
58
|
+
delete originalLayouts.current[id];
|
|
59
|
+
}
|
|
51
60
|
if (id === TEMPORARY_ITEM_ID) {
|
|
52
61
|
resetTemporaryLayout();
|
|
53
62
|
}
|
|
@@ -102,7 +111,55 @@ function useMemoStateContext(props) {
|
|
|
102
111
|
forceUpdateLayout((prev) => prev + 1);
|
|
103
112
|
}
|
|
104
113
|
}, []);
|
|
105
|
-
|
|
114
|
+
React.useMemo(() => {
|
|
115
|
+
const groups = props.groups;
|
|
116
|
+
const layout = props.layout;
|
|
117
|
+
const defaultProps = props.registerManager._gridLayout || {};
|
|
118
|
+
const nowrapGroups = {};
|
|
119
|
+
let hasNowrapGroups = false;
|
|
120
|
+
if (defaultProps.compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
121
|
+
nowrapGroups[DEFAULT_GROUP] = {
|
|
122
|
+
items: [],
|
|
123
|
+
leftSpace: defaultProps.cols,
|
|
124
|
+
};
|
|
125
|
+
hasNowrapGroups = true;
|
|
126
|
+
}
|
|
127
|
+
if (groups) {
|
|
128
|
+
groups.forEach((group) => {
|
|
129
|
+
var _a;
|
|
130
|
+
const resultProps = ((_a = group.gridProperties) === null || _a === void 0 ? void 0 : _a.call(group, defaultProps)) || {};
|
|
131
|
+
if (resultProps.compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
132
|
+
nowrapGroups[group.id] = {
|
|
133
|
+
items: [],
|
|
134
|
+
leftSpace: resultProps.cols,
|
|
135
|
+
};
|
|
136
|
+
hasNowrapGroups = true;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (hasNowrapGroups) {
|
|
141
|
+
layout.forEach((item) => {
|
|
142
|
+
const widgetId = item.i;
|
|
143
|
+
const parentId = item.parent || DEFAULT_GROUP;
|
|
144
|
+
if (nowrapGroups[parentId]) {
|
|
145
|
+
// Collecting nowrap elements
|
|
146
|
+
nowrapGroups[parentId].items.push(item);
|
|
147
|
+
nowrapGroups[parentId].leftSpace -= item.w;
|
|
148
|
+
}
|
|
149
|
+
else if (nowrapAdjustedLayouts.current[widgetId]) {
|
|
150
|
+
// If element is not in horizontal-nowrap cleaning up and reverting adjustLayout values
|
|
151
|
+
delete nowrapAdjustedLayouts.current[widgetId];
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
Object.entries(nowrapGroups).forEach(([, { items, leftSpace }]) => {
|
|
155
|
+
items.forEach((item) => {
|
|
156
|
+
// setting maxW with adjustLayout fields and saving previous
|
|
157
|
+
nowrapAdjustedLayouts.current[item.i] = item.w + leftSpace;
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}, [props.registerManager, props.groups, props.layout]);
|
|
162
|
+
const itemsParams = useDeepEqualMemo(() => getItemsParams({
|
|
106
163
|
defaultGlobalParams: props.defaultGlobalParams,
|
|
107
164
|
globalParams: props.globalParams,
|
|
108
165
|
config: props.config,
|
|
@@ -115,7 +172,7 @@ function useMemoStateContext(props) {
|
|
|
115
172
|
props.itemsStateAndParams,
|
|
116
173
|
props.registerManager,
|
|
117
174
|
]);
|
|
118
|
-
const itemsState =
|
|
175
|
+
const itemsState = useDeepEqualMemo(() => getItemsState({
|
|
119
176
|
config: props.config,
|
|
120
177
|
itemsStateAndParams: props.itemsStateAndParams,
|
|
121
178
|
}), [props.config, props.itemsStateAndParams]);
|
|
@@ -130,12 +187,31 @@ function useMemoStateContext(props) {
|
|
|
130
187
|
.filter(Boolean);
|
|
131
188
|
}, []);
|
|
132
189
|
const resultLayout = React.useMemo(() => {
|
|
190
|
+
const adjusted = adjustedLayouts.current;
|
|
191
|
+
const original = originalLayouts.current;
|
|
192
|
+
const nowrapAdjust = nowrapAdjustedLayouts.current;
|
|
133
193
|
return props.layout.map((item) => {
|
|
134
|
-
|
|
135
|
-
|
|
194
|
+
const widgetId = item.i;
|
|
195
|
+
if (adjusted[widgetId] || nowrapAdjust[widgetId]) {
|
|
196
|
+
original[widgetId] = item;
|
|
197
|
+
// eslint-disable-next-line no-unused-vars
|
|
198
|
+
const _a = adjusted[widgetId] || item, { parent } = _a, adjustedItem = __rest(_a, ["parent"]);
|
|
199
|
+
adjustedItem.w = item.w;
|
|
200
|
+
adjustedItem.x = item.x;
|
|
201
|
+
adjustedItem.y = item.y;
|
|
202
|
+
if (item.parent) {
|
|
203
|
+
adjustedItem.parent = item.parent;
|
|
204
|
+
}
|
|
205
|
+
if (nowrapAdjust[widgetId]) {
|
|
206
|
+
adjustedItem.maxW = nowrapAdjust[widgetId];
|
|
207
|
+
}
|
|
208
|
+
return adjustedItem;
|
|
136
209
|
}
|
|
137
210
|
else {
|
|
138
|
-
|
|
211
|
+
if (original[widgetId]) {
|
|
212
|
+
delete original[widgetId];
|
|
213
|
+
}
|
|
214
|
+
return item;
|
|
139
215
|
}
|
|
140
216
|
});
|
|
141
217
|
}, [props.layout, layoutUpdateCounter]);
|
|
@@ -157,17 +233,31 @@ function useMemoStateContext(props) {
|
|
|
157
233
|
return null;
|
|
158
234
|
}
|
|
159
235
|
}, [dragProps, props.registerManager]);
|
|
160
|
-
const onDropDragOver = React.useCallback(() => {
|
|
236
|
+
const onDropDragOver = React.useCallback((_e, gridProps, groupLayout) => {
|
|
161
237
|
if (temporaryLayout) {
|
|
162
238
|
resetTemporaryLayout();
|
|
163
239
|
return false;
|
|
164
240
|
}
|
|
165
|
-
if (dragOverPlugin) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
241
|
+
if (!dragOverPlugin) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
let maxW = gridProps.cols;
|
|
245
|
+
const { defaultLayout } = dragOverPlugin;
|
|
246
|
+
const maxH = Math.min(gridProps.maxRows || Infinity, defaultLayout.maxH || Infinity);
|
|
247
|
+
if (gridProps.compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
|
|
248
|
+
maxW = groupLayout.reduce((memo, item) => memo - item.w, gridProps.cols);
|
|
249
|
+
}
|
|
250
|
+
if (maxW === 0 ||
|
|
251
|
+
maxH === 0 ||
|
|
252
|
+
maxW < defaultLayout.minW ||
|
|
253
|
+
maxH < defaultLayout.minH) {
|
|
254
|
+
return false;
|
|
169
255
|
}
|
|
170
|
-
|
|
256
|
+
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 || {};
|
|
257
|
+
return {
|
|
258
|
+
h: maxH ? Math.min(h, maxH) : h,
|
|
259
|
+
w: maxW ? Math.min(w, maxW) : w,
|
|
260
|
+
};
|
|
171
261
|
}, [resetTemporaryLayout, temporaryLayout, dragOverPlugin, dragProps]);
|
|
172
262
|
const onDropProp = props.onDrop;
|
|
173
263
|
const onDrop = React.useCallback((newLayout, item) => {
|
|
@@ -181,11 +271,11 @@ function useMemoStateContext(props) {
|
|
|
181
271
|
onDropProp({
|
|
182
272
|
newLayout: newLayout.reduce((memo, l) => {
|
|
183
273
|
if (l.i !== item.i) {
|
|
184
|
-
memo.push(pick(l,
|
|
274
|
+
memo.push(pick(l, ITEM_PROPS));
|
|
185
275
|
}
|
|
186
276
|
return memo;
|
|
187
277
|
}, []),
|
|
188
|
-
itemLayout: pick(item,
|
|
278
|
+
itemLayout: pick(item, ITEM_PROPS),
|
|
189
279
|
commit: resetTemporaryLayout,
|
|
190
280
|
dragProps,
|
|
191
281
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
3
|
+
export const useDeepEqualMemo = (predicate, deps) => {
|
|
4
|
+
const previousValueRef = React.useRef({});
|
|
5
|
+
return React.useMemo(() => {
|
|
6
|
+
const value = predicate();
|
|
7
|
+
if (!isEqual(previousValueRef.current, value)) {
|
|
8
|
+
previousValueRef.current = value;
|
|
9
|
+
}
|
|
10
|
+
return previousValueRef.current;
|
|
11
|
+
}, [previousValueRef, ...deps]);
|
|
12
|
+
};
|
|
@@ -19,7 +19,9 @@ export interface DashkitGroupRenderProps {
|
|
|
19
19
|
items: ConfigItem[];
|
|
20
20
|
layout: ConfigLayout[];
|
|
21
21
|
}
|
|
22
|
-
export type ReactGridLayoutProps = Omit<ReactGridLayout.ReactGridLayoutProps, 'children' | 'innerRef' | 'key' | 'layout' | 'isDraggable' | 'isResizable' | 'onDragStart' | 'onDragStop' | 'onResizeStart' | 'onResizeStop' | 'draggableHandle' | 'isDroppable' | 'onDropDragOver' | 'onDrop' | 'draggableCancel'
|
|
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
|
+
};
|
|
23
25
|
export interface DashKitGroup {
|
|
24
26
|
id?: string;
|
|
25
27
|
render?: (id: string, children: React.ReactNode, props: DashkitGroupRenderProps) => React.ReactNode;
|