mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 12:27:43 +00:00
fix(docs): anchor link scrolling with conflict prevention (#5186)
This commit is contained in:
committed by
GitHub
parent
72d63b6e0f
commit
91778b5bbd
107
docs/components/anchor-scroll-fix.tsx
Normal file
107
docs/components/anchor-scroll-fix.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export function AnchorScroll() {
|
||||
const scrollTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||
const isScrollingRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
function calculateScrollOffset() {
|
||||
const root = document.documentElement;
|
||||
const navHeight = parseInt(
|
||||
getComputedStyle(root).getPropertyValue("--fd-nav-height") || "56",
|
||||
);
|
||||
const bannerHeight = parseInt(
|
||||
getComputedStyle(root).getPropertyValue("--fd-banner-height") || "0",
|
||||
);
|
||||
const tocnavHeight = parseInt(
|
||||
getComputedStyle(root).getPropertyValue("--fd-tocnav-height") || "0",
|
||||
);
|
||||
|
||||
return navHeight + bannerHeight + tocnavHeight + 24;
|
||||
}
|
||||
|
||||
function smoothScrollToElement(element: HTMLElement) {
|
||||
if (isScrollingRef.current) return;
|
||||
|
||||
isScrollingRef.current = true;
|
||||
document.documentElement.setAttribute("data-anchor-scrolling", "true");
|
||||
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
const scrollOffset = calculateScrollOffset();
|
||||
const targetPosition =
|
||||
window.pageYOffset + elementRect.top - scrollOffset;
|
||||
|
||||
// Simple smooth scroll animation
|
||||
const startPosition = window.pageYOffset;
|
||||
const distance = targetPosition - startPosition;
|
||||
const duration = Math.min(500, Math.abs(distance) * 0.3);
|
||||
const startTime = performance.now();
|
||||
|
||||
function animateScroll(currentTime: number) {
|
||||
const elapsed = currentTime - startTime;
|
||||
const progress = Math.min(elapsed / duration, 1);
|
||||
const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);
|
||||
const currentPosition =
|
||||
startPosition + distance * easeOutCubic(progress);
|
||||
|
||||
window.scrollTo(0, currentPosition);
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animateScroll);
|
||||
} else {
|
||||
document.documentElement.removeAttribute("data-anchor-scrolling");
|
||||
isScrollingRef.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(animateScroll);
|
||||
}
|
||||
|
||||
function handleAnchorScroll() {
|
||||
if (window.location.hash) {
|
||||
const element = document.getElementById(window.location.hash.slice(1));
|
||||
if (element) {
|
||||
scrollTimeoutRef.current = setTimeout(
|
||||
() => smoothScrollToElement(element),
|
||||
100,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleHashChange() {
|
||||
const element = document.getElementById(window.location.hash.slice(1));
|
||||
if (element) smoothScrollToElement(element);
|
||||
}
|
||||
|
||||
function handleAnchorClick(event: Event) {
|
||||
const link = (event.target as HTMLElement).closest(
|
||||
'a[href^="#"]',
|
||||
) as HTMLAnchorElement;
|
||||
|
||||
if (link?.hash) {
|
||||
event.preventDefault();
|
||||
const element = document.getElementById(link.hash.slice(1));
|
||||
|
||||
if (element) {
|
||||
history.pushState(null, "", link.hash);
|
||||
smoothScrollToElement(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleAnchorScroll();
|
||||
window.addEventListener("hashchange", handleHashChange);
|
||||
document.addEventListener("click", handleAnchorClick);
|
||||
|
||||
return () => {
|
||||
if (scrollTimeoutRef.current) clearTimeout(scrollTimeoutRef.current);
|
||||
window.removeEventListener("hashchange", handleHashChange);
|
||||
document.removeEventListener("click", handleAnchorClick);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user