feat: Refactor panel component, add adaptive width observer to optimize panel width management (#21576)
This commit is contained in:
@@ -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 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> = ({
|
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>
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user