@flowgram.ai/panel-manager-plugin 0.1.0-alpha.18 → 0.1.0-alpha.20
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 +15 -13
- package/.rush/temp/shrinkwrap-deps.json +5 -1
- package/dist/esm/index.js +205 -67
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +46 -12
- package/dist/index.d.ts +46 -12
- package/dist/index.js +215 -66
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
- package/rush-logs/panel-manager-plugin.build.log +9 -9
- package/src/components/panel-layer/css.ts +18 -13
- package/src/components/panel-layer/float-panel.tsx +22 -8
- package/src/components/panel-layer/index.ts +1 -1
- package/src/components/panel-layer/panel-layer.tsx +28 -13
- package/src/components/resize-bar/index.tsx +80 -0
- package/src/create-panel-manager-plugin.ts +3 -5
- package/src/hooks/use-global-css.ts +31 -0
- package/src/index.ts +3 -1
- package/src/services/float-panel.ts +26 -2
- package/src/services/panel-config.ts +9 -0
- package/src/services/panel-layer.ts +27 -18
- package/src/services/panel-manager.ts +4 -4
- package/src/types.ts +2 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/create-panel-manager-plugin.ts","../src/services/panel-config.ts","../src/services/panel-manager.ts","../src/services/float-panel.ts","../src/services/panel-layer.ts","../src/components/panel-layer/float-panel.tsx","../src/hooks/use-panel-manager.ts","../src/components/panel-layer/css.ts","../src/components/panel-layer/panel-layer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/** create plugin function */\nexport { createPanelManagerPlugin } from './create-panel-manager-plugin';\n\n/** services */\nexport { PanelManager } from './services';\n\n/** react hooks */\nexport { usePanelManager } from './hooks/use-panel-manager';\n\n/** types */\nexport type { Area, PanelFactory } from './types';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport { defineConfig } from './services/panel-config';\nimport { PanelManager, PanelManagerConfig, PanelLayer } from './services';\n\nexport const createPanelManagerPlugin = definePluginCreator<Partial<PanelManagerConfig>>({\n onBind: ({ bind }) => {\n bind(PanelManager).to(PanelManager).inSingletonScope();\n bind(PanelManagerConfig).toConstantValue(defineConfig({}));\n },\n onInit(ctx, opt) {\n ctx.playground.registerLayer(PanelLayer);\n const config = defineConfig(opt);\n ctx.container.rebind(PanelManagerConfig).toConstantValue(config);\n const panelManager = ctx.container.get<PanelManager>(PanelManager);\n panelManager.init();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { PanelFactory, PanelConfig } from '../types';\n\nexport interface PanelManagerConfig {\n factories: PanelFactory<any>[];\n right: PanelConfig;\n bottom: PanelConfig;\n}\n\nexport const PanelManagerConfig = Symbol('PanelManagerConfig');\n\nexport const defineConfig = (config: Partial<PanelManagerConfig>) => {\n const defaultConfig: PanelManagerConfig = {\n right: {\n max: 1,\n },\n bottom: {\n max: 1,\n },\n factories: [],\n };\n return {\n ...defaultConfig,\n ...config,\n };\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable, inject } from 'inversify';\n\nimport { PanelManagerConfig } from './panel-config';\nimport type { Area, PanelFactory } from '../types';\nimport { FloatPanel } from './float-panel';\n\n@injectable()\nexport class PanelManager {\n @inject(PanelManagerConfig) private readonly config: PanelManagerConfig;\n\n readonly panelRegistry = new Map<string, PanelFactory<any>>();\n\n right: FloatPanel;\n\n bottom: FloatPanel;\n\n init() {\n this.config.factories.forEach((factory) => this.register(factory));\n this.right = new FloatPanel(this.config.right);\n this.bottom = new FloatPanel(this.config.bottom);\n }\n\n register<T extends any>(factory: PanelFactory<T>) {\n this.panelRegistry.set(factory.key, factory);\n }\n\n open(key: string, area: Area = 'right', options?: any) {\n const factory = this.panelRegistry.get(key);\n if (!factory) {\n return;\n }\n const panel = this.getPanel(area);\n panel.open(factory, options);\n }\n\n close(key: string, area: Area = 'right') {\n const panel = this.getPanel(area);\n panel.close(key);\n }\n\n getPanel(area: Area) {\n return area === 'right' ? this.right : this.bottom;\n }\n\n dispose() {\n this.right.dispose();\n this.bottom.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Emitter } from '@flowgram.ai/utils';\n\nimport type { PanelFactory, PanelConfig } from '../types';\n\nexport interface PanelElement {\n key: string;\n el: React.ReactNode;\n}\n\nexport class FloatPanel {\n elements: PanelElement[] = [];\n\n private onUpdateEmitter = new Emitter<void>();\n\n onUpdate = this.onUpdateEmitter.event;\n\n constructor(private config: PanelConfig) {}\n\n open(factory: PanelFactory<any>, options: any) {\n const el = factory.render(options?.props);\n const idx = this.elements.findIndex((e) => e.key === factory.key);\n if (idx >= 0) {\n this.elements[idx] = { el, key: factory.key };\n } else {\n this.elements.push({ el, key: factory.key });\n if (this.elements.length > this.config.max) {\n this.elements.shift();\n }\n }\n this.onUpdateEmitter.fire();\n }\n\n close(key?: string) {\n if (!key) {\n this.elements = [];\n } else {\n this.elements = this.elements.filter((e) => e.key !== key);\n }\n this.onUpdateEmitter.fire();\n }\n\n dispose() {\n this.elements = [];\n this.onUpdateEmitter.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { createElement } from 'react';\n\nimport { injectable } from 'inversify';\nimport { domUtils } from '@flowgram.ai/utils';\nimport { Layer } from '@flowgram.ai/core';\n\nimport { PanelLayer as PanelLayerComp } from '../components/panel-layer';\n\n@injectable()\nexport class PanelLayer extends Layer {\n node = domUtils.createDivWithClass('gedit-flow-panel-layer');\n\n layout: JSX.Element | null = null;\n\n onReady(): void {\n const commonStyle = {\n pointerEvents: 'none',\n zIndex: 11,\n };\n domUtils.setStyle(this.node, commonStyle);\n this.config.onDataChange(() => {\n const { width, height, scrollX, scrollY } = this.config.config;\n domUtils.setStyle(this.node, {\n ...commonStyle,\n width,\n height,\n left: scrollX,\n top: scrollY,\n });\n });\n }\n\n render(): JSX.Element {\n if (!this.layout) {\n this.layout = createElement(PanelLayerComp);\n }\n return this.layout;\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect, useRef, startTransition, useState } from 'react';\n\nimport { Area } from '../../types';\nimport { usePanelManager } from '../../hooks/use-panel-manager';\nimport { floatPanelWrap } from './css';\n\nexport const FloatPanel: React.FC<{ area: Area }> = ({ area }) => {\n const [, setVersion] = useState(0);\n const panelManager = usePanelManager();\n const panel = useRef(panelManager.getPanel(area));\n const render = () =>\n panel.current.elements.map((i) => (\n <div\n className=\"float-panel-wrap\"\n key={i.key}\n style={floatPanelWrap}\n onMouseDown={(e) => e.stopPropagation()}\n >\n {i.el}\n </div>\n ));\n const node = useRef(render());\n\n useEffect(() => {\n const dispose = panel.current.onUpdate(() => {\n startTransition(() => {\n node.current = render();\n setVersion((v) => v + 1);\n });\n });\n return () => dispose.dispose();\n }, [panel]);\n\n return <>{node.current}</>;\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useService } from '@flowgram.ai/core';\n\nimport { PanelManager } from '../services/panel-manager';\n\nexport const usePanelManager = () => useService<PanelManager>(PanelManager);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport const panelLayer: React.CSSProperties = {\n pointerEvents: 'none',\n position: 'absolute',\n top: 0,\n left: 0,\n\n display: 'flex',\n columnGap: '4px',\n width: '100%',\n height: '100%',\n padding: '4px',\n boxSizing: 'border-box',\n};\n\nexport const leftArea: React.CSSProperties = {\n width: '100%',\n minWidth: 0,\n flexGrow: 0,\n flexShrink: 1,\n\n display: 'flex',\n flexDirection: 'column',\n rowGap: '4px',\n};\n\nexport const rightArea: React.CSSProperties = {\n height: '100%',\n flexGrow: 1,\n flexShrink: 0,\n minWidth: 0,\n\n display: 'flex',\n columnGap: '4px',\n};\n\nexport const mainArea: React.CSSProperties = {\n position: 'relative',\n overflow: 'hidden',\n flexGrow: 0,\n flexShrink: 1,\n width: '100%',\n height: '100%',\n};\n\nexport const bottomArea: React.CSSProperties = {\n flexGrow: 1,\n flexShrink: 0,\n width: '100%',\n minHeight: 0,\n};\n\nexport const floatPanelWrap: React.CSSProperties = {\n pointerEvents: 'auto',\n height: '100%',\n width: '100%',\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FloatPanel } from './float-panel';\nimport { panelLayer, leftArea, rightArea, mainArea, bottomArea } from './css';\n\nexport const PanelLayer: React.FC<React.PropsWithChildren> = ({ children }) => (\n <div className=\"panel-layer\" style={panelLayer}>\n <div className=\"left-area\" style={leftArea}>\n <div className=\"main-area\" style={mainArea}>\n {children}\n </div>\n <div className=\"bottom-area\" style={bottomArea}>\n <FloatPanel area=\"bottom\" />\n </div>\n </div>\n <div className=\"right-area\" style={rightArea}>\n <FloatPanel area=\"right\" />\n </div>\n </div>\n);\n"],"mappings":"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","names":["import_core","import_react","import_inversify","import_utils","import_core","FloatPanel","import_jsx_runtime","FloatPanel","PanelLayer","PanelLayer"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create-panel-manager-plugin.ts","../src/services/panel-config.ts","../src/services/panel-manager.ts","../src/services/float-panel.ts","../src/services/panel-layer.ts","../src/components/panel-layer/panel-layer.tsx","../src/hooks/use-global-css.ts","../src/components/panel-layer/float-panel.tsx","../src/hooks/use-panel-manager.ts","../src/components/panel-layer/css.ts","../src/components/resize-bar/index.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/** create plugin function */\nexport { createPanelManagerPlugin } from './create-panel-manager-plugin';\n\n/** services */\nexport { PanelManager, type PanelManagerConfig } from './services';\n\n/** react hooks */\nexport { usePanelManager } from './hooks/use-panel-manager';\n\nexport { ResizeBar } from './components/resize-bar';\n\n/** types */\nexport type { Area, PanelFactory } from './types';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport { defineConfig } from './services/panel-config';\nimport { PanelManager, PanelManagerConfig, PanelLayer } from './services';\n\nexport const createPanelManagerPlugin = definePluginCreator<Partial<PanelManagerConfig>>({\n onBind: ({ bind }, opt) => {\n bind(PanelManager).to(PanelManager).inSingletonScope();\n bind(PanelManagerConfig).toConstantValue(defineConfig(opt));\n },\n onInit(ctx) {\n ctx.playground.registerLayer(PanelLayer);\n const panelManager = ctx.container.get<PanelManager>(PanelManager);\n panelManager.init();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport type { PanelFactory, PanelConfig } from '../types';\nimport type { PanelLayerProps } from '../components/panel-layer';\n\nexport interface PanelManagerConfig {\n factories: PanelFactory<any>[];\n right: PanelConfig;\n bottom: PanelConfig;\n autoResize: boolean;\n layerProps: PanelLayerProps;\n getPopupContainer: (ctx: PluginContext) => HTMLElement; // default playground.node.parentElement\n}\n\nexport const PanelManagerConfig = Symbol('PanelManagerConfig');\n\nexport const defineConfig = (config: Partial<PanelManagerConfig>) => {\n const defaultConfig: PanelManagerConfig = {\n right: {\n max: 1,\n },\n bottom: {\n max: 1,\n },\n factories: [],\n autoResize: true,\n layerProps: {},\n getPopupContainer: (ctx: PluginContext) => ctx.playground.node.parentNode as HTMLElement,\n };\n return {\n ...defaultConfig,\n ...config,\n };\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable, inject } from 'inversify';\n\nimport { PanelManagerConfig } from './panel-config';\nimport type { Area, PanelFactory } from '../types';\nimport { FloatPanel } from './float-panel';\n\n@injectable()\nexport class PanelManager {\n @inject(PanelManagerConfig) readonly config: PanelManagerConfig;\n\n readonly panelRegistry = new Map<string, PanelFactory<any>>();\n\n right: FloatPanel;\n\n bottom: FloatPanel;\n\n init() {\n this.config.factories.forEach((factory) => this.register(factory));\n this.right = new FloatPanel(this.config.right);\n this.bottom = new FloatPanel(this.config.bottom);\n }\n\n register<T extends any>(factory: PanelFactory<T>) {\n this.panelRegistry.set(factory.key, factory);\n }\n\n open(key: string, area: Area = 'right', options?: any) {\n const factory = this.panelRegistry.get(key);\n if (!factory) {\n return;\n }\n const panel = this.getPanel(area);\n panel.open(factory, options);\n }\n\n close(key?: string) {\n this.right.close(key);\n this.bottom.close(key);\n }\n\n getPanel(area: Area) {\n return area === 'right' ? this.right : this.bottom;\n }\n\n dispose() {\n this.right.dispose();\n this.bottom.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Emitter } from '@flowgram.ai/utils';\n\nimport type { PanelFactory, PanelConfig } from '../types';\n\nexport interface PanelElement {\n key: string;\n style?: React.CSSProperties;\n el: React.ReactNode;\n}\n\nconst PANEL_SIZE_DEFAULT = 400;\n\nexport class FloatPanel {\n elements: PanelElement[] = [];\n\n private onUpdateEmitter = new Emitter<void>();\n\n sizeMap = new Map<string, number>();\n\n onUpdate = this.onUpdateEmitter.event;\n\n currentFactoryKey = '';\n\n updateSize(newSize: number) {\n this.sizeMap.set(this.currentFactoryKey, newSize);\n this.onUpdateEmitter.fire();\n }\n\n get currentSize(): number {\n return this.sizeMap.get(this.currentFactoryKey) || PANEL_SIZE_DEFAULT;\n }\n\n constructor(private config: PanelConfig) {}\n\n open(factory: PanelFactory<any>, options: any) {\n const el = factory.render(options?.props);\n const idx = this.elements.findIndex((e) => e.key === factory.key);\n this.currentFactoryKey = factory.key;\n if (!this.sizeMap.has(factory.key)) {\n this.sizeMap.set(factory.key, factory.defaultSize || PANEL_SIZE_DEFAULT);\n }\n if (idx >= 0) {\n this.elements[idx] = { el, key: factory.key, style: factory.style };\n } else {\n this.elements.push({ el, key: factory.key, style: factory.style });\n if (this.elements.length > this.config.max) {\n this.elements.shift();\n }\n }\n this.onUpdateEmitter.fire();\n }\n\n get visible() {\n return this.elements.length > 0;\n }\n\n close(key?: string) {\n if (!key) {\n this.elements = [];\n } else {\n this.elements = this.elements.filter((e) => e.key !== key);\n }\n this.onUpdateEmitter.fire();\n }\n\n dispose() {\n this.elements = [];\n this.onUpdateEmitter.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport ReactDOM from 'react-dom';\nimport { createElement } from 'react';\n\nimport { injectable, inject } from 'inversify';\nimport { domUtils, Disposable } from '@flowgram.ai/utils';\nimport { Layer, PluginContext } from '@flowgram.ai/core';\n\nimport { PanelLayer as PanelLayerComp } from '../components/panel-layer';\nimport { PanelManagerConfig } from './panel-config';\n\n@injectable()\nexport class PanelLayer extends Layer {\n @inject(PanelManagerConfig) private readonly panelConfig: PanelManagerConfig;\n\n @inject(PluginContext) private readonly pluginContext: PluginContext;\n\n readonly panelRoot = domUtils.createDivWithClass('gedit-flow-panel-layer');\n\n layout: JSX.Element | null = null;\n\n onReady(): void {\n this.panelConfig.getPopupContainer(this.pluginContext).appendChild(this.panelRoot);\n this.toDispose.push(\n Disposable.create(() => {\n // Remove from PopupContainer\n this.panelRoot.remove();\n })\n );\n const commonStyle = {\n pointerEvents: 'none',\n width: '100%',\n height: '100%',\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 100,\n };\n domUtils.setStyle(this.panelRoot, commonStyle);\n }\n\n render(): JSX.Element {\n if (!this.layout) {\n const { children, ...layoutProps } = this.panelConfig.layerProps;\n this.layout = createElement(PanelLayerComp, layoutProps, children);\n }\n return ReactDOM.createPortal(this.layout, this.panelRoot);\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport clsx from 'clsx';\n\nimport { useGlobalCSS } from '../../hooks/use-global-css';\nimport { FloatPanel } from './float-panel';\nimport { leftArea, rightArea, mainArea, bottomArea, globalCSS } from './css';\n\nexport type PanelLayerProps = React.PropsWithChildren<{\n className?: string;\n style?: React.CSSProperties;\n}>;\n\nexport const PanelLayer: React.FC<PanelLayerProps> = ({ className, style, children }) => {\n useGlobalCSS({\n cssText: globalCSS,\n id: 'flow-panel-layer-css',\n });\n\n return (\n <div className={clsx('gedit-flow-panel-layer-wrap', className)} style={style}>\n <div className=\"gedit-flow-panel-left-area\" style={leftArea}>\n <div className=\"gedit-flow-panel-main-area\" style={mainArea}>\n {children}\n </div>\n <div className=\"gedit-flow-panel-bottom-area\" style={bottomArea}>\n <FloatPanel area=\"bottom\" />\n </div>\n </div>\n <div className=\"gedit-flow-panel-right-area\" style={rightArea}>\n <FloatPanel area=\"right\" />\n </div>\n </div>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect } from 'react';\n\ninterface UseGlobalCSSOptions {\n cssText: string;\n id: string;\n cleanup?: boolean;\n}\n\nexport const useGlobalCSS = ({ cssText, id, cleanup }: UseGlobalCSSOptions) => {\n useEffect(() => {\n /** SSR safe */\n if (typeof document === 'undefined') return;\n\n if (document.getElementById(id)) return;\n\n const style = document.createElement('style');\n style.id = id;\n style.textContent = cssText;\n document.head.appendChild(style);\n\n return () => {\n const existing = document.getElementById(id);\n if (existing && cleanup) existing.remove();\n };\n }, [id]);\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useEffect, useRef, startTransition, useState, useCallback } from 'react';\n\nimport { Area } from '../../types';\nimport { usePanelManager } from '../../hooks/use-panel-manager';\nimport { floatPanelWrap } from './css';\nimport { ResizeBar } from '../resize-bar';\n\nexport const FloatPanel: React.FC<{ area: Area }> = ({ area }) => {\n const [, setVersion] = useState(0);\n const panelManager = usePanelManager();\n const panel = useRef(panelManager.getPanel(area));\n const render = () =>\n panel.current.elements.map((i) => (\n <div className=\"float-panel-wrap\" key={i.key} style={{ ...floatPanelWrap, ...i.style }}>\n {i.el}\n </div>\n ));\n const node = useRef(render());\n\n useEffect(() => {\n const dispose = panel.current.onUpdate(() => {\n startTransition(() => {\n node.current = render();\n setVersion((v) => v + 1);\n });\n });\n return () => dispose.dispose();\n }, [panel]);\n const onResize = useCallback((newSize: number) => panel.current!.updateSize(newSize), []);\n const size = panel.current!.currentSize;\n const sizeStyle =\n area === 'right' ? { width: size, height: '100%' } : { height: size, width: '100%' };\n\n return (\n <div\n className=\"gedit-flow-panel\"\n style={{\n position: 'relative',\n display: panel.current.visible ? 'block' : 'none',\n ...sizeStyle,\n }}\n >\n {panelManager.config.autoResize && panel.current.elements.length > 0 && (\n <ResizeBar size={size} isVertical={area === 'right'} onResize={onResize} />\n )}\n {node.current}\n </div>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useService } from '@flowgram.ai/core';\n\nimport { PanelManager } from '../services/panel-manager';\n\nexport const usePanelManager = () => useService<PanelManager>(PanelManager);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport const globalCSS = `\n .gedit-flow-panel-layer * {\n box-sizing: border-box;\n }\n .gedit-flow-panel-layer-wrap {\n pointer-events: none;\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n column-gap: 4px;\n width: 100%;\n height: 100%;\n padding: 4px;\n overflow: hidden;\n }\n`;\n\nexport const leftArea: React.CSSProperties = {\n width: '100%',\n minWidth: 0,\n flexGrow: 0,\n flexShrink: 1,\n\n display: 'flex',\n flexDirection: 'column',\n rowGap: '4px',\n};\n\nexport const rightArea: React.CSSProperties = {\n height: '100%',\n flexGrow: 1,\n flexShrink: 0,\n minWidth: 0,\n\n display: 'flex',\n columnGap: '4px',\n};\n\nexport const mainArea: React.CSSProperties = {\n position: 'relative',\n overflow: 'hidden',\n flexGrow: 0,\n flexShrink: 1,\n width: '100%',\n height: '100%',\n};\n\nexport const bottomArea: React.CSSProperties = {\n flexGrow: 1,\n flexShrink: 0,\n width: '100%',\n minHeight: 0,\n};\n\nexport const floatPanelWrap: React.CSSProperties = {\n pointerEvents: 'auto',\n height: '100%',\n width: '100%',\n overflow: 'auto',\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { useRef, useState } from 'react';\n\ninterface Props {\n onResize: (w: number) => void;\n size: number;\n isVertical?: boolean;\n}\n\nexport const ResizeBar: React.FC<Props> = ({ onResize, size, isVertical }) => {\n const currentPoint = useRef<null | number>(null);\n const [isDragging, setIsDragging] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n return (\n <div\n onMouseDown={(e) => {\n currentPoint.current = isVertical ? e.clientX : e.clientY;\n e.stopPropagation();\n e.preventDefault();\n setIsDragging(true);\n const mouseUp = () => {\n currentPoint.current = null;\n document.body.removeEventListener('mouseup', mouseUp);\n document.body.removeEventListener('mousemove', mouseMove);\n setIsDragging(false);\n };\n const mouseMove = (e: MouseEvent) => {\n const delta = currentPoint.current! - (isVertical ? e.clientX : e.clientY);\n onResize(size + delta);\n };\n document.body.addEventListener('mouseup', mouseUp);\n document.body.addEventListener('mousemove', mouseMove);\n }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n zIndex: 999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'auto',\n ...(isVertical\n ? {\n cursor: 'ew-resize',\n height: '100%',\n marginLeft: -5,\n width: 10,\n }\n : {\n cursor: 'ns-resize',\n width: '100%',\n marginTop: -5,\n height: 10,\n }),\n }}\n >\n <div\n style={{\n ...(isVertical\n ? {\n width: 3,\n height: '100%',\n }\n : {\n height: 3,\n width: '100%',\n }),\n backgroundColor: isDragging || isHovered ? 'var(--g-playground-line)' : 'transparent',\n }}\n />\n </div>\n );\n};\n"],"mappings":"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","names":["import_core","import_react","import_inversify","import_utils","import_core","import_react","import_react","e","import_jsx_runtime","FloatPanel","import_jsx_runtime","clsx","FloatPanel","PanelLayer","ReactDOM","PanelLayer"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowgram.ai/panel-manager-plugin",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.20",
|
|
4
4
|
"homepage": "https://flowgram.ai/",
|
|
5
5
|
"repository": "https://github.com/bytedance/flowgram.ai",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,19 +14,23 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"inversify": "^6.0.1",
|
|
17
|
-
"
|
|
18
|
-
"@flowgram.ai/
|
|
17
|
+
"clsx": "^1.1.1",
|
|
18
|
+
"@flowgram.ai/core": "0.1.0-alpha.20",
|
|
19
|
+
"@flowgram.ai/utils": "0.1.0-alpha.20"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"react": "^18",
|
|
23
|
+
"react-dom": "^18",
|
|
22
24
|
"@types/react": "^18",
|
|
25
|
+
"@types/react-dom": "^18",
|
|
23
26
|
"tsup": "^8.0.1",
|
|
24
27
|
"typescript": "^5.8.3",
|
|
25
|
-
"@flowgram.ai/
|
|
26
|
-
"@flowgram.ai/
|
|
28
|
+
"@flowgram.ai/ts-config": "0.1.0-alpha.20",
|
|
29
|
+
"@flowgram.ai/eslint-config": "0.1.0-alpha.20"
|
|
27
30
|
},
|
|
28
31
|
"peerDependencies": {
|
|
29
|
-
"react": ">=16.8"
|
|
32
|
+
"react": ">=16.8",
|
|
33
|
+
"react-dom": ">=16.8"
|
|
30
34
|
},
|
|
31
35
|
"peerDependenciesMeta": {
|
|
32
36
|
"react": {
|
|
@@ -9,13 +9,13 @@ CLI tsup v8.5.0
|
|
|
9
9
|
CLI Target: es2020
|
|
10
10
|
CJS Build start
|
|
11
11
|
ESM Build start
|
|
12
|
-
CJS dist/index.js
|
|
13
|
-
CJS dist/index.js.map
|
|
14
|
-
CJS ⚡️ Build success in
|
|
15
|
-
ESM dist/esm/index.js
|
|
16
|
-
ESM dist/esm/index.js.map
|
|
17
|
-
ESM ⚡️ Build success in
|
|
12
|
+
CJS dist/index.js 13.82 KB
|
|
13
|
+
CJS dist/index.js.map 22.26 KB
|
|
14
|
+
CJS ⚡️ Build success in 98ms
|
|
15
|
+
ESM dist/esm/index.js 11.54 KB
|
|
16
|
+
ESM dist/esm/index.js.map 21.81 KB
|
|
17
|
+
ESM ⚡️ Build success in 99ms
|
|
18
18
|
DTS Build start
|
|
19
|
-
DTS ⚡️ Build success in
|
|
20
|
-
DTS dist/index.d.ts
|
|
21
|
-
DTS dist/index.d.mts
|
|
19
|
+
DTS ⚡️ Build success in 3462ms
|
|
20
|
+
DTS dist/index.d.ts 2.78 KB
|
|
21
|
+
DTS dist/index.d.mts 2.78 KB
|
|
@@ -3,19 +3,23 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
export const globalCSS = `
|
|
7
|
+
.gedit-flow-panel-layer * {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
.gedit-flow-panel-layer-wrap {
|
|
11
|
+
pointer-events: none;
|
|
12
|
+
position: absolute;
|
|
13
|
+
top: 0;
|
|
14
|
+
left: 0;
|
|
15
|
+
display: flex;
|
|
16
|
+
column-gap: 4px;
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
padding: 4px;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
19
23
|
|
|
20
24
|
export const leftArea: React.CSSProperties = {
|
|
21
25
|
width: '100%',
|
|
@@ -58,4 +62,5 @@ export const floatPanelWrap: React.CSSProperties = {
|
|
|
58
62
|
pointerEvents: 'auto',
|
|
59
63
|
height: '100%',
|
|
60
64
|
width: '100%',
|
|
65
|
+
overflow: 'auto',
|
|
61
66
|
};
|
|
@@ -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 && panel.current.elements.length > 0 && (
|
|
49
|
+
<ResizeBar size={size} isVertical={area === 'right'} onResize={onResize} />
|
|
50
|
+
)}
|
|
51
|
+
{node.current}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
40
54
|
};
|
|
@@ -3,21 +3,36 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import clsx from 'clsx';
|
|
7
|
+
|
|
8
|
+
import { useGlobalCSS } from '../../hooks/use-global-css';
|
|
6
9
|
import { FloatPanel } from './float-panel';
|
|
7
|
-
import {
|
|
10
|
+
import { leftArea, rightArea, mainArea, bottomArea, globalCSS } from './css';
|
|
11
|
+
|
|
12
|
+
export type PanelLayerProps = React.PropsWithChildren<{
|
|
13
|
+
className?: string;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
}>;
|
|
8
16
|
|
|
9
|
-
export const PanelLayer: React.FC<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
export const PanelLayer: React.FC<PanelLayerProps> = ({ className, style, children }) => {
|
|
18
|
+
useGlobalCSS({
|
|
19
|
+
cssText: globalCSS,
|
|
20
|
+
id: 'flow-panel-layer-css',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className={clsx('gedit-flow-panel-layer-wrap', className)} style={style}>
|
|
25
|
+
<div className="gedit-flow-panel-left-area" style={leftArea}>
|
|
26
|
+
<div className="gedit-flow-panel-main-area" style={mainArea}>
|
|
27
|
+
{children}
|
|
28
|
+
</div>
|
|
29
|
+
<div className="gedit-flow-panel-bottom-area" style={bottomArea}>
|
|
30
|
+
<FloatPanel area="bottom" />
|
|
31
|
+
</div>
|
|
14
32
|
</div>
|
|
15
|
-
<div className="
|
|
16
|
-
<FloatPanel area="
|
|
33
|
+
<div className="gedit-flow-panel-right-area" style={rightArea}>
|
|
34
|
+
<FloatPanel area="right" />
|
|
17
35
|
</div>
|
|
18
36
|
</div>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -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
|
-
onInit(ctx
|
|
16
|
+
onInit(ctx) {
|
|
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
|
},
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
|
|
8
|
+
interface UseGlobalCSSOptions {
|
|
9
|
+
cssText: string;
|
|
10
|
+
id: string;
|
|
11
|
+
cleanup?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const useGlobalCSS = ({ cssText, id, cleanup }: UseGlobalCSSOptions) => {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
/** SSR safe */
|
|
17
|
+
if (typeof document === 'undefined') return;
|
|
18
|
+
|
|
19
|
+
if (document.getElementById(id)) return;
|
|
20
|
+
|
|
21
|
+
const style = document.createElement('style');
|
|
22
|
+
style.id = id;
|
|
23
|
+
style.textContent = cssText;
|
|
24
|
+
document.head.appendChild(style);
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
const existing = document.getElementById(id);
|
|
28
|
+
if (existing && cleanup) existing.remove();
|
|
29
|
+
};
|
|
30
|
+
}, [id]);
|
|
31
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
export { createPanelManagerPlugin } from './create-panel-manager-plugin';
|
|
8
8
|
|
|
9
9
|
/** services */
|
|
10
|
-
export { PanelManager } from './services';
|
|
10
|
+
export { PanelManager, type PanelManagerConfig } from './services';
|
|
11
11
|
|
|
12
12
|
/** react hooks */
|
|
13
13
|
export { usePanelManager } from './hooks/use-panel-manager';
|
|
14
14
|
|
|
15
|
+
export { ResizeBar } from './components/resize-bar';
|
|
16
|
+
|
|
15
17
|
/** types */
|
|
16
18
|
export type { Area, PanelFactory } from './types';
|
|
@@ -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,18 @@
|
|
|
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';
|
|
9
|
+
import type { PanelLayerProps } from '../components/panel-layer';
|
|
7
10
|
|
|
8
11
|
export interface PanelManagerConfig {
|
|
9
12
|
factories: PanelFactory<any>[];
|
|
10
13
|
right: PanelConfig;
|
|
11
14
|
bottom: PanelConfig;
|
|
15
|
+
autoResize: boolean;
|
|
16
|
+
layerProps: PanelLayerProps;
|
|
17
|
+
getPopupContainer: (ctx: PluginContext) => HTMLElement; // default playground.node.parentElement
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export const PanelManagerConfig = Symbol('PanelManagerConfig');
|
|
@@ -22,6 +28,9 @@ export const defineConfig = (config: Partial<PanelManagerConfig>) => {
|
|
|
22
28
|
max: 1,
|
|
23
29
|
},
|
|
24
30
|
factories: [],
|
|
31
|
+
autoResize: true,
|
|
32
|
+
layerProps: {},
|
|
33
|
+
getPopupContainer: (ctx: PluginContext) => ctx.playground.node.parentNode as HTMLElement,
|
|
25
34
|
};
|
|
26
35
|
return {
|
|
27
36
|
...defaultConfig,
|
|
@@ -3,42 +3,51 @@
|
|
|
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
|
+
const { children, ...layoutProps } = this.panelConfig.layerProps;
|
|
49
|
+
this.layout = createElement(PanelLayerComp, layoutProps, children);
|
|
41
50
|
}
|
|
42
|
-
return this.layout;
|
|
51
|
+
return ReactDOM.createPortal(this.layout, this.panelRoot);
|
|
43
52
|
}
|
|
44
53
|
}
|
|
@@ -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) {
|