@flowgram.ai/panel-manager-plugin 0.4.18 → 0.5.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/.rush/temp/chunked-rush-logs/panel-manager-plugin.build.chunks.jsonl +9 -9
- package/.rush/temp/package-deps_build.json +13 -12
- package/.rush/temp/shrinkwrap-deps.json +4 -1
- package/CHANGELOG.json +3 -3
- package/CHANGELOG.md +3 -3
- package/dist/esm/index.js +163 -51
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +36 -12
- package/dist/index.d.ts +36 -12
- package/dist/index.js +175 -52
- package/dist/index.js.map +1 -1
- package/package.json +9 -6
- package/rush-logs/panel-manager-plugin.build.log +9 -9
- package/src/components/panel-layer/css.ts +8 -0
- package/src/components/panel-layer/float-panel.tsx +22 -8
- package/src/components/panel-layer/panel-layer.tsx +7 -6
- package/src/components/resize-bar/index.tsx +80 -0
- package/src/create-panel-manager-plugin.ts +2 -4
- package/src/index.ts +2 -0
- package/src/services/float-panel.ts +26 -2
- package/src/services/panel-config.ts +6 -0
- package/src/services/panel-layer.ts +25 -17
- package/src/services/panel-manager.ts +4 -4
- package/src/types.ts +2 -0
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useEffect, useRef, startTransition, useState } from 'react';
|
|
6
|
+
import { useEffect, useRef, startTransition, useState, useCallback } from 'react';
|
|
7
7
|
|
|
8
8
|
import { Area } from '../../types';
|
|
9
9
|
import { usePanelManager } from '../../hooks/use-panel-manager';
|
|
10
10
|
import { floatPanelWrap } from './css';
|
|
11
|
+
import { ResizeBar } from '../resize-bar';
|
|
11
12
|
|
|
12
13
|
export const FloatPanel: React.FC<{ area: Area }> = ({ area }) => {
|
|
13
14
|
const [, setVersion] = useState(0);
|
|
@@ -15,12 +16,7 @@ export const FloatPanel: React.FC<{ area: Area }> = ({ area }) => {
|
|
|
15
16
|
const panel = useRef(panelManager.getPanel(area));
|
|
16
17
|
const render = () =>
|
|
17
18
|
panel.current.elements.map((i) => (
|
|
18
|
-
<div
|
|
19
|
-
className="float-panel-wrap"
|
|
20
|
-
key={i.key}
|
|
21
|
-
style={floatPanelWrap}
|
|
22
|
-
onMouseDown={(e) => e.stopPropagation()}
|
|
23
|
-
>
|
|
19
|
+
<div className="float-panel-wrap" key={i.key} style={{ ...floatPanelWrap, ...i.style }}>
|
|
24
20
|
{i.el}
|
|
25
21
|
</div>
|
|
26
22
|
));
|
|
@@ -35,6 +31,24 @@ export const FloatPanel: React.FC<{ area: Area }> = ({ area }) => {
|
|
|
35
31
|
});
|
|
36
32
|
return () => dispose.dispose();
|
|
37
33
|
}, [panel]);
|
|
34
|
+
const onResize = useCallback((newSize: number) => panel.current!.updateSize(newSize), []);
|
|
35
|
+
const size = panel.current!.currentSize;
|
|
36
|
+
const sizeStyle =
|
|
37
|
+
area === 'right' ? { width: size, height: '100%' } : { height: size, width: '100%' };
|
|
38
38
|
|
|
39
|
-
return
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className="gedit-flow-panel"
|
|
42
|
+
style={{
|
|
43
|
+
position: 'relative',
|
|
44
|
+
display: panel.current.visible ? 'block' : 'none',
|
|
45
|
+
...sizeStyle,
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{panelManager.config.autoResize && (
|
|
49
|
+
<ResizeBar size={size} isVertical={area === 'right'} onResize={onResize} />
|
|
50
|
+
)}
|
|
51
|
+
{node.current}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
40
54
|
};
|
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { FloatPanel } from './float-panel';
|
|
7
|
-
import { panelLayer, leftArea, rightArea, mainArea, bottomArea } from './css';
|
|
7
|
+
import { panelLayer, leftArea, rightArea, mainArea, bottomArea, globalCSS } from './css';
|
|
8
8
|
|
|
9
9
|
export const PanelLayer: React.FC<React.PropsWithChildren> = ({ children }) => (
|
|
10
|
-
<div
|
|
11
|
-
<
|
|
12
|
-
|
|
10
|
+
<div style={panelLayer}>
|
|
11
|
+
<style dangerouslySetInnerHTML={{ __html: globalCSS }} />
|
|
12
|
+
<div className="gedit-flow-panel-left-area" style={leftArea}>
|
|
13
|
+
<div className="gedit-flow-panel-main-area" style={mainArea}>
|
|
13
14
|
{children}
|
|
14
15
|
</div>
|
|
15
|
-
<div className="bottom-area" style={bottomArea}>
|
|
16
|
+
<div className="gedit-flow-panel-bottom-area" style={bottomArea}>
|
|
16
17
|
<FloatPanel area="bottom" />
|
|
17
18
|
</div>
|
|
18
19
|
</div>
|
|
19
|
-
<div className="right-area" style={rightArea}>
|
|
20
|
+
<div className="gedit-flow-panel-right-area" style={rightArea}>
|
|
20
21
|
<FloatPanel area="right" />
|
|
21
22
|
</div>
|
|
22
23
|
</div>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useRef, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
onResize: (w: number) => void;
|
|
10
|
+
size: number;
|
|
11
|
+
isVertical?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ResizeBar: React.FC<Props> = ({ onResize, size, isVertical }) => {
|
|
15
|
+
const currentPoint = useRef<null | number>(null);
|
|
16
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
17
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
onMouseDown={(e) => {
|
|
21
|
+
currentPoint.current = isVertical ? e.clientX : e.clientY;
|
|
22
|
+
e.stopPropagation();
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
setIsDragging(true);
|
|
25
|
+
const mouseUp = () => {
|
|
26
|
+
currentPoint.current = null;
|
|
27
|
+
document.body.removeEventListener('mouseup', mouseUp);
|
|
28
|
+
document.body.removeEventListener('mousemove', mouseMove);
|
|
29
|
+
setIsDragging(false);
|
|
30
|
+
};
|
|
31
|
+
const mouseMove = (e: MouseEvent) => {
|
|
32
|
+
const delta = currentPoint.current! - (isVertical ? e.clientX : e.clientY);
|
|
33
|
+
onResize(size + delta);
|
|
34
|
+
};
|
|
35
|
+
document.body.addEventListener('mouseup', mouseUp);
|
|
36
|
+
document.body.addEventListener('mousemove', mouseMove);
|
|
37
|
+
}}
|
|
38
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
39
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
40
|
+
style={{
|
|
41
|
+
position: 'absolute',
|
|
42
|
+
top: 0,
|
|
43
|
+
left: 0,
|
|
44
|
+
zIndex: 999,
|
|
45
|
+
display: 'flex',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
justifyContent: 'center',
|
|
48
|
+
pointerEvents: 'auto',
|
|
49
|
+
...(isVertical
|
|
50
|
+
? {
|
|
51
|
+
cursor: 'ew-resize',
|
|
52
|
+
height: '100%',
|
|
53
|
+
marginLeft: -5,
|
|
54
|
+
width: 10,
|
|
55
|
+
}
|
|
56
|
+
: {
|
|
57
|
+
cursor: 'ns-resize',
|
|
58
|
+
width: '100%',
|
|
59
|
+
marginTop: -5,
|
|
60
|
+
height: 10,
|
|
61
|
+
}),
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<div
|
|
65
|
+
style={{
|
|
66
|
+
...(isVertical
|
|
67
|
+
? {
|
|
68
|
+
width: 3,
|
|
69
|
+
height: '100%',
|
|
70
|
+
}
|
|
71
|
+
: {
|
|
72
|
+
height: 3,
|
|
73
|
+
width: '100%',
|
|
74
|
+
}),
|
|
75
|
+
backgroundColor: isDragging || isHovered ? 'var(--g-playground-line)' : 'transparent',
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
@@ -9,14 +9,12 @@ import { defineConfig } from './services/panel-config';
|
|
|
9
9
|
import { PanelManager, PanelManagerConfig, PanelLayer } from './services';
|
|
10
10
|
|
|
11
11
|
export const createPanelManagerPlugin = definePluginCreator<Partial<PanelManagerConfig>>({
|
|
12
|
-
onBind: ({ bind }) => {
|
|
12
|
+
onBind: ({ bind }, opt) => {
|
|
13
13
|
bind(PanelManager).to(PanelManager).inSingletonScope();
|
|
14
|
-
bind(PanelManagerConfig).toConstantValue(defineConfig(
|
|
14
|
+
bind(PanelManagerConfig).toConstantValue(defineConfig(opt));
|
|
15
15
|
},
|
|
16
16
|
onInit(ctx, opt) {
|
|
17
17
|
ctx.playground.registerLayer(PanelLayer);
|
|
18
|
-
const config = defineConfig(opt);
|
|
19
|
-
ctx.container.rebind(PanelManagerConfig).toConstantValue(config);
|
|
20
18
|
const panelManager = ctx.container.get<PanelManager>(PanelManager);
|
|
21
19
|
panelManager.init();
|
|
22
20
|
},
|
package/src/index.ts
CHANGED
|
@@ -9,25 +9,45 @@ import type { PanelFactory, PanelConfig } from '../types';
|
|
|
9
9
|
|
|
10
10
|
export interface PanelElement {
|
|
11
11
|
key: string;
|
|
12
|
+
style?: React.CSSProperties;
|
|
12
13
|
el: React.ReactNode;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
const PANEL_SIZE_DEFAULT = 400;
|
|
17
|
+
|
|
15
18
|
export class FloatPanel {
|
|
16
19
|
elements: PanelElement[] = [];
|
|
17
20
|
|
|
18
21
|
private onUpdateEmitter = new Emitter<void>();
|
|
19
22
|
|
|
23
|
+
sizeMap = new Map<string, number>();
|
|
24
|
+
|
|
20
25
|
onUpdate = this.onUpdateEmitter.event;
|
|
21
26
|
|
|
27
|
+
currentFactoryKey = '';
|
|
28
|
+
|
|
29
|
+
updateSize(newSize: number) {
|
|
30
|
+
this.sizeMap.set(this.currentFactoryKey, newSize);
|
|
31
|
+
this.onUpdateEmitter.fire();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get currentSize(): number {
|
|
35
|
+
return this.sizeMap.get(this.currentFactoryKey) || PANEL_SIZE_DEFAULT;
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
constructor(private config: PanelConfig) {}
|
|
23
39
|
|
|
24
40
|
open(factory: PanelFactory<any>, options: any) {
|
|
25
41
|
const el = factory.render(options?.props);
|
|
26
42
|
const idx = this.elements.findIndex((e) => e.key === factory.key);
|
|
43
|
+
this.currentFactoryKey = factory.key;
|
|
44
|
+
if (!this.sizeMap.has(factory.key)) {
|
|
45
|
+
this.sizeMap.set(factory.key, factory.defaultSize || PANEL_SIZE_DEFAULT);
|
|
46
|
+
}
|
|
27
47
|
if (idx >= 0) {
|
|
28
|
-
this.elements[idx] = { el, key: factory.key };
|
|
48
|
+
this.elements[idx] = { el, key: factory.key, style: factory.style };
|
|
29
49
|
} else {
|
|
30
|
-
this.elements.push({ el, key: factory.key });
|
|
50
|
+
this.elements.push({ el, key: factory.key, style: factory.style });
|
|
31
51
|
if (this.elements.length > this.config.max) {
|
|
32
52
|
this.elements.shift();
|
|
33
53
|
}
|
|
@@ -35,6 +55,10 @@ export class FloatPanel {
|
|
|
35
55
|
this.onUpdateEmitter.fire();
|
|
36
56
|
}
|
|
37
57
|
|
|
58
|
+
get visible() {
|
|
59
|
+
return this.elements.length > 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
38
62
|
close(key?: string) {
|
|
39
63
|
if (!key) {
|
|
40
64
|
this.elements = [];
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { PluginContext } from '@flowgram.ai/core';
|
|
7
|
+
|
|
6
8
|
import type { PanelFactory, PanelConfig } from '../types';
|
|
7
9
|
|
|
8
10
|
export interface PanelManagerConfig {
|
|
9
11
|
factories: PanelFactory<any>[];
|
|
10
12
|
right: PanelConfig;
|
|
11
13
|
bottom: PanelConfig;
|
|
14
|
+
getPopupContainer: (ctx: PluginContext) => HTMLElement; // default playground.node.parentElement
|
|
15
|
+
autoResize: boolean;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
export const PanelManagerConfig = Symbol('PanelManagerConfig');
|
|
@@ -22,6 +26,8 @@ export const defineConfig = (config: Partial<PanelManagerConfig>) => {
|
|
|
22
26
|
max: 1,
|
|
23
27
|
},
|
|
24
28
|
factories: [],
|
|
29
|
+
getPopupContainer: (ctx: PluginContext) => ctx.playground.node.parentNode as HTMLElement,
|
|
30
|
+
autoResize: true,
|
|
25
31
|
};
|
|
26
32
|
return {
|
|
27
33
|
...defaultConfig,
|
|
@@ -3,42 +3,50 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import ReactDOM from 'react-dom';
|
|
6
7
|
import { createElement } from 'react';
|
|
7
8
|
|
|
8
|
-
import { injectable } from 'inversify';
|
|
9
|
-
import { domUtils } from '@flowgram.ai/utils';
|
|
10
|
-
import { Layer } from '@flowgram.ai/core';
|
|
9
|
+
import { injectable, inject } from 'inversify';
|
|
10
|
+
import { domUtils, Disposable } from '@flowgram.ai/utils';
|
|
11
|
+
import { Layer, PluginContext } from '@flowgram.ai/core';
|
|
11
12
|
|
|
12
13
|
import { PanelLayer as PanelLayerComp } from '../components/panel-layer';
|
|
14
|
+
import { PanelManagerConfig } from './panel-config';
|
|
13
15
|
|
|
14
16
|
@injectable()
|
|
15
17
|
export class PanelLayer extends Layer {
|
|
16
|
-
|
|
18
|
+
@inject(PanelManagerConfig) private readonly panelConfig: PanelManagerConfig;
|
|
19
|
+
|
|
20
|
+
@inject(PluginContext) private readonly pluginContext: PluginContext;
|
|
21
|
+
|
|
22
|
+
readonly panelRoot = domUtils.createDivWithClass('gedit-flow-panel-layer');
|
|
17
23
|
|
|
18
24
|
layout: JSX.Element | null = null;
|
|
19
25
|
|
|
20
26
|
onReady(): void {
|
|
27
|
+
this.panelConfig.getPopupContainer(this.pluginContext).appendChild(this.panelRoot);
|
|
28
|
+
this.toDispose.push(
|
|
29
|
+
Disposable.create(() => {
|
|
30
|
+
// Remove from PopupContainer
|
|
31
|
+
this.panelRoot.remove();
|
|
32
|
+
})
|
|
33
|
+
);
|
|
21
34
|
const commonStyle = {
|
|
22
35
|
pointerEvents: 'none',
|
|
23
|
-
|
|
36
|
+
width: '100%',
|
|
37
|
+
height: '100%',
|
|
38
|
+
position: 'absolute',
|
|
39
|
+
left: 0,
|
|
40
|
+
top: 0,
|
|
41
|
+
zIndex: 100,
|
|
24
42
|
};
|
|
25
|
-
domUtils.setStyle(this.
|
|
26
|
-
this.config.onDataChange(() => {
|
|
27
|
-
const { width, height, scrollX, scrollY } = this.config.config;
|
|
28
|
-
domUtils.setStyle(this.node, {
|
|
29
|
-
...commonStyle,
|
|
30
|
-
width,
|
|
31
|
-
height,
|
|
32
|
-
left: scrollX,
|
|
33
|
-
top: scrollY,
|
|
34
|
-
});
|
|
35
|
-
});
|
|
43
|
+
domUtils.setStyle(this.panelRoot, commonStyle);
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
render(): JSX.Element {
|
|
39
47
|
if (!this.layout) {
|
|
40
48
|
this.layout = createElement(PanelLayerComp);
|
|
41
49
|
}
|
|
42
|
-
return this.layout;
|
|
50
|
+
return ReactDOM.createPortal(this.layout, this.panelRoot);
|
|
43
51
|
}
|
|
44
52
|
}
|
|
@@ -11,7 +11,7 @@ import { FloatPanel } from './float-panel';
|
|
|
11
11
|
|
|
12
12
|
@injectable()
|
|
13
13
|
export class PanelManager {
|
|
14
|
-
@inject(PanelManagerConfig)
|
|
14
|
+
@inject(PanelManagerConfig) readonly config: PanelManagerConfig;
|
|
15
15
|
|
|
16
16
|
readonly panelRegistry = new Map<string, PanelFactory<any>>();
|
|
17
17
|
|
|
@@ -38,9 +38,9 @@ export class PanelManager {
|
|
|
38
38
|
panel.open(factory, options);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
close(key
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
close(key?: string) {
|
|
42
|
+
this.right.close(key);
|
|
43
|
+
this.bottom.close(key);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
getPanel(area: Area) {
|