import { useEffect, useRef, type CSSProperties } from 'react'; export interface ScrollProgressProps { /** Element to track. Defaults to `document.documentElement`. */ target?: HTMLElement | null; /** Bar position. Default 'top'. */ position?: 'top' | 'bottom'; /** Bar height in pixels. Default 3. */ thickness?: number; /** Bar fill color. Default `var(--bl-accent)`. */ color?: string; className?: string; style?: CSSProperties; } /** * `` — fixed progress bar reflecting scroll position * of a target (defaults to the document). Common chrome element on * long-form pages and onboarding flows. * * Updates the bar's `scaleX` transform directly via a ref so React * doesn't re-render on every scroll event. */ export function ScrollProgress({ target, position = 'top', thickness = 3, color = 'var(--bl-accent, #6366f1)', className, style, }: ScrollProgressProps) { const ref = useRef(null); useEffect(() => { const root = target ?? (typeof document !== 'undefined' ? document.documentElement : null); if (!root) return; const update = () => { const el = ref.current; if (!el) return; const max = root.scrollHeight - root.clientHeight; const pct = max > 0 ? Math.min(1, root.scrollTop / max) : 0; el.style.transform = `scaleX(${pct})`; }; update(); const scrollEl = root === document.documentElement ? window : root; scrollEl.addEventListener('scroll', update, { passive: true }); window.addEventListener('resize', update); return () => { scrollEl.removeEventListener('scroll', update); window.removeEventListener('resize', update); }; }, [target]); return (
); }