aboutsummaryrefslogtreecommitdiff
path: root/vnext/src/ui/Header.js
diff options
context:
space:
mode:
Diffstat (limited to 'vnext/src/ui/Header.js')
-rw-r--r--vnext/src/ui/Header.js69
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
+};