@ulu/frontend
Version:
A versatile SCSS and JavaScript component library offering configurable, accessible components and flexible integration into any project, with SCSS modules suitable for modern JS frameworks.
77 lines (70 loc) • 2.44 kB
JavaScript
/**
* @todo This file is untested since conversion to module
*/
import ElementWaypoint from "./element-waypoint.js";
export default function init(anchors, caret, options) {
const defaults = {
offsetTop: "20%",
activeClass: "active"
};
options = Object.assign(defaults, options);
const targets = anchors.map(a => document.getElementById(a.hash.substr(1)));
const { activeClass } = options;
let caretNotEntered = true;
let caretVisible;
targets.forEach(element => new ElementWaypoint({ offsetTop: options.offsetTop, handler, element }));
function handler(entering, direction) {
const { element } = this.options;
const anchor = anchors[ targets.indexOf(element) ];
const index = anchors.indexOf(anchor);
if (entering) {
removeActiveAll();
activateAnchor(anchor);
anchor.classList.add(activeClass);
// Above the first
} else if (index === 0 && direction === "up") {
removeActiveAll(true);
// Since we are using headlines instaed of containers we need to
// activate when user is scrolling up. By finding the index of the anchor
// above the recently deactivated headline target
} else if (direction === "up") {
removeActiveAll();
activateAnchor(anchors[index - 1]);
}
}
function removeActiveAll(hideCaret) {
anchors.forEach(anchor => anchor.classList.remove(activeClass));
if (hideCaret) {
setCaretVisibility(false);
}
}
function activateAnchor(anchor) {
// Block transtions on first reveal
if (caretNotEntered) {
caret.style.transition = 'none';
}
anchor.classList.add(activeClass);
setCaretPosition(anchor);
if (!caretVisible) {
setCaretVisibility(true);
}
// Add the transitions back in for the next change to visiblity or position
if (caret && caretNotEntered) {
caretNotEntered = false;
caret.offsetHeight; // Force repaint (visiblity above)
caret.style.transition = ''; // Then remove the transition block
}
}
function setCaretPosition(anchor) {
if (!caret) return;
const position = anchor.offsetTop;
const height = anchor.clientHeight;
caret.style.transform = `translateY(${ position + (height / 2) }px)`;
// caret.style.height = `${ anchor.clientHeight }px`;
}
function setCaretVisibility(visible) {
if (!caret) return;
caret.style.opacity = +(visible);
caretVisible = visible;
}
}