@gravity-ui/dashkit 8.5.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.
Files changed (38) hide show
  1. package/README.md +11 -4
  2. package/build/cjs/components/DashKit/DashKit.d.ts +3 -2
  3. package/build/cjs/components/DashKitView/DashKitView.js +2 -2
  4. package/build/cjs/components/GridItem/GridItem.js +2 -4
  5. package/build/cjs/components/GridLayout/GridLayout.d.ts +16 -1
  6. package/build/cjs/components/GridLayout/GridLayout.js +81 -10
  7. package/build/cjs/components/Item/Item.d.ts +4 -0
  8. package/build/cjs/components/OverlayControls/OverlayControls.d.ts +8 -6
  9. package/build/cjs/components/OverlayControls/OverlayControls.js +58 -42
  10. package/build/cjs/constants/common.d.ts +1 -0
  11. package/build/cjs/constants/common.js +2 -1
  12. package/build/cjs/context/DashKitContext.d.ts +1 -0
  13. package/build/cjs/context/DashKitContext.js +3 -1
  14. package/build/cjs/hocs/prepareItem.d.ts +4 -0
  15. package/build/cjs/hocs/prepareItem.js +33 -22
  16. package/build/cjs/hocs/withContext.js +129 -21
  17. package/build/cjs/hooks/useDeepEqualMemo.d.ts +2 -0
  18. package/build/cjs/hooks/useDeepEqualMemo.js +17 -0
  19. package/build/cjs/typings/config.d.ts +3 -1
  20. package/build/esm/components/DashKit/DashKit.d.ts +3 -2
  21. package/build/esm/components/DashKitView/DashKitView.js +2 -2
  22. package/build/esm/components/GridItem/GridItem.js +2 -4
  23. package/build/esm/components/GridLayout/GridLayout.d.ts +16 -1
  24. package/build/esm/components/GridLayout/GridLayout.js +82 -11
  25. package/build/esm/components/Item/Item.d.ts +4 -0
  26. package/build/esm/components/OverlayControls/OverlayControls.d.ts +8 -6
  27. package/build/esm/components/OverlayControls/OverlayControls.js +59 -43
  28. package/build/esm/constants/common.d.ts +1 -0
  29. package/build/esm/constants/common.js +1 -0
  30. package/build/esm/context/DashKitContext.d.ts +1 -0
  31. package/build/esm/context/DashKitContext.js +2 -1
  32. package/build/esm/hocs/prepareItem.d.ts +4 -0
  33. package/build/esm/hocs/prepareItem.js +33 -22
  34. package/build/esm/hocs/withContext.js +132 -23
  35. package/build/esm/hooks/useDeepEqualMemo.d.ts +2 -0
  36. package/build/esm/hooks/useDeepEqualMemo.js +12 -0
  37. package/build/esm/typings/config.d.ts +3 -1
  38. package/package.json +1 -1
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
 
@@ -475,6 +481,7 @@ const CustomThemeWrapper = (props: {
475
481
  By default, storybook runs on `http://localhost:7120/`.
476
482
  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
483
 
484
+
478
485
  ### Example of an nginx config for development on a dev machine
479
486
 
480
487
  ```bash
@@ -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,
@@ -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, onDropDragOver } = this.context;
112
+ this._onDropDragOver = (group, e) => {
113
+ const { editMode, dragOverPlugin } = this.context;
51
114
  if (!editMode || !dragOverPlugin) {
52
115
  return false;
53
116
  }
54
- return onDropDragOver(e);
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;
@@ -129,26 +197,29 @@ class GridLayout extends react_1.default.PureComponent {
129
197
  }
130
198
  const id = constants_1.TEMPORARY_ITEM_ID;
131
199
  const { type } = temporaryLayout.dragProps;
132
- return (react_1.default.createElement(GridItem_1.default, { key: id, id: id, item: { id, type, data: {} }, layout: temporaryLayout.data, adjustWidgetLayout: this.adjustWidgetLayout, isDragging: this.state.isDragging, isPlaceholder: true, noOverlay: noOverlay, withCustomHandle: Boolean(draggableHandleClassName), overlayControls: this.props.overlayControls }));
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) }));
133
201
  }
134
202
  renderGroup(group, renderLayout, renderItems, offset = 0, groupGridProperties) {
135
203
  const { registerManager, editMode, noOverlay, focusable, draggableHandleClassName, outerDnDEnable, } = this.context;
136
204
  const properties = groupGridProperties
137
205
  ? groupGridProperties(Object.assign({}, registerManager.gridLayout))
138
206
  : registerManager.gridLayout;
139
- return (react_1.default.createElement(ReactGridLayout_1.Layout, Object.assign({}, properties, { layout: renderLayout, key: `group_${group}`, isDraggable: editMode, isResizable: editMode, onDragStart: this._onStart, onDragStop: (...args) => this._onStop(group, ...args), onResizeStart: this._onStart, onResizeStop: (...args) => this._onStop(group, ...args) }, (draggableHandleClassName
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: this._onDropDragOver,
145
- onDrop: (...args) => this._onDrop(group, ...args),
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: (pluginRef) => {
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) }));
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,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',
@@ -11,3 +11,4 @@ export declare const MenuItems: {
11
11
  export declare const DEFAULT_WIDGET_HEIGHT = 3;
12
12
  export declare const DEFAULT_WIDGET_WIDTH = 3;
13
13
  export declare const DEFAULT_GROUP = "__default";
14
+ export declare const COMPACT_TYPE_HORIZONTAL_NOWRAP = "horizontal-nowrap";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_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';
@@ -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;
@@ -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;