diff options
Diffstat (limited to 'vnext/src/ui/Header.js')
-rw-r--r-- | vnext/src/ui/Header.js | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/vnext/src/ui/Header.js b/vnext/src/ui/Header.js new file mode 100644 index 00000000..48f89360 --- /dev/null +++ b/vnext/src/ui/Header.js @@ -0,0 +1,69 @@ +import React, { useEffect, useCallback, useRef } from 'react'; +import ReactDOM from 'react-dom'; +import PropTypes from 'prop-types'; + +const elClassHidden = 'header--hidden'; + +const header = document.getElementById('header'); +header.removeChild(document.getElementById('header_wrapper')); + +export default function Header({ children }) { + let dHeight = useRef(0); + let wHeight = useRef(0); + let wScrollCurrent = useRef(0); + let wScrollBefore = useRef(0); + let wScrollDiff = useRef(0); + + useEffect(() => { + window.addEventListener('scroll', () => (!window.requestAnimationFrame) + ? throttle(250, updateHeader) + : window.requestAnimationFrame(updateHeader), false); + }, [updateHeader]); + let throttle = (delay, fn) => { + var last, deferTimer; + return function () { + var context = this, args = arguments, now = +new Date; + if (last && now < last + delay) { + clearTimeout(deferTimer); + deferTimer = setTimeout( + function () { + last = now; + fn.apply(context, args); + }, + delay); + } else { + last = now; + fn.apply(context, args); + } + }; + }; + let updateHeader = useCallback(() => { + dHeight.current = document.body.offsetHeight; + wHeight.current = window.innerHeight; + wScrollCurrent.current = window.pageYOffset; + wScrollDiff.current = wScrollBefore.current - wScrollCurrent.current; + + if (wScrollCurrent.current <= 0) { + // scrolled to the very top; element sticks to the top + header.classList.remove(elClassHidden); + } else if (wScrollDiff > 0 && header.classList.contains(elClassHidden)) { + // scrolled up; element slides in + header.classList.remove(elClassHidden); + } else if (wScrollDiff.current < 0) { + // scrolled down + if (wScrollCurrent.current + wHeight.current >= dHeight.current && header.classList.contains(elClassHidden)) { + // scrolled to the very bottom; element slides in + header.classList.remove(elClassHidden); + } else { + // scrolled down; element slides out + header.classList.add(elClassHidden); + } + } + wScrollBefore.current = wScrollCurrent.current; + }, []); + return ReactDOM.createPortal(children, header); +} + +Header.propTypes = { + children: PropTypes.node +}; |