UNPKG

stylescape

Version:

Stylescape is a visual identity framework developed by Scape Agency.

179 lines 5.85 kB
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