Last active
December 6, 2018 19:48
-
-
Save TrySound/75c96aad964e8991e37015342c8a643e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import * as React from 'react'; | |
import ResizeObserverPolyfill from 'resize-observer-polyfill'; | |
import invariant from 'tiny-invariant'; | |
const useLayoutEffect = (React: any).useLayoutEffect; | |
const useEffect = (React: any).useEffect; | |
type Rect = {| | |
x: number, | |
y: number, | |
width: number, | |
height: number, | |
|}; | |
const getRect = element => { | |
const width = element.offsetWidth; | |
const height = element.offsetHeight; | |
const rect = element.getBoundingClientRect(); | |
return { | |
x: rect.left, | |
y: rect.top, | |
width, | |
height, | |
}; | |
}; | |
export const useMeasure = <T: React.ElementType>(measureRef: { | |
current: React.ElementRef<T> | null, | |
}): ?Rect => { | |
const [rect, setRect] = React.useState<?Rect>(null); | |
const observer = React.useRef(null); | |
if (!observer.current) { | |
observer.current = new ResizeObserverPolyfill(entries => { | |
const target = entries[0].target; | |
if (target instanceof HTMLElement) { | |
setRect(getRect(target)); | |
} | |
}); | |
} | |
if (typeof window !== 'undefined') { | |
useLayoutEffect(() => { | |
invariant( | |
measureRef.current instanceof HTMLElement, | |
'Measuring ref should be an HTMLElement', | |
); | |
setRect(getRect(measureRef.current)); | |
}, []); | |
} | |
useEffect(() => { | |
if (measureRef.current instanceof HTMLElement && observer.current) { | |
observer.current.observe(measureRef.current); | |
return () => { | |
if (observer.current) { | |
observer.current.disconnect(); | |
} | |
}; | |
} | |
}, []); | |
return rect; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment