Утилиты
Небольшие самостоятельные помощники, которые используются внутри движков выше, и экспортируются для повторного использования в своих эффектах.
Перевод значения между диапазонами
mapRange() — линейно переводит значение из одного диапазона в другой.
function mapRange(
value: number,
from: [number, number],
to: [number, number],
clampResult?: boolean,
): numberПараметры
value
number · по умолчанию: —
Значение для преобразования, выраженное в диапазоне from.
from
[number, number] · по умолчанию: —
Входной диапазон, в котором сейчас выражено value.
to
[number, number] · по умолчанию: —
Выходной диапазон, в который нужно преобразовать значение.
clampResult
boolean · по умолчанию: false
При true держит результат в пределах to на краях, вместо экстраполяции за них — корректно обрабатывает и перевёрнутый диапазон to (например, [100, -100]).
Возвращаемое значение
number — преобразованное значение.
Пример:
import { mapRange } from '@macrulez/inview-core'
mapRange(0.5, [0, 1], [0, 200]) // 100
mapRange(1.2, [0, 1], [0, 200], true) // 200 (ограничено)Привязка к CSS-переменной
bindCSSVar() — записывает числовое значение прогресса в CSS custom property на элементе, чтобы результирующий визуальный эффект можно было собрать на чистом CSS.
function bindCSSVar(element: HTMLElement, name: string, value: number | string): voidПараметры
element
HTMLElement · по умолчанию: —
name
string · по умолчанию: —
Имя custom property. Если name ещё не начинается с --, префикс добавляется автоматически.
value
number | string · по умолчанию: —
Возвращаемое значение
void
Пример:
import { bindCSSVar } from '@macrulez/inview-core'
bindCSSVar(el, 'progress', 0.42) // el.style.setProperty('--progress', '0.42').card {
opacity: var(--progress);
}Предпочтение сниженной анимации
prefersReducedMotion() — читает медиа-запрос prefers-reduced-motion.
function prefersReducedMotion(): booleanВозвращаемое значение
boolean — false, если window/matchMedia недоступны (SSR), иначе window.matchMedia('(prefers-reduced-motion: reduce)').matches.
Одноразовая проверка — не замечает изменение настройки ОС посреди сессии, если что-то ещё не вызовет её заново. Для реактивного значения, обновляющегося на событие change медиа-запроса, используйте usePrefersReducedMotion():
function usePrefersReducedMotion(): Ref<boolean> // Vue
function usePrefersReducedMotion(): boolean // React<script setup lang="ts">
import { usePrefersReducedMotion } from '@macrulez/inview-vue'
const reduced = usePrefersReducedMotion()
</script>Vue composable подписывается на событие change медиа-запроса и отписывается при размонтировании, возвращая Ref<boolean>; про React-хук (построенный на useSyncExternalStore) — см. React-хуки.
Прокрутка к элементу
scrollToElement() — плавно скроллит контейнер (по умолчанию window) так, чтобы элемент оказался у его края, со смещением в пикселях — случай «доскроллить до элемента», который ScrollEngine.scrollTo сам по себе не покрывает (он принимает только сырую позицию x/y, а не элемент).
function scrollToElement(el: Element, options?: ScrollToElementOptions): voidПараметры
el
Element · по умолчанию: —
options
ScrollToElementOptions · по умолчанию: {}
| Поле | Тип | По умолчанию |
|---|---|---|
target | Window | HTMLElement | window |
offset | number | 0 — зазор в пикселях между краем элемента и краем контейнера |
axis | 'x' | 'y' | 'y' |
behavior | 'auto' | 'smooth' | 'smooth', если только prefersReducedMotion() не вернул true — тогда 'auto' |
Возвращаемое значение
void
Использует нативную анимацию плавного скролла браузера, а не рукописный rAF-цикл — поэтому duration/easing не настраиваются, вместо этого передайте behavior: 'auto' для мгновенного прыжка.
Пример:
import { scrollToElement } from '@macrulez/inview-core'
scrollToElement(sectionEl, { offset: 80 }) // например, чтобы не перекрыть sticky-шапкуuseScrollTo (Vue)
function useScrollTo(
target?: MaybeRefOrGetter<Window | HTMLElement | null | undefined>,
): (el: Element | null | undefined, options?: UseScrollToOptions) => voidВозвращает колбэк scrollTo(el, options?), привязанный к target (по умолчанию window). target принимает ref/геттер и перечитывается через toValue() при каждом вызове — если реф позже указывает на другой контейнер, это подхватывается автоматически, без повторного вызова useScrollTo().
<script setup lang="ts">
import { useScrollTo } from '@macrulez/inview-vue'
const scrollTo = useScrollTo()
</script>
<template>
<button @click="scrollTo(sectionEl, { offset: 80 })">Перейти</button>
</template>Про React-хук — см. React-хуки; там target — обычное значение, захваченное в массиве зависимостей useCallback, так что новый target даёт новый колбэк вместо перечитывания вживую.
Ограничение значения
clamp() — ограничивает значение диапазоном [min, max].
function clamp(value: number, min: number, max: number): numberПараметры
value
number · по умолчанию: —
min
number · по умолчанию: —
max
number · по умолчанию: —
Возвращаемое значение
number — value, ограниченное диапазоном [min, max].
Задержка стаггера
staggerDelay() — вычисляет CSS transition-delay для index-го элемента в стаггер-эффекте (плитка/список появляются один за другим), вместо того чтобы писать Math.min(i, max) * step руками в каждом месте вызова.
function staggerDelay(index: number, options?: StaggerDelayOptions): stringПараметры
index
number · по умолчанию: —
Позиция элемента в последовательности (с нуля).
options
StaggerDelayOptions · по умолчанию: {}
| Поле | Тип | По умолчанию |
|---|---|---|
step | number | 60 — задержка в мс на один шаг |
max | number | Infinity — ограничивает эффективный индекс, чтобы 50-й элемент не ждал почти секунду |
unit | 'ms' | 's' | 'ms' |
mode | 'linear' | 'cycle' | 'linear' — на max рост выравнивается. 'cycle' возвращается к 0 после max, повторяющейся волной |
Возвращаемое значение
string — CSS-значение времени (например, '180ms', '1s').
Пример:
import { staggerDelay } from '@macrulez/inview-core'
staggerDelay(3) // '180ms'
staggerDelay(10, { step: 70, max: 4 }) // '280ms' — индекс ограничен четвёркой
staggerDelay(2, { step: 500, unit: 's' }) // '1s'
// mode: 'cycle' возвращается к 0 после max вместо выравнивания —
// повторяющаяся волна (0, 70, 140, 210, 0, 70, 140, 210, ...) для
// длинного списка/сетки, вместо того чтобы всё после индекса 3 делило
// одну задержку:
staggerDelay(5, { step: 70, max: 3, mode: 'cycle' }) // '70ms' — индекс 5 оборачивается в тот же слот, что индекс 1Опция stagger у createRevealController построена поверх этой функции — вызывайте её напрямую для самостоятельно написанного стаггер-эффекта в v-for/.map() вместо контроллера.
useStagger (Vue)
function useStagger(
index: MaybeRefOrGetter<number>,
options?: MaybeRefOrGetter<StaggerDelayOptions | undefined>,
): ComputedRef<string>Обёртка computed, пересчитывающая значение при изменении index/options (как ref/геттера), вместо вызова staggerDelay() руками в каждом месте самостоятельно написанного стаггер-эффекта в v-for.
<script setup lang="ts">
import { useStagger } from '@macrulez/inview-vue'
const delay = useStagger(index, { step: 70, max: 4 })
</script>
<template>
<div class="reveal" :style="{ transitionDelay: delay }" />
</template>Про React-хук — см. React-хуки; тонкая, не мемоизированная обёртка — вычисление достаточно дешёвое, чтобы просто вызывать его каждый рендер.
Пресеты плавности
easings — набор пресетов плавности, применяемых к значению прогресса 0..1 перед тем, как передать его в эффект (смещение параллакса, CSS-переменную и т. д.).
type Easing = (t: number) => number
const easings: Record<EasingName, Easing>
type EasingName = keyof typeof easingsИмена пресетов: linear, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInSine, easeOutSine, easeInOutSine.
Пример:
import { easings } from '@macrulez/inview-core'
const eased = easings.easeOutCubic(0.5)