feat: Refactor panel component, add adaptive width observer to optimize panel width management (#21576)

This commit is contained in:
GuanMu
2025-06-27 10:50:33 +08:00
committed by GitHub
parent 81fc49d78c
commit 787ad5ab38

View File

@@ -1,5 +1,5 @@
import type { FC } from 'react' import type { FC } from 'react'
import { memo, useEffect, useRef } from 'react' import { memo, useCallback, useEffect, useRef } from 'react'
import { useNodes } from 'reactflow' import { useNodes } from 'reactflow'
import type { CommonNodeType } from '../types' import type { CommonNodeType } from '../types'
import { Panel as NodePanel } from '../nodes' import { Panel as NodePanel } from '../nodes'
@@ -13,6 +13,51 @@ export type PanelProps = {
right?: React.ReactNode right?: React.ReactNode
} }
} }
/**
* Reference MDN standard implementationhttps://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> = ({ const Panel: FC<PanelProps> = ({
components, components,
}) => { }) => {
@@ -20,44 +65,21 @@ const Panel: FC<PanelProps> = ({
const selectedNode = nodes.find(node => node.data.selected) const selectedNode = nodes.find(node => node.data.selected)
const showEnvPanel = useStore(s => s.showEnvPanel) const showEnvPanel = useStore(s => s.showEnvPanel)
const isRestoring = useStore(s => s.isRestoring) const isRestoring = useStore(s => s.isRestoring)
const showWorkflowVersionHistoryPanel = useStore(s => s.showWorkflowVersionHistoryPanel)
const rightPanelRef = useRef<HTMLDivElement>(null)
const setRightPanelWidth = useStore(s => s.setRightPanelWidth) const setRightPanelWidth = useStore(s => s.setRightPanelWidth)
// 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 otherPanelRef = useRef<HTMLDivElement>(null)
const setOtherPanelWidth = useStore(s => s.setOtherPanelWidth) const setOtherPanelWidth = useStore(s => s.setOtherPanelWidth)
// get other panel width const rightPanelRef = useResizeObserver(
useEffect(() => { setRightPanelWidth,
if (otherPanelRef.current) { [setRightPanelWidth, selectedNode, showEnvPanel, showWorkflowVersionHistoryPanel],
const resizeOtherPanelObserver = new ResizeObserver((entries) => { )
for (const entry of entries) {
const { inlineSize } = entry.borderBoxSize[0] const otherPanelRef = useResizeObserver(
setOtherPanelWidth(inlineSize) setOtherPanelWidth,
} [setOtherPanelWidth, showEnvPanel, showWorkflowVersionHistoryPanel],
}) )
resizeOtherPanelObserver.observe(otherPanelRef.current)
return () => {
resizeOtherPanelObserver.disconnect()
}
}
}, [setOtherPanelWidth])
return ( return (
<div <div
ref={rightPanelRef} ref={rightPanelRef}
@@ -65,26 +87,14 @@ const Panel: FC<PanelProps> = ({
className={cn('absolute bottom-1 right-0 top-14 z-10 flex outline-none')} className={cn('absolute bottom-1 right-0 top-14 z-10 flex outline-none')}
key={`${isRestoring}`} key={`${isRestoring}`}
> >
{ {components?.left}
components?.left {!!selectedNode && <NodePanel {...selectedNode} />}
}
{
!!selectedNode && (
<NodePanel {...selectedNode!} />
)
}
<div <div
className='relative' className="relative"
ref={otherPanelRef} ref={otherPanelRef}
> >
{ {components?.right}
components?.right {showEnvPanel && <EnvPanel />}
}
{
showEnvPanel && (
<EnvPanel />
)
}
</div> </div>
</div> </div>
) )