use-expand-collapse.js 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  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. () => {
  17. const expandCollapseEl = ref.current
  18. if (expandCollapseEl) {
  19. const expandedSize =
  20. dimension === 'height'
  21. ? expandCollapseEl.scrollHeight
  22. : expandCollapseEl.scrollWidth
  23. const needsExpandCollapse = expandedSize > collapsedSize
  24. if (isExpanded) {
  25. setSizing({ size: expandedSize, needsExpandCollapse })
  26. } else {
  27. setSizing({
  28. size: needsExpandCollapse ? collapsedSize : expandedSize,
  29. needsExpandCollapse
  30. })
  31. }
  32. }
  33. },
  34. [isExpanded]
  35. )
  36. const expandableClasses = classNames(
  37. 'expand-collapse-container',
  38. classes.container,
  39. !isExpanded ? classes.containerCollapsed : null
  40. )
  41. function handleToggle() {
  42. setIsExpanded(!isExpanded)
  43. }
  44. return {
  45. isExpanded,
  46. needsExpandCollapse: sizing.needsExpandCollapse,
  47. expandableProps: {
  48. ref,
  49. style: {
  50. [dimension === 'height' ? 'height' : 'width']: `${sizing.size}px`
  51. },
  52. className: expandableClasses
  53. },
  54. toggleProps: {
  55. onClick: handleToggle
  56. }
  57. }
  58. }
  59. export default useExpandCollapse