npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

scroll-father

v2.4.1

Published

Scroll Father: A library for scroll events and dynamic class handling.

Readme

Scroll Father

Scroll Father — лёгкий TypeScript toolkit для повседневного scroll UI: плавные якоря, scrollspy, reveal-анимации, progress bar, определение направления скролла и бесконечная загрузка. Библиотека не заменяет нативный скролл тяжёлой магией, а даёт аккуратные DOM-примитивы с cleanup, accessibility-настройками и zero-dependency core.

Возможности

  • Anchor scroll: плавные якоря с fixed-header offset, hash-режимами, delegated listener и focus для accessibility.
  • ScrollSpy: активная секция, подсветка меню, aria-current и data-active-section.
  • Reveal on scroll: AOS-подобный state engine без CSS-пресетов и зависимостей.
  • Scroll progress: CSS variable и callback для progress bar чтения или scroll-контейнера.
  • Infinite loading: sentinel-based загрузка через IntersectionObserver, состояния, retry, abort и prefill.
  • Legacy helpers: debounce scroll, scroll state, direction tracking и простая infinite scroll функция.
  • TypeScript: типы экспортируются из пакета.
  • Cleanup-first: инициализаторы возвращают функцию очистки или безопасно no-op в SSR.

Установка

npm i scroll-father

CDN/IIFE:

<script src="https://cdn.jsdelivr.net/npm/scroll-father/ScrollFather.min.js"></script>

Демо

Локальная витрина показывает реальные сценарии Scroll Father: якоря, scrollspy, reveal, progress bar, direction tracking и infinite loader на одной странице.

npm run demos

Быстрый старт

import {
	initAnchorScroll,
	initScrollSpy,
	initRevealOnScroll,
	initScrollProgress,
	initInfiniteLoader,
} from 'scroll-father';

Большинство функций возвращают cleanup() — вызовите его, когда поведение больше не нужно.

Anchor Scroll

Решает типичную боль якорей: fixed header, hash, focus, динамические ссылки.

const cleanupAnchors = initAnchorScroll({
	offset: () => document.querySelector('.header')?.clientHeight ?? 0,
	behavior: 'smooth',
	updateHash: 'replace', // 'keep' | 'clear' | 'replace' | 'push' | false
	focusTarget: true,
	delegated: true,
});

Совместимый alias старого API тоже остаётся:

import { smootherAllAnchorLinks } from 'scroll-father';

const cleanup = smootherAllAnchorLinks({ offset: 80, clearHash: false });

Можно установить статичный offset:

let offset = 0;
if (window.innerWidth >= breakpoints['2xl']) offset = 96;
else offset = 60;

smootherAllAnchorLinks({ offset });

Можно вычислять offset перед каждым новым скроллом:

const setOffsetBeforeScroll = () => {
	if (document.body.getAttribute('data-scroll-direction') === 'up') {
		return window.innerWidth >= breakpoints['2xl'] ? 96 : 60;
	}

	return 0;
};

smootherAllAnchorLinks({ setOffsetBeforeScroll });

ScrollSpy

Подсвечивает активный пункт меню и секцию.

const cleanupSpy = initScrollSpy({
	sections: 'section[id]',
	navLinks: '.docs-nav a[href^="#"]',
	offset: 96,
	activeClass: 'is-active',
	sectionActiveClass: 'is-current-section',
	attribute: 'data-active-section',
	ariaCurrent: 'location',
	onChange: ({ activeId, direction }) => {
		console.log(activeId, direction);
	},
});

Reveal On Scroll

Библиотека только ставит state, классы и CSS variables. Анимацию удобно держать в CSS.

const cleanupReveal = initRevealOnScroll({
	elements: '[data-reveal]',
	visibleClass: 'is-visible',
	attribute: 'data-reveal-state',
	once: true,
	stagger: 80,
});
[data-reveal] {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.45s ease,
		transform 0.45s ease;
	transition-delay: var(--reveal-delay, 0ms);
}

[data-reveal-state='visible'] {
	opacity: 1;
	transform: translateY(0);
}

Scroll Progress

Пишет прогресс 0..1 в CSS variable и callback.

const cleanupProgress = initScrollProgress({
	cssVariable: '--reading-progress',
	attribute: 'data-reading-progress',
	onChange: ({ progress }) => {
		console.log(Math.round(progress * 100));
	},
});
.progress-bar {
	transform: scaleX(var(--reading-progress, 0));
	transform-origin: left;
}

Infinite Loader

Новый sentinel-based loader для списков, каталогов и лент.

const cleanupLoader = initInfiniteLoader({
	sentinel: '#load-more-sentinel',
	rootMargin: '400px 0px',
	prefill: true,
	loadMore: async ({ page, signal, done }) => {
		const response = await fetch(`/api/items?page=${page}`, { signal });
		const items = await response.json();

		renderItems(items);

		if (items.length === 0) {
			done();
		}
	},
	onStateChange: ({ state }) => {
		document.body.dataset.loaderState = state;
	},
	onError: ({ error, retry }) => {
		console.error(error);
		showRetryButton(retry);
	},
});

Legacy Helpers

Scroll State

const cleanupScrollState = trackScrollState({
	attribute: 'data-scrolled',
	element: document.body,
	onScrollStart: () => console.log('Скролл начался'),
	onScrollReset: () => console.log('Скролл сброшен'),
});

Scroll Direction

const cleanupDirection = initScrollDirectionTracking(false, 6);

Ставит data-scroll-direction="up|down" на body.

Debounce Scroll

const cleanupDebounce = debounceScroll(() => {
	console.log('scroll settled');
}, 200);

Simple Infinite Scroll

const cleanupInfiniteScroll = initInfiniteScroll(fetchMoreData, {
	threshold: 300,
	onError: error => console.error(error),
});

Intersection Section

const cleanupObserver = initIntersectionSection(
	document.querySelector('#hero')!,
	() => console.log('visible'),
	() => console.log('hidden'),
);

API

  • initAnchorScroll(options?)
  • initScrollSpy(options?)
  • initRevealOnScroll(options?)
  • initScrollProgress(options?)
  • initInfiniteLoader(options)
  • smootherAllAnchorLinks(options?)
  • trackScrollState(options?)
  • initScrollDirectionTracking(trackUserEventsOnly?, thresholdPx?)
  • debounceScroll(callback, delay?)
  • initInfiniteScroll(loadMoreCallback, options?)
  • initIntersectionSection(section, onStart, onEnd, options?)

Лицензия

MIT — см. LICENSE.