use-toolbar-breakpoint.js 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { useEffect, useLayoutEffect, useMemo, useState } from 'react'
  2. import classnames from 'classnames'
  3. const measureContentWidth = element =>
  4. [...element.querySelectorAll('button')].reduce(
  5. (output, item) => output + item.scrollWidth,
  6. 0
  7. )
  8. export default function useToolbarBreakpoint(element) {
  9. const [breakpoint, setBreakpoint] = useState(2)
  10. const [recalculate, setRecalculate] = useState(true)
  11. const [resizeObserver] = useState(
  12. () =>
  13. new ResizeObserver(() => {
  14. setBreakpoint(2)
  15. setRecalculate(true)
  16. })
  17. )
  18. const [mutationObserver] = useState(
  19. () =>
  20. new MutationObserver(() => {
  21. setBreakpoint(2)
  22. setRecalculate(true)
  23. })
  24. )
  25. useEffect(() => {
  26. if (element && mutationObserver && resizeObserver) {
  27. resizeObserver.observe(element)
  28. mutationObserver.observe(element, {
  29. childList: true,
  30. subtree: true,
  31. characterData: true,
  32. })
  33. return () => {
  34. mutationObserver.disconnect()
  35. resizeObserver.disconnect()
  36. }
  37. }
  38. }, [element, mutationObserver, resizeObserver])
  39. useLayoutEffect(() => {
  40. if (recalculate && element && breakpoint) {
  41. const contentWidth = measureContentWidth(element) + 150 // NOTE: remove this constant?
  42. if (contentWidth > element.clientWidth) {
  43. setBreakpoint(value => value - 1)
  44. } else {
  45. setRecalculate(false)
  46. }
  47. }
  48. }, [element, breakpoint, recalculate])
  49. return useMemo(
  50. () =>
  51. classnames({
  52. toolbar: true,
  53. 'toolbar-pdf': true,
  54. 'toolbar-large': breakpoint === 2,
  55. 'toolbar-medium': breakpoint === 1,
  56. 'toolbar-small': breakpoint === 0,
  57. }),
  58. [breakpoint]
  59. )
  60. }