@flowgram.ai/panel-manager-plugin 0.1.8

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.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Emitter } from '@flowgram.ai/utils';
7
+
8
+ import type { PanelFactory, PanelConfig } from '../types';
9
+
10
+ export interface PanelElement {
11
+ key: string;
12
+ el: React.ReactNode;
13
+ }
14
+
15
+ export class FloatPanel {
16
+ elements: PanelElement[] = [];
17
+
18
+ private onUpdateEmitter = new Emitter<void>();
19
+
20
+ onUpdate = this.onUpdateEmitter.event;
21
+
22
+ constructor(private config: PanelConfig) {}
23
+
24
+ open(factory: PanelFactory<any>, options: any) {
25
+ const el = factory.render(options?.props);
26
+ const idx = this.elements.findIndex((e) => e.key === factory.key);
27
+ if (idx >= 0) {
28
+ this.elements[idx] = { el, key: factory.key };
29
+ } else {
30
+ this.elements.push({ el, key: factory.key });
31
+ if (this.elements.length > this.config.max) {
32
+ this.elements.shift();
33
+ }
34
+ }
35
+ this.onUpdateEmitter.fire();
36
+ }
37
+
38
+ close(key?: string) {
39
+ if (!key) {
40
+ this.elements = [];
41
+ } else {
42
+ this.elements = this.elements.filter((e) => e.key !== key);
43
+ }
44
+ this.onUpdateEmitter.fire();
45
+ }
46
+
47
+ dispose() {
48
+ this.elements = [];
49
+ this.onUpdateEmitter.dispose();
50
+ }
51
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export { PanelManager } from './panel-manager';
7
+ export { PanelManagerConfig } from './panel-config';
8
+ export { PanelLayer } from './panel-layer';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import type { PanelFactory, PanelConfig } from '../types';
7
+
8
+ export interface PanelManagerConfig {
9
+ factories: PanelFactory<any>[];
10
+ right: PanelConfig;
11
+ bottom: PanelConfig;
12
+ }
13
+
14
+ export const PanelManagerConfig = Symbol('PanelManagerConfig');
15
+
16
+ export const defineConfig = (config: Partial<PanelManagerConfig>) => {
17
+ const defaultConfig: PanelManagerConfig = {
18
+ right: {
19
+ max: 1,
20
+ },
21
+ bottom: {
22
+ max: 1,
23
+ },
24
+ factories: [],
25
+ };
26
+ return {
27
+ ...defaultConfig,
28
+ ...config,
29
+ };
30
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { createElement } from 'react';
7
+
8
+ import { injectable } from 'inversify';
9
+ import { domUtils } from '@flowgram.ai/utils';
10
+ import { Layer } from '@flowgram.ai/core';
11
+
12
+ import { PanelLayer as PanelLayerComp } from '../components/panel-layer';
13
+
14
+ @injectable()
15
+ export class PanelLayer extends Layer {
16
+ node = domUtils.createDivWithClass('gedit-flow-panel-layer');
17
+
18
+ layout: JSX.Element | null = null;
19
+
20
+ onReady(): void {
21
+ const commonStyle = {
22
+ pointerEvents: 'none',
23
+ zIndex: 11,
24
+ };
25
+ domUtils.setStyle(this.node, commonStyle);
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
+ });
36
+ }
37
+
38
+ render(): JSX.Element {
39
+ if (!this.layout) {
40
+ this.layout = createElement(PanelLayerComp);
41
+ }
42
+ return this.layout;
43
+ }
44
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { injectable, inject } from 'inversify';
7
+
8
+ import { PanelManagerConfig } from './panel-config';
9
+ import type { Area, PanelFactory } from '../types';
10
+ import { FloatPanel } from './float-panel';
11
+
12
+ @injectable()
13
+ export class PanelManager {
14
+ @inject(PanelManagerConfig) private readonly config: PanelManagerConfig;
15
+
16
+ readonly panelRegistry = new Map<string, PanelFactory<any>>();
17
+
18
+ right: FloatPanel;
19
+
20
+ bottom: FloatPanel;
21
+
22
+ init() {
23
+ this.config.factories.forEach((factory) => this.register(factory));
24
+ this.right = new FloatPanel(this.config.right);
25
+ this.bottom = new FloatPanel(this.config.bottom);
26
+ }
27
+
28
+ register<T extends any>(factory: PanelFactory<T>) {
29
+ this.panelRegistry.set(factory.key, factory);
30
+ }
31
+
32
+ open(key: string, area: Area = 'right', options?: any) {
33
+ const factory = this.panelRegistry.get(key);
34
+ if (!factory) {
35
+ return;
36
+ }
37
+ const panel = this.getPanel(area);
38
+ panel.open(factory, options);
39
+ }
40
+
41
+ close(key: string, area: Area = 'right') {
42
+ const panel = this.getPanel(area);
43
+ panel.close(key);
44
+ }
45
+
46
+ getPanel(area: Area) {
47
+ return area === 'right' ? this.right : this.bottom;
48
+ }
49
+
50
+ dispose() {
51
+ this.right.dispose();
52
+ this.bottom.dispose();
53
+ }
54
+ }
package/src/types.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export type Area = 'right' | 'bottom';
7
+
8
+ export interface PanelConfig {
9
+ /** max panel */
10
+ max: number;
11
+ }
12
+
13
+ export interface PanelFactory<T extends any> {
14
+ key: string;
15
+ render: (props: T) => React.ReactNode;
16
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "@flowgram.ai/ts-config/tsconfig.flow.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx"
5
+ },
6
+ "include": [
7
+ "./src"
8
+ ],
9
+ "exclude": [
10
+ "node_modules"
11
+ ]
12
+ }