useBreakpoints.tsx 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import {useEffect, useState} from 'react';
  2. import type {Theme} from '@emotion/react';
  3. import {useTheme} from '@emotion/react';
  4. import debounce from 'lodash/debounce';
  5. import isEqual from 'lodash/isEqual';
  6. import {useInstantRef} from 'sentry/utils/metrics';
  7. type Breakpoint = keyof Theme['breakpoints'];
  8. export function checkBreakpoints(
  9. breakpoints: Theme['breakpoints'],
  10. width: number
  11. ): Record<Breakpoint, boolean> {
  12. return Object.entries(breakpoints).reduce(
  13. (acc, [key, value]) => {
  14. // Assuming breakpoints are pixel values
  15. acc[key as Breakpoint] = width >= parseInt(value, 10);
  16. return acc;
  17. },
  18. {} as Record<Breakpoint, boolean>
  19. );
  20. }
  21. /**
  22. * Returns the currently active breakpoints
  23. */
  24. export function useBreakpoints(): Record<Breakpoint, boolean> {
  25. const theme = useTheme();
  26. const [value, setValue] = useState(
  27. checkBreakpoints(theme.breakpoints, window.innerWidth)
  28. );
  29. const valueRef = useInstantRef(value);
  30. useEffect(() => {
  31. const handleResize = debounce(() => {
  32. const newValue = checkBreakpoints(theme.breakpoints, window.innerWidth);
  33. if (!isEqual(newValue, valueRef.current)) {
  34. setValue(newValue);
  35. }
  36. }, 100);
  37. window.addEventListener('resize', handleResize, {passive: true});
  38. return () => {
  39. window.removeEventListener('resize', handleResize);
  40. handleResize.cancel();
  41. };
  42. }, [theme.breakpoints, valueRef]);
  43. return value;
  44. }