@gravity-ui/dashkit 8.6.0 → 8.7.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 CHANGED
@@ -35,7 +35,8 @@ interface DashKitProps {
35
35
  itemsStateAndParams: ItemsStateAndParams;
36
36
  settings: SettingsProps;
37
37
  context: ContextProps;
38
- overlayControls?: Record<string, OverlayControlItem[]>;
38
+ overlayControls?: Record<string, OverlayControlItem[]> | null;
39
+ overlayMenuItems?: MenuItems[] | null;
39
40
  noOverlay?: boolean;
40
41
  focusable?: boolean;
41
42
  draggableHandleClassName?: string;
@@ -51,7 +52,8 @@ interface DashKitProps {
51
52
  - **itemsStateAndParams**: [itemsStateAndParams](#temsStateAndParams).
52
53
  - **settings**: DashKit settings.
53
54
  - **context**: Object that will be propped up on all widgets.
54
- - **overlayControls**: Object that overrides widget controls at the time of editing. If not transmitted, basic controls will be displayed.
55
+ - **overlayControls**: Object that overrides widget controls at the time of editing. If not transmitted, basic controls will be displayed. If `null` passed only close button or custom menu will be displayed.
56
+ - **overlayMenuItems**: Custom dropdown menu items
55
57
  - **noOverlay**: If `true`, overlay and controls are not displayed while editing.
56
58
  - **focusable**: If `true`, grid items will be focusable.
57
59
  - **draggableHandleClassName** : СSS class name of the element that makes the widget draggable.
@@ -343,6 +345,10 @@ type MenuItem = {
343
345
  };
344
346
 
345
347
  // use array of menu items in settings
348
+ <Dashkit overlayMenuItems={[] as Array<MenuItem> | null} />
349
+
350
+ [deprecated]
351
+ // overlayMenuItems property has greater priority over setSettings menu
346
352
  DashKit.setSettings({menu: [] as Array<MenuItem>});
347
353
  ```
348
354
 
@@ -386,7 +392,7 @@ type ItemDropProps = {
386
392
  #### Example:
387
393
 
388
394
  ```jsx
389
- const menuItems = [
395
+ const overlayMenuItems = [
390
396
  {
391
397
  id: 'chart',
392
398
  icon: <Icon data={ChartColumn} />,
@@ -405,7 +411,7 @@ const onDrop = (dropProps: ItemDropProps) => {
405
411
 
406
412
  <DashKitDnDWrapper>
407
413
  <DashKit editMode={true} config={config} onChange={onChange} onDrop={onDrop} />
408
- <ActionPanel items={menuItems} />
414
+ <ActionPanel items={overlayMenuItems} />
409
415
  </DashKitDnDWrapper>
410
416
  ```
411
417
 
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
  import type { Config, ConfigItem, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
- import { ContextProps, DashKitGroup, Plugin, SetConfigItem, SetNewItemOptions, Settings, SettingsProps } from '../../typings';
3
+ import { ContextProps, DashKitGroup, MenuItem, 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 {
7
7
  config: Config;
8
8
  editMode: boolean;
9
9
  draggableHandleClassName?: string;
10
- overlayControls?: Record<string, OverlayControlItem[]>;
10
+ overlayControls?: Record<string, OverlayControlItem[]> | null;
11
+ overlayMenuItems?: MenuItem[] | null;
11
12
  }
12
13
  interface DashKitDefaultProps {
13
14
  onItemEdit: (item: ConfigItem) => void;
@@ -9,10 +9,10 @@ const cn_1 = require("../../utils/cn");
9
9
  const GridLayout_1 = tslib_1.__importDefault(require("../GridLayout/GridLayout"));
10
10
  const MobileLayout_1 = tslib_1.__importDefault(require("../MobileLayout/MobileLayout"));
11
11
  const b = (0, cn_1.cn)('dashkit');
12
- function DashKitView(props) {
12
+ function DashKitView() {
13
13
  const context = react_1.default.useContext(DashKitContext_1.DashKitContext);
14
14
  const { registerManager, forwardedMetaRef } = context;
15
- return (react_1.default.createElement("div", { className: b({ theme: registerManager.settings.theme }) }, registerManager.settings.isMobile ? (react_1.default.createElement(MobileLayout_1.default, null)) : (react_1.default.createElement(GridLayout_1.default, { ref: forwardedMetaRef, overlayControls: props.overlayControls }))));
15
+ return (react_1.default.createElement("div", { className: b({ theme: registerManager.settings.theme }) }, registerManager.settings.isMobile ? (react_1.default.createElement(MobileLayout_1.default, null)) : (react_1.default.createElement(GridLayout_1.default, { ref: forwardedMetaRef }))));
16
16
  }
17
17
  const DashKitViewWithContext = (0, withContext_1.withContext)(DashKitView);
18
18
  const DashKitViewForwardedMeta = react_1.default.forwardRef((props, ref) => {
@@ -58,16 +58,15 @@ class GridItem extends react_1.default.PureComponent {
58
58
  };
59
59
  }
60
60
  renderOverlay() {
61
- const { overlayControls, isPlaceholder } = this.props;
61
+ const { isPlaceholder } = this.props;
62
62
  const { editMode } = this.context;
63
63
  if (!editMode || this.props.item.data._editActive || isPlaceholder) {
64
64
  return null;
65
65
  }
66
66
  const { item } = this.props;
67
- const controls = overlayControls && overlayControls[item.type];
68
67
  return (react_1.default.createElement(react_1.default.Fragment, null,
69
68
  react_1.default.createElement("div", { className: b('overlay') }),
70
- react_1.default.createElement(OverlayControls_1.default, { configItem: item, items: controls, overlayControls: overlayControls })));
69
+ react_1.default.createElement(OverlayControls_1.default, { configItem: item })));
71
70
  }
72
71
  render() {
73
72
  // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable
@@ -108,7 +107,6 @@ GridItem.propTypes = {
108
107
  item: prop_types_1.default.object,
109
108
  isDragging: prop_types_1.default.bool,
110
109
  layout: prop_types_1.default.array,
111
- overlayControls: prop_types_1.default.object,
112
110
  forwardedRef: prop_types_1.default.any,
113
111
  forwardedPluginRef: prop_types_1.default.any,
114
112
  isPlaceholder: prop_types_1.default.bool,
@@ -197,7 +197,7 @@ class GridLayout extends react_1.default.PureComponent {
197
197
  }
198
198
  const id = constants_1.TEMPORARY_ITEM_ID;
199
199
  const { type } = temporaryLayout.dragProps;
200
- 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 }));
200
+ 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) }));
201
201
  }
202
202
  renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
203
203
  const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
@@ -219,7 +219,7 @@ class GridLayout extends react_1.default.PureComponent {
219
219
  }
220
220
  : null), { draggableCancel: `.${constants_1.OVERLAY_CONTROLS_CLASS_NAME}` }),
221
221
  renderItems.map((item, i) => {
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 }));
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) }));
223
223
  }),
224
224
  this.renderTemporaryPlaceholder()));
225
225
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { ButtonSize, ButtonView, IconProps, MenuItemProps } from '@gravity-ui/uikit';
3
- import type { Config, ConfigItem, ItemState, PluginBase, StringParams } from '../../shared';
4
- import type { RegisterManager } from '../../utils/register-manager';
3
+ import type { ConfigItem, ConfigLayout, ItemState, PluginBase, StringParams } from '../../shared';
4
+ import { MenuItem } from '../../typings';
5
5
  export declare enum OverlayControlsPosition {
6
6
  TopRight = "top_right",
7
7
  TopLeft = "top_left",
@@ -13,6 +13,7 @@ export interface OverlayControlItem {
13
13
  icon?: IconProps['data'];
14
14
  iconSize?: number | string;
15
15
  handler?: (item: ConfigItem) => void;
16
+ visible?: (item: ConfigItem) => boolean;
16
17
  allWidgetsControls?: boolean;
17
18
  excludeWidgetsTypes?: Array<PluginBase['type']>;
18
19
  id?: string;
@@ -35,8 +36,6 @@ interface OverlayControlsDefaultProps {
35
36
  }
36
37
  interface OverlayControlsProps extends OverlayControlsDefaultProps {
37
38
  configItem: ConfigItem;
38
- items?: OverlayControlItem[];
39
- overlayControls?: Record<string, OverlayControlItem[]>;
40
39
  }
41
40
  type PreparedCopyItemOptionsArg = Pick<ConfigItem, 'data' | 'type' | 'defaults' | 'namespace'> & {
42
41
  timestamp: number;
@@ -49,21 +48,24 @@ export type PreparedCopyItemOptions<C extends object = {}> = PreparedCopyItemOpt
49
48
  copyContext?: C;
50
49
  };
51
50
  type DashKitCtx = React.Context<{
51
+ overlayControls?: Record<string, OverlayControlItem[]>;
52
52
  context: Record<string, any>;
53
- registerManager: RegisterManager;
53
+ menu: MenuItem[];
54
54
  itemsParams: Record<string, StringParams>;
55
55
  itemsState: Record<string, ItemState>;
56
56
  editItem: (item: ConfigItem) => void;
57
57
  removeItem: (id: string) => void;
58
- config: Config;
58
+ getLayoutItem: (id: string) => ConfigLayout | void;
59
59
  }>;
60
60
  declare class OverlayControls extends React.Component<OverlayControlsProps> {
61
61
  static contextType: React.Context<any>;
62
62
  static defaultProps: OverlayControlsDefaultProps;
63
63
  context: React.ContextType<DashKitCtx>;
64
64
  render(): JSX.Element;
65
+ private getItems;
65
66
  private renderControlsItem;
66
67
  private getDropDownMenuItemConfig;
68
+ private getDefaultControls;
67
69
  private renderControls;
68
70
  private renderMenu;
69
71
  private isDefaultMenu;
@@ -24,6 +24,11 @@ const DEFAULT_DROPDOWN_MENU = [constants_1.MenuItems.Copy, constants_1.MenuItems
24
24
  class OverlayControls extends react_1.default.Component {
25
25
  constructor() {
26
26
  super(...arguments);
27
+ this.getItems = () => {
28
+ const { overlayControls } = this.context;
29
+ const { configItem } = this.props;
30
+ return (overlayControls && overlayControls[configItem.type]) || [];
31
+ };
27
32
  this.renderControlsItem = (item, index, length) => {
28
33
  const { view, size } = this.props;
29
34
  const { title, handler, icon, iconSize, qa } = item;
@@ -31,18 +36,28 @@ class OverlayControls extends react_1.default.Component {
31
36
  return (react_1.default.createElement(uikit_1.Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => onItemClickHandler(this.props.configItem), qa: qa },
32
37
  react_1.default.createElement(uikit_1.Icon, { data: icon || CogIcon_1.CogIcon, size: icon ? iconSize : 24 })));
33
38
  };
39
+ this.getDefaultControls = () => {
40
+ const { view, size } = this.props;
41
+ if (this.context.overlayControls === null) {
42
+ return null;
43
+ }
44
+ return (react_1.default.createElement(uikit_1.Button, { view: view, size: size, title: (0, i18n_1.i18n)('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
45
+ react_1.default.createElement(uikit_1.Icon, { data: CogIcon_1.CogIcon, size: "24" })));
46
+ };
34
47
  this.getCustomLeftOverlayControls = () => {
35
48
  // выбираем только items-ы у которых проставлено поле `allWidgetsControls:true`
36
49
  // те контролы, которые будут показываться слева от меню
37
50
  let controls = [];
38
- for (const controlItem of Object.values(this.props.overlayControls || {})) {
51
+ for (const controlItem of Object.values(this.context.overlayControls || {})) {
39
52
  controls = controls.concat((controlItem.filter((item) => {
40
53
  var _a;
41
54
  // если тип виджета-плагина в списке исключаемых, то не показываем такой контрол
42
55
  if ((_a = item.excludeWidgetsTypes) === null || _a === void 0 ? void 0 : _a.includes(this.props.configItem.type)) {
43
56
  return false;
44
57
  }
45
- return item.allWidgetsControls;
58
+ return item.visible
59
+ ? item.visible(this.props.configItem)
60
+ : item.allWidgetsControls;
46
61
  }) || []).map((item) => {
47
62
  var _a;
48
63
  if (!(item === null || item === void 0 ? void 0 : item.id)) {
@@ -57,15 +72,14 @@ class OverlayControls extends react_1.default.Component {
57
72
  };
58
73
  this.onCopyItem = () => {
59
74
  var _a;
60
- const correspondedItemLayout = this.context.config.layout.find((item) => {
61
- return item.i === this.props.configItem.id;
62
- });
75
+ const { configItem } = this.props;
76
+ const correspondedItemLayout = this.context.getLayoutItem(configItem.id);
63
77
  let options = {
64
78
  timestamp: Date.now(),
65
- data: this.props.configItem.data,
66
- type: this.props.configItem.type,
67
- defaults: this.props.configItem.defaults,
68
- namespace: this.props.configItem.namespace,
79
+ data: configItem.data,
80
+ type: configItem.type,
81
+ defaults: configItem.defaults,
82
+ namespace: configItem.namespace,
69
83
  layout: {
70
84
  w: correspondedItemLayout.w,
71
85
  h: correspondedItemLayout.h,
@@ -87,7 +101,8 @@ class OverlayControls extends react_1.default.Component {
87
101
  };
88
102
  }
89
103
  render() {
90
- const { items = [], position } = this.props;
104
+ const { position } = this.props;
105
+ const items = this.getItems();
91
106
  const hasCustomControlsWithWidgets = items.length > 0;
92
107
  const controls = hasCustomControlsWithWidgets
93
108
  ? this.getCustomControlsWithWidgets()
@@ -122,11 +137,9 @@ class OverlayControls extends react_1.default.Component {
122
137
  return null;
123
138
  }
124
139
  renderControls() {
125
- const { view, size } = this.props;
126
140
  const customLeftControls = this.getCustomLeftOverlayControls();
127
141
  const hasCustomOverlayLeftControls = Boolean(customLeftControls.length);
128
- const defaultControl = (react_1.default.createElement(uikit_1.Button, { view: view, size: size, title: (0, i18n_1.i18n)('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
129
- react_1.default.createElement(uikit_1.Icon, { data: CogIcon_1.CogIcon, size: "24" })));
142
+ const defaultControl = this.getDefaultControls();
130
143
  const controls = hasCustomOverlayLeftControls
131
144
  ? customLeftControls.map((item, index, items) => this.renderControlsItem(item, index, items.length + 1))
132
145
  : defaultControl;
@@ -139,50 +152,58 @@ class OverlayControls extends react_1.default.Component {
139
152
  }
140
153
  renderMenu() {
141
154
  const { view, size } = this.props;
142
- const { registerManager } = this.context;
143
- const withMenu = Array.isArray(registerManager.settings.menu) && registerManager.settings.menu.length;
144
- return (react_1.default.createElement(react_1.default.Fragment, null, withMenu ? (this.renderDropdownMenu()) : (react_1.default.createElement(uikit_1.Button, { view: view, size: size, title: (0, i18n_1.i18n)('label_delete'), pin: "brick-round", onClick: this.onRemoveItem, qa: "dashkit-overlay-control-menu" },
145
- react_1.default.createElement(uikit_1.Icon, { data: CloseIcon_1.CloseIcon, size: "12" })))));
155
+ const dropdown = this.renderDropdownMenu();
156
+ if (dropdown) {
157
+ return dropdown;
158
+ }
159
+ return (react_1.default.createElement(uikit_1.Button, { key: 'delete-control', view: view, size: size, title: (0, i18n_1.i18n)('label_delete'), pin: "brick-round", onClick: this.onRemoveItem, qa: "dashkit-overlay-control-menu" },
160
+ react_1.default.createElement(uikit_1.Icon, { data: CloseIcon_1.CloseIcon, size: "12" })));
146
161
  }
147
162
  isDefaultMenu(menu) {
148
163
  return menu === null || menu === void 0 ? void 0 : menu.every((item) => Object.values(constants_1.MenuItems).includes(String(item)));
149
164
  }
150
165
  renderDropdownMenu() {
151
166
  const { view, size } = this.props;
152
- const { registerManager, itemsParams, itemsState } = this.context;
167
+ const { menu: contextMenu, itemsParams, itemsState } = this.context;
153
168
  const configItem = this.props.configItem;
154
169
  const itemParams = itemsParams[configItem.id];
155
170
  const itemState = itemsState[configItem.id];
156
- let menu = registerManager.settings.menu;
157
- if (!menu.length) {
158
- menu = DEFAULT_DROPDOWN_MENU;
159
- }
171
+ const menu = (contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.length) > 0 ? contextMenu : DEFAULT_DROPDOWN_MENU;
160
172
  const isDefaultMenu = this.isDefaultMenu(menu);
161
- let items = isDefaultMenu
162
- ? (menu || []).map((name) => this.getDropDownMenuItemConfig(name, true))
163
- : menu.map((item) => {
173
+ const items = isDefaultMenu
174
+ ? (menu || []).reduce((memo, name) => {
175
+ const item = this.getDropDownMenuItemConfig(name, true);
176
+ if (item) {
177
+ memo.push(item);
178
+ }
179
+ return memo;
180
+ }, [])
181
+ : menu.reduce((memo, item) => {
164
182
  var _a;
165
183
  if (typeof item === 'string') {
166
- return null;
184
+ return memo;
167
185
  }
168
186
  // custom menu dropdown item filter
169
187
  if (item.visible && !item.visible(configItem)) {
170
- return null;
188
+ return memo;
171
189
  }
172
190
  const itemHandler = item.handler;
173
191
  const itemAction = typeof itemHandler === 'function'
174
192
  ? () => itemHandler(configItem, itemParams, itemState)
175
193
  : ((_a = this.getDropDownMenuItemConfig(item.id)) === null || _a === void 0 ? void 0 : _a.action) || (() => { });
176
- return {
194
+ memo.push({
177
195
  // @ts-expect-error
178
196
  text: item.title || (0, i18n_1.i18n)(item.id),
179
197
  icon: item.icon,
180
198
  action: itemAction,
181
199
  className: item.className,
182
200
  qa: item.qa,
183
- };
184
- });
185
- items = items.filter(Boolean);
201
+ });
202
+ return memo;
203
+ }, []);
204
+ if (items.length === 0) {
205
+ return null;
206
+ }
186
207
  return (react_1.default.createElement(uikit_1.DropdownMenu, { items: items, renderSwitcher: (props) => (react_1.default.createElement(uikit_1.Button, Object.assign({}, props, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" }),
187
208
  react_1.default.createElement(uikit_1.Icon, { data: DotsIcon_1.DotsIcon, size: "16" }))) }));
188
209
  }
@@ -202,19 +223,14 @@ class OverlayControls extends react_1.default.Component {
202
223
  return 'brick-brick';
203
224
  }
204
225
  getCustomControlsWithWidgets() {
205
- // Добавляем контрол удаления виджета по умолчанию
206
- const deleteControl = {
207
- title: (0, i18n_1.i18n)('label_delete'),
208
- icon: CloseIcon_1.CloseIcon,
209
- iconSize: 12,
210
- handler: this.onRemoveItem,
211
- };
212
- const { items = [] } = this.props;
213
- const customOverlayControls = [...items, deleteControl];
214
- return customOverlayControls.map((item, index, controlItems) => this.renderControlsItem(item, index, controlItems.length));
226
+ const items = this.getItems();
227
+ const result = items.map((item, index, controlItems) => this.renderControlsItem(item, index, controlItems.length));
228
+ // Добавляем контрол удаления или меню виджета по умолчанию
229
+ result.push(this.renderMenu());
230
+ return result;
215
231
  }
216
232
  }
217
- OverlayControls.contextType = DashKitContext_1.DashKitContext;
233
+ OverlayControls.contextType = DashKitContext_1.DashkitOvelayControlsContext;
218
234
  OverlayControls.defaultProps = {
219
235
  position: OverlayControlsPosition.TopRight,
220
236
  view: 'flat',
@@ -1,3 +1,4 @@
1
1
  export const DashKitContext: React.Context<any>;
2
+ export const DashkitOvelayControlsContext: React.Context<any>;
2
3
  export const DashKitDnDContext: React.Context<any>;
3
4
  import React from 'react';
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DashKitDnDContext = exports.DashKitContext = void 0;
3
+ exports.DashKitDnDContext = exports.DashkitOvelayControlsContext = exports.DashKitContext = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const DashKitContext = react_1.default.createContext();
7
7
  exports.DashKitContext = DashKitContext;
8
+ const DashkitOvelayControlsContext = react_1.default.createContext();
9
+ exports.DashkitOvelayControlsContext = DashkitOvelayControlsContext;
8
10
  const DashKitDnDContext = react_1.default.createContext();
9
11
  exports.DashKitDnDContext = DashKitDnDContext;
@@ -54,12 +54,13 @@ function useMemoStateContext(props) {
54
54
  onChange({ config: newConfig });
55
55
  }
56
56
  }, [props.config, onChange]);
57
+ const getLayoutItem = react_1.default.useCallback((id) => {
58
+ return props.config.layout.find(({ i }) => i === id);
59
+ }, [props.config.layout]);
57
60
  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
- }
61
+ delete nowrapAdjustedLayouts.current[id];
62
+ delete adjustedLayouts.current[id];
63
+ delete originalLayouts.current[id];
63
64
  if (id === common_1.TEMPORARY_ITEM_ID) {
64
65
  resetTemporaryLayout();
65
66
  }
@@ -195,7 +196,7 @@ function useMemoStateContext(props) {
195
196
  const nowrapAdjust = nowrapAdjustedLayouts.current;
196
197
  return props.layout.map((item) => {
197
198
  const widgetId = item.i;
198
- if (adjusted[widgetId] || nowrapAdjust[widgetId]) {
199
+ if (widgetId in adjusted || widgetId in nowrapAdjust) {
199
200
  original[widgetId] = item;
200
201
  // eslint-disable-next-line no-unused-vars
201
202
  const _a = adjusted[widgetId] || item, { parent } = _a, adjustedItem = tslib_1.__rest(_a, ["parent"]);
@@ -205,13 +206,13 @@ function useMemoStateContext(props) {
205
206
  if (item.parent) {
206
207
  adjustedItem.parent = item.parent;
207
208
  }
208
- if (nowrapAdjust[widgetId]) {
209
+ if (widgetId in nowrapAdjust) {
209
210
  adjustedItem.maxW = nowrapAdjust[widgetId];
210
211
  }
211
212
  return adjustedItem;
212
213
  }
213
214
  else {
214
- if (original[widgetId]) {
215
+ if (widgetId in original) {
215
216
  delete original[widgetId];
216
217
  }
217
218
  return item;
@@ -283,7 +284,7 @@ function useMemoStateContext(props) {
283
284
  dragProps,
284
285
  });
285
286
  }, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
286
- return react_1.default.useMemo(() => ({
287
+ const dashkitContextValue = react_1.default.useMemo(() => ({
287
288
  layout: resultLayout,
288
289
  temporaryLayout,
289
290
  config: props.config,
@@ -299,10 +300,8 @@ function useMemoStateContext(props) {
299
300
  itemsParams,
300
301
  registerManager: props.registerManager,
301
302
  onItemStateAndParamsChange,
302
- removeItem: onItemRemove,
303
303
  onDrop,
304
304
  onDropDragOver,
305
- editItem: props.onItemEdit,
306
305
  layoutChange: onLayoutChange,
307
306
  getItemsMeta,
308
307
  reloadItems,
@@ -327,10 +326,8 @@ function useMemoStateContext(props) {
327
326
  itemsParams,
328
327
  props.registerManager,
329
328
  onItemStateAndParamsChange,
330
- onItemRemove,
331
329
  onDrop,
332
330
  onDropDragOver,
333
- props.onItemEdit,
334
331
  onLayoutChange,
335
332
  getItemsMeta,
336
333
  reloadItems,
@@ -341,12 +338,34 @@ function useMemoStateContext(props) {
341
338
  outerDnDEnable,
342
339
  dragOverPlugin,
343
340
  ]);
341
+ const overlayMenuItems = props.overlayMenuItems || props.registerManager.settings.menu;
342
+ const controlsContextValue = react_1.default.useMemo(() => ({
343
+ overlayControls: props.overlayControls,
344
+ context: props.context,
345
+ menu: overlayMenuItems,
346
+ itemsParams: itemsParams,
347
+ itemsState: itemsState,
348
+ editItem: props.onItemEdit,
349
+ removeItem: onItemRemove,
350
+ getLayoutItem: getLayoutItem,
351
+ }), [
352
+ itemsParams,
353
+ itemsState,
354
+ props.context,
355
+ props.onItemEdit,
356
+ onItemRemove,
357
+ props.overlayControls,
358
+ overlayMenuItems,
359
+ getLayoutItem,
360
+ ]);
361
+ return { controlsContextValue, dashkitContextValue };
344
362
  }
345
363
  function withContext(Component) {
346
364
  const WithContext = (props) => {
347
- const contextValue = useMemoStateContext(props);
348
- return (react_1.default.createElement(DashKitContext_1.DashKitContext.Provider, { value: contextValue },
349
- react_1.default.createElement(Component, { overlayControls: props.overlayControls })));
365
+ const { dashkitContextValue, controlsContextValue } = useMemoStateContext(props);
366
+ return (react_1.default.createElement(DashKitContext_1.DashKitContext.Provider, { value: dashkitContextValue },
367
+ react_1.default.createElement(DashKitContext_1.DashkitOvelayControlsContext.Provider, { value: controlsContextValue },
368
+ react_1.default.createElement(Component, null))));
350
369
  };
351
370
  WithContext.displayName = `withContext(${Component.displayName || Component.name || 'Component'}`;
352
371
  return WithContext;
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
  import type { Config, ConfigItem, GlobalParams, ItemDropProps, ItemsStateAndParams } from '../../shared';
3
- import { ContextProps, DashKitGroup, Plugin, SetConfigItem, SetNewItemOptions, Settings, SettingsProps } from '../../typings';
3
+ import { ContextProps, DashKitGroup, MenuItem, 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 {
7
7
  config: Config;
8
8
  editMode: boolean;
9
9
  draggableHandleClassName?: string;
10
- overlayControls?: Record<string, OverlayControlItem[]>;
10
+ overlayControls?: Record<string, OverlayControlItem[]> | null;
11
+ overlayMenuItems?: MenuItem[] | null;
11
12
  }
12
13
  interface DashKitDefaultProps {
13
14
  onItemEdit: (item: ConfigItem) => void;
@@ -7,10 +7,10 @@ import GridLayout from '../GridLayout/GridLayout';
7
7
  import MobileLayout from '../MobileLayout/MobileLayout';
8
8
  import './DashKitView.css';
9
9
  const b = cn('dashkit');
10
- function DashKitView(props) {
10
+ function DashKitView() {
11
11
  const context = React.useContext(DashKitContext);
12
12
  const { registerManager, forwardedMetaRef } = context;
13
- return (React.createElement("div", { className: b({ theme: registerManager.settings.theme }) }, registerManager.settings.isMobile ? (React.createElement(MobileLayout, null)) : (React.createElement(GridLayout, { ref: forwardedMetaRef, overlayControls: props.overlayControls }))));
13
+ return (React.createElement("div", { className: b({ theme: registerManager.settings.theme }) }, registerManager.settings.isMobile ? (React.createElement(MobileLayout, null)) : (React.createElement(GridLayout, { ref: forwardedMetaRef }))));
14
14
  }
15
15
  const DashKitViewWithContext = withContext(DashKitView);
16
16
  const DashKitViewForwardedMeta = React.forwardRef((props, ref) => {
@@ -56,16 +56,15 @@ class GridItem extends React.PureComponent {
56
56
  };
57
57
  }
58
58
  renderOverlay() {
59
- const { overlayControls, isPlaceholder } = this.props;
59
+ const { isPlaceholder } = this.props;
60
60
  const { editMode } = this.context;
61
61
  if (!editMode || this.props.item.data._editActive || isPlaceholder) {
62
62
  return null;
63
63
  }
64
64
  const { item } = this.props;
65
- const controls = overlayControls && overlayControls[item.type];
66
65
  return (React.createElement(React.Fragment, null,
67
66
  React.createElement("div", { className: b('overlay') }),
68
- React.createElement(OverlayControls, { configItem: item, items: controls, overlayControls: overlayControls })));
67
+ React.createElement(OverlayControls, { configItem: item })));
69
68
  }
70
69
  render() {
71
70
  // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable
@@ -106,7 +105,6 @@ GridItem.propTypes = {
106
105
  item: PropTypes.object,
107
106
  isDragging: PropTypes.bool,
108
107
  layout: PropTypes.array,
109
- overlayControls: PropTypes.object,
110
108
  forwardedRef: PropTypes.any,
111
109
  forwardedPluginRef: PropTypes.any,
112
110
  isPlaceholder: PropTypes.bool,
@@ -194,7 +194,7 @@ class GridLayout extends React.PureComponent {
194
194
  }
195
195
  const id = TEMPORARY_ITEM_ID;
196
196
  const { type } = temporaryLayout.dragProps;
197
- 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 }));
197
+ 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) }));
198
198
  }
199
199
  renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
200
200
  const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
@@ -216,7 +216,7 @@ class GridLayout extends React.PureComponent {
216
216
  }
217
217
  : null), { draggableCancel: `.${OVERLAY_CONTROLS_CLASS_NAME}` }),
218
218
  renderItems.map((item, i) => {
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 }));
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) }));
220
220
  }),
221
221
  this.renderTemporaryPlaceholder()));
222
222
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { ButtonSize, ButtonView, IconProps, MenuItemProps } from '@gravity-ui/uikit';
3
- import type { Config, ConfigItem, ItemState, PluginBase, StringParams } from '../../shared';
4
- import type { RegisterManager } from '../../utils/register-manager';
3
+ import type { ConfigItem, ConfigLayout, ItemState, PluginBase, StringParams } from '../../shared';
4
+ import { MenuItem } from '../../typings';
5
5
  import './OverlayControls.css';
6
6
  export declare enum OverlayControlsPosition {
7
7
  TopRight = "top_right",
@@ -14,6 +14,7 @@ export interface OverlayControlItem {
14
14
  icon?: IconProps['data'];
15
15
  iconSize?: number | string;
16
16
  handler?: (item: ConfigItem) => void;
17
+ visible?: (item: ConfigItem) => boolean;
17
18
  allWidgetsControls?: boolean;
18
19
  excludeWidgetsTypes?: Array<PluginBase['type']>;
19
20
  id?: string;
@@ -36,8 +37,6 @@ interface OverlayControlsDefaultProps {
36
37
  }
37
38
  interface OverlayControlsProps extends OverlayControlsDefaultProps {
38
39
  configItem: ConfigItem;
39
- items?: OverlayControlItem[];
40
- overlayControls?: Record<string, OverlayControlItem[]>;
41
40
  }
42
41
  type PreparedCopyItemOptionsArg = Pick<ConfigItem, 'data' | 'type' | 'defaults' | 'namespace'> & {
43
42
  timestamp: number;
@@ -50,21 +49,24 @@ export type PreparedCopyItemOptions<C extends object = {}> = PreparedCopyItemOpt
50
49
  copyContext?: C;
51
50
  };
52
51
  type DashKitCtx = React.Context<{
52
+ overlayControls?: Record<string, OverlayControlItem[]>;
53
53
  context: Record<string, any>;
54
- registerManager: RegisterManager;
54
+ menu: MenuItem[];
55
55
  itemsParams: Record<string, StringParams>;
56
56
  itemsState: Record<string, ItemState>;
57
57
  editItem: (item: ConfigItem) => void;
58
58
  removeItem: (id: string) => void;
59
- config: Config;
59
+ getLayoutItem: (id: string) => ConfigLayout | void;
60
60
  }>;
61
61
  declare class OverlayControls extends React.Component<OverlayControlsProps> {
62
62
  static contextType: React.Context<any>;
63
63
  static defaultProps: OverlayControlsDefaultProps;
64
64
  context: React.ContextType<DashKitCtx>;
65
65
  render(): JSX.Element;
66
+ private getItems;
66
67
  private renderControlsItem;
67
68
  private getDropDownMenuItemConfig;
69
+ private getDefaultControls;
68
70
  private renderControls;
69
71
  private renderMenu;
70
72
  private isDefaultMenu;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Button, DropdownMenu, Icon, } from '@gravity-ui/uikit';
3
3
  import noop from 'lodash/noop';
4
4
  import { COPIED_WIDGET_STORE_KEY, MenuItems, OVERLAY_CONTROLS_CLASS_NAME } from '../../constants';
5
- import { DashKitContext } from '../../context/DashKitContext';
5
+ import { DashkitOvelayControlsContext } from '../../context/DashKitContext';
6
6
  import { i18n } from '../../i18n';
7
7
  import { CloseIcon } from '../../icons/CloseIcon';
8
8
  import { CogIcon } from '../../icons/CogIcon';
@@ -21,6 +21,11 @@ const DEFAULT_DROPDOWN_MENU = [MenuItems.Copy, MenuItems.Delete];
21
21
  class OverlayControls extends React.Component {
22
22
  constructor() {
23
23
  super(...arguments);
24
+ this.getItems = () => {
25
+ const { overlayControls } = this.context;
26
+ const { configItem } = this.props;
27
+ return (overlayControls && overlayControls[configItem.type]) || [];
28
+ };
24
29
  this.renderControlsItem = (item, index, length) => {
25
30
  const { view, size } = this.props;
26
31
  const { title, handler, icon, iconSize, qa } = item;
@@ -28,18 +33,28 @@ class OverlayControls extends React.Component {
28
33
  return (React.createElement(Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => onItemClickHandler(this.props.configItem), qa: qa },
29
34
  React.createElement(Icon, { data: icon || CogIcon, size: icon ? iconSize : 24 })));
30
35
  };
36
+ this.getDefaultControls = () => {
37
+ const { view, size } = this.props;
38
+ if (this.context.overlayControls === null) {
39
+ return null;
40
+ }
41
+ return (React.createElement(Button, { view: view, size: size, title: i18n('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
42
+ React.createElement(Icon, { data: CogIcon, size: "24" })));
43
+ };
31
44
  this.getCustomLeftOverlayControls = () => {
32
45
  // выбираем только items-ы у которых проставлено поле `allWidgetsControls:true`
33
46
  // те контролы, которые будут показываться слева от меню
34
47
  let controls = [];
35
- for (const controlItem of Object.values(this.props.overlayControls || {})) {
48
+ for (const controlItem of Object.values(this.context.overlayControls || {})) {
36
49
  controls = controls.concat((controlItem.filter((item) => {
37
50
  var _a;
38
51
  // если тип виджета-плагина в списке исключаемых, то не показываем такой контрол
39
52
  if ((_a = item.excludeWidgetsTypes) === null || _a === void 0 ? void 0 : _a.includes(this.props.configItem.type)) {
40
53
  return false;
41
54
  }
42
- return item.allWidgetsControls;
55
+ return item.visible
56
+ ? item.visible(this.props.configItem)
57
+ : item.allWidgetsControls;
43
58
  }) || []).map((item) => {
44
59
  var _a;
45
60
  if (!(item === null || item === void 0 ? void 0 : item.id)) {
@@ -54,15 +69,14 @@ class OverlayControls extends React.Component {
54
69
  };
55
70
  this.onCopyItem = () => {
56
71
  var _a;
57
- const correspondedItemLayout = this.context.config.layout.find((item) => {
58
- return item.i === this.props.configItem.id;
59
- });
72
+ const { configItem } = this.props;
73
+ const correspondedItemLayout = this.context.getLayoutItem(configItem.id);
60
74
  let options = {
61
75
  timestamp: Date.now(),
62
- data: this.props.configItem.data,
63
- type: this.props.configItem.type,
64
- defaults: this.props.configItem.defaults,
65
- namespace: this.props.configItem.namespace,
76
+ data: configItem.data,
77
+ type: configItem.type,
78
+ defaults: configItem.defaults,
79
+ namespace: configItem.namespace,
66
80
  layout: {
67
81
  w: correspondedItemLayout.w,
68
82
  h: correspondedItemLayout.h,
@@ -84,7 +98,8 @@ class OverlayControls extends React.Component {
84
98
  };
85
99
  }
86
100
  render() {
87
- const { items = [], position } = this.props;
101
+ const { position } = this.props;
102
+ const items = this.getItems();
88
103
  const hasCustomControlsWithWidgets = items.length > 0;
89
104
  const controls = hasCustomControlsWithWidgets
90
105
  ? this.getCustomControlsWithWidgets()
@@ -119,11 +134,9 @@ class OverlayControls extends React.Component {
119
134
  return null;
120
135
  }
121
136
  renderControls() {
122
- const { view, size } = this.props;
123
137
  const customLeftControls = this.getCustomLeftOverlayControls();
124
138
  const hasCustomOverlayLeftControls = Boolean(customLeftControls.length);
125
- const defaultControl = (React.createElement(Button, { view: view, size: size, title: i18n('label_settings'), pin: "round-brick", onClick: this.onEditItem, qa: "dashkit-overlay-control-settings" },
126
- React.createElement(Icon, { data: CogIcon, size: "24" })));
139
+ const defaultControl = this.getDefaultControls();
127
140
  const controls = hasCustomOverlayLeftControls
128
141
  ? customLeftControls.map((item, index, items) => this.renderControlsItem(item, index, items.length + 1))
129
142
  : defaultControl;
@@ -136,50 +149,58 @@ class OverlayControls extends React.Component {
136
149
  }
137
150
  renderMenu() {
138
151
  const { view, size } = this.props;
139
- const { registerManager } = this.context;
140
- const withMenu = Array.isArray(registerManager.settings.menu) && registerManager.settings.menu.length;
141
- return (React.createElement(React.Fragment, null, withMenu ? (this.renderDropdownMenu()) : (React.createElement(Button, { view: view, size: size, title: i18n('label_delete'), pin: "brick-round", onClick: this.onRemoveItem, qa: "dashkit-overlay-control-menu" },
142
- React.createElement(Icon, { data: CloseIcon, size: "12" })))));
152
+ const dropdown = this.renderDropdownMenu();
153
+ if (dropdown) {
154
+ return dropdown;
155
+ }
156
+ return (React.createElement(Button, { key: 'delete-control', view: view, size: size, title: i18n('label_delete'), pin: "brick-round", onClick: this.onRemoveItem, qa: "dashkit-overlay-control-menu" },
157
+ React.createElement(Icon, { data: CloseIcon, size: "12" })));
143
158
  }
144
159
  isDefaultMenu(menu) {
145
160
  return menu === null || menu === void 0 ? void 0 : menu.every((item) => Object.values(MenuItems).includes(String(item)));
146
161
  }
147
162
  renderDropdownMenu() {
148
163
  const { view, size } = this.props;
149
- const { registerManager, itemsParams, itemsState } = this.context;
164
+ const { menu: contextMenu, itemsParams, itemsState } = this.context;
150
165
  const configItem = this.props.configItem;
151
166
  const itemParams = itemsParams[configItem.id];
152
167
  const itemState = itemsState[configItem.id];
153
- let menu = registerManager.settings.menu;
154
- if (!menu.length) {
155
- menu = DEFAULT_DROPDOWN_MENU;
156
- }
168
+ const menu = (contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.length) > 0 ? contextMenu : DEFAULT_DROPDOWN_MENU;
157
169
  const isDefaultMenu = this.isDefaultMenu(menu);
158
- let items = isDefaultMenu
159
- ? (menu || []).map((name) => this.getDropDownMenuItemConfig(name, true))
160
- : menu.map((item) => {
170
+ const items = isDefaultMenu
171
+ ? (menu || []).reduce((memo, name) => {
172
+ const item = this.getDropDownMenuItemConfig(name, true);
173
+ if (item) {
174
+ memo.push(item);
175
+ }
176
+ return memo;
177
+ }, [])
178
+ : menu.reduce((memo, item) => {
161
179
  var _a;
162
180
  if (typeof item === 'string') {
163
- return null;
181
+ return memo;
164
182
  }
165
183
  // custom menu dropdown item filter
166
184
  if (item.visible && !item.visible(configItem)) {
167
- return null;
185
+ return memo;
168
186
  }
169
187
  const itemHandler = item.handler;
170
188
  const itemAction = typeof itemHandler === 'function'
171
189
  ? () => itemHandler(configItem, itemParams, itemState)
172
190
  : ((_a = this.getDropDownMenuItemConfig(item.id)) === null || _a === void 0 ? void 0 : _a.action) || (() => { });
173
- return {
191
+ memo.push({
174
192
  // @ts-expect-error
175
193
  text: item.title || i18n(item.id),
176
194
  icon: item.icon,
177
195
  action: itemAction,
178
196
  className: item.className,
179
197
  qa: item.qa,
180
- };
181
- });
182
- items = items.filter(Boolean);
198
+ });
199
+ return memo;
200
+ }, []);
201
+ if (items.length === 0) {
202
+ return null;
203
+ }
183
204
  return (React.createElement(DropdownMenu, { items: items, renderSwitcher: (props) => (React.createElement(Button, Object.assign({}, props, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" }),
184
205
  React.createElement(Icon, { data: DotsIcon, size: "16" }))) }));
185
206
  }
@@ -199,19 +220,14 @@ class OverlayControls extends React.Component {
199
220
  return 'brick-brick';
200
221
  }
201
222
  getCustomControlsWithWidgets() {
202
- // Добавляем контрол удаления виджета по умолчанию
203
- const deleteControl = {
204
- title: i18n('label_delete'),
205
- icon: CloseIcon,
206
- iconSize: 12,
207
- handler: this.onRemoveItem,
208
- };
209
- const { items = [] } = this.props;
210
- const customOverlayControls = [...items, deleteControl];
211
- return customOverlayControls.map((item, index, controlItems) => this.renderControlsItem(item, index, controlItems.length));
223
+ const items = this.getItems();
224
+ const result = items.map((item, index, controlItems) => this.renderControlsItem(item, index, controlItems.length));
225
+ // Добавляем контрол удаления или меню виджета по умолчанию
226
+ result.push(this.renderMenu());
227
+ return result;
212
228
  }
213
229
  }
214
- OverlayControls.contextType = DashKitContext;
230
+ OverlayControls.contextType = DashkitOvelayControlsContext;
215
231
  OverlayControls.defaultProps = {
216
232
  position: OverlayControlsPosition.TopRight,
217
233
  view: 'flat',
@@ -1,3 +1,4 @@
1
1
  export const DashKitContext: React.Context<any>;
2
+ export const DashkitOvelayControlsContext: React.Context<any>;
2
3
  export const DashKitDnDContext: React.Context<any>;
3
4
  import React from 'react';
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
2
  const DashKitContext = React.createContext();
3
+ const DashkitOvelayControlsContext = React.createContext();
3
4
  const DashKitDnDContext = React.createContext();
4
- export { DashKitContext, DashKitDnDContext };
5
+ export { DashKitContext, DashkitOvelayControlsContext, DashKitDnDContext };
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import isEqual from 'lodash/isEqual';
4
4
  import pick from 'lodash/pick';
5
5
  import { COMPACT_TYPE_HORIZONTAL_NOWRAP, DEFAULT_GROUP, DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, TEMPORARY_ITEM_ID, } from '../constants/common';
6
- import { DashKitContext, DashKitDnDContext } from '../context/DashKitContext';
6
+ import { DashKitContext, DashKitDnDContext, DashkitOvelayControlsContext, } from '../context/DashKitContext';
7
7
  import { useDeepEqualMemo } from '../hooks/useDeepEqualMemo';
8
8
  import { getItemsParams, getItemsState } from '../shared';
9
9
  import { UpdateManager } from '../utils';
@@ -51,12 +51,13 @@ function useMemoStateContext(props) {
51
51
  onChange({ config: newConfig });
52
52
  }
53
53
  }, [props.config, onChange]);
54
+ const getLayoutItem = React.useCallback((id) => {
55
+ return props.config.layout.find(({ i }) => i === id);
56
+ }, [props.config.layout]);
54
57
  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
- }
58
+ delete nowrapAdjustedLayouts.current[id];
59
+ delete adjustedLayouts.current[id];
60
+ delete originalLayouts.current[id];
60
61
  if (id === TEMPORARY_ITEM_ID) {
61
62
  resetTemporaryLayout();
62
63
  }
@@ -192,7 +193,7 @@ function useMemoStateContext(props) {
192
193
  const nowrapAdjust = nowrapAdjustedLayouts.current;
193
194
  return props.layout.map((item) => {
194
195
  const widgetId = item.i;
195
- if (adjusted[widgetId] || nowrapAdjust[widgetId]) {
196
+ if (widgetId in adjusted || widgetId in nowrapAdjust) {
196
197
  original[widgetId] = item;
197
198
  // eslint-disable-next-line no-unused-vars
198
199
  const _a = adjusted[widgetId] || item, { parent } = _a, adjustedItem = __rest(_a, ["parent"]);
@@ -202,13 +203,13 @@ function useMemoStateContext(props) {
202
203
  if (item.parent) {
203
204
  adjustedItem.parent = item.parent;
204
205
  }
205
- if (nowrapAdjust[widgetId]) {
206
+ if (widgetId in nowrapAdjust) {
206
207
  adjustedItem.maxW = nowrapAdjust[widgetId];
207
208
  }
208
209
  return adjustedItem;
209
210
  }
210
211
  else {
211
- if (original[widgetId]) {
212
+ if (widgetId in original) {
212
213
  delete original[widgetId];
213
214
  }
214
215
  return item;
@@ -280,7 +281,7 @@ function useMemoStateContext(props) {
280
281
  dragProps,
281
282
  });
282
283
  }, [dragProps, onDropProp, setTemporaryLayout, resetTemporaryLayout]);
283
- return React.useMemo(() => ({
284
+ const dashkitContextValue = React.useMemo(() => ({
284
285
  layout: resultLayout,
285
286
  temporaryLayout,
286
287
  config: props.config,
@@ -296,10 +297,8 @@ function useMemoStateContext(props) {
296
297
  itemsParams,
297
298
  registerManager: props.registerManager,
298
299
  onItemStateAndParamsChange,
299
- removeItem: onItemRemove,
300
300
  onDrop,
301
301
  onDropDragOver,
302
- editItem: props.onItemEdit,
303
302
  layoutChange: onLayoutChange,
304
303
  getItemsMeta,
305
304
  reloadItems,
@@ -324,10 +323,8 @@ function useMemoStateContext(props) {
324
323
  itemsParams,
325
324
  props.registerManager,
326
325
  onItemStateAndParamsChange,
327
- onItemRemove,
328
326
  onDrop,
329
327
  onDropDragOver,
330
- props.onItemEdit,
331
328
  onLayoutChange,
332
329
  getItemsMeta,
333
330
  reloadItems,
@@ -338,12 +335,34 @@ function useMemoStateContext(props) {
338
335
  outerDnDEnable,
339
336
  dragOverPlugin,
340
337
  ]);
338
+ const overlayMenuItems = props.overlayMenuItems || props.registerManager.settings.menu;
339
+ const controlsContextValue = React.useMemo(() => ({
340
+ overlayControls: props.overlayControls,
341
+ context: props.context,
342
+ menu: overlayMenuItems,
343
+ itemsParams: itemsParams,
344
+ itemsState: itemsState,
345
+ editItem: props.onItemEdit,
346
+ removeItem: onItemRemove,
347
+ getLayoutItem: getLayoutItem,
348
+ }), [
349
+ itemsParams,
350
+ itemsState,
351
+ props.context,
352
+ props.onItemEdit,
353
+ onItemRemove,
354
+ props.overlayControls,
355
+ overlayMenuItems,
356
+ getLayoutItem,
357
+ ]);
358
+ return { controlsContextValue, dashkitContextValue };
341
359
  }
342
360
  export function withContext(Component) {
343
361
  const WithContext = (props) => {
344
- const contextValue = useMemoStateContext(props);
345
- return (React.createElement(DashKitContext.Provider, { value: contextValue },
346
- React.createElement(Component, { overlayControls: props.overlayControls })));
362
+ const { dashkitContextValue, controlsContextValue } = useMemoStateContext(props);
363
+ return (React.createElement(DashKitContext.Provider, { value: dashkitContextValue },
364
+ React.createElement(DashkitOvelayControlsContext.Provider, { value: controlsContextValue },
365
+ React.createElement(Component, null))));
347
366
  };
348
367
  WithContext.displayName = `withContext(${Component.displayName || Component.name || 'Component'}`;
349
368
  return WithContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dashkit",
3
- "version": "8.6.0",
3
+ "version": "8.7.0",
4
4
  "description": "Library for rendering dashboard grid layout",
5
5
  "license": "MIT",
6
6
  "repository": {