您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import type { FC } from 'react'
  2. import { memo, useCallback, useEffect, useRef } from 'react'
  3. import { useNodes } from 'reactflow'
  4. import type { CommonNodeType } from '../types'
  5. import { Panel as NodePanel } from '../nodes'
  6. import { useStore } from '../store'
  7. import EnvPanel from './env-panel'
  8. import cn from '@/utils/classnames'
  9. export type PanelProps = {
  10. components?: {
  11. left?: React.ReactNode
  12. right?: React.ReactNode
  13. }
  14. }
  15. /**
  16. * Reference MDN standard implementation:https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserverEntry/borderBoxSize
  17. */
  18. const getEntryWidth = (entry: ResizeObserverEntry, element: HTMLElement): number => {
  19. if (entry.borderBoxSize?.length > 0)
  20. return entry.borderBoxSize[0].inlineSize
  21. if (entry.contentRect.width > 0)
  22. return entry.contentRect.width
  23. return element.getBoundingClientRect().width
  24. }
  25. const useResizeObserver = (
  26. callback: (width: number) => void,
  27. dependencies: React.DependencyList = [],
  28. ) => {
  29. const elementRef = useRef<HTMLDivElement>(null)
  30. const stableCallback = useCallback(callback, [callback])
  31. useEffect(() => {
  32. const element = elementRef.current
  33. if (!element) return
  34. const resizeObserver = new ResizeObserver((entries) => {
  35. for (const entry of entries) {
  36. const width = getEntryWidth(entry, element)
  37. stableCallback(width)
  38. }
  39. })
  40. resizeObserver.observe(element)
  41. const initialWidth = element.getBoundingClientRect().width
  42. stableCallback(initialWidth)
  43. return () => {
  44. resizeObserver.disconnect()
  45. }
  46. }, [stableCallback, ...dependencies])
  47. return elementRef
  48. }
  49. const Panel: FC<PanelProps> = ({
  50. components,
  51. }) => {
  52. const nodes = useNodes<CommonNodeType>()
  53. const selectedNode = nodes.find(node => node.data.selected)
  54. const showEnvPanel = useStore(s => s.showEnvPanel)
  55. const isRestoring = useStore(s => s.isRestoring)
  56. const showWorkflowVersionHistoryPanel = useStore(s => s.showWorkflowVersionHistoryPanel)
  57. const setRightPanelWidth = useStore(s => s.setRightPanelWidth)
  58. const setOtherPanelWidth = useStore(s => s.setOtherPanelWidth)
  59. const rightPanelRef = useResizeObserver(
  60. setRightPanelWidth,
  61. [setRightPanelWidth, selectedNode, showEnvPanel, showWorkflowVersionHistoryPanel],
  62. )
  63. const otherPanelRef = useResizeObserver(
  64. setOtherPanelWidth,
  65. [setOtherPanelWidth, showEnvPanel, showWorkflowVersionHistoryPanel],
  66. )
  67. return (
  68. <div
  69. ref={rightPanelRef}
  70. tabIndex={-1}
  71. className={cn('absolute bottom-1 right-0 top-14 z-10 flex outline-none')}
  72. key={`${isRestoring}`}
  73. >
  74. {components?.left}
  75. {!!selectedNode && <NodePanel {...selectedNode} />}
  76. <div
  77. className="relative"
  78. ref={otherPanelRef}
  79. >
  80. {components?.right}
  81. {showEnvPanel && <EnvPanel />}
  82. </div>
  83. </div>
  84. )
  85. }
  86. export default memo(Panel)