hiding-header
Version:
Toggles header visibility on scroll.
221 lines (217 loc) • 8.47 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function hidingHeader(container, _a) {
var _b = _a === void 0 ? {} : _a, _c = _b.heightPropertyName, heightPropertyName = _c === void 0 ? '--hidingHeader-height' : _c, _d = _b.boundsHeightPropertyName, boundsHeightPropertyName = _d === void 0 ? '--hidingHeader-bounds-height' : _d, _e = _b.animationOffsetPropertyName, animationOffsetPropertyName = _e === void 0 ? '--hidingHeader-animation-offset' : _e, _f = _b.snap, snap = _f === void 0 ? true : _f, _g = _b.onHeightChange, onHeightChange = _g === void 0 ? function () { } : _g, _h = _b.onVisibleHeightChange, onVisibleHeightChange = _h === void 0 ? function () { } : _h, _j = _b.onHomeChange, onHomeChange = _j === void 0 ? function () { } : _j;
var content = container.querySelector('*');
var lastScrollTopPosition = 0;
var contentHeight = (function () {
var getContentHeight = function () { return content.clientHeight; };
var setContentHeightProperty = function (height) {
container.style.setProperty(heightPropertyName, "".concat(height, "px"));
};
var resizeObserver = new ResizeObserver(function () {
var newContentHeight = getContentHeight();
if (contentHeight !== newContentHeight) {
contentHeight = newContentHeight;
setContentHeightProperty(contentHeight);
onScroll();
onHeightChange(contentHeight);
}
});
resizeObserver.observe(content);
var initialHeight = getContentHeight();
setContentHeightProperty(initialHeight);
return initialHeight;
})();
var visibleHeight = contentHeight;
var paused = false;
var home = true;
var lastBoundsHeight = 0;
var pointersDown = 0;
var parent = container.parentElement;
if (parent === null) {
throw new Error('Missing parent element.');
}
var getParentHeight = function () {
return parent.clientHeight;
};
var getGlobalTopOffset = function () {
return container.offsetTop;
};
var getRelativeTopOffset = function () {
var _a;
return getGlobalTopOffset() - (((_a = container.parentElement) === null || _a === void 0 ? void 0 : _a.offsetTop) || 0);
};
var animateOffset = function (initialOffset) {
if (initialOffset === 0) {
return; // Nothing to animate
}
content.style.transition = 'none';
container.style.setProperty(animationOffsetPropertyName, "".concat(initialOffset, "px"));
content.offsetHeight; // Trigger transition
content.style.transition = '';
container.style.setProperty(animationOffsetPropertyName, '0px');
};
var updateBoundsHeight = function (boundsHeight) {
if (boundsHeight !== lastBoundsHeight) {
container.style.setProperty(boundsHeightPropertyName, "".concat(boundsHeight, "px"));
lastBoundsHeight = boundsHeight;
}
};
var capBoundsHeight = function (rawBoundsHeight) {
return Math.min(getParentHeight() - getRelativeTopOffset(), Math.max(contentHeight, rawBoundsHeight));
};
var snapIfPossible = function () {
if (snap && visibleHeight !== 0 && visibleHeight !== contentHeight) {
if (visibleHeight < contentHeight / 2) {
hide();
}
else {
reveal();
}
}
};
var onScrollStopDebounced = (function () {
var timer;
return function () {
window.clearTimeout(timer);
timer = window.setTimeout(function () {
if (snap && pointersDown === 0) {
snapIfPossible();
}
}, 100);
};
})();
var updateVisibleHeight = function () {
visibleHeight = (function () {
var top = content.getBoundingClientRect().top;
var newVisibleHeight = Math.max(0, Math.min(contentHeight + top, contentHeight));
if (visibleHeight !== newVisibleHeight) {
onVisibleHeightChange(newVisibleHeight);
}
return newVisibleHeight;
})();
};
var updateHome = function () {
home = (function () {
var newHome = contentHeight >= lastBoundsHeight;
if (home !== newHome) {
onHomeChange(newHome);
}
return newHome;
})();
};
var onTransitioning = function () {
updateVisibleHeight();
};
(function () {
var running = false;
var loop = function () {
if (!running) {
return;
}
onTransitioning();
requestAnimationFrame(loop);
};
// @TODO: remove listeners on destroy()
content.addEventListener('transitionstart', function () {
running = true;
loop();
});
// @TODO: remove listeners on destroy()
content.addEventListener('transitionend', function () {
running = false;
onTransitioning();
});
})();
var onScroll = function () {
var globalTopOffset = getGlobalTopOffset();
// Handle bounds height
var scrollTopPosition = window.scrollY;
var isScrollingDown = scrollTopPosition > lastScrollTopPosition;
if (!paused) {
var boundsHeight = capBoundsHeight((function () {
if (isScrollingDown) {
var newBoundsHeight = scrollTopPosition - globalTopOffset;
if (lastBoundsHeight < newBoundsHeight) {
return newBoundsHeight;
}
return lastBoundsHeight;
}
else {
var newBoundsHeight = scrollTopPosition - globalTopOffset + contentHeight;
if (lastBoundsHeight > newBoundsHeight) {
return newBoundsHeight;
}
return lastBoundsHeight;
}
})());
updateBoundsHeight(boundsHeight);
onScrollStopDebounced();
updateVisibleHeight();
updateHome();
}
lastScrollTopPosition = scrollTopPosition;
};
var onResize = onScroll;
var onPointerDown = function () {
pointersDown++;
onScroll();
};
var onPointerUp = function () {
pointersDown--;
onScroll();
};
var initialize = function () {
window.addEventListener('scroll', onScroll);
window.addEventListener('resize', onResize);
document.addEventListener('pointerdown', onPointerDown);
document.addEventListener('pointerup', onPointerUp);
onScroll();
};
var destroy = function () {
window.removeEventListener('scroll', onScroll);
window.removeEventListener('resize', onResize);
document.removeEventListener('pointerdown', onPointerDown);
document.removeEventListener('pointerup', onPointerUp);
};
initialize();
var run = function () {
paused = false;
};
var pause = function () {
paused = true;
};
var isPaused = function () {
return paused;
};
var isHome = function () { return home; };
var reveal = function () {
var scrollTopPosition = window.scrollY;
var globalTopOffset = getGlobalTopOffset();
var boundsHeight = capBoundsHeight(scrollTopPosition - globalTopOffset + contentHeight);
animateOffset(lastBoundsHeight - boundsHeight);
updateBoundsHeight(boundsHeight);
};
var hide = function () {
var scrollTopPosition = window.scrollY;
var globalTopOffset = getGlobalTopOffset();
var boundsHeight = capBoundsHeight(scrollTopPosition - globalTopOffset);
animateOffset(lastBoundsHeight - boundsHeight);
updateBoundsHeight(boundsHeight);
};
var getHeight = function () { return contentHeight; };
var getVisibleHeight = function () { return visibleHeight; };
return {
run: run,
pause: pause,
isPaused: isPaused,
isHome: isHome,
reveal: reveal,
hide: hide,
getHeight: getHeight,
getVisibleHeight: getVisibleHeight,
destroy: destroy,
};
}
exports.hidingHeader = hidingHeader;