Created
December 2, 2020 22:51
-
-
Save adam-zethraeus/1fafa2f4b8aead44eaffbc8c6634ce8e to your computer and use it in GitHub Desktop.
useViewportSpace.ts
This file contains 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
import { useState, useEffect, MutableRefObject } from 'react'; | |
type Location = { x: number; y: number }; | |
type Size = { width: number; height: number }; | |
type Space = { location: Location; size: Size }; | |
// The viewport information for the passed Div. | |
const useViewportSpace = ( | |
scrollArea: MutableRefObject<HTMLDivElement | undefined>, | |
): { content?: Space; viewport?: Space } => { | |
const [space, setSpace] = useState<{ content?: Space; viewport?: Space }>({ | |
content: undefined, | |
viewport: undefined, | |
}); | |
// Called only on the client, and only once due to empty dependency list. | |
useEffect((): (() => void) => { | |
const element = scrollArea.current; | |
let content: () => Space | undefined; | |
let viewport: () => Space | undefined; | |
if (!element) { | |
content = () => undefined; | |
viewport = () => undefined; | |
} else { | |
content = () => ({ | |
// The location of the content is always at (0,0) relative to its viewport. | |
location: { | |
x: 0, | |
y: 0, | |
}, | |
size: { | |
width: element.scrollWidth, | |
height: element.scrollHeight, | |
}, | |
}); | |
viewport = () => ({ | |
location: { | |
x: element.scrollLeft, | |
y: element.scrollTop, | |
}, | |
size: { | |
width: element.clientWidth, | |
height: element.clientHeight, | |
}, | |
}); | |
} | |
const updateViewport = () => { | |
setSpace({ | |
content: content(), | |
viewport: viewport(), | |
}); | |
}; | |
// Set values for initial return. | |
updateViewport(); | |
// Set up listeners for changes. | |
element.addEventListener('resize', updateViewport); | |
element.addEventListener('scroll', updateViewport); | |
return () => { | |
// Tear down listeners when we're disposed. | |
element.removeEventListener('resize', updateViewport); | |
element.removeEventListener('scroll', updateViewport); | |
}; | |
}, [scrollArea.current]); | |
return space; | |
}; | |
export default useViewportSpace; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment