use-fixed-size-column.ts 1.6 KB

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