| @@ -1,5 +1,5 @@ | |||
| import type { FC } from 'react' | |||
| import { memo, useEffect, useRef } from 'react' | |||
| import { memo, useCallback, useEffect, useRef } from 'react' | |||
| import { useNodes } from 'reactflow' | |||
| import type { CommonNodeType } from '../types' | |||
| import { Panel as NodePanel } from '../nodes' | |||
| @@ -13,6 +13,51 @@ export type PanelProps = { | |||
| right?: React.ReactNode | |||
| } | |||
| } | |||
| /** | |||
| * Reference MDN standard implementation:https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserverEntry/borderBoxSize | |||
| */ | |||
| const getEntryWidth = (entry: ResizeObserverEntry, element: HTMLElement): number => { | |||
| if (entry.borderBoxSize?.length > 0) | |||
| return entry.borderBoxSize[0].inlineSize | |||
| if (entry.contentRect.width > 0) | |||
| return entry.contentRect.width | |||
| return element.getBoundingClientRect().width | |||
| } | |||
| const useResizeObserver = ( | |||
| callback: (width: number) => void, | |||
| dependencies: React.DependencyList = [], | |||
| ) => { | |||
| const elementRef = useRef<HTMLDivElement>(null) | |||
| const stableCallback = useCallback(callback, [callback]) | |||
| useEffect(() => { | |||
| const element = elementRef.current | |||
| if (!element) return | |||
| const resizeObserver = new ResizeObserver((entries) => { | |||
| for (const entry of entries) { | |||
| const width = getEntryWidth(entry, element) | |||
| stableCallback(width) | |||
| } | |||
| }) | |||
| resizeObserver.observe(element) | |||
| const initialWidth = element.getBoundingClientRect().width | |||
| stableCallback(initialWidth) | |||
| return () => { | |||
| resizeObserver.disconnect() | |||
| } | |||
| }, [stableCallback, ...dependencies]) | |||
| return elementRef | |||
| } | |||
| const Panel: FC<PanelProps> = ({ | |||
| components, | |||
| }) => { | |||
| @@ -20,44 +65,21 @@ const Panel: FC<PanelProps> = ({ | |||
| const selectedNode = nodes.find(node => node.data.selected) | |||
| const showEnvPanel = useStore(s => s.showEnvPanel) | |||
| const isRestoring = useStore(s => s.isRestoring) | |||
| const showWorkflowVersionHistoryPanel = useStore(s => s.showWorkflowVersionHistoryPanel) | |||
| const rightPanelRef = useRef<HTMLDivElement>(null) | |||
| const setRightPanelWidth = useStore(s => s.setRightPanelWidth) | |||
| const setOtherPanelWidth = useStore(s => s.setOtherPanelWidth) | |||
| // get right panel width | |||
| useEffect(() => { | |||
| if (rightPanelRef.current) { | |||
| const resizeRightPanelObserver = new ResizeObserver((entries) => { | |||
| for (const entry of entries) { | |||
| const { inlineSize } = entry.borderBoxSize[0] | |||
| setRightPanelWidth(inlineSize) | |||
| } | |||
| }) | |||
| resizeRightPanelObserver.observe(rightPanelRef.current) | |||
| return () => { | |||
| resizeRightPanelObserver.disconnect() | |||
| } | |||
| } | |||
| }, [setRightPanelWidth]) | |||
| const rightPanelRef = useResizeObserver( | |||
| setRightPanelWidth, | |||
| [setRightPanelWidth, selectedNode, showEnvPanel, showWorkflowVersionHistoryPanel], | |||
| ) | |||
| const otherPanelRef = useRef<HTMLDivElement>(null) | |||
| const setOtherPanelWidth = useStore(s => s.setOtherPanelWidth) | |||
| const otherPanelRef = useResizeObserver( | |||
| setOtherPanelWidth, | |||
| [setOtherPanelWidth, showEnvPanel, showWorkflowVersionHistoryPanel], | |||
| ) | |||
| // get other panel width | |||
| useEffect(() => { | |||
| if (otherPanelRef.current) { | |||
| const resizeOtherPanelObserver = new ResizeObserver((entries) => { | |||
| for (const entry of entries) { | |||
| const { inlineSize } = entry.borderBoxSize[0] | |||
| setOtherPanelWidth(inlineSize) | |||
| } | |||
| }) | |||
| resizeOtherPanelObserver.observe(otherPanelRef.current) | |||
| return () => { | |||
| resizeOtherPanelObserver.disconnect() | |||
| } | |||
| } | |||
| }, [setOtherPanelWidth]) | |||
| return ( | |||
| <div | |||
| ref={rightPanelRef} | |||
| @@ -65,26 +87,14 @@ const Panel: FC<PanelProps> = ({ | |||
| className={cn('absolute bottom-1 right-0 top-14 z-10 flex outline-none')} | |||
| key={`${isRestoring}`} | |||
| > | |||
| { | |||
| components?.left | |||
| } | |||
| { | |||
| !!selectedNode && ( | |||
| <NodePanel {...selectedNode!} /> | |||
| ) | |||
| } | |||
| {components?.left} | |||
| {!!selectedNode && <NodePanel {...selectedNode} />} | |||
| <div | |||
| className='relative' | |||
| className="relative" | |||
| ref={otherPanelRef} | |||
| > | |||
| { | |||
| components?.right | |||
| } | |||
| { | |||
| showEnvPanel && ( | |||
| <EnvPanel /> | |||
| ) | |||
| } | |||
| {components?.right} | |||
| {showEnvPanel && <EnvPanel />} | |||
| </div> | |||
| </div> | |||
| ) | |||