@flowgram.ai/panel-manager-plugin 1.0.2 → 1.0.3

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/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/resize-bar/index.tsx","../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\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, opt) {\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';\n\nexport interface PanelManagerConfig {\n factories: PanelFactory<any>[];\n right: PanelConfig;\n bottom: PanelConfig;\n getPopupContainer: (ctx: PluginContext) => HTMLElement; // default playground.node.parentElement\n autoResize: boolean;\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 getPopupContainer: (ctx: PluginContext) => ctx.playground.node.parentNode as HTMLElement,\n autoResize: true,\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 this.layout = createElement(PanelLayerComp);\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 { 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`;\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 overflow: 'hidden',\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","/**\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, globalCSS } from './css';\n\nexport const PanelLayer: React.FC<React.PropsWithChildren> = ({ children }) => (\n <div style={panelLayer}>\n <style dangerouslySetInnerHTML={{ __html: globalCSS }} />\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"],"mappings":"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","names":["import_core","import_react","import_inversify","import_utils","import_core","import_react","e","import_jsx_runtime","FloatPanel","import_jsx_runtime","FloatPanel","PanelLayer","ReactDOM","PanelLayer"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/create-panel-manager-plugin.ts","../src/services/panel-factory.ts","../src/services/panel-restore.ts","../src/components/resize-bar/index.tsx","../src/services/panel-config.ts","../src/services/panel-manager.ts","../src/services/panel-layer.ts","../src/components/panel-layer/panel-layer.tsx","../src/hooks/use-global-css.ts","../src/components/panel-layer/panel.tsx","../src/hooks/use-panel-manager.ts","../src/contexts.ts","../src/components/panel-layer/css.ts","../src/components/panel-layer/docked-panel-layer.tsx","../src/hooks/use-panel.ts"],"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, PanelRestore, type PanelManagerConfig } from './services';\n\n/** react hooks */\nexport { usePanelManager } from './hooks/use-panel-manager';\nexport { usePanel } from './hooks/use-panel';\n\nexport { DockedPanelLayer, type DockedPanelLayerProps } from './components/panel-layer';\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 {\n PanelEntityFactory,\n PanelEntity,\n PanelEntityFactoryConstant,\n PanelEntityConfigConstant,\n} from './services/panel-factory';\nimport { defineConfig } from './services/panel-config';\nimport {\n PanelManager,\n PanelManagerConfig,\n PanelLayer,\n PanelRestore,\n PanelRestoreImpl,\n} from './services';\n\nexport const createPanelManagerPlugin = definePluginCreator<Partial<PanelManagerConfig>>({\n onBind: ({ bind }, opt) => {\n bind(PanelManager).to(PanelManager).inSingletonScope();\n bind(PanelRestore).to(PanelRestoreImpl).inSingletonScope();\n bind(PanelManagerConfig).toConstantValue(defineConfig(opt));\n bind(PanelEntityFactory).toFactory(\n (context) =>\n ({\n factory,\n config,\n }: {\n factory: PanelEntityFactoryConstant;\n config: PanelEntityConfigConstant;\n }) => {\n const container = context.container.createChild();\n container.bind(PanelEntityFactoryConstant).toConstantValue(factory);\n container.bind(PanelEntityConfigConstant).toConstantValue(config);\n const panel = container.resolve(PanelEntity);\n panel.init();\n return panel;\n }\n );\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 { createStore, StoreApi } from 'zustand/vanilla';\nimport { nanoid } from 'nanoid';\nimport { inject, injectable } from 'inversify';\n\nimport type { PanelFactory, PanelEntityConfig, Area } from '../types';\nimport { PanelRestore } from './panel-restore';\n\nexport const PanelEntityFactory = Symbol('PanelEntityFactory');\nexport type PanelEntityFactory = (options: {\n factory: PanelEntityFactoryConstant;\n config: PanelEntityConfigConstant;\n}) => PanelEntity;\n\nexport const PanelEntityFactoryConstant = Symbol('PanelEntityFactoryConstant');\nexport type PanelEntityFactoryConstant = PanelFactory<any>;\nexport const PanelEntityConfigConstant = Symbol('PanelEntityConfigConstant');\nexport type PanelEntityConfigConstant = PanelEntityConfig<any> & {\n area: Area;\n};\n\nconst PANEL_SIZE_DEFAULT = 400;\n\ninterface PanelEntityState {\n size: number;\n}\n\n@injectable()\nexport class PanelEntity {\n @inject(PanelRestore) restore: PanelRestore;\n\n /** 面板工厂 */\n @inject(PanelEntityFactoryConstant) public factory: PanelEntityFactoryConstant;\n\n @inject(PanelEntityConfigConstant) public config: PanelEntityConfigConstant;\n\n private initialized = false;\n\n /** 实例唯一标识 */\n id: string = nanoid();\n\n /** 渲染缓存 */\n node: React.ReactNode = null;\n\n store: StoreApi<PanelEntityState>;\n\n get area() {\n return this.config.area;\n }\n\n get key() {\n return this.factory.key;\n }\n\n get renderer() {\n if (!this.node) {\n this.node = this.factory.render(this.config.props);\n }\n return this.node;\n }\n\n init() {\n if (this.initialized) {\n return;\n }\n this.initialized = true;\n const cache = this.restore.restore<PanelEntityState>(this.key);\n this.store = createStore<PanelEntityState>(() => ({\n size: this.config.defaultSize || this.factory.defaultSize || PANEL_SIZE_DEFAULT,\n ...(cache ?? {}),\n }));\n }\n\n dispose() {\n this.restore.store(this.key, this.store.getState());\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable } from 'inversify';\n\nexport const PanelRestore = Symbol('PanelRestore');\nexport interface PanelRestore {\n store: (k: string, v: any) => void;\n restore: <T>(k: string) => T | undefined;\n}\n\n@injectable()\nexport class PanelRestoreImpl implements PanelRestore {\n map = new Map<string, any>();\n\n store(k: string, v: any) {\n this.map.set(k, v);\n }\n\n restore<T>(k: string): T | undefined {\n return this.map.get(k) as T;\n }\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 size: number;\n direction?: 'vertical' | 'horizontal';\n onResize: (w: number) => void;\n}\n\nexport const ResizeBar: React.FC<Props> = ({ onResize, size, direction }) => {\n const currentPoint = useRef<null | number>(null);\n const [isDragging, setIsDragging] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n\n const isVertical = direction === 'vertical';\n\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","/**\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 { ResizeBar } from '../components/resize-bar';\nimport type { PanelLayerProps } from '../components/panel-layer';\n\nexport interface PanelManagerConfig {\n factories: PanelFactory<any>[];\n right: PanelConfig;\n bottom: PanelConfig;\n dockedRight: PanelConfig;\n dockedBottom: PanelConfig;\n /** Resizable, and multi-panel options mutually exclusive */\n autoResize: boolean;\n layerProps: PanelLayerProps;\n resizeBarRender: ({\n size,\n }: {\n size: number;\n direction?: 'vertical' | 'horizontal';\n onResize: (size: number) => void;\n }) => React.ReactNode;\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 dockedRight: {\n max: 1,\n },\n dockedBottom: {\n max: 1,\n },\n factories: [],\n autoResize: true,\n layerProps: {},\n resizeBarRender: ResizeBar,\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';\nimport { Emitter } from '@flowgram.ai/utils';\n\nimport { PanelManagerConfig } from './panel-config';\nimport type { Area, PanelEntityConfig, PanelFactory } from '../types';\nimport { PanelEntity, PanelEntityFactory } from './panel-factory';\n\n@injectable()\nexport class PanelManager {\n @inject(PanelManagerConfig) readonly config: PanelManagerConfig;\n\n @inject(PanelEntityFactory) readonly createPanel: PanelEntityFactory;\n\n readonly panelRegistry = new Map<string, PanelFactory<any>>();\n\n private panels = new Map<string, PanelEntity>();\n\n private onPanelsChangeEvent = new Emitter<void>();\n\n public onPanelsChange = this.onPanelsChangeEvent.event;\n\n init() {\n this.config.factories.forEach((factory) => this.register(factory));\n }\n\n /** registry panel factory */\n register<T extends any>(factory: PanelFactory<T>) {\n this.panelRegistry.set(factory.key, factory);\n }\n\n /** open panel */\n public open(key: string, area: Area = 'right', options?: PanelEntityConfig) {\n const factory = this.panelRegistry.get(key);\n if (!factory) {\n return;\n }\n\n const sameKeyPanels = this.getPanels(area).filter((p) => p.key === key);\n if (!factory.allowDuplicates && sameKeyPanels.length) {\n sameKeyPanels.forEach((p) => this.remove(p.id));\n }\n\n const panel = this.createPanel({\n factory,\n config: {\n area,\n ...options,\n },\n });\n\n this.panels.set(panel.id, panel);\n this.trim(area);\n this.onPanelsChangeEvent.fire();\n console.log('jxj', this.panels);\n }\n\n /** close panel */\n public close(key?: string) {\n const panels = this.getPanels();\n const closedPanels = key ? panels.filter((p) => p.key === key) : panels;\n closedPanels.forEach((p) => this.remove(p.id));\n this.onPanelsChangeEvent.fire();\n }\n\n private trim(area: Area) {\n const panels = this.getPanels(area);\n const areaConfig = this.getAreaConfig(area);\n console.log('jxj', areaConfig.max, panels.length);\n while (panels.length > areaConfig.max) {\n const removed = panels.shift();\n if (removed) {\n this.remove(removed.id);\n }\n }\n }\n\n private remove(id: string) {\n const panel = this.panels.get(id);\n if (panel) {\n panel.dispose();\n this.panels.delete(id);\n }\n }\n\n getPanels(area?: Area) {\n const panels: PanelEntity[] = [];\n this.panels.forEach((panel) => {\n if (!area || panel.area === area) {\n panels.push(panel);\n }\n });\n return panels;\n }\n\n getAreaConfig(area: Area) {\n switch (area) {\n case 'docked-bottom':\n return this.config.dockedBottom;\n case 'docked-right':\n return this.config.dockedRight;\n case 'bottom':\n return this.config.bottom;\n case 'right':\n default:\n return this.config.right;\n }\n }\n\n dispose() {\n this.onPanelsChangeEvent.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 { PanelArea } from './panel';\nimport { globalCSS } from './css';\n\nexport type PanelLayerProps = React.PropsWithChildren<{\n /** 模式:悬浮|挤压 */\n mode?: 'floating' | 'docked';\n className?: string;\n style?: React.CSSProperties;\n}>;\n\nexport const PanelLayer: React.FC<PanelLayerProps> = ({\n mode = 'floating',\n className,\n style,\n children,\n}) => {\n useGlobalCSS({\n cssText: globalCSS,\n id: 'flow-panel-layer-css',\n });\n\n return (\n <div\n className={clsx(\n 'gedit-flow-panel-layer-wrap',\n mode === 'docked' && 'gedit-flow-panel-layer-wrap-docked',\n mode === 'floating' && 'gedit-flow-panel-layer-wrap-floating',\n className\n )}\n style={style}\n >\n <div className=\"gedit-flow-panel-left-area\">\n <div className=\"gedit-flow-panel-main-area\">{children}</div>\n <div className=\"gedit-flow-panel-bottom-area\">\n <PanelArea area={mode === 'docked' ? 'docked-bottom' : 'bottom'} />\n </div>\n </div>\n <div className=\"gedit-flow-panel-right-area\">\n <PanelArea area={mode === 'docked' ? 'docked-right' : '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, startTransition, useState, useRef } from 'react';\n\nimport { useStoreWithEqualityFn } from 'zustand/traditional';\nimport { shallow } from 'zustand/shallow';\nimport clsx from 'clsx';\n\nimport { Area } from '../../types';\nimport { PanelEntity } from '../../services/panel-factory';\nimport { usePanelManager } from '../../hooks/use-panel-manager';\nimport { PanelContext } from '../../contexts';\n\nconst PanelItem: React.FC<{ panel: PanelEntity }> = ({ panel }) => {\n const panelManager = usePanelManager();\n const ref = useRef<HTMLDivElement>(null);\n const resize =\n panel.factory.resize !== undefined ? panel.factory.resize : panelManager.config.autoResize;\n\n const isHorizontal = ['right', 'docked-right'].includes(panel.area);\n\n const size = useStoreWithEqualityFn(panel.store, (s) => s.size, shallow);\n\n const sizeStyle = isHorizontal ? { width: size } : { height: size };\n const handleResize = (next: number) => {\n let nextSize = next;\n if (typeof panel.factory.maxSize === 'number' && nextSize > panel.factory.maxSize) {\n nextSize = panel.factory.maxSize;\n } else if (typeof panel.factory.minSize === 'number' && nextSize < panel.factory.minSize) {\n nextSize = panel.factory.minSize;\n }\n panel.store.setState({ size: nextSize });\n };\n\n useEffect(() => {\n /** The set size may be illegal and needs to be updated according to the real element rendered for the first time. */\n if (ref.current) {\n const { width, height } = ref.current.getBoundingClientRect();\n const realSize = isHorizontal ? width : height;\n panel.store.setState({ size: realSize });\n }\n }, []);\n\n return (\n <div\n className={clsx(\n 'gedit-flow-panel-wrap',\n isHorizontal ? 'panel-horizontal' : 'panel-vertical'\n )}\n key={panel.id}\n ref={ref}\n style={{ ...panel.factory.style, ...panel.config.style, ...sizeStyle }}\n >\n {resize &&\n panelManager.config.resizeBarRender({\n size,\n direction: isHorizontal ? 'vertical' : 'horizontal',\n onResize: handleResize,\n })}\n {panel.renderer}\n </div>\n );\n};\n\nexport const PanelArea: React.FC<{ area: Area }> = ({ area }) => {\n const panelManager = usePanelManager();\n const [panels, setPanels] = useState(panelManager.getPanels(area));\n\n useEffect(() => {\n const dispose = panelManager.onPanelsChange(() => {\n startTransition(() => {\n setPanels(panelManager.getPanels(area));\n });\n });\n return () => dispose.dispose();\n }, []);\n\n return (\n <>\n {panels.map((panel) => (\n <PanelContext.Provider value={panel} key={panel.id}>\n <PanelItem panel={panel} />\n </PanelContext.Provider>\n ))}\n </>\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\nimport { createContext } from 'react';\n\nimport type { PanelEntity } from './services/panel-factory';\n\nexport const PanelContext = createContext({} as PanelEntity);\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-wrap * {\n box-sizing: border-box;\n }\n .gedit-flow-panel-layer-wrap {\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n .gedit-flow-panel-layer-wrap-docked {\n\n }\n .gedit-flow-panel-layer-wrap-floating {\n column-gap: 4px;\n padding: 4px;\n pointer-events: none;\n }\n\n .gedit-flow-panel-left-area {\n width: 100%;\n min-width: 0;\n flex-grow: 0;\n flex-shrink: 1;\n display: flex;\n flex-direction: column;\n }\n .gedit-flow-panel-layer-wrap-floating .gedit-flow-panel-left-area {\n row-gap: 4px;\n }\n .gedit-flow-panel-right-area {\n height: 100%;\n flex-grow: 1;\n flex-shrink: 0;\n min-width: 0;\n display: flex;\n column-gap: 4px;\n max-width: 100%;\n }\n\n .gedit-flow-panel-main-area {\n position: relative;\n overflow: hidden;\n flex-grow: 0;\n flex-shrink: 1;\n width: 100%;\n height: 100%;\n }\n .gedit-flow-panel-bottom-area {\n flex-grow: 1;\n flex-shrink: 0;\n width: 100%;\n min-height: 0;\n }\n .gedit-flow-panel-wrap {\n pointer-events: auto;\n overflow: auto;\n position: relative;\n }\n .gedit-flow-panel-wrap.panel-horizontal {\n height: 100%;\n }\n .gedit-flow-panel-wrap.panel-vertical {\n width: 100%;\n }\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { PanelLayer, PanelLayerProps } from './panel-layer';\n\nexport type DockedPanelLayerProps = Omit<PanelLayerProps, 'mode'>;\n\nexport const DockedPanelLayer: React.FC<DockedPanelLayerProps> = (props) => (\n <PanelLayer mode=\"docked\" {...props} />\n);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useContext } from 'react';\n\nimport { PanelContext } from '../contexts';\n\nexport const usePanel = () => useContext(PanelContext);\n"],"mappings":"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","names":["import_core","import_inversify","e","import_inversify","import_react","import_inversify","import_utils","import_core","import_clsx","import_react","import_react","import_react","import_jsx_runtime","clsx","import_jsx_runtime","clsx","import_jsx_runtime","PanelLayer","ReactDOM","PanelLayer","import_react"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowgram.ai/panel-manager-plugin",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "homepage": "https://flowgram.ai/",
5
5
  "repository": "https://github.com/bytedance/flowgram.ai",
6
6
  "license": "MIT",
@@ -14,8 +14,12 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "dependencies": {
16
16
  "inversify": "^6.0.1",
17
- "@flowgram.ai/core": "1.0.2",
18
- "@flowgram.ai/utils": "1.0.2"
17
+ "clsx": "^1.1.1",
18
+ "nanoid": "^5.0.9",
19
+ "zustand": "^5.0.8",
20
+ "use-sync-external-store": "^1.6.0",
21
+ "@flowgram.ai/utils": "1.0.3",
22
+ "@flowgram.ai/core": "1.0.3"
19
23
  },
20
24
  "devDependencies": {
21
25
  "react": "^18",
@@ -24,8 +28,8 @@
24
28
  "@types/react-dom": "^18",
25
29
  "tsup": "^8.0.1",
26
30
  "typescript": "^5.8.3",
27
- "@flowgram.ai/ts-config": "1.0.2",
28
- "@flowgram.ai/eslint-config": "1.0.2"
31
+ "@flowgram.ai/ts-config": "1.0.3",
32
+ "@flowgram.ai/eslint-config": "1.0.3"
29
33
  },
30
34
  "peerDependencies": {
31
35
  "react": ">=16.8",
@@ -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.02 KB
13
- CJS dist/index.js.map 20.59 KB
14
- CJS ⚡️ Build success in 84ms
15
- ESM dist/esm/index.js 10.77 KB
16
- ESM dist/esm/index.js.map 20.15 KB
17
- ESM ⚡️ Build success in 85ms
12
+ CJS dist/index.js 18.85 KB
13
+ CJS dist/index.js.map 31.19 KB
14
+ CJS ⚡️ Build success in 119ms
15
+ ESM dist/esm/index.js 16.16 KB
16
+ ESM dist/esm/index.js.map 30.61 KB
17
+ ESM ⚡️ Build success in 120ms
18
18
  DTS Build start
19
- DTS ⚡️ Build success in 3234ms
20
- DTS dist/index.d.ts 2.53 KB
21
- DTS dist/index.d.mts 2.53 KB
19
+ DTS ⚡️ Build success in 3004ms
20
+ DTS dist/index.d.ts 4.74 KB
21
+ DTS dist/index.d.mts 4.74 KB
@@ -4,66 +4,71 @@
4
4
  */
5
5
 
6
6
  export const globalCSS = `
7
- .gedit-flow-panel-layer * {
7
+ .gedit-flow-panel-layer-wrap * {
8
8
  box-sizing: border-box;
9
9
  }
10
- `;
11
-
12
- export const panelLayer: React.CSSProperties = {
13
- pointerEvents: 'none',
14
- position: 'absolute',
15
- top: 0,
16
- left: 0,
17
-
18
- display: 'flex',
19
- columnGap: '4px',
20
- width: '100%',
21
- height: '100%',
22
- padding: '4px',
23
- boxSizing: 'border-box',
24
- overflow: 'hidden',
25
- };
26
-
27
- export const leftArea: React.CSSProperties = {
28
- width: '100%',
29
- minWidth: 0,
30
- flexGrow: 0,
31
- flexShrink: 1,
32
-
33
- display: 'flex',
34
- flexDirection: 'column',
35
- rowGap: '4px',
36
- };
37
-
38
- export const rightArea: React.CSSProperties = {
39
- height: '100%',
40
- flexGrow: 1,
41
- flexShrink: 0,
42
- minWidth: 0,
43
-
44
- display: 'flex',
45
- columnGap: '4px',
46
- };
10
+ .gedit-flow-panel-layer-wrap {
11
+ position: absolute;
12
+ top: 0;
13
+ left: 0;
14
+ display: flex;
15
+ width: 100%;
16
+ height: 100%;
17
+ overflow: hidden;
18
+ }
19
+ .gedit-flow-panel-layer-wrap-docked {
47
20
 
48
- export const mainArea: React.CSSProperties = {
49
- position: 'relative',
50
- overflow: 'hidden',
51
- flexGrow: 0,
52
- flexShrink: 1,
53
- width: '100%',
54
- height: '100%',
55
- };
21
+ }
22
+ .gedit-flow-panel-layer-wrap-floating {
23
+ column-gap: 4px;
24
+ padding: 4px;
25
+ pointer-events: none;
26
+ }
56
27
 
57
- export const bottomArea: React.CSSProperties = {
58
- flexGrow: 1,
59
- flexShrink: 0,
60
- width: '100%',
61
- minHeight: 0,
62
- };
28
+ .gedit-flow-panel-left-area {
29
+ width: 100%;
30
+ min-width: 0;
31
+ flex-grow: 0;
32
+ flex-shrink: 1;
33
+ display: flex;
34
+ flex-direction: column;
35
+ }
36
+ .gedit-flow-panel-layer-wrap-floating .gedit-flow-panel-left-area {
37
+ row-gap: 4px;
38
+ }
39
+ .gedit-flow-panel-right-area {
40
+ height: 100%;
41
+ flex-grow: 1;
42
+ flex-shrink: 0;
43
+ min-width: 0;
44
+ display: flex;
45
+ column-gap: 4px;
46
+ max-width: 100%;
47
+ }
63
48
 
64
- export const floatPanelWrap: React.CSSProperties = {
65
- pointerEvents: 'auto',
66
- height: '100%',
67
- width: '100%',
68
- overflow: 'auto',
69
- };
49
+ .gedit-flow-panel-main-area {
50
+ position: relative;
51
+ overflow: hidden;
52
+ flex-grow: 0;
53
+ flex-shrink: 1;
54
+ width: 100%;
55
+ height: 100%;
56
+ }
57
+ .gedit-flow-panel-bottom-area {
58
+ flex-grow: 1;
59
+ flex-shrink: 0;
60
+ width: 100%;
61
+ min-height: 0;
62
+ }
63
+ .gedit-flow-panel-wrap {
64
+ pointer-events: auto;
65
+ overflow: auto;
66
+ position: relative;
67
+ }
68
+ .gedit-flow-panel-wrap.panel-horizontal {
69
+ height: 100%;
70
+ }
71
+ .gedit-flow-panel-wrap.panel-vertical {
72
+ width: 100%;
73
+ }
74
+ `;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { PanelLayer, PanelLayerProps } from './panel-layer';
7
+
8
+ export type DockedPanelLayerProps = Omit<PanelLayerProps, 'mode'>;
9
+
10
+ export const DockedPanelLayer: React.FC<DockedPanelLayerProps> = (props) => (
11
+ <PanelLayer mode="docked" {...props} />
12
+ );
@@ -3,4 +3,5 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- export { PanelLayer } from './panel-layer';
6
+ export { PanelLayer, type PanelLayerProps } from './panel-layer';
7
+ export { DockedPanelLayer, type DockedPanelLayerProps } from './docked-panel-layer';
@@ -3,22 +3,49 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import { FloatPanel } from './float-panel';
7
- import { panelLayer, leftArea, rightArea, mainArea, bottomArea, globalCSS } from './css';
6
+ import clsx from 'clsx';
8
7
 
9
- export const PanelLayer: React.FC<React.PropsWithChildren> = ({ children }) => (
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}>
14
- {children}
8
+ import { useGlobalCSS } from '../../hooks/use-global-css';
9
+ import { PanelArea } from './panel';
10
+ import { globalCSS } from './css';
11
+
12
+ export type PanelLayerProps = React.PropsWithChildren<{
13
+ /** 模式:悬浮|挤压 */
14
+ mode?: 'floating' | 'docked';
15
+ className?: string;
16
+ style?: React.CSSProperties;
17
+ }>;
18
+
19
+ export const PanelLayer: React.FC<PanelLayerProps> = ({
20
+ mode = 'floating',
21
+ className,
22
+ style,
23
+ children,
24
+ }) => {
25
+ useGlobalCSS({
26
+ cssText: globalCSS,
27
+ id: 'flow-panel-layer-css',
28
+ });
29
+
30
+ return (
31
+ <div
32
+ className={clsx(
33
+ 'gedit-flow-panel-layer-wrap',
34
+ mode === 'docked' && 'gedit-flow-panel-layer-wrap-docked',
35
+ mode === 'floating' && 'gedit-flow-panel-layer-wrap-floating',
36
+ className
37
+ )}
38
+ style={style}
39
+ >
40
+ <div className="gedit-flow-panel-left-area">
41
+ <div className="gedit-flow-panel-main-area">{children}</div>
42
+ <div className="gedit-flow-panel-bottom-area">
43
+ <PanelArea area={mode === 'docked' ? 'docked-bottom' : 'bottom'} />
44
+ </div>
15
45
  </div>
16
- <div className="gedit-flow-panel-bottom-area" style={bottomArea}>
17
- <FloatPanel area="bottom" />
46
+ <div className="gedit-flow-panel-right-area">
47
+ <PanelArea area={mode === 'docked' ? 'docked-right' : 'right'} />
18
48
  </div>
19
49
  </div>
20
- <div className="gedit-flow-panel-right-area" style={rightArea}>
21
- <FloatPanel area="right" />
22
- </div>
23
- </div>
24
- );
50
+ );
51
+ };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { useEffect, startTransition, useState, useRef } from 'react';
7
+
8
+ import { useStoreWithEqualityFn } from 'zustand/traditional';
9
+ import { shallow } from 'zustand/shallow';
10
+ import clsx from 'clsx';
11
+
12
+ import { Area } from '../../types';
13
+ import { PanelEntity } from '../../services/panel-factory';
14
+ import { usePanelManager } from '../../hooks/use-panel-manager';
15
+ import { PanelContext } from '../../contexts';
16
+
17
+ const PanelItem: React.FC<{ panel: PanelEntity }> = ({ panel }) => {
18
+ const panelManager = usePanelManager();
19
+ const ref = useRef<HTMLDivElement>(null);
20
+ const resize =
21
+ panel.factory.resize !== undefined ? panel.factory.resize : panelManager.config.autoResize;
22
+
23
+ const isHorizontal = ['right', 'docked-right'].includes(panel.area);
24
+
25
+ const size = useStoreWithEqualityFn(panel.store, (s) => s.size, shallow);
26
+
27
+ const sizeStyle = isHorizontal ? { width: size } : { height: size };
28
+ const handleResize = (next: number) => {
29
+ let nextSize = next;
30
+ if (typeof panel.factory.maxSize === 'number' && nextSize > panel.factory.maxSize) {
31
+ nextSize = panel.factory.maxSize;
32
+ } else if (typeof panel.factory.minSize === 'number' && nextSize < panel.factory.minSize) {
33
+ nextSize = panel.factory.minSize;
34
+ }
35
+ panel.store.setState({ size: nextSize });
36
+ };
37
+
38
+ useEffect(() => {
39
+ /** The set size may be illegal and needs to be updated according to the real element rendered for the first time. */
40
+ if (ref.current) {
41
+ const { width, height } = ref.current.getBoundingClientRect();
42
+ const realSize = isHorizontal ? width : height;
43
+ panel.store.setState({ size: realSize });
44
+ }
45
+ }, []);
46
+
47
+ return (
48
+ <div
49
+ className={clsx(
50
+ 'gedit-flow-panel-wrap',
51
+ isHorizontal ? 'panel-horizontal' : 'panel-vertical'
52
+ )}
53
+ key={panel.id}
54
+ ref={ref}
55
+ style={{ ...panel.factory.style, ...panel.config.style, ...sizeStyle }}
56
+ >
57
+ {resize &&
58
+ panelManager.config.resizeBarRender({
59
+ size,
60
+ direction: isHorizontal ? 'vertical' : 'horizontal',
61
+ onResize: handleResize,
62
+ })}
63
+ {panel.renderer}
64
+ </div>
65
+ );
66
+ };
67
+
68
+ export const PanelArea: React.FC<{ area: Area }> = ({ area }) => {
69
+ const panelManager = usePanelManager();
70
+ const [panels, setPanels] = useState(panelManager.getPanels(area));
71
+
72
+ useEffect(() => {
73
+ const dispose = panelManager.onPanelsChange(() => {
74
+ startTransition(() => {
75
+ setPanels(panelManager.getPanels(area));
76
+ });
77
+ });
78
+ return () => dispose.dispose();
79
+ }, []);
80
+
81
+ return (
82
+ <>
83
+ {panels.map((panel) => (
84
+ <PanelContext.Provider value={panel} key={panel.id}>
85
+ <PanelItem panel={panel} />
86
+ </PanelContext.Provider>
87
+ ))}
88
+ </>
89
+ );
90
+ };
@@ -6,15 +6,18 @@
6
6
  import React, { useRef, useState } from 'react';
7
7
 
8
8
  interface Props {
9
- onResize: (w: number) => void;
10
9
  size: number;
11
- isVertical?: boolean;
10
+ direction?: 'vertical' | 'horizontal';
11
+ onResize: (w: number) => void;
12
12
  }
13
13
 
14
- export const ResizeBar: React.FC<Props> = ({ onResize, size, isVertical }) => {
14
+ export const ResizeBar: React.FC<Props> = ({ onResize, size, direction }) => {
15
15
  const currentPoint = useRef<null | number>(null);
16
16
  const [isDragging, setIsDragging] = useState(false);
17
17
  const [isHovered, setIsHovered] = useState(false);
18
+
19
+ const isVertical = direction === 'vertical';
20
+
18
21
  return (
19
22
  <div
20
23
  onMouseDown={(e) => {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { createContext } from 'react';
7
+
8
+ import type { PanelEntity } from './services/panel-factory';
9
+
10
+ export const PanelContext = createContext({} as PanelEntity);
@@ -5,15 +5,45 @@
5
5
 
6
6
  import { definePluginCreator } from '@flowgram.ai/core';
7
7
 
8
+ import {
9
+ PanelEntityFactory,
10
+ PanelEntity,
11
+ PanelEntityFactoryConstant,
12
+ PanelEntityConfigConstant,
13
+ } from './services/panel-factory';
8
14
  import { defineConfig } from './services/panel-config';
9
- import { PanelManager, PanelManagerConfig, PanelLayer } from './services';
15
+ import {
16
+ PanelManager,
17
+ PanelManagerConfig,
18
+ PanelLayer,
19
+ PanelRestore,
20
+ PanelRestoreImpl,
21
+ } from './services';
10
22
 
11
23
  export const createPanelManagerPlugin = definePluginCreator<Partial<PanelManagerConfig>>({
12
24
  onBind: ({ bind }, opt) => {
13
25
  bind(PanelManager).to(PanelManager).inSingletonScope();
26
+ bind(PanelRestore).to(PanelRestoreImpl).inSingletonScope();
14
27
  bind(PanelManagerConfig).toConstantValue(defineConfig(opt));
28
+ bind(PanelEntityFactory).toFactory(
29
+ (context) =>
30
+ ({
31
+ factory,
32
+ config,
33
+ }: {
34
+ factory: PanelEntityFactoryConstant;
35
+ config: PanelEntityConfigConstant;
36
+ }) => {
37
+ const container = context.container.createChild();
38
+ container.bind(PanelEntityFactoryConstant).toConstantValue(factory);
39
+ container.bind(PanelEntityConfigConstant).toConstantValue(config);
40
+ const panel = container.resolve(PanelEntity);
41
+ panel.init();
42
+ return panel;
43
+ }
44
+ );
15
45
  },
16
- onInit(ctx, opt) {
46
+ onInit(ctx) {
17
47
  ctx.playground.registerLayer(PanelLayer);
18
48
  const panelManager = ctx.container.get<PanelManager>(PanelManager);
19
49
  panelManager.init();
@@ -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
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { useContext } from 'react';
7
+
8
+ import { PanelContext } from '../contexts';
9
+
10
+ export const usePanel = () => useContext(PanelContext);
package/src/index.ts CHANGED
@@ -7,11 +7,13 @@
7
7
  export { createPanelManagerPlugin } from './create-panel-manager-plugin';
8
8
 
9
9
  /** services */
10
- export { PanelManager } from './services';
10
+ export { PanelManager, PanelRestore, type PanelManagerConfig } from './services';
11
11
 
12
12
  /** react hooks */
13
13
  export { usePanelManager } from './hooks/use-panel-manager';
14
+ export { usePanel } from './hooks/use-panel';
14
15
 
16
+ export { DockedPanelLayer, type DockedPanelLayerProps } from './components/panel-layer';
15
17
  export { ResizeBar } from './components/resize-bar';
16
18
 
17
19
  /** types */
@@ -6,3 +6,4 @@
6
6
  export { PanelManager } from './panel-manager';
7
7
  export { PanelManagerConfig } from './panel-config';
8
8
  export { PanelLayer } from './panel-layer';
9
+ export { PanelRestore, PanelRestoreImpl } from './panel-restore';