use-fixed-size-column.ts 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { useCallback, useEffect, useRef, useState } from 'react'
  2. import { ImperativePanelHandle } from 'react-resizable-panels'
  3. import { PanelGroupOnLayout } from 'react-resizable-panels/src/types'
  4. export default function useFixedSizeColumn(
  5. defaultSize: number,
  6. isOpen: boolean
  7. ) {
  8. const fixedPanelRef = useRef<ImperativePanelHandle>(null)
  9. const fixedPanelWidthRef = useRef({ size: defaultSize, pixels: 0 })
  10. const [initialLayoutDone, setInitialLayoutDone] = useState(false)
  11. const measureFixedPanelSizePixels = useCallback(() => {
  12. return fixedPanelRef.current?.getSize('pixels') || 0
  13. }, [fixedPanelRef])
  14. const handleLayout = useCallback(
  15. sizes => {
  16. // Measure the pixel width here because it's not always up to date in the
  17. // panel's onResize
  18. fixedPanelWidthRef.current = {
  19. size: sizes[0],
  20. pixels: measureFixedPanelSizePixels(),
  21. }
  22. setInitialLayoutDone(true)
  23. },
  24. [measureFixedPanelSizePixels]
  25. ) as PanelGroupOnLayout
  26. useEffect(() => {
  27. if (!isOpen) {
  28. return
  29. }
  30. // Only start watching for resizes once the initial layout is done,
  31. // otherwise we could measure the fixed column while it has zero width and
  32. // collapse it
  33. if (!initialLayoutDone || !fixedPanelRef.current) {
  34. return
  35. }
  36. const fixedPanelElement = document.querySelector(
  37. `[data-panel-id="${fixedPanelRef.current.getId()}"]`
  38. )
  39. const panelGroupElement = fixedPanelElement?.closest('[data-panel-group]')
  40. if (!panelGroupElement || !fixedPanelElement) {
  41. return
  42. }
  43. const resizeObserver = new ResizeObserver(() => {
  44. fixedPanelRef.current?.resize(fixedPanelWidthRef.current.pixels, 'pixels')
  45. })
  46. resizeObserver.observe(panelGroupElement)
  47. return () => resizeObserver.unobserve(panelGroupElement)
  48. }, [fixedPanelRef, measureFixedPanelSizePixels, initialLayoutDone, isOpen])
  49. return {
  50. fixedPanelRef,
  51. fixedPanelWidthRef,
  52. handleLayout,
  53. }
  54. }