@gravity-ui/dashkit 8.0.2 → 8.1.0-beta.1

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 (62) hide show
  1. package/README.md +1 -0
  2. package/build/cjs/components/ActionPanel/ActionPanel.d.ts +13 -1
  3. package/build/cjs/components/ActionPanel/ActionPanel.js +25 -6
  4. package/build/cjs/components/ActionPanel/types.d.ts +1 -0
  5. package/build/cjs/components/DashKit/DashKit.d.ts +10 -3
  6. package/build/cjs/components/DashKit/DashKit.js +2 -0
  7. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +6 -0
  8. package/build/cjs/components/DashKitDnDWrapper/DashKitDnDWrapper.js +24 -0
  9. package/build/cjs/components/GridItem/GridItem.css +7 -0
  10. package/build/cjs/components/GridItem/GridItem.d.ts +2 -2
  11. package/build/cjs/components/GridItem/GridItem.js +63 -4
  12. package/build/cjs/components/GridLayout/GridLayout.d.ts +3 -0
  13. package/build/cjs/components/GridLayout/GridLayout.js +90 -10
  14. package/build/cjs/components/Item/Item.css +1 -1
  15. package/build/cjs/components/Item/Item.d.ts +1 -0
  16. package/build/cjs/components/Item/Item.js +7 -1
  17. package/build/cjs/components/index.d.ts +1 -0
  18. package/build/cjs/components/index.js +1 -0
  19. package/build/cjs/constants/common.d.ts +2 -0
  20. package/build/cjs/constants/common.js +3 -1
  21. package/build/cjs/context/DashKitContext.d.ts +1 -0
  22. package/build/cjs/context/DashKitContext.js +3 -1
  23. package/build/cjs/hocs/prepareItem.d.ts +1 -0
  24. package/build/cjs/hocs/prepareItem.js +4 -2
  25. package/build/cjs/hocs/withContext.js +87 -6
  26. package/build/cjs/shared/constants/common.d.ts +1 -0
  27. package/build/cjs/shared/constants/common.js +2 -1
  28. package/build/cjs/typings/config.d.ts +3 -0
  29. package/build/cjs/typings/plugin.d.ts +1 -0
  30. package/build/cjs/utils/update-manager.d.ts +2 -2
  31. package/build/cjs/utils/update-manager.js +25 -7
  32. package/build/esm/components/ActionPanel/ActionPanel.d.ts +13 -1
  33. package/build/esm/components/ActionPanel/ActionPanel.js +23 -5
  34. package/build/esm/components/ActionPanel/types.d.ts +1 -0
  35. package/build/esm/components/DashKit/DashKit.d.ts +10 -3
  36. package/build/esm/components/DashKit/DashKit.js +2 -0
  37. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.d.ts +6 -0
  38. package/build/esm/components/DashKitDnDWrapper/DashKitDnDWrapper.js +19 -0
  39. package/build/esm/components/GridItem/GridItem.css +7 -0
  40. package/build/esm/components/GridItem/GridItem.d.ts +2 -2
  41. package/build/esm/components/GridItem/GridItem.js +63 -4
  42. package/build/esm/components/GridLayout/GridLayout.d.ts +3 -0
  43. package/build/esm/components/GridLayout/GridLayout.js +91 -11
  44. package/build/esm/components/Item/Item.css +1 -1
  45. package/build/esm/components/Item/Item.d.ts +1 -0
  46. package/build/esm/components/Item/Item.js +7 -1
  47. package/build/esm/components/index.d.ts +1 -0
  48. package/build/esm/components/index.js +1 -0
  49. package/build/esm/constants/common.d.ts +2 -0
  50. package/build/esm/constants/common.js +2 -0
  51. package/build/esm/context/DashKitContext.d.ts +1 -0
  52. package/build/esm/context/DashKitContext.js +2 -1
  53. package/build/esm/hocs/prepareItem.d.ts +1 -0
  54. package/build/esm/hocs/prepareItem.js +4 -2
  55. package/build/esm/hocs/withContext.js +88 -7
  56. package/build/esm/shared/constants/common.d.ts +1 -0
  57. package/build/esm/shared/constants/common.js +1 -0
  58. package/build/esm/typings/config.d.ts +3 -0
  59. package/build/esm/typings/plugin.d.ts +1 -0
  60. package/build/esm/utils/update-manager.d.ts +2 -2
  61. package/build/esm/utils/update-manager.js +25 -7
  62. package/package.json +1 -1
@@ -4,6 +4,7 @@ exports.withContext = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
7
+ const common_1 = require("../constants/common");
7
8
  const DashKitContext_1 = require("../context/DashKitContext");
8
9
  const shared_1 = require("../shared");
9
10
  const utils_1 = require("../utils");
@@ -15,6 +16,10 @@ function useMemoStateContext(props) {
15
16
  // (высота) из конфига будет запоминаться в originalLayouts, новое значение высоты в adjustedLayouts
16
17
  const originalLayouts = react_1.default.useRef({});
17
18
  const adjustedLayouts = react_1.default.useRef({});
19
+ const [temporaryLayout, setTemporaryLayout] = react_1.default.useState(null);
20
+ const resetTemporaryLayout = react_1.default.useCallback(() => setTemporaryLayout(null), [setTemporaryLayout]);
21
+ const dndContext = react_1.default.useContext(DashKitContext_1.DashKitDnDContext);
22
+ const outerDnDEnable = Boolean(dndContext);
18
23
  // TODO: need move originalLayouts, adjustedLayouts to state
19
24
  const [layoutUpdateCounter, forceUpdateLayout] = react_1.default.useState(0);
20
25
  const onChange = react_1.default.useCallback(({ config = props.config, itemsStateAndParams = props.itemsStateAndParams }) => {
@@ -45,12 +50,27 @@ function useMemoStateContext(props) {
45
50
  }
46
51
  }, [props.config, onChange]);
47
52
  const onItemRemove = react_1.default.useCallback((id) => {
48
- onChange(utils_1.UpdateManager.removeItem({
49
- id,
50
- config: props.config,
51
- itemsStateAndParams: props.itemsStateAndParams,
52
- }));
53
- }, [props.config, props.itemsStateAndParams, onChange]);
53
+ if (id === common_1.TEMPORARY_ITEM_ID) {
54
+ resetTemporaryLayout();
55
+ }
56
+ else {
57
+ if (temporaryLayout) {
58
+ setTemporaryLayout(temporaryLayout.filter(({ i }) => i !== id));
59
+ }
60
+ onChange(utils_1.UpdateManager.removeItem({
61
+ id,
62
+ config: props.config,
63
+ itemsStateAndParams: props.itemsStateAndParams,
64
+ }));
65
+ }
66
+ }, [
67
+ props.config,
68
+ props.itemsStateAndParams,
69
+ temporaryLayout,
70
+ onChange,
71
+ setTemporaryLayout,
72
+ resetTemporaryLayout,
73
+ ]);
54
74
  const onItemStateAndParamsChange = react_1.default.useCallback((id, stateAndParams, options) => {
55
75
  onChange({
56
76
  itemsStateAndParams: utils_1.UpdateManager.changeStateAndParams({
@@ -124,11 +144,62 @@ function useMemoStateContext(props) {
124
144
  const reloadItems = react_1.default.useCallback((pluginsRefs, data) => {
125
145
  pluginsRefs.forEach((ref) => ref && ref.reload && ref.reload(data));
126
146
  }, []);
147
+ const draggedPluginRef = react_1.default.useRef(dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType);
148
+ react_1.default.useEffect(() => {
149
+ if (!(dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType) && !temporaryLayout) {
150
+ draggedPluginRef.current = null;
151
+ }
152
+ else if (dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType) {
153
+ draggedPluginRef.current = dndContext.dragPluginType;
154
+ }
155
+ }, [draggedPluginRef, dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType, temporaryLayout]);
156
+ const dndPluginType = draggedPluginRef.current || (dndContext === null || dndContext === void 0 ? void 0 : dndContext.dragPluginType);
157
+ const dragOverPlugin = react_1.default.useMemo(() => {
158
+ const pluginType = dndPluginType;
159
+ if (pluginType === null && temporaryLayout === null)
160
+ return null;
161
+ if (props.registerManager.check(pluginType)) {
162
+ return props.registerManager.getItem(pluginType);
163
+ }
164
+ else {
165
+ // eslint-disable-next-line no-console
166
+ console.error(`Uknown pluginType: ${pluginType}`);
167
+ return null;
168
+ }
169
+ }, [dndPluginType, props.registerManager, temporaryLayout]);
170
+ const onDropDragOver = react_1.default.useCallback(() => {
171
+ if (temporaryLayout) {
172
+ resetTemporaryLayout();
173
+ return false;
174
+ }
175
+ if (dragOverPlugin === null || dragOverPlugin === void 0 ? void 0 : dragOverPlugin.defaultLayout) {
176
+ const { h = 3, w = 3 } = dragOverPlugin.defaultLayout;
177
+ return { h, w };
178
+ }
179
+ return false;
180
+ }, [resetTemporaryLayout, temporaryLayout, dragOverPlugin]);
181
+ const onDrop = react_1.default.useCallback((newLayout, item) => {
182
+ setTemporaryLayout(newLayout);
183
+ const { i, w, h, x, y } = item;
184
+ props.onDrop({
185
+ newLayout: newLayout.reduce((memo, l) => {
186
+ if (l.i !== i) {
187
+ memo.push({ i: l.i, w: l.w, h: l.h, x: l.x, y: l.y });
188
+ }
189
+ return memo;
190
+ }, []),
191
+ itemLayout: { w, h, x, y },
192
+ pluginType: dndPluginType,
193
+ commit: resetTemporaryLayout,
194
+ });
195
+ }, [dndPluginType, props.onDrop]);
127
196
  return react_1.default.useMemo(() => ({
128
197
  layout: resultLayout,
198
+ temporaryLayout,
129
199
  config: props.config,
130
200
  context: props.context,
131
201
  noOverlay: props.noOverlay,
202
+ focusable: props.focusable,
132
203
  defaultGlobalParams: props.globalParams,
133
204
  globalParams: props.globalParams,
134
205
  editMode: props.editMode,
@@ -138,6 +209,8 @@ function useMemoStateContext(props) {
138
209
  registerManager: props.registerManager,
139
210
  onItemStateAndParamsChange,
140
211
  removeItem: onItemRemove,
212
+ onDrop,
213
+ onDropDragOver,
141
214
  editItem: props.onItemEdit,
142
215
  layoutChange: onLayoutChange,
143
216
  getItemsMeta,
@@ -146,11 +219,15 @@ function useMemoStateContext(props) {
146
219
  revertToOriginalLayout,
147
220
  forwardedMetaRef: props.forwardedMetaRef,
148
221
  draggableHandleClassName: props.draggableHandleClassName,
222
+ outerDnDEnable,
223
+ dragOverPlugin,
149
224
  }), [
150
225
  resultLayout,
226
+ temporaryLayout,
151
227
  props.config,
152
228
  props.context,
153
229
  props.noOverlay,
230
+ props.focusable,
154
231
  props.globalParams,
155
232
  props.editMode,
156
233
  props.settings,
@@ -159,6 +236,8 @@ function useMemoStateContext(props) {
159
236
  props.registerManager,
160
237
  onItemStateAndParamsChange,
161
238
  onItemRemove,
239
+ onDrop,
240
+ onDropDragOver,
162
241
  props.onItemEdit,
163
242
  onLayoutChange,
164
243
  getItemsMeta,
@@ -167,6 +246,8 @@ function useMemoStateContext(props) {
167
246
  revertToOriginalLayout,
168
247
  props.forwardedMetaRef,
169
248
  props.draggableHandleClassName,
249
+ outerDnDEnable,
250
+ dragOverPlugin,
170
251
  ]);
171
252
  }
172
253
  function withContext(Component) {
@@ -1,3 +1,4 @@
1
1
  export declare const CURRENT_VERSION = 2;
2
2
  export declare const META_KEY = "__meta__";
3
3
  export declare const ACTION_PARAM_PREFIX = "_ap_";
4
+ export declare const TERMORARY_ITEM_ID = "__dropping-elem__";
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ACTION_PARAM_PREFIX = exports.META_KEY = exports.CURRENT_VERSION = void 0;
3
+ exports.TERMORARY_ITEM_ID = exports.ACTION_PARAM_PREFIX = exports.META_KEY = exports.CURRENT_VERSION = void 0;
4
4
  exports.CURRENT_VERSION = 2;
5
5
  exports.META_KEY = '__meta__';
6
6
  exports.ACTION_PARAM_PREFIX = '_ap_';
7
+ exports.TERMORARY_ITEM_ID = '__dropping-elem__';
@@ -8,3 +8,6 @@ export type SetConfigItem = ConfigItem | AddConfigItem;
8
8
  export type SetItemOptions = {
9
9
  excludeIds?: string[];
10
10
  };
11
+ export type SetNewItemOptions = SetItemOptions & {
12
+ updateLayout?: ConfigLayout[];
13
+ };
@@ -36,4 +36,5 @@ export interface PluginDefaultLayout {
36
36
  export interface Plugin<P extends PluginWidgetProps<T> = any, T = StringParams> extends PluginBase {
37
37
  defaultLayout?: PluginDefaultLayout;
38
38
  renderer: (props: P, forwardedRef: React.RefObject<any>) => React.ReactNode;
39
+ placeholderRenderer?: (props: P, forwardedRef: React.RefObject<any>) => React.ReactNode;
39
40
  }
@@ -1,5 +1,5 @@
1
1
  import type { Config, ConfigItem, ItemStateAndParams, ItemStateAndParamsChangeOptions, ItemsStateAndParams } from '../shared';
2
- import type { AddConfigItem, SetItemOptions, WidgetLayout } from '../typings';
2
+ import type { AddConfigItem, SetItemOptions, SetNewItemOptions, WidgetLayout } from '../typings';
3
3
  import { RegisterManagerPluginLayout } from './register-manager';
4
4
  interface RemoveItemArg {
5
5
  id: string;
@@ -19,7 +19,7 @@ export declare class UpdateManager {
19
19
  namespace: string;
20
20
  layout: RegisterManagerPluginLayout;
21
21
  config: Config;
22
- options: SetItemOptions;
22
+ options: SetNewItemOptions;
23
23
  }): Config;
24
24
  static editItem({ item, namespace, config, options, }: {
25
25
  item: ConfigItem;
@@ -216,19 +216,37 @@ function changeGroupParams({ groupItemIds, initiatorId, initiatorItem, itemsStat
216
216
  }
217
217
  class UpdateManager {
218
218
  static addItem({ item, namespace = constants_1.DEFAULT_NAMESPACE, layout, config, options, }) {
219
- const layoutY = Math.max(0, ...config.layout.map(({ h, y }) => h + y));
220
- const saveDefaultLayout = (0, pick_1.default)(layout, ['h', 'w', 'x', 'y']);
221
219
  const salt = config.salt;
222
220
  const newItemData = getNewItemData({ item, config, salt, counter: config.counter, options });
223
221
  let counter = newItemData.counter;
224
222
  const newIdData = (0, get_new_id_1.getNewId)({ config, salt, counter, excludeIds: newItemData.excludeIds });
225
223
  counter = newIdData.counter;
226
224
  const newItem = Object.assign(Object.assign({}, item), { id: newIdData.id, data: newItemData.data, namespace });
227
- return (0, immutability_helper_1.default)(config, {
228
- items: { $push: [newItem] },
229
- layout: { $push: [Object.assign(Object.assign({}, saveDefaultLayout), { y: layoutY, i: newItem.id })] },
230
- counter: { $set: counter },
231
- });
225
+ const saveDefaultLayout = (0, pick_1.default)(layout, ['h', 'w', 'x', 'y']);
226
+ if (options.updateLayout) {
227
+ const byId = options.updateLayout.reduce((memo, t) => {
228
+ memo[t.i] = t;
229
+ return memo;
230
+ }, {});
231
+ const newLayout = [
232
+ ...config.layout.map((t) => (Object.assign(Object.assign({}, t), (byId[t.i] || {})))),
233
+ Object.assign(Object.assign({}, saveDefaultLayout), { i: newItem.id }),
234
+ ];
235
+ return (0, immutability_helper_1.default)(config, {
236
+ items: { $push: [newItem] },
237
+ layout: { $set: newLayout },
238
+ counter: { $set: counter },
239
+ });
240
+ }
241
+ else {
242
+ const layoutY = Math.max(0, ...config.layout.map(({ h, y }) => h + y));
243
+ const newLayoutItem = Object.assign(Object.assign({}, saveDefaultLayout), { y: layoutY, i: newItem.id });
244
+ return (0, immutability_helper_1.default)(config, {
245
+ items: { $push: [newItem] },
246
+ layout: { $push: [newLayoutItem] },
247
+ counter: { $set: counter },
248
+ });
249
+ }
232
250
  }
233
251
  static editItem({ item, namespace = constants_1.DEFAULT_NAMESPACE, config, options, }) {
234
252
  const itemIndex = config.items.findIndex(({ id }) => item.id === id);
@@ -1,4 +1,16 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  import { ActionPanelProps } from './types';
3
3
  import './ActionPanel.css';
4
+ export type ActionPanelItem = {
5
+ id: string;
6
+ icon: React.ReactNode;
7
+ title: string;
8
+ onClick?: () => void;
9
+ className?: string;
10
+ qa?: string;
11
+ pluginType?: string;
12
+ };
13
+ export declare const ActionPanelItemContainer: ({ item }: {
14
+ item: ActionPanelItem;
15
+ }) => JSX.Element;
4
16
  export declare const ActionPanel: (props: ActionPanelProps) => JSX.Element | null;
@@ -1,18 +1,36 @@
1
1
  import React from 'react';
2
2
  import { CSSTransition } from 'react-transition-group';
3
+ import { DashKitDnDContext } from '../../context/DashKitContext';
3
4
  import { cn } from '../../utils/cn';
4
5
  import './ActionPanel.css';
5
6
  const b = cn('dashkit-action-panel');
7
+ export const ActionPanelItemContainer = ({ item }) => {
8
+ const dragContext = React.useContext(DashKitDnDContext);
9
+ const onDragStart = React.useCallback((e) => {
10
+ dragContext.onDragStart(e, item.pluginType);
11
+ }, [dragContext === null || dragContext === void 0 ? void 0 : dragContext.onDragStart, item.pluginType]);
12
+ const onDragEnd = React.useCallback((e) => {
13
+ dragContext.onDragEnd(e);
14
+ }, [dragContext === null || dragContext === void 0 ? void 0 : dragContext.onDragEnd]);
15
+ let dndProps = {};
16
+ if (item.pluginType) {
17
+ dndProps = {
18
+ draggable: true,
19
+ unselectable: 'on',
20
+ onDragStart,
21
+ onDragEnd,
22
+ };
23
+ }
24
+ return (React.createElement("div", Object.assign({ role: "button", className: b('item', item.className), key: `dk-action-panel-${item.id}`, onClick: item.onClick, "data-qa": item.qa }, dndProps),
25
+ React.createElement("div", { className: b('icon') }, item.icon),
26
+ React.createElement("div", { className: b('title'), title: item.title }, item.title)));
27
+ };
6
28
  export const ActionPanel = (props) => {
7
29
  var _a, _b;
8
30
  const isDisabled = (_a = props.disable) !== null && _a !== void 0 ? _a : false;
9
31
  const isAnimated = (_b = props.toggleAnimation) !== null && _b !== void 0 ? _b : false;
10
32
  const nodeRef = React.useRef(null);
11
- const content = (React.createElement("div", { ref: nodeRef, className: b(null, props.className) }, props.items.map((item) => {
12
- return (React.createElement("div", { role: "button", className: b('item', item.className), key: `dk-action-panel-${item.id}`, onClick: item.onClick, "data-qa": item.qa },
13
- React.createElement("div", { className: b('icon') }, item.icon),
14
- React.createElement("div", { className: b('title'), title: item.title }, item.title)));
15
- })));
33
+ const content = (React.createElement("div", { ref: nodeRef, className: b(null, props.className) }, props.items.map((item, i) => (React.createElement(ActionPanelItemContainer, { key: `item_${i}`, item: item })))));
16
34
  if (isAnimated) {
17
35
  return (React.createElement(CSSTransition, { in: !isDisabled, nodeRef: nodeRef, classNames: b(null), timeout: 300, unmountOnExit: true }, content));
18
36
  }
@@ -6,6 +6,7 @@ export type ActionPanelItem = {
6
6
  onClick?: () => void;
7
7
  className?: string;
8
8
  qa?: string;
9
+ pluginType?: string;
9
10
  };
10
11
  export type ActionPanelProps = {
11
12
  items: ActionPanelItem[];
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import type { Config, ConfigItem, GlobalParams, ItemsStateAndParams } from '../../shared';
3
- import { ContextProps, Plugin, SetConfigItem, SetItemOptions, Settings, SettingsProps } from '../../typings';
2
+ import type { Config, ConfigItem, ConfigLayout, GlobalParams, ItemsStateAndParams } from '../../shared';
3
+ import { ContextProps, 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 {
@@ -15,12 +15,19 @@ interface DashKitDefaultProps {
15
15
  config: Config;
16
16
  itemsStateAndParams: ItemsStateAndParams;
17
17
  }) => void;
18
+ onDrop: (dropProps: {
19
+ commit: () => void;
20
+ pluginType: string;
21
+ itemLayout: ConfigLayout;
22
+ newLayout: ConfigLayout[];
23
+ }) => void;
18
24
  defaultGlobalParams: GlobalParams;
19
25
  globalParams: GlobalParams;
20
26
  itemsStateAndParams: ItemsStateAndParams;
21
27
  settings: SettingsProps;
22
28
  context: ContextProps;
23
29
  noOverlay: boolean;
30
+ focusable?: boolean;
24
31
  }
25
32
  export interface DashKitProps extends DashKitGeneralProps, Partial<DashKitDefaultProps> {
26
33
  }
@@ -33,7 +40,7 @@ export declare class DashKit extends React.PureComponent<DashKitInnerProps> {
33
40
  item: SetConfigItem;
34
41
  namespace?: string;
35
42
  config: Config;
36
- options?: SetItemOptions;
43
+ options?: SetNewItemOptions;
37
44
  }): Config;
38
45
  static removeItem({ id, config, itemsStateAndParams, }: {
39
46
  id: string;
@@ -54,6 +54,7 @@ export class DashKit extends React.PureComponent {
54
54
  DashKit.defaultProps = {
55
55
  onItemEdit: noop,
56
56
  onChange: noop,
57
+ onDrop: noop,
57
58
  defaultGlobalParams: {},
58
59
  globalParams: {},
59
60
  itemsStateAndParams: {},
@@ -63,4 +64,5 @@ DashKit.defaultProps = {
63
64
  },
64
65
  context: {},
65
66
  noOverlay: false,
67
+ focusable: false,
66
68
  };
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ type DashKitDnDWrapperProps = {
3
+ children: React.ReactElement;
4
+ };
5
+ export declare const DashKitDnDWrapper: React.FC<DashKitDnDWrapperProps>;
6
+ export {};
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { DashKitDnDContext } from '../../context/DashKitContext';
3
+ export const DashKitDnDWrapper = (props) => {
4
+ const [dragPluginType, setDragPluginType] = React.useState(null);
5
+ const onDragStart = React.useCallback((_, type) => {
6
+ setDragPluginType(type);
7
+ }, [setDragPluginType]);
8
+ const onDragEnd = React.useCallback((_) => {
9
+ setDragPluginType(null);
10
+ }, [setDragPluginType]);
11
+ const contextValue = React.useMemo(() => {
12
+ return {
13
+ dragPluginType,
14
+ onDragStart,
15
+ onDragEnd,
16
+ };
17
+ }, [dragPluginType, onDragStart, onDragEnd]);
18
+ return (React.createElement(DashKitDnDContext.Provider, { value: contextValue }, props.children));
19
+ };
@@ -1,6 +1,9 @@
1
1
  .dashkit-grid-item {
2
2
  position: relative;
3
3
  }
4
+ .dashkit-grid-item:focus {
5
+ outline: none;
6
+ }
4
7
  .dashkit-grid-item__overlay {
5
8
  --_-dashkit-overlay-color: var(--dashkit-overlay-color, var(--g-color-base-generic));
6
9
  --_-dashkit-overlay-border-color: var(--dashkit-overlay-border-color, rgba(0, 0, 0, 0.1));
@@ -56,6 +59,10 @@
56
59
  will-change: transform;
57
60
  }
58
61
 
62
+ .react-grid-item.dashkit-grid-item_is-focused {
63
+ z-index: 2;
64
+ }
65
+
59
66
  .react-grid-item.react-grid-placeholder {
60
67
  --_-dashkit-placeholder-color: var(--dashkit-placeholder-color, #fc0);
61
68
  --_-dashkit-placeholder-opacity: var(--dashkit-placeholder-opacity, 0.2);
@@ -1,3 +1,3 @@
1
- declare const _default: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
2
- export default _default;
1
+ export default GridItemForwarderRef;
2
+ declare const GridItemForwarderRef: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
3
3
  import React from 'react';
@@ -6,7 +6,55 @@ import Item from '../Item/Item';
6
6
  import OverlayControls from '../OverlayControls/OverlayControls';
7
7
  import './GridItem.css';
8
8
  const b = cn('dashkit-grid-item');
9
+ class WindowFocusObserver {
10
+ constructor() {
11
+ this.blurHandler = (e) => {
12
+ if (e.target === window) {
13
+ this.isFocused = false;
14
+ }
15
+ };
16
+ this.focusHandler = (e) => {
17
+ if (e.target === window) {
18
+ this.isFocused = true;
19
+ }
20
+ };
21
+ this.subscribers = 0;
22
+ this.isFocused = !document.hidden;
23
+ window.addEventListener('blur', this.blurHandler, true);
24
+ window.addEventListener('focus', this.focusHandler, true);
25
+ }
26
+ // Method to get state after all blur\focus events in document are triggered
27
+ async getFocuseState() {
28
+ return new Promise((resolve) => {
29
+ requestAnimationFrame(() => {
30
+ resolve(this.isFocused);
31
+ });
32
+ });
33
+ }
34
+ }
35
+ const windowFocusObserver = new WindowFocusObserver();
9
36
  class GridItem extends React.PureComponent {
37
+ constructor() {
38
+ super(...arguments);
39
+ this.state = {
40
+ isFocused: false,
41
+ };
42
+ this.onFocusHandler = () => {
43
+ this.setState({ isFocused: true });
44
+ if (this.controller) {
45
+ this.controller.abort();
46
+ }
47
+ };
48
+ this.onBlurHandler = () => {
49
+ this.controller = new AbortController();
50
+ windowFocusObserver.getFocuseState().then((isWindowFocused) => {
51
+ if (!this.controller.signal.aborted && isWindowFocused) {
52
+ this.setState({ isFocused: false });
53
+ }
54
+ this.controller = null;
55
+ });
56
+ };
57
+ }
10
58
  renderOverlay() {
11
59
  const { overlayControls } = this.props;
12
60
  const { editMode } = this.context;
@@ -22,7 +70,7 @@ class GridItem extends React.PureComponent {
22
70
  render() {
23
71
  // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable
24
72
  // https://github.com/STRML/react-grid-layout/issues/721
25
- const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, withCustomHandle, } = this.props;
73
+ const { style, onMouseDown, onMouseUp, onTouchEnd, onTouchStart, children, className, isDragging, noOverlay, focusable, withCustomHandle, isPlaceholder, } = this.props;
26
74
  const { editMode } = this.context;
27
75
  const width = Number.parseInt(style.width, 10);
28
76
  const height = Number.parseInt(style.height, 10);
@@ -37,10 +85,17 @@ class GridItem extends React.PureComponent {
37
85
  const { _editActive } = this.props.item.data;
38
86
  return (React.createElement("div", Object.assign({ className: b({
39
87
  'is-dragging': isDragging,
88
+ 'is-focused': this.state.isFocused,
40
89
  'with-custom-handle': withCustomHandle,
41
- }, preparedClassName), "data-qa": "dashkit-grid-item", style: style, ref: this.props.forwardedRef }, reactGridLayoutProps),
90
+ }, preparedClassName), "data-qa": "dashkit-grid-item", style: style, ref: this.props.forwardedRef }, reactGridLayoutProps, (focusable
91
+ ? {
92
+ onFocus: this.onFocusHandler,
93
+ onBlur: this.onBlurHandler,
94
+ tabIndex: -1,
95
+ }
96
+ : {})),
42
97
  React.createElement("div", { className: b('item', { editMode: editMode && !_editActive && !noOverlay }) },
43
- React.createElement(Item, { id: this.props.id, item: this.props.item, shouldItemUpdate: !isDragging, width: width, height: height, transform: transform, adjustWidgetLayout: this.props.adjustWidgetLayout, layout: this.props.layout, forwardedPluginRef: this.props.forwardedPluginRef })),
98
+ React.createElement(Item, { id: this.props.id, item: this.props.item, shouldItemUpdate: !isDragging, width: width, height: height, transform: transform, isPlaceholder: isPlaceholder, adjustWidgetLayout: this.props.adjustWidgetLayout, layout: this.props.layout, forwardedPluginRef: this.props.forwardedPluginRef })),
44
99
  !noOverlay && this.renderOverlay(),
45
100
  preparedChildren));
46
101
  }
@@ -54,11 +109,13 @@ GridItem.propTypes = {
54
109
  overlayControls: PropTypes.object,
55
110
  forwardedRef: PropTypes.any,
56
111
  forwardedPluginRef: PropTypes.any,
112
+ isPlaceholder: PropTypes.bool,
57
113
  // from react-grid-layout:
58
114
  children: PropTypes.node,
59
115
  className: PropTypes.string,
60
116
  style: PropTypes.object,
61
117
  noOverlay: PropTypes.bool,
118
+ focusable: PropTypes.bool,
62
119
  withCustomHandle: PropTypes.bool,
63
120
  onMouseDown: PropTypes.func,
64
121
  onMouseUp: PropTypes.func,
@@ -66,6 +123,8 @@ GridItem.propTypes = {
66
123
  onTouchStart: PropTypes.func,
67
124
  };
68
125
  GridItem.contextType = DashKitContext;
69
- export default React.forwardRef((props, ref) => {
126
+ const GridItemForwarderRef = React.forwardRef((props, ref) => {
70
127
  return React.createElement(GridItem, Object.assign({}, props, { forwardedRef: ref }));
71
128
  });
129
+ GridItemForwarderRef.displayName = 'forwardRef(GridItem)';
130
+ export default GridItemForwarderRef;
@@ -21,6 +21,9 @@ export default class GridLayout extends React.PureComponent<any, any, any> {
21
21
  reloadItems(): void;
22
22
  _onStart: () => void;
23
23
  _onStop: (newLayout: any) => void;
24
+ _onDropDragOver: (e: any) => any;
25
+ _onDrop: (layout: any, item: any, e: any) => false | undefined;
26
+ renderTemporaryPlaceholder(): JSX.Element | null;
24
27
  render(): JSX.Element;
25
28
  }
26
29
  import React from 'react';