stylescape
Version:
Stylescape is a visual identity framework developed by Scape Agency.
179 lines • 5.85 kB
JavaScript
const easingFunctions = {
linear: (t) => t,
easeIn: (t) => t * t,
easeOut: (t) => t * (2 - t),
easeInOut: (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
};
export function scrollTo(target, options = {}) {
const { offset = 0, duration = 500, easing = "easeInOut", onComplete, } = options;
let targetPosition;
if (typeof target === "number") {
targetPosition = target;
}
else {
const element = typeof target === "string"
? document.querySelector(target)
: target;
if (!element) {
console.warn("[Stylescape] scrollTo target not found:", target);
return;
}
targetPosition =
element.getBoundingClientRect().top + window.pageYOffset;
}
const startPosition = window.pageYOffset;
const distance = targetPosition + offset - startPosition;
const easingFn = easingFunctions[easing];
let startTime = null;
function animation(currentTime) {
if (startTime === null)
startTime = currentTime;
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
window.scrollTo(0, startPosition + distance * easingFn(progress));
if (elapsed < duration) {
requestAnimationFrame(animation);
}
else {
onComplete?.();
}
}
requestAnimationFrame(animation);
}
export function scrollToPosition(y, options = {}) {
if (options.smooth && options.duration) {
scrollTo(y, { duration: options.duration });
}
else {
window.scrollTo({
top: y,
behavior: options.smooth ? "smooth" : "auto",
});
}
}
export function scrollToTop(options = {}) {
scrollToPosition(0, options);
}
export function scrollToBottom(options = {}) {
const documentHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
scrollToPosition(documentHeight, options);
}
export class ScrollToTopButton {
constructor(options = {}) {
this.ticking = false;
this.handleScroll = () => {
if (!this.ticking) {
requestAnimationFrame(() => {
this.checkScroll();
this.ticking = false;
});
this.ticking = true;
}
};
this.handleClick = (event) => {
event.preventDefault();
if (this.options.smooth) {
scrollTo(0, { duration: this.options.duration });
}
else {
window.scrollTo(0, 0);
}
};
this.button =
typeof options.button === "string"
? document.querySelector(options.button)
: (options.button ?? null);
this.options = {
button: this.button ?? document.createElement("button"),
threshold: options.threshold ?? 300,
smooth: options.smooth ?? true,
duration: options.duration ?? 500,
visibleClass: options.visibleClass ?? "scroll-to-top--visible",
};
if (!this.button) {
console.warn("[Stylescape] ScrollToTopButton: button not found");
return;
}
this.init();
}
show() {
this.button?.classList.add(this.options.visibleClass);
this.button?.setAttribute("aria-hidden", "false");
}
hide() {
this.button?.classList.remove(this.options.visibleClass);
this.button?.setAttribute("aria-hidden", "true");
}
destroy() {
window.removeEventListener("scroll", this.handleScroll);
this.button?.removeEventListener("click", this.handleClick);
this.button = null;
}
static init() {
const buttons = [];
document
.querySelectorAll('[data-ss="scroll-to-top"]')
.forEach((el) => {
const threshold = el.dataset.ssScrollThreshold;
buttons.push(new ScrollToTopButton({
button: el,
threshold: threshold
? parseInt(threshold, 10)
: undefined,
}));
});
return buttons;
}
init() {
if (!this.button)
return;
this.button.setAttribute("aria-label", this.button.getAttribute("aria-label") || "Scroll to top");
this.button.setAttribute("aria-hidden", "true");
this.checkScroll();
window.addEventListener("scroll", this.handleScroll, {
passive: true,
});
this.button.addEventListener("click", this.handleClick);
}
checkScroll() {
const scrollY = window.pageYOffset || document.documentElement.scrollTop;
if (scrollY > this.options.threshold) {
this.show();
}
else {
this.hide();
}
}
}
export function initScrollLinks() {
document
.querySelectorAll('[data-ss="scroll-to"]')
.forEach((el) => {
const target = el.dataset.ssScrollTarget || el.getAttribute("href");
const offset = el.dataset.ssScrollOffset;
const duration = el.dataset.ssScrollDuration;
el.addEventListener("click", (event) => {
event.preventDefault();
if (target) {
scrollTo(target, {
offset: offset ? parseInt(offset, 10) : 0,
duration: duration ? parseInt(duration, 10) : 500,
});
}
});
});
}
export function initScrollUtilities() {
initScrollLinks();
ScrollToTopButton.init();
}
export default {
scrollTo,
scrollToPosition,
scrollToTop,
scrollToBottom,
ScrollToTopButton,
initScrollLinks,
initScrollUtilities,
};
//# sourceMappingURL=scroll.js.map