use-expand-collapse.js 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { useRef, useState, useLayoutEffect } from 'react'
  2. import classNames from 'classnames'
  3. function useExpandCollapse({
  4. initiallyExpanded = false,
  5. collapsedSize = '0',
  6. dimension = 'height',
  7. classes = {},
  8. } = {}) {
  9. const ref = useRef()
  10. const [isExpanded, setIsExpanded] = useState(initiallyExpanded)
  11. const [sizing, setSizing] = useState({
  12. size: null,
  13. needsExpandCollapse: null,
  14. })
  15. useLayoutEffect(() => {
  16. const expandCollapseEl = ref.current
  17. if (expandCollapseEl) {
  18. const expandedSize =
  19. dimension === 'height'
  20. ? expandCollapseEl.scrollHeight
  21. : expandCollapseEl.scrollWidth
  22. const needsExpandCollapse = expandedSize > collapsedSize
  23. if (isExpanded) {
  24. setSizing({ size: expandedSize, needsExpandCollapse })
  25. } else {
  26. setSizing({
  27. size: needsExpandCollapse ? collapsedSize : expandedSize,
  28. needsExpandCollapse,
  29. })
  30. }
  31. }
  32. }, [isExpanded, collapsedSize, dimension])
  33. const expandableClasses = classNames(
  34. 'expand-collapse-container',
  35. classes.container,
  36. !isExpanded ? classes.containerCollapsed : null
  37. )
  38. function handleToggle() {
  39. setIsExpanded(!isExpanded)
  40. }
  41. return {
  42. isExpanded,
  43. needsExpandCollapse: sizing.needsExpandCollapse,
  44. expandableProps: {
  45. ref,
  46. style: {
  47. [dimension === 'height' ? 'height' : 'width']: `${sizing.size}px`,
  48. },
  49. className: expandableClasses,
  50. },
  51. toggleProps: {
  52. onClick: handleToggle,
  53. },
  54. }
  55. }
  56. export default useExpandCollapse