@gravity-ui/dashkit 10.2.0 → 10.3.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 +95 -19
- package/build/cjs/components/DashKit/DashKit.d.ts +11 -1
- package/build/cjs/components/DashKit/DashKit.js +55 -7
- package/build/cjs/components/DashKit/DashKit.js.map +1 -1
- package/build/cjs/components/DashKit/__tests__/controlled-layout.test.d.ts +4 -0
- package/build/cjs/components/DashKit/__tests__/controlled-layout.test.js +196 -0
- package/build/cjs/components/DashKit/__tests__/controlled-layout.test.js.map +1 -0
- package/build/cjs/components/DashKit/__tests__/events.test.d.ts +1 -0
- package/build/cjs/components/DashKit/__tests__/events.test.js +227 -0
- package/build/cjs/components/DashKit/__tests__/events.test.js.map +1 -0
- package/build/cjs/components/DashKitView/DashKitView.d.ts +1 -1
- package/build/cjs/components/DashKitView/DashKitView.js +1 -3
- package/build/cjs/components/DashKitView/DashKitView.js.map +1 -1
- package/build/cjs/components/GridLayout/GroupLayout.js +2 -2
- package/build/cjs/components/GridLayout/GroupLayout.js.map +1 -1
- package/build/cjs/components/GridLayout/ReactGridLayout.d.ts +1 -0
- package/build/cjs/components/GridLayout/ReactGridLayout.js +37 -0
- package/build/cjs/components/GridLayout/ReactGridLayout.js.map +1 -1
- package/build/cjs/components/OverlayControls/OverlayControls.js +1 -1
- package/build/cjs/components/OverlayControls/OverlayControls.js.map +1 -1
- package/build/cjs/context/DashKitContext.d.ts +1 -0
- package/build/cjs/context/DashKitContext.js.map +1 -1
- package/build/cjs/context/DashkitOverlayControlsContext.d.ts +1 -1
- package/build/cjs/context/DashkitOverlayControlsContext.js +2 -2
- package/build/cjs/context/DashkitOverlayControlsContext.js.map +1 -1
- package/build/cjs/hocs/withContext.d.ts +2 -2
- package/build/cjs/hocs/withContext.js +61 -31
- package/build/cjs/hocs/withContext.js.map +1 -1
- package/build/cjs/package.json +1 -1
- package/build/cjs/plugins/Text/Text.js +1 -1
- package/build/cjs/plugins/Text/Text.js.map +1 -1
- package/build/cjs/shared/types/config.d.ts +2 -0
- package/build/cjs/shared/types/config.js +9 -0
- package/build/cjs/shared/types/config.js.map +1 -1
- package/build/cjs/typings/events.d.ts +34 -0
- package/build/cjs/typings/events.js +3 -0
- package/build/cjs/typings/events.js.map +1 -0
- package/build/cjs/typings/index.d.ts +1 -0
- package/build/cjs/typings/index.js +1 -0
- package/build/cjs/typings/index.js.map +1 -1
- package/build/cjs/utils/__tests__/get-layout-patches.test.d.ts +1 -0
- package/build/cjs/utils/__tests__/get-layout-patches.test.js +51 -0
- package/build/cjs/utils/__tests__/get-layout-patches.test.js.map +1 -0
- package/build/cjs/utils/enrichLayoutWithDefaults.d.ts +5 -0
- package/build/cjs/utils/enrichLayoutWithDefaults.js +29 -0
- package/build/cjs/utils/enrichLayoutWithDefaults.js.map +1 -0
- package/build/cjs/utils/events.d.ts +10 -0
- package/build/cjs/utils/events.js +34 -0
- package/build/cjs/utils/events.js.map +1 -0
- package/build/cjs/utils/get-layout-patches.d.ts +3 -0
- package/build/cjs/utils/get-layout-patches.js +23 -0
- package/build/cjs/utils/get-layout-patches.js.map +1 -0
- package/build/cjs/utils/index.d.ts +3 -0
- package/build/cjs/utils/index.js +3 -0
- package/build/cjs/utils/index.js.map +1 -1
- package/build/cjs/utils/update-manager.js +2 -2
- package/build/cjs/utils/update-manager.js.map +1 -1
- package/build/esm/components/DashKit/DashKit.d.ts +11 -1
- package/build/esm/components/DashKit/DashKit.js +54 -6
- package/build/esm/components/DashKit/DashKit.js.map +1 -1
- package/build/esm/components/DashKit/__tests__/controlled-layout.test.d.ts +4 -0
- package/build/esm/components/DashKit/__tests__/controlled-layout.test.js +193 -0
- package/build/esm/components/DashKit/__tests__/controlled-layout.test.js.map +1 -0
- package/build/esm/components/DashKit/__tests__/events.test.d.ts +1 -0
- package/build/esm/components/DashKit/__tests__/events.test.js +225 -0
- package/build/esm/components/DashKit/__tests__/events.test.js.map +1 -0
- package/build/esm/components/DashKitView/DashKitView.d.ts +1 -1
- package/build/esm/components/DashKitView/DashKitView.js +1 -3
- package/build/esm/components/DashKitView/DashKitView.js.map +1 -1
- package/build/esm/components/GridLayout/GroupLayout.js +2 -2
- package/build/esm/components/GridLayout/GroupLayout.js.map +1 -1
- package/build/esm/components/GridLayout/ReactGridLayout.d.ts +1 -0
- package/build/esm/components/GridLayout/ReactGridLayout.js +37 -0
- package/build/esm/components/GridLayout/ReactGridLayout.js.map +1 -1
- package/build/esm/components/OverlayControls/OverlayControls.js +2 -2
- package/build/esm/components/OverlayControls/OverlayControls.js.map +1 -1
- package/build/esm/context/DashKitContext.d.ts +1 -0
- package/build/esm/context/DashKitContext.js.map +1 -1
- package/build/esm/context/DashkitOverlayControlsContext.d.ts +1 -1
- package/build/esm/context/DashkitOverlayControlsContext.js +1 -1
- package/build/esm/context/DashkitOverlayControlsContext.js.map +1 -1
- package/build/esm/hocs/withContext.d.ts +2 -2
- package/build/esm/hocs/withContext.js +64 -34
- package/build/esm/hocs/withContext.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/plugins/Text/Text.js +1 -1
- package/build/esm/plugins/Text/Text.js.map +1 -1
- package/build/esm/shared/types/config.d.ts +2 -0
- package/build/esm/shared/types/config.js +8 -1
- package/build/esm/shared/types/config.js.map +1 -1
- package/build/esm/typings/events.d.ts +34 -0
- package/build/esm/typings/events.js +2 -0
- package/build/esm/typings/events.js.map +1 -0
- package/build/esm/typings/index.d.ts +1 -0
- package/build/esm/typings/index.js +1 -0
- package/build/esm/typings/index.js.map +1 -1
- package/build/esm/utils/__tests__/get-layout-patches.test.d.ts +1 -0
- package/build/esm/utils/__tests__/get-layout-patches.test.js +49 -0
- package/build/esm/utils/__tests__/get-layout-patches.test.js.map +1 -0
- package/build/esm/utils/enrichLayoutWithDefaults.d.ts +5 -0
- package/build/esm/utils/enrichLayoutWithDefaults.js +25 -0
- package/build/esm/utils/enrichLayoutWithDefaults.js.map +1 -0
- package/build/esm/utils/events.d.ts +10 -0
- package/build/esm/utils/events.js +30 -0
- package/build/esm/utils/events.js.map +1 -0
- package/build/esm/utils/get-layout-patches.d.ts +3 -0
- package/build/esm/utils/get-layout-patches.js +19 -0
- package/build/esm/utils/get-layout-patches.js.map +1 -0
- package/build/esm/utils/index.d.ts +3 -0
- package/build/esm/utils/index.js +3 -0
- package/build/esm/utils/index.js.map +1 -1
- package/build/esm/utils/update-manager.js +3 -3
- package/build/esm/utils/update-manager.js.map +1 -1
- package/package.json +4 -1
- package/build/cjs/hooks/useCalcLayout.d.ts +0 -3
- package/build/cjs/hooks/useCalcLayout.js +0 -40
- package/build/cjs/hooks/useCalcLayout.js.map +0 -1
- package/build/esm/hooks/useCalcLayout.d.ts +0 -3
- package/build/esm/hooks/useCalcLayout.js +0 -35
- package/build/esm/hooks/useCalcLayout.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,12 +25,12 @@ Plugins are required to create custom widgets.
|
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
27
|
type ItemManipulationCallback = (eventData: {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
layout: Layout[];
|
|
29
|
+
oldItem: Layout;
|
|
30
|
+
newItem: Layout;
|
|
31
|
+
placeholder: Layout;
|
|
32
|
+
e: MouseEvent;
|
|
33
|
+
element: HTMLElement;
|
|
34
34
|
}) => void;
|
|
35
35
|
|
|
36
36
|
interface DashKitProps {
|
|
@@ -366,6 +366,80 @@ interface ItemsStateAndParamsBase {
|
|
|
366
366
|
type ItemsStateAndParams = StateAndParamsMeta & ItemsStateAndParamsBase;
|
|
367
367
|
```
|
|
368
368
|
|
|
369
|
+
### Experimental DashKit events
|
|
370
|
+
|
|
371
|
+
> Experimental: this API can change in minor releases.
|
|
372
|
+
|
|
373
|
+
`DashKit` exposes an experimental instance event API. Use a component ref and subscribe with `dashkitRef.current?.on(eventName, handler)`. The method returns an unsubscribe callback.
|
|
374
|
+
|
|
375
|
+
The first supported event is `change`. It is emitted when the layout changes, before `onChange` is called. The handler can read the full next and previous layouts, read layout patches, or call `preventDefault()` to stop the default `onChange` call.
|
|
376
|
+
|
|
377
|
+
```tsx
|
|
378
|
+
import React from 'react';
|
|
379
|
+
import {DashKit} from '@gravity-ui/dashkit';
|
|
380
|
+
import type {DashKitChangeEvent} from '@gravity-ui/dashkit';
|
|
381
|
+
|
|
382
|
+
function Dashboard() {
|
|
383
|
+
const dashkitRef = React.useRef<DashKit>(null);
|
|
384
|
+
|
|
385
|
+
React.useEffect(() => {
|
|
386
|
+
const unsubscribe = dashkitRef.current?.on('change', (event: DashKitChangeEvent) => {
|
|
387
|
+
console.log(event.patches);
|
|
388
|
+
|
|
389
|
+
if (event.patches.length > 0) {
|
|
390
|
+
event.preventDefault();
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
return () => unsubscribe?.();
|
|
395
|
+
}, []);
|
|
396
|
+
|
|
397
|
+
return <DashKit ref={dashkitRef} config={config} editMode={true} onChange={onChange} />;
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
type DashKitLayoutPatch = Pick<ConfigLayout, 'i'> &
|
|
403
|
+
Partial<Pick<ConfigLayout, 'x' | 'y' | 'w' | 'h' | 'parent'>>;
|
|
404
|
+
|
|
405
|
+
type DashKitChangeEvent = {
|
|
406
|
+
patches: DashKitLayoutPatch[];
|
|
407
|
+
layout: ConfigLayout[];
|
|
408
|
+
previousLayout: ConfigLayout[];
|
|
409
|
+
preventDefault: () => void;
|
|
410
|
+
readonly defaultPrevented: boolean;
|
|
411
|
+
};
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
#### Event-driven layout updates
|
|
415
|
+
|
|
416
|
+
If you use `preventDefault()` in the `change` event handler, you can now handle layout updates without re-initializing the config prop. DashKit maintains an internal baseline and computes patches incrementally:
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
function Dashboard() {
|
|
420
|
+
const [config, setConfig] = useState(initialConfig);
|
|
421
|
+
const dashkitRef = useRef<DashKit>(null);
|
|
422
|
+
|
|
423
|
+
useEffect(() => {
|
|
424
|
+
const unsubscribe = dashkitRef.current?.on('change', (event) => {
|
|
425
|
+
event.preventDefault(); // Don't call onChange
|
|
426
|
+
|
|
427
|
+
// Send only the incremental patches to your backend
|
|
428
|
+
sendPatches(event.patches);
|
|
429
|
+
|
|
430
|
+
// No need to call setConfig({ ...config, layout: event.layout })
|
|
431
|
+
// DashKit maintains the visual state internally
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
return unsubscribe;
|
|
435
|
+
}, []);
|
|
436
|
+
|
|
437
|
+
return <DashKit ref={dashkitRef} config={config} editMode onChange={() => {}} />;
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Important:** If you later update `config.layout` from props (e.g., from server sync), DashKit will reset its internal baseline to match the new prop. This ensures compatibility with both event-driven and controlled workflows.
|
|
442
|
+
|
|
369
443
|
### Menu
|
|
370
444
|
|
|
371
445
|
You can specify custom DashKit widget overlay menu in edit mode
|
|
@@ -406,7 +480,10 @@ interface DashKitDnDWrapperProps {
|
|
|
406
480
|
dragImageSrc?: string;
|
|
407
481
|
onDragStart?: (dragProps: ItemDragProps) => void;
|
|
408
482
|
onDragEnd?: () => void;
|
|
409
|
-
onDropDragOver?: (
|
|
483
|
+
onDropDragOver?: (
|
|
484
|
+
draggedItem: DraggedOverItem,
|
|
485
|
+
sharedItem: DraggedOverItem | null,
|
|
486
|
+
) => void | boolean;
|
|
410
487
|
}
|
|
411
488
|
```
|
|
412
489
|
|
|
@@ -416,25 +493,25 @@ interface DashKitDnDWrapperProps {
|
|
|
416
493
|
|
|
417
494
|
```ts
|
|
418
495
|
type ItemDragProps = {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
496
|
+
type: string; // Plugin type
|
|
497
|
+
layout?: {
|
|
498
|
+
// Optional. Layout item size for preview and init
|
|
499
|
+
w?: number;
|
|
500
|
+
h?: number;
|
|
501
|
+
};
|
|
502
|
+
extra?: any; // Custom user context
|
|
425
503
|
};
|
|
426
504
|
```
|
|
427
505
|
|
|
428
506
|
```ts
|
|
429
507
|
type ItemDropProps = {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
508
|
+
commit: () => void; // Callback should be called after all config operations are made
|
|
509
|
+
dragProps: ItemDragProps; // Item drag props
|
|
510
|
+
itemLayout: ConfigLayout; // Calculated item layout dimensions
|
|
511
|
+
newLayout: ConfigLayout[]; // New layout after element is dropped
|
|
434
512
|
};
|
|
435
513
|
```
|
|
436
514
|
|
|
437
|
-
|
|
438
515
|
#### Example:
|
|
439
516
|
|
|
440
517
|
```jsx
|
|
@@ -527,7 +604,6 @@ const CustomThemeWrapper = (props: {
|
|
|
527
604
|
By default, storybook runs on `http://localhost:7120/`.
|
|
528
605
|
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.
|
|
529
606
|
|
|
530
|
-
|
|
531
607
|
### Example of an nginx config for development on a dev machine
|
|
532
608
|
|
|
533
609
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Config, ConfigItem, ConfigLayout, GlobalParams, ItemDropProps, ItemsStateAndParams } from "../../shared/index.js";
|
|
3
|
-
import type { AddNewItemOptions, ContextProps, DashKitGroup, ItemManipulationCallback, MenuItem, Plugin, SetConfigItem, Settings, SettingsProps } from "../../typings/index.js";
|
|
3
|
+
import type { AddNewItemOptions, ContextProps, DashKitEventHandler, DashKitEventMap, DashKitEventName, DashKitGroup, ItemManipulationCallback, MenuItem, Plugin, SetConfigItem, Settings, SettingsProps } from "../../typings/index.js";
|
|
4
4
|
import GridLayout from "../GridLayout/GridLayout.js";
|
|
5
5
|
import type { OverlayControlItem, PreparedCopyItemOptions } from "../OverlayControls/OverlayControls.js";
|
|
6
6
|
interface DashKitGeneralProps {
|
|
@@ -72,11 +72,21 @@ export declare class DashKit extends React.PureComponent<DashKitInnerProps> {
|
|
|
72
72
|
groups?: DashKitGroup[];
|
|
73
73
|
}): ConfigLayout[];
|
|
74
74
|
metaRef: React.RefObject<GridLayout | null>;
|
|
75
|
+
private _handlers;
|
|
75
76
|
render(): React.JSX.Element;
|
|
76
77
|
getItemsMeta(): Promise<any>[];
|
|
77
78
|
reloadItems(options?: {
|
|
78
79
|
targetIds?: string[];
|
|
79
80
|
force?: boolean;
|
|
80
81
|
}): void;
|
|
82
|
+
/**
|
|
83
|
+
* @experimental This API can change in minor releases.
|
|
84
|
+
* @param eventName Event name.
|
|
85
|
+
* @param handler Event handler.
|
|
86
|
+
* @returns Unsubscribe callback.
|
|
87
|
+
*/
|
|
88
|
+
on<T extends DashKitEventName>(eventName: T, handler: DashKitEventHandler<T>): () => void;
|
|
89
|
+
[_emitSymbol]: <T extends DashKitEventName>(eventName: T, event: DashKitEventMap[T]) => void;
|
|
90
|
+
private _off;
|
|
81
91
|
}
|
|
82
92
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var _a;
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DashKit = void 0;
|
|
4
|
+
exports.DashKit = exports._emitSymbol = void 0;
|
|
4
5
|
const tslib_1 = require("tslib");
|
|
5
6
|
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
7
|
const noop_1 = tslib_1.__importDefault(require("lodash/noop.js"));
|
|
@@ -11,6 +12,12 @@ const utils_1 = require("../../utils/index.js");
|
|
|
11
12
|
const DashKitDnDWrapper_1 = require("../DashKitDnDWrapper/DashKitDnDWrapper.js");
|
|
12
13
|
const DashKitView_1 = tslib_1.__importDefault(require("../DashKitView/DashKitView.js"));
|
|
13
14
|
const registerManager = new utils_1.RegisterManager();
|
|
15
|
+
/**
|
|
16
|
+
* @internal Not part of the public API. Do not use in production code.
|
|
17
|
+
* Module-scoped symbol — not accessible to external consumers holding a ref,
|
|
18
|
+
* preventing synthetic event injection via instance._emit.
|
|
19
|
+
*/
|
|
20
|
+
exports._emitSymbol = Symbol('DashKit._emit');
|
|
14
21
|
const getReflowProps = (props) => Object.assign({ compactType: 'vertical', cols: 36 }, (0, pick_1.default)(props, 'cols', 'maxRows', 'compactType'));
|
|
15
22
|
const getReflowGroupsConfig = (groups = []) => {
|
|
16
23
|
const defaultGridProps = getReflowProps(registerManager.gridLayout);
|
|
@@ -29,6 +36,22 @@ class DashKit extends react_1.default.PureComponent {
|
|
|
29
36
|
constructor() {
|
|
30
37
|
super(...arguments);
|
|
31
38
|
this.metaRef = react_1.default.createRef();
|
|
39
|
+
this._handlers = new Map();
|
|
40
|
+
this[_a] = (eventName, event) => {
|
|
41
|
+
const handlers = this._handlers.get(eventName);
|
|
42
|
+
if (!handlers) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
for (const handler of handlers) {
|
|
46
|
+
try {
|
|
47
|
+
handler(event);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
// eslint-disable-next-line no-console
|
|
51
|
+
console.error('DashKit: event handler error', e);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
32
55
|
}
|
|
33
56
|
static registerPlugins(...plugins) {
|
|
34
57
|
plugins.forEach((plugin) => {
|
|
@@ -54,7 +77,8 @@ class DashKit extends react_1.default.PureComponent {
|
|
|
54
77
|
}
|
|
55
78
|
else {
|
|
56
79
|
const item = setItem;
|
|
57
|
-
const
|
|
80
|
+
const registerManagerItem = registerManager.getItem(item.type);
|
|
81
|
+
const layout = Object.assign({}, registerManagerItem.defaultLayout);
|
|
58
82
|
const reflowLayoutOptions = getReflowGroupsConfig(groups);
|
|
59
83
|
const copyItem = Object.assign({}, item);
|
|
60
84
|
if (copyItem.layout) {
|
|
@@ -81,22 +105,46 @@ class DashKit extends react_1.default.PureComponent {
|
|
|
81
105
|
});
|
|
82
106
|
}
|
|
83
107
|
render() {
|
|
84
|
-
const content = (react_1.default.createElement(DashKitView_1.default, Object.assign({ registerManager: registerManager, ref: this.metaRef }, this.props)));
|
|
108
|
+
const content = (react_1.default.createElement(DashKitView_1.default, Object.assign({ registerManager: registerManager, ref: this.metaRef }, this.props, { emitDashKitEvent: this[exports._emitSymbol] })));
|
|
85
109
|
if (!this.context && this.props.groups) {
|
|
86
110
|
return react_1.default.createElement(DashKitDnDWrapper_1.DashKitDnDWrapper, null, content);
|
|
87
111
|
}
|
|
88
112
|
return content;
|
|
89
113
|
}
|
|
90
114
|
getItemsMeta() {
|
|
91
|
-
var
|
|
92
|
-
return (
|
|
115
|
+
var _b, _c;
|
|
116
|
+
return (_c = (_b = this.metaRef.current) === null || _b === void 0 ? void 0 : _b.getItemsMeta()) !== null && _c !== void 0 ? _c : [];
|
|
93
117
|
}
|
|
94
118
|
reloadItems(options) {
|
|
95
|
-
var
|
|
96
|
-
(
|
|
119
|
+
var _b;
|
|
120
|
+
(_b = this.metaRef.current) === null || _b === void 0 ? void 0 : _b.reloadItems(options);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* @experimental This API can change in minor releases.
|
|
124
|
+
* @param eventName Event name.
|
|
125
|
+
* @param handler Event handler.
|
|
126
|
+
* @returns Unsubscribe callback.
|
|
127
|
+
*/
|
|
128
|
+
on(eventName, handler) {
|
|
129
|
+
var _b;
|
|
130
|
+
if (!this._handlers.has(eventName)) {
|
|
131
|
+
this._handlers.set(eventName, new Set());
|
|
132
|
+
}
|
|
133
|
+
(_b = this._handlers.get(eventName)) === null || _b === void 0 ? void 0 : _b.add(handler);
|
|
134
|
+
return () => this._off(eventName, handler);
|
|
135
|
+
}
|
|
136
|
+
_off(eventName, handler) {
|
|
137
|
+
const handlers = this._handlers.get(eventName);
|
|
138
|
+
if (handlers) {
|
|
139
|
+
handlers.delete(handler);
|
|
140
|
+
if (handlers.size === 0) {
|
|
141
|
+
this._handlers.delete(eventName);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
97
144
|
}
|
|
98
145
|
}
|
|
99
146
|
exports.DashKit = DashKit;
|
|
147
|
+
_a = exports._emitSymbol;
|
|
100
148
|
DashKit.defaultProps = {
|
|
101
149
|
onItemEdit: noop_1.default,
|
|
102
150
|
onChange: noop_1.default,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashKit.js","sourceRoot":"../../../../src","sources":["components/DashKit/DashKit.tsx"],"names":[],"mappings":";;;;AAAA,0DAA0B;AAE1B,kEAA+B;AAC/B,kEAA+B;AAE/B,wDAAiE;AACjE,oDAAgD;AAuBhD,gDAAyE;AACzE,iFAAyE;AACzE,wFAAqD;AAoDrD,MAAM,eAAe,GAAG,IAAI,uBAAe,EAAE,CAAC;AAE9C,MAAM,cAAc,GAAG,CAAC,KAA2B,EAAqB,EAAE,CACtE,MAAM,CAAC,MAAM,CACT,EAAC,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAC,EACnC,IAAA,cAAI,EAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,CAChD,CAAC;AAEN,MAAM,qBAAqB,GAAG,CAAC,SAAyB,EAAE,EAAE,EAAE;IAC1D,MAAM,gBAAgB,GAAG,cAAc,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;IAEpE,OAAO;QACH,YAAY,EAAE,gBAAgB;QAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAoC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACjE,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,IAAI,yBAAa,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,cAAc;gBAC5B,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;gBACpD,CAAC,CAAC,gBAAgB,CAAC;YAEvB,OAAO,IAAI,CAAC;QAChB,CAAC,EAAE,EAAE,CAAC;KACT,CAAC;AACN,CAAC,CAAC;AAEF,MAAa,OAAQ,SAAQ,eAAK,CAAC,aAAgC;IAAnE;;QA0GI,YAAO,GAAG,eAAK,CAAC,SAAS,EAAc,CAAC;IAqB5C,CAAC;IA5GG,MAAM,CAAC,eAAe,CAAC,GAAG,OAAiB;QACvC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACvB,eAAe,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACP,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,GAAG,OAAiB;QACrC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACvB,eAAe,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,QAAkB;QACjC,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,EACX,IAAI,EAAE,OAAO,EACb,SAAS,GAAG,6BAAiB,EAC7B,MAAM,EACN,OAAO,GAAG,EAAE,EACZ,MAAM,GAAG,EAAE,GAOd;QACG,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,qBAAa,CAAC,QAAQ,CAAC;gBAC1B,IAAI,EAAE,OAAO;gBACb,SAAS;gBACT,MAAM;gBACN,OAAO;aACV,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,MAAM,IAAI,GAAG,OAAwB,CAAC;YACtC,MAAM,MAAM,qBAAO,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC;YAErE,MAAM,mBAAmB,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAE1D,MAAM,QAAQ,qBAAO,IAAI,CAAC,CAAC;YAE3B,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAClB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACvC,OAAO,QAAQ,CAAC,MAAM,CAAC;YAC3B,CAAC;YAED,OAAO,qBAAa,CAAC,OAAO,CAAC;gBACzB,IAAI,EAAE,QAAQ;gBACd,SAAS;gBACT,MAAM;gBACN,MAAM;gBACN,OAAO,kCAAM,OAAO,KAAE,mBAAmB,GAAC;aAC7C,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,EACd,EAAE,EACF,MAAM,EACN,mBAAmB,GAKtB;QACG,OAAO,qBAAa,CAAC,UAAU,CAAC,EAAC,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,EAChB,aAAa,EACb,MAAM,EACN,MAAM,GAKT;QACG,OAAO,IAAA,oBAAY,EAAC;YAChB,aAAa;YACb,MAAM;YACN,mBAAmB,EAAE,qBAAqB,CAAC,MAAM,CAAC;SACrD,CAAC,CAAC;IACP,CAAC;IAID,MAAM;QACF,MAAM,OAAO,GAAG,CACZ,8BAAC,qBAAW,kBAAC,eAAe,EAAE,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,IAAM,IAAI,CAAC,KAAK,EAAI,CACvF,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACrC,OAAO,8BAAC,qCAAiB,QAAE,OAAO,CAAqB,CAAC;QAC5D,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,YAAY;;QACR,OAAO,MAAA,MAAA,IAAI,CAAC,OAAO,CAAC,OAAO,0CAAE,YAAY,EAAE,mCAAI,EAAE,CAAC;IACtD,CAAC;IAED,WAAW,CAAC,OAAiD;;QACzD,MAAA,IAAI,CAAC,OAAO,CAAC,OAAO,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;;AA9HL,0BA+HC;AA9HU,oBAAY,GAAwB;IACvC,UAAU,EAAE,cAAI;IAChB,QAAQ,EAAE,cAAI;IACd,MAAM,EAAE,cAAI;IACZ,mBAAmB,EAAE,EAAE;IACvB,YAAY,EAAE,EAAE;IAChB,mBAAmB,EAAE,EAAE;IACvB,QAAQ,EAAE;QACN,kBAAkB,EAAE,CAAC;QACrB,aAAa,EAAE,KAAK;KACvB;IACD,OAAO,EAAE,EAAE;IACX,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;CACnB,AAdkB,CAcjB;AAEK,mBAAW,GAAG,2BAAiB,AAApB,CAAqB","sourcesContent":["import React from 'react';\n\nimport noop from 'lodash/noop';\nimport pick from 'lodash/pick';\n\nimport {DEFAULT_GROUP, DEFAULT_NAMESPACE} from '../../constants';\nimport {DashKitDnDContext} from '../../context';\nimport type {\n Config,\n ConfigItem,\n ConfigLayout,\n GlobalParams,\n ItemDropProps,\n ItemsStateAndParams,\n} from '../../shared';\nimport type {\n AddConfigItem,\n AddNewItemOptions,\n ContextProps,\n DashKitGroup,\n GridReflowOptions,\n ItemManipulationCallback,\n MenuItem,\n Plugin,\n ReactGridLayoutProps,\n SetConfigItem,\n Settings,\n SettingsProps,\n} from '../../typings';\nimport {RegisterManager, UpdateManager, reflowLayout} from '../../utils';\nimport {DashKitDnDWrapper} from '../DashKitDnDWrapper/DashKitDnDWrapper';\nimport DashKitView from '../DashKitView/DashKitView';\nimport GridLayout from '../GridLayout/GridLayout';\nimport type {OverlayControlItem, PreparedCopyItemOptions} from '../OverlayControls/OverlayControls';\n\ninterface DashKitGeneralProps {\n config: Config;\n editMode: boolean;\n draggableHandleClassName?: string;\n overlayControls?: Record<string, OverlayControlItem[]> | null;\n overlayMenuItems?: MenuItem[] | null;\n}\n\ninterface DashKitDefaultProps {\n defaultGlobalParams: GlobalParams;\n globalParams: GlobalParams;\n itemsStateAndParams: ItemsStateAndParams;\n settings: SettingsProps;\n context: ContextProps;\n noOverlay: boolean;\n focusable?: boolean;\n groups?: DashKitGroup[];\n\n onItemEdit: (item: ConfigItem) => void;\n onChange: (data: {\n config: Config;\n itemsStateAndParams: ItemsStateAndParams;\n groups?: DashKitGroup[];\n }) => void;\n\n onDrop: (dropProps: ItemDropProps) => void;\n\n onItemMountChange?: (item: ConfigItem, state: {isAsync: boolean; isMounted: boolean}) => void;\n onItemRender?: (item: ConfigItem) => void;\n\n getPreparedCopyItemOptions?: (options: PreparedCopyItemOptions) => PreparedCopyItemOptions;\n onCopyFulfill?: (error: null | Error, data?: PreparedCopyItemOptions) => void;\n\n onItemFocus?: (item: ConfigItem) => void;\n onItemBlur?: (item: ConfigItem) => void;\n\n onDragStart?: ItemManipulationCallback;\n onDrag?: ItemManipulationCallback;\n onDragStop?: ItemManipulationCallback;\n onResizeStart?: ItemManipulationCallback;\n onResize?: ItemManipulationCallback;\n onResizeStop?: ItemManipulationCallback;\n}\n\nexport interface DashKitProps extends DashKitGeneralProps, Partial<DashKitDefaultProps> {}\n\ntype DashKitInnerProps = DashKitGeneralProps & DashKitDefaultProps;\n\nconst registerManager = new RegisterManager();\n\nconst getReflowProps = (props: ReactGridLayoutProps): GridReflowOptions =>\n Object.assign(\n {compactType: 'vertical', cols: 36},\n pick(props, 'cols', 'maxRows', 'compactType'),\n );\n\nconst getReflowGroupsConfig = (groups: DashKitGroup[] = []) => {\n const defaultGridProps = getReflowProps(registerManager.gridLayout);\n\n return {\n defaultProps: defaultGridProps,\n groups: groups.reduce<Record<string, GridReflowOptions>>((memo, g) => {\n const groupId = g.id || DEFAULT_GROUP;\n memo[groupId] = g.gridProperties\n ? getReflowProps(g.gridProperties(defaultGridProps))\n : defaultGridProps;\n\n return memo;\n }, {}),\n };\n};\n\nexport class DashKit extends React.PureComponent<DashKitInnerProps> {\n static defaultProps: DashKitDefaultProps = {\n onItemEdit: noop,\n onChange: noop,\n onDrop: noop,\n defaultGlobalParams: {},\n globalParams: {},\n itemsStateAndParams: {},\n settings: {\n autoupdateInterval: 0,\n silentLoading: false,\n },\n context: {},\n noOverlay: false,\n focusable: false,\n };\n\n static contextType = DashKitDnDContext;\n\n static registerPlugins(...plugins: Plugin[]) {\n plugins.forEach((plugin) => {\n registerManager.registerPlugin(plugin);\n });\n }\n\n static reloadPlugins(...plugins: Plugin[]) {\n plugins.forEach((plugin) => {\n registerManager.reloadPlugin(plugin);\n });\n }\n\n static setSettings(settings: Settings) {\n registerManager.setSettings(settings);\n }\n\n static setItem({\n item: setItem,\n namespace = DEFAULT_NAMESPACE,\n config,\n options = {},\n groups = [],\n }: {\n item: SetConfigItem;\n namespace?: string;\n config: Config;\n options?: Omit<AddNewItemOptions, 'reflowLayoutOptions'>;\n groups?: DashKitGroup[];\n }): Config {\n if (setItem.id) {\n return UpdateManager.editItem({\n item: setItem,\n namespace,\n config,\n options,\n });\n } else {\n const item = setItem as AddConfigItem;\n const layout = {...registerManager.getItem(item.type).defaultLayout};\n\n const reflowLayoutOptions = getReflowGroupsConfig(groups);\n\n const copyItem = {...item};\n\n if (copyItem.layout) {\n Object.assign(layout, copyItem.layout);\n delete copyItem.layout;\n }\n\n return UpdateManager.addItem({\n item: copyItem,\n namespace,\n config,\n layout,\n options: {...options, reflowLayoutOptions},\n });\n }\n }\n\n static removeItem({\n id,\n config,\n itemsStateAndParams,\n }: {\n id: string;\n config: Config;\n itemsStateAndParams: ItemsStateAndParams;\n }): {config: Config; itemsStateAndParams: ItemsStateAndParams} {\n return UpdateManager.removeItem({id, config, itemsStateAndParams});\n }\n\n static reflowLayout({\n newLayoutItem,\n layout,\n groups,\n }: {\n newLayoutItem?: ConfigLayout;\n layout: ConfigLayout[];\n groups?: DashKitGroup[];\n }) {\n return reflowLayout({\n newLayoutItem,\n layout,\n reflowLayoutOptions: getReflowGroupsConfig(groups),\n });\n }\n\n metaRef = React.createRef<GridLayout>();\n\n render() {\n const content = (\n <DashKitView registerManager={registerManager} ref={this.metaRef} {...this.props} />\n );\n\n if (!this.context && this.props.groups) {\n return <DashKitDnDWrapper>{content}</DashKitDnDWrapper>;\n }\n\n return content;\n }\n\n getItemsMeta() {\n return this.metaRef.current?.getItemsMeta() ?? [];\n }\n\n reloadItems(options?: {targetIds?: string[]; force?: boolean}) {\n this.metaRef.current?.reloadItems(options);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DashKit.js","sourceRoot":"../../../../src","sources":["components/DashKit/DashKit.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\n\nimport noop from 'lodash/noop';\nimport pick from 'lodash/pick';\n\nimport {DEFAULT_GROUP, DEFAULT_NAMESPACE} from '../../constants';\nimport {DashKitDnDContext} from '../../context';\nimport type {\n Config,\n ConfigItem,\n ConfigLayout,\n GlobalParams,\n ItemDropProps,\n ItemsStateAndParams,\n} from '../../shared';\nimport type {\n AddConfigItem,\n AddNewItemOptions,\n ContextProps,\n DashKitEventHandler,\n DashKitEventMap,\n DashKitEventName,\n DashKitGroup,\n GridReflowOptions,\n ItemManipulationCallback,\n MenuItem,\n Plugin,\n ReactGridLayoutProps,\n SetConfigItem,\n Settings,\n SettingsProps,\n} from '../../typings';\nimport {RegisterManager, UpdateManager, reflowLayout} from '../../utils';\nimport {DashKitDnDWrapper} from '../DashKitDnDWrapper/DashKitDnDWrapper';\nimport DashKitView from '../DashKitView/DashKitView';\nimport GridLayout from '../GridLayout/GridLayout';\nimport type {OverlayControlItem, PreparedCopyItemOptions} from '../OverlayControls/OverlayControls';\n\ninterface DashKitGeneralProps {\n config: Config;\n editMode: boolean;\n draggableHandleClassName?: string;\n overlayControls?: Record<string, OverlayControlItem[]> | null;\n overlayMenuItems?: MenuItem[] | null;\n}\n\ninterface DashKitDefaultProps {\n defaultGlobalParams: GlobalParams;\n globalParams: GlobalParams;\n itemsStateAndParams: ItemsStateAndParams;\n settings: SettingsProps;\n context: ContextProps;\n noOverlay: boolean;\n focusable?: boolean;\n groups?: DashKitGroup[];\n\n onItemEdit: (item: ConfigItem) => void;\n onChange: (data: {\n config: Config;\n itemsStateAndParams: ItemsStateAndParams;\n groups?: DashKitGroup[];\n }) => void;\n\n onDrop: (dropProps: ItemDropProps) => void;\n\n onItemMountChange?: (item: ConfigItem, state: {isAsync: boolean; isMounted: boolean}) => void;\n onItemRender?: (item: ConfigItem) => void;\n\n getPreparedCopyItemOptions?: (options: PreparedCopyItemOptions) => PreparedCopyItemOptions;\n onCopyFulfill?: (error: null | Error, data?: PreparedCopyItemOptions) => void;\n\n onItemFocus?: (item: ConfigItem) => void;\n onItemBlur?: (item: ConfigItem) => void;\n\n onDragStart?: ItemManipulationCallback;\n onDrag?: ItemManipulationCallback;\n onDragStop?: ItemManipulationCallback;\n onResizeStart?: ItemManipulationCallback;\n onResize?: ItemManipulationCallback;\n onResizeStop?: ItemManipulationCallback;\n}\n\nexport interface DashKitProps extends DashKitGeneralProps, Partial<DashKitDefaultProps> {}\n\ntype DashKitInnerProps = DashKitGeneralProps & DashKitDefaultProps;\n\nconst registerManager = new RegisterManager();\n\n/**\n * @internal Not part of the public API. Do not use in production code.\n * Module-scoped symbol — not accessible to external consumers holding a ref,\n * preventing synthetic event injection via instance._emit.\n */\nexport const _emitSymbol = Symbol('DashKit._emit');\n\nconst getReflowProps = (props: ReactGridLayoutProps): GridReflowOptions =>\n Object.assign(\n {compactType: 'vertical', cols: 36},\n pick(props, 'cols', 'maxRows', 'compactType'),\n );\n\nconst getReflowGroupsConfig = (groups: DashKitGroup[] = []) => {\n const defaultGridProps = getReflowProps(registerManager.gridLayout);\n\n return {\n defaultProps: defaultGridProps,\n groups: groups.reduce<Record<string, GridReflowOptions>>((memo, g) => {\n const groupId = g.id || DEFAULT_GROUP;\n memo[groupId] = g.gridProperties\n ? getReflowProps(g.gridProperties(defaultGridProps))\n : defaultGridProps;\n\n return memo;\n }, {}),\n };\n};\n\nexport class DashKit extends React.PureComponent<DashKitInnerProps> {\n static defaultProps: DashKitDefaultProps = {\n onItemEdit: noop,\n onChange: noop,\n onDrop: noop,\n defaultGlobalParams: {},\n globalParams: {},\n itemsStateAndParams: {},\n settings: {\n autoupdateInterval: 0,\n silentLoading: false,\n },\n context: {},\n noOverlay: false,\n focusable: false,\n };\n\n static contextType = DashKitDnDContext;\n\n static registerPlugins(...plugins: Plugin[]) {\n plugins.forEach((plugin) => {\n registerManager.registerPlugin(plugin);\n });\n }\n\n static reloadPlugins(...plugins: Plugin[]) {\n plugins.forEach((plugin) => {\n registerManager.reloadPlugin(plugin);\n });\n }\n\n static setSettings(settings: Settings) {\n registerManager.setSettings(settings);\n }\n\n static setItem({\n item: setItem,\n namespace = DEFAULT_NAMESPACE,\n config,\n options = {},\n groups = [],\n }: {\n item: SetConfigItem;\n namespace?: string;\n config: Config;\n options?: Omit<AddNewItemOptions, 'reflowLayoutOptions'>;\n groups?: DashKitGroup[];\n }): Config {\n if (setItem.id) {\n return UpdateManager.editItem({\n item: setItem,\n namespace,\n config,\n options,\n });\n } else {\n const item = setItem as AddConfigItem;\n const registerManagerItem = registerManager.getItem(item.type);\n\n const layout = {...registerManagerItem.defaultLayout};\n\n const reflowLayoutOptions = getReflowGroupsConfig(groups);\n\n const copyItem = {...item};\n\n if (copyItem.layout) {\n Object.assign(layout, copyItem.layout);\n delete copyItem.layout;\n }\n\n return UpdateManager.addItem({\n item: copyItem,\n namespace,\n config,\n layout,\n options: {...options, reflowLayoutOptions},\n });\n }\n }\n\n static removeItem({\n id,\n config,\n itemsStateAndParams,\n }: {\n id: string;\n config: Config;\n itemsStateAndParams: ItemsStateAndParams;\n }): {config: Config; itemsStateAndParams: ItemsStateAndParams} {\n return UpdateManager.removeItem({id, config, itemsStateAndParams});\n }\n\n static reflowLayout({\n newLayoutItem,\n layout,\n groups,\n }: {\n newLayoutItem?: ConfigLayout;\n layout: ConfigLayout[];\n groups?: DashKitGroup[];\n }) {\n return reflowLayout({\n newLayoutItem,\n layout,\n reflowLayoutOptions: getReflowGroupsConfig(groups),\n });\n }\n\n metaRef = React.createRef<GridLayout>();\n\n private _handlers = new Map<string, Set<(...args: any[]) => void>>();\n\n render() {\n const content = (\n <DashKitView\n registerManager={registerManager}\n ref={this.metaRef}\n {...this.props}\n emitDashKitEvent={this[_emitSymbol]}\n />\n );\n\n if (!this.context && this.props.groups) {\n return <DashKitDnDWrapper>{content}</DashKitDnDWrapper>;\n }\n\n return content;\n }\n\n getItemsMeta() {\n return this.metaRef.current?.getItemsMeta() ?? [];\n }\n\n reloadItems(options?: {targetIds?: string[]; force?: boolean}) {\n this.metaRef.current?.reloadItems(options);\n }\n\n /**\n * @experimental This API can change in minor releases.\n * @param eventName Event name.\n * @param handler Event handler.\n * @returns Unsubscribe callback.\n */\n on<T extends DashKitEventName>(eventName: T, handler: DashKitEventHandler<T>): () => void {\n if (!this._handlers.has(eventName)) {\n this._handlers.set(eventName, new Set());\n }\n this._handlers.get(eventName)?.add(handler);\n return () => this._off(eventName, handler);\n }\n\n [_emitSymbol] = <T extends DashKitEventName>(eventName: T, event: DashKitEventMap[T]): void => {\n const handlers = this._handlers.get(eventName);\n if (!handlers) {\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as DashKitEventHandler<T>)(event);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('DashKit: event handler error', e);\n }\n }\n };\n\n private _off<T extends DashKitEventName>(eventName: T, handler: DashKitEventHandler<T>): void {\n const handlers = this._handlers.get(eventName);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this._handlers.delete(eventName);\n }\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @jest-environment jsdom
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
jest.mock('@gravity-ui/icons', () => ({
|
|
8
|
+
Ellipsis: 'ellipsis',
|
|
9
|
+
Gear: 'gear',
|
|
10
|
+
Xmark: 'xmark',
|
|
11
|
+
}));
|
|
12
|
+
jest.mock('@gravity-ui/uikit', () => {
|
|
13
|
+
const ReactMock = require('react');
|
|
14
|
+
return {
|
|
15
|
+
Button: ({ children }) => ReactMock.createElement('button', null, children),
|
|
16
|
+
DropdownMenu: () => null,
|
|
17
|
+
Icon: () => null,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
jest.mock('../../GridLayout/GridLayout', () => {
|
|
21
|
+
const ReactMock = require('react');
|
|
22
|
+
return ReactMock.forwardRef(() => null);
|
|
23
|
+
});
|
|
24
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
25
|
+
const react_2 = require("@testing-library/react");
|
|
26
|
+
const context_1 = require("../../../context/index.js");
|
|
27
|
+
const withContext_1 = require("../../../hocs/withContext.js");
|
|
28
|
+
const utils_1 = require("../../../utils/index.js");
|
|
29
|
+
const DashKit_1 = require("../DashKit.js");
|
|
30
|
+
const PLUGIN_TYPE = 'controlled-layout-test';
|
|
31
|
+
const createConfig = (x) => ({
|
|
32
|
+
salt: 'test',
|
|
33
|
+
counter: 1,
|
|
34
|
+
items: [{ id: 'item1', type: PLUGIN_TYPE, namespace: 'default', data: {} }],
|
|
35
|
+
layout: [{ i: 'item1', x, y: 0, w: 2, h: 2 }],
|
|
36
|
+
aliases: {},
|
|
37
|
+
connections: [],
|
|
38
|
+
});
|
|
39
|
+
const createProps = ({ config, emitDashKitEvent, onChange = jest.fn(), }) => {
|
|
40
|
+
const registerManager = new utils_1.RegisterManager();
|
|
41
|
+
registerManager.registerPlugin({
|
|
42
|
+
type: PLUGIN_TYPE,
|
|
43
|
+
defaultLayout: { x: 0, y: 0, w: 2, h: 2 },
|
|
44
|
+
renderer: () => null,
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
config,
|
|
48
|
+
editMode: true,
|
|
49
|
+
layout: config.layout,
|
|
50
|
+
registerManager,
|
|
51
|
+
forwardedMetaRef: react_1.default.createRef(),
|
|
52
|
+
emitDashKitEvent,
|
|
53
|
+
itemsStateAndParams: {},
|
|
54
|
+
defaultGlobalParams: {},
|
|
55
|
+
globalParams: {},
|
|
56
|
+
context: {},
|
|
57
|
+
settings: {
|
|
58
|
+
autoupdateInterval: 0,
|
|
59
|
+
silentLoading: false,
|
|
60
|
+
},
|
|
61
|
+
noOverlay: false,
|
|
62
|
+
focusable: false,
|
|
63
|
+
onItemEdit: jest.fn(),
|
|
64
|
+
onChange,
|
|
65
|
+
onDrop: jest.fn(),
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
let captured = {};
|
|
69
|
+
const ContextCapture = () => {
|
|
70
|
+
captured = react_1.default.useContext(context_1.DashKitContext);
|
|
71
|
+
return null;
|
|
72
|
+
};
|
|
73
|
+
const TestComponent = (0, withContext_1.withContext)(ContextCapture);
|
|
74
|
+
describe('DashKit controlled layout strategy', () => {
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
captured = {};
|
|
77
|
+
});
|
|
78
|
+
it('Case 1: keeps internal layout after change event without config update, then applies external config update', () => {
|
|
79
|
+
const initialConfig = createConfig(0);
|
|
80
|
+
const nextInternalLayout = [{ i: 'item1', x: 1, y: 0, w: 2, h: 2 }];
|
|
81
|
+
const externalConfig = createConfig(3);
|
|
82
|
+
const dashkit = new DashKit_1.DashKit(DashKit_1.DashKit.defaultProps);
|
|
83
|
+
const onChange = jest.fn();
|
|
84
|
+
const onEventChange = jest.fn();
|
|
85
|
+
dashkit.on('change', onEventChange);
|
|
86
|
+
const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
87
|
+
config: initialConfig,
|
|
88
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
89
|
+
onChange,
|
|
90
|
+
}))));
|
|
91
|
+
// Layout is now enriched with plugin defaults (minW, minH, etc)
|
|
92
|
+
expect(captured.layout).toMatchObject(initialConfig.layout);
|
|
93
|
+
expect(captured.layout[0]).toHaveProperty('minW');
|
|
94
|
+
expect(captured.layout[0]).toHaveProperty('minH');
|
|
95
|
+
(0, react_2.act)(() => {
|
|
96
|
+
captured.layoutChange(nextInternalLayout);
|
|
97
|
+
});
|
|
98
|
+
// Verify that change event was fired with correct layout
|
|
99
|
+
expect(onEventChange).toHaveBeenCalledTimes(1);
|
|
100
|
+
expect(onEventChange.mock.calls[0][0].layout).toEqual(nextInternalLayout);
|
|
101
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
102
|
+
// Now apply external config update
|
|
103
|
+
(0, react_2.act)(() => {
|
|
104
|
+
rerender(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
105
|
+
config: externalConfig,
|
|
106
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
107
|
+
onChange,
|
|
108
|
+
}))));
|
|
109
|
+
});
|
|
110
|
+
// External props should win and layout should be updated
|
|
111
|
+
expect(captured.layout).toMatchObject(externalConfig.layout);
|
|
112
|
+
});
|
|
113
|
+
it('Case 2: uses on(change) without updating props - internal state persists', () => {
|
|
114
|
+
const initialConfig = createConfig(0);
|
|
115
|
+
const nextInternalLayout = [{ i: 'item1', x: 5, y: 0, w: 2, h: 2 }];
|
|
116
|
+
const dashkit = new DashKit_1.DashKit(DashKit_1.DashKit.defaultProps);
|
|
117
|
+
const onChange = jest.fn();
|
|
118
|
+
const onEventChange = jest.fn();
|
|
119
|
+
const capturedLayouts = [];
|
|
120
|
+
// Listen to change event but DON'T update props
|
|
121
|
+
dashkit.on('change', (event) => {
|
|
122
|
+
capturedLayouts.push(event.layout);
|
|
123
|
+
onEventChange(event);
|
|
124
|
+
});
|
|
125
|
+
const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
126
|
+
config: initialConfig,
|
|
127
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
128
|
+
onChange,
|
|
129
|
+
}))));
|
|
130
|
+
// Initial layout should be enriched
|
|
131
|
+
expect(captured.layout).toMatchObject(initialConfig.layout);
|
|
132
|
+
// Trigger layout change
|
|
133
|
+
(0, react_2.act)(() => {
|
|
134
|
+
captured.layoutChange(nextInternalLayout);
|
|
135
|
+
});
|
|
136
|
+
// Event should fire with new layout
|
|
137
|
+
expect(onEventChange).toHaveBeenCalledTimes(1);
|
|
138
|
+
expect(capturedLayouts[0]).toEqual(nextInternalLayout);
|
|
139
|
+
// onChange callback fires (consumer COULD update props here, but doesn't in this case)
|
|
140
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
141
|
+
// Props remain unchanged - simulating consumer NOT updating props
|
|
142
|
+
(0, react_2.act)(() => {
|
|
143
|
+
rerender(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
144
|
+
config: initialConfig,
|
|
145
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
146
|
+
onChange,
|
|
147
|
+
}))));
|
|
148
|
+
});
|
|
149
|
+
// Layout should still reflect the change (internal state wins)
|
|
150
|
+
// Note: we verify the event fired correctly
|
|
151
|
+
expect(onEventChange).toHaveBeenCalledTimes(1);
|
|
152
|
+
expect(capturedLayouts[0]).toMatchObject(nextInternalLayout);
|
|
153
|
+
});
|
|
154
|
+
it('Case 3: alternates between props.layout updates and on(change) events', () => {
|
|
155
|
+
const config1 = createConfig(0);
|
|
156
|
+
const config2 = createConfig(2);
|
|
157
|
+
const internalChange = [{ i: 'item1', x: 5, y: 0, w: 2, h: 2 }];
|
|
158
|
+
const config3 = createConfig(8);
|
|
159
|
+
const dashkit = new DashKit_1.DashKit(DashKit_1.DashKit.defaultProps);
|
|
160
|
+
const onChange = jest.fn();
|
|
161
|
+
const onEventChange = jest.fn();
|
|
162
|
+
dashkit.on('change', onEventChange);
|
|
163
|
+
const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
164
|
+
config: config1,
|
|
165
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
166
|
+
onChange,
|
|
167
|
+
}))));
|
|
168
|
+
// Start with config1
|
|
169
|
+
expect(captured.layout).toMatchObject(config1.layout);
|
|
170
|
+
// Update via props (external update)
|
|
171
|
+
(0, react_2.act)(() => {
|
|
172
|
+
rerender(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
173
|
+
config: config2,
|
|
174
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
175
|
+
onChange,
|
|
176
|
+
}))));
|
|
177
|
+
});
|
|
178
|
+
expect(captured.layout).toMatchObject(config2.layout);
|
|
179
|
+
// Update via internal change (user drag)
|
|
180
|
+
(0, react_2.act)(() => {
|
|
181
|
+
captured.layoutChange(internalChange);
|
|
182
|
+
});
|
|
183
|
+
expect(onEventChange).toHaveBeenCalledTimes(1);
|
|
184
|
+
expect(onEventChange.mock.calls[0][0].layout).toEqual(internalChange);
|
|
185
|
+
// Update via props again (external update wins)
|
|
186
|
+
(0, react_2.act)(() => {
|
|
187
|
+
rerender(react_1.default.createElement(TestComponent, Object.assign({}, createProps({
|
|
188
|
+
config: config3,
|
|
189
|
+
emitDashKitEvent: dashkit[DashKit_1._emitSymbol],
|
|
190
|
+
onChange,
|
|
191
|
+
}))));
|
|
192
|
+
});
|
|
193
|
+
expect(captured.layout).toMatchObject(config3.layout);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
//# sourceMappingURL=controlled-layout.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlled-layout.test.js","sourceRoot":"../../../../../src","sources":["components/DashKit/__tests__/controlled-layout.test.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * @jest-environment jsdom\n */\n\njest.mock('@gravity-ui/icons', () => ({\n Ellipsis: 'ellipsis',\n Gear: 'gear',\n Xmark: 'xmark',\n}));\n\njest.mock('@gravity-ui/uikit', () => {\n const ReactMock = require('react');\n\n return {\n Button: ({children}: {children?: unknown}) =>\n ReactMock.createElement('button', null, children),\n DropdownMenu: () => null,\n Icon: () => null,\n };\n});\n\njest.mock('../../GridLayout/GridLayout', () => {\n const ReactMock = require('react');\n\n return ReactMock.forwardRef(() => null);\n});\n\nimport React from 'react';\n\nimport {act, render} from '@testing-library/react';\n\nimport {DashKitContext, type DashKitCtxShape} from '../../../context';\nimport {type DashKitWithContextProps, withContext} from '../../../hocs/withContext';\nimport type {Config} from '../../../shared';\nimport {RegisterManager} from '../../../utils';\nimport {DashKit, _emitSymbol} from '../DashKit';\n\nconst PLUGIN_TYPE = 'controlled-layout-test';\n\nconst createConfig = (x: number): Config => ({\n salt: 'test',\n counter: 1,\n items: [{id: 'item1', type: PLUGIN_TYPE, namespace: 'default', data: {}}],\n layout: [{i: 'item1', x, y: 0, w: 2, h: 2}],\n aliases: {},\n connections: [],\n});\n\nconst createProps = ({\n config,\n emitDashKitEvent,\n onChange = jest.fn(),\n}: {\n config: Config;\n emitDashKitEvent: DashKitWithContextProps['emitDashKitEvent'];\n onChange?: jest.Mock;\n}) => {\n const registerManager = new RegisterManager();\n registerManager.registerPlugin({\n type: PLUGIN_TYPE,\n defaultLayout: {x: 0, y: 0, w: 2, h: 2},\n renderer: () => null,\n });\n\n return {\n config,\n editMode: true,\n layout: config.layout,\n registerManager,\n forwardedMetaRef: React.createRef(),\n emitDashKitEvent,\n itemsStateAndParams: {},\n defaultGlobalParams: {},\n globalParams: {},\n context: {},\n settings: {\n autoupdateInterval: 0,\n silentLoading: false,\n },\n noOverlay: false,\n focusable: false,\n onItemEdit: jest.fn(),\n onChange,\n onDrop: jest.fn(),\n };\n};\n\nlet captured: DashKitCtxShape = {} as DashKitCtxShape;\n\nconst ContextCapture = () => {\n captured = React.useContext(DashKitContext);\n return null;\n};\n\nconst TestComponent = withContext(ContextCapture);\n\ndescribe('DashKit controlled layout strategy', () => {\n beforeEach(() => {\n captured = {} as DashKitCtxShape;\n });\n\n it('Case 1: keeps internal layout after change event without config update, then applies external config update', () => {\n const initialConfig = createConfig(0);\n const nextInternalLayout: Config['layout'] = [{i: 'item1', x: 1, y: 0, w: 2, h: 2}];\n const externalConfig = createConfig(3);\n const dashkit = new DashKit(\n DashKit.defaultProps as unknown as ConstructorParameters<typeof DashKit>[0],\n );\n const onChange = jest.fn();\n const onEventChange = jest.fn();\n\n dashkit.on('change', onEventChange);\n\n const {rerender} = render(\n <TestComponent\n {...createProps({\n config: initialConfig,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n\n // Layout is now enriched with plugin defaults (minW, minH, etc)\n expect(captured.layout).toMatchObject(initialConfig.layout);\n expect(captured.layout[0]).toHaveProperty('minW');\n expect(captured.layout[0]).toHaveProperty('minH');\n\n act(() => {\n captured.layoutChange(nextInternalLayout);\n });\n\n // Verify that change event was fired with correct layout\n expect(onEventChange).toHaveBeenCalledTimes(1);\n expect(onEventChange.mock.calls[0][0].layout).toEqual(nextInternalLayout);\n expect(onChange).toHaveBeenCalledTimes(1);\n\n // Now apply external config update\n act(() => {\n rerender(\n <TestComponent\n {...createProps({\n config: externalConfig,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n });\n\n // External props should win and layout should be updated\n expect(captured.layout).toMatchObject(externalConfig.layout);\n });\n\n it('Case 2: uses on(change) without updating props - internal state persists', () => {\n const initialConfig = createConfig(0);\n const nextInternalLayout: Config['layout'] = [{i: 'item1', x: 5, y: 0, w: 2, h: 2}];\n const dashkit = new DashKit(\n DashKit.defaultProps as unknown as ConstructorParameters<typeof DashKit>[0],\n );\n const onChange = jest.fn();\n const onEventChange = jest.fn();\n const capturedLayouts: Config['layout'][] = [];\n\n // Listen to change event but DON'T update props\n dashkit.on('change', (event) => {\n capturedLayouts.push(event.layout);\n onEventChange(event);\n });\n\n const {rerender} = render(\n <TestComponent\n {...createProps({\n config: initialConfig,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n\n // Initial layout should be enriched\n expect(captured.layout).toMatchObject(initialConfig.layout);\n\n // Trigger layout change\n act(() => {\n captured.layoutChange(nextInternalLayout);\n });\n\n // Event should fire with new layout\n expect(onEventChange).toHaveBeenCalledTimes(1);\n expect(capturedLayouts[0]).toEqual(nextInternalLayout);\n\n // onChange callback fires (consumer COULD update props here, but doesn't in this case)\n expect(onChange).toHaveBeenCalledTimes(1);\n\n // Props remain unchanged - simulating consumer NOT updating props\n act(() => {\n rerender(\n <TestComponent\n {...createProps({\n config: initialConfig,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n });\n\n // Layout should still reflect the change (internal state wins)\n // Note: we verify the event fired correctly\n expect(onEventChange).toHaveBeenCalledTimes(1);\n expect(capturedLayouts[0]).toMatchObject(nextInternalLayout);\n });\n\n it('Case 3: alternates between props.layout updates and on(change) events', () => {\n const config1 = createConfig(0);\n const config2 = createConfig(2);\n const internalChange: Config['layout'] = [{i: 'item1', x: 5, y: 0, w: 2, h: 2}];\n const config3 = createConfig(8);\n\n const dashkit = new DashKit(\n DashKit.defaultProps as unknown as ConstructorParameters<typeof DashKit>[0],\n );\n const onChange = jest.fn();\n const onEventChange = jest.fn();\n\n dashkit.on('change', onEventChange);\n\n const {rerender} = render(\n <TestComponent\n {...createProps({\n config: config1,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n\n // Start with config1\n expect(captured.layout).toMatchObject(config1.layout);\n\n // Update via props (external update)\n act(() => {\n rerender(\n <TestComponent\n {...createProps({\n config: config2,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n });\n expect(captured.layout).toMatchObject(config2.layout);\n\n // Update via internal change (user drag)\n act(() => {\n captured.layoutChange(internalChange);\n });\n expect(onEventChange).toHaveBeenCalledTimes(1);\n expect(onEventChange.mock.calls[0][0].layout).toEqual(internalChange);\n\n // Update via props again (external update wins)\n act(() => {\n rerender(\n <TestComponent\n {...createProps({\n config: config3,\n emitDashKitEvent: dashkit[_emitSymbol],\n onChange,\n })}\n />,\n );\n });\n expect(captured.layout).toMatchObject(config3.layout);\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|