Довідник API для Vue

Повний довідник @reelkit/vue : компоненти, композабли та утиліти.

Reel

Тег: <Reel>

Props

ReelProps

PropТипТипове значенняОпис
countnumberrequiredЗагальна кількість слайдів
direction'vertical' | 'horizontal''vertical'Напрямок прокручування
size[number, number] | undefinedundefinedШирина й висота у вигляді [width, height]. Якщо не задано, вимірюється автоматично через ResizeObserver
initialIndexnumber0Початковий індекс слайда
loopbooleanfalseВмикає нескінченний цикл
transitionTransitionTransformFnslideTransitionФункція ефекту переходу. Вбудовані: slideTransition, fadeTransition, flipTransition, cubeTransition, zoomTransition
transitionDurationnumber300Тривалість анімації в мілісекундах
swipeDistanceFactornumber0.12Поріг свайпу (0–1)
enableGesturesbooleantrueВмикає навігацію перетягуванням дотиком або мишею
enableNavKeysbooleantrueВмикає навігацію стрілками клавіатури
enableWheelbooleanfalseВмикає навігацію колесом миші
wheelDebounceMsnumber200Дебаунс події колеса в мілісекундах
rangeExtractor(index: number, count: number) => number[]defaultRangeExtractorВласна функція, що визначає, які індекси рендеряться
keyExtractor(index: number, indexInRange: number) => stringindex => index.toString()Власна функція ключів для рендерингу слайдів (корисно з циклом)
ariaLabelstringundefinedДоступна назва області каруселі
reelStyleRecord<string, string | number>undefinedВбудовані стилі для кореневого контейнера
reelClassstring | Array | ObjectundefinedКласи CSS для кореневого контейнера
onNavKeyPress(increment: -1 | 1) => voidundefinedПропс-колбек, що замінює стандартну навігацію стрілками вгору й вниз. Якщо його передати, навігацію реалізуєте ви самі (наприклад, викликаєте reelRef.value.next()). Не передавайте, щоб лишити стандартну поведінку.

Events

EventPayloadОпис
beforeChange(index: number, nextIndex: number, indexInRange: number)Видається перед початком переходу між слайдами
afterChange(index: number, indexInRange: number)Видається після завершення переходу між слайдами
slideDragStart(index: number)Видається на початку перетягування
slideDragEnd(index: number)Видається, коли перетягування завершується (палець або кнопку відпустили)
slideDragCanceled(index: number)Видається, коли перетягування скасовано (слайд повертається назад)
tap(event: GestureCommonEvent)Видається на одиночний дотик
doubleTap(event: GestureCommonEvent)Видається на подвійний дотик
longPress(event: GestureCommonEvent)Видається на початку довгого натискання
longPressEnd(event: GestureEvent)Видається після завершення довгого натискання

Slots

vue-html
<Reel :count="items.length">
  <template #item="{ index, indexInRange, size }">
    <!-- index       : number         — absolute slide index (0 to count-1) -->
    <!-- indexInRange : number         — position in the visible window (0, 1, or 2) -->
    <!-- size         : [number,number] — [width, height] of the container -->
    <MySlide :index="index" :size="size" />
  </template>

  <!-- default slot: overlay content rendered on top of the slides -->
  <ReelIndicator />
</Reel>
SlotВластивості області слотаОпис
#item{ index: number, indexInRange: number, size: [number, number] }Рендерить кожен видимий слайд. Викликається для кожного індексу у віртуалізованому діапазоні
defaultnoneВміст оверлея поверх усіх слайдів (індикатори, елементи керування тощо)

ReelExpose

Імперативний API, доступний через шаблонний ref:

vue
<script setup lang="ts">
import { ref } from 'vue';
import { Reel, type ReelExpose } from '@reelkit/vue';

const reelRef = ref<ReelExpose | null>(null);

function prev()  { reelRef.value?.prev(); }
function next()  { reelRef.value?.next(); }
function jump(i: number) { reelRef.value?.goTo(i, true); }
</script>

<template>
  <Reel ref="reelRef" :count="100">
    <template #item="{ index }">
      <div>Slide {{ index }}</div>
    </template>
  </Reel>
</template>
МетодТипОпис
next()() => voidПерейти до наступного слайда
prev()() => voidПерейти до попереднього слайда
goTo(index, animate?)(number, boolean?) => Promise<void>Перехід до слайда за індексом
adjust()() => voidПерерахувати позиції слайдів (корисно після зміни макета)
observe()() => voidПочати слухати події жестів, клавіатури та колеса
unobserve()() => voidПрипинити слухати події жестів, клавіатури та колеса

ReelIndicator

Тег: <ReelIndicator>

Props

ReelIndicatorProps

PropТипТипове значенняОпис
countnumber | undefinedautoЗагальна кількість елементів. Береться з контексту батьківського Reel, якщо компонент вкладений у нього; передавайте явно за окремого використання
activenumber | undefinedautoПоточний активний індекс. Береться з контексту батьківського Reel, якщо компонент вкладений у нього; передавайте явно за окремого використання
direction'vertical' | 'horizontal''vertical'Орієнтація індикатора
radiusnumber3Радіус точки в пікселях
visiblenumber5Максимум одночасно видимих точок звичайного розміру
gapnumber4Відстань між точками в пікселях
activeColorstring'#fff'Колір активної точки
inactiveColorstring'rgba(255, 255, 255, 0.5)'Колір неактивної точки
edgeScalenumber0.5Коефіцієнт масштабу крайніх точок за межами видимого
onDotClick(index: number) => voidundefinedВласний обробник кліку. Якщо не задано всередині Reel, типово відбувається перехід до індексу натиснутої точки
indicatorClassstring | Array | ObjectundefinedКласи CSS для кореневого елемента tablist
indicatorStyleCSSPropertiesundefinedВбудовані стилі, додані до кореневого елемента tablist

Events

EventPayloadОпис
dotClick(index: number)Видається на клік по точці; передає індекс точки

SwipeToClose

Тег: <SwipeToClose> — загортає свій типовий слот у контейнер, чутливий до дотику, який можна закрити свайпом.

Props

SwipeToCloseProps

PropТипТипове значенняОпис
direction'up' | 'down'requiredНапрямок свайпу, що закриває. Беріть "up" для Lightbox й "down" для історій
enabledbooleantrueЧи активний жест свайпу для закриття
thresholdnumber0.2Частка висоти області перегляду, потрібна для закриття (0–1)

Events

EventPayloadОпис
close()Видається, коли свайп перевищує поріг і анімація закриття завершилася

Slots

SlotОпис
defaultВміст, який треба загорнути в обробку свайпу для закриття

Observe

Тег: <Observe :signals="[…]"> — перемальовує свій типовий слот, щойно змінюється один із сигналів, і більше нічого навколо.

Читання сигналу ядра у функції рендеру чи в шаблоні само по собі не підписує на нього. Звична відповідь — toVueRef, але він прив’язує сигнал до компонента, який його викликав, тож сигнал, що змінюється часто, перемальовує цілий компонент. Observe — вужча межа: обгорніть нею ту частину, що показує значення, і решта компонента лишиться на місці. Саме цим користується плеєр історій, щоб оновлювати заголовок і смугу прогресу, не перемальовуючи жоден зі слайдерів.

PropТипОпис
signalsreadonly Subscribable[]Сигнали, за якими стежити. Інший набір змінює підписку, той самий — зберігає її. На демонтажі все звільняється.

Тип пропсів експортовано як ObserveProps.

vue
<script setup lang="ts">
import { Observe, createTimerController, toVueRef } from '@reelkit/vue';

const timer = createTimerController({ duration: 5000 });

// toVueRef binds the signal to THIS component: every tick re-renders all of
// it. Fine for a small component, wasteful when something heavy sits beside
// the part that changes.
const progress = toVueRef(timer.progress);
</script>

<template>
  <section>
    <!-- Only the slot below re-renders on a tick; the list keeps its DOM. -->
    <Observe :signals="[timer.progress]">
      <progress :value="timer.progress.value" max="1" />
    </Observe>

    <ExpensiveList :items="items" />

    <!-- The same value through toVueRef, for comparison. -->
    <p>{{ Math.round(progress * 100) }}%</p>
  </section>
</template>

Беріть toVueRef, коли за сигналом стежить цілий компонент, і Observe, коли лише його частина.

SoundProvider

Тег: <SoundProvider> — постачальник контексту, що створює екземпляр SoundController і надає його нащадкам через RK_SOUND_KEY. Свій типовий слот рендерить прозоро.

vue
<template>
  <SoundProvider>
    <Reel :count="items.length">
      <template #item="{ index }">
        <VideoSlide :index="index" />
      </template>
      <MuteButton />
    </Reel>
  </SoundProvider>
</template>

RK_REEL_KEY & useReelContext

An InjectionKey<ReelContextValue> який надає <Reel> своїм нащадкам. Використовується всередині <ReelIndicator> для автоматичного під’єднання. Викликайте useReelContext() у власних компонентах, яким потрібен контекст слайдера.

vue
<script setup lang="ts">
import { useReelContext } from '@reelkit/vue';

const ctx = useReelContext();

function jump(index: number) {
  ctx?.goTo(index, true);
}
</script>
ВластивістьТипОпис
indexSignal<number>Реактивний індекс поточного слайда
countSignal<number>Реактивна загальна кількість елементів
goTo(index: number, animate?: boolean) => Promise<void>Програмний перехід до слайда

Composables

useBodyLock

Блокує прокручування body документа, коли передане значення — true. Використовує підрахунок посилань, тож кілька одночасних викликачів блокують і розблоковують незалежно. Автоматично розблоковує при демонтажі.

typescript
import { ref } from 'vue';
import { useBodyLock } from '@reelkit/vue';

const isOpen = ref(false);
useBodyLock(isOpen);

// Also accepts a static boolean
useBodyLock(true);
ParameterТипОпис
lockedRef<boolean> | booleanЧи блокувати прокручування body. Приймає реактивний ref або звичайне булеве значення

useFullscreen

UseFullscreenOptions → UseFullscreenReturn

Композабл для роботи з Fullscreen API з кросбраузерною підтримкою. Автоматично виходить із повного екрана при демонтажі.

typescript
import { ref } from 'vue';
import { useFullscreen } from '@reelkit/vue';

const containerRef = ref<HTMLElement | null>(null);
const { isFullscreen, request, exit, toggle } = useFullscreen({
  elementRef: containerRef,
});
ReturnТипОпис
isFullscreenSignal<boolean>Сигнал ядра, що відображає поточний стан повного екрана (читайте .value)
request() => Promise<void>Запитує повний екран для елемента за посиланням. Якщо в повному екрані вже інший елемент, спершу відбувається вихід із нього (з очікуванням).
exit() => Promise<void>Вийти з повного екрана
toggle() => Promise<void>Перемкнути стан повного екрана

useSoundState

Дає доступ до поточного SoundController з контексту. Викликати треба всередині <SoundProvider>. Поза ним кидає помилку.

typescript
import { useSoundState } from '@reelkit/vue';

// Inside a SoundProvider descendant
const sound = useSoundState();

sound.muted;    // Signal<boolean>
sound.toggle(); // Toggle muted state

useOverlayUrlState

OverlayUrlStateOptions

Будує контролер стану в URL для оверлея, який ви передаєте в <LightboxUrlOverlay> як його :controller prop.

See Стан в URL у посібнику для Vue — там покроковий розбір і приклади.

OptionТипТипове значенняОпис
paramstringrequiredПараметр запиту, що несе активний слайд, наприклад "photo".
adapterUrlAdapterHistory APIСистема навігації, через яку читати й писати. У застосунку з роутером передайте адаптер на його базі, щоб власне місцеположення роутера не застаріло.
codec{ decode(raw) => Id | null; encode(id) => string }requiredФормат передавання: текст параметра ↔ стабільна ідентичність, незалежно від колекції. Іде разом із локатором як узгоджена пара з однаковим Id — розгорніть ...urlIndexKey(() => props.images.length) для типової галереї з ?photo=3 або передайте власний (base64, slug), щоб закладка пережила зміну порядку галереї.
locator{ locate(id) => number | null; locateAsync?(id) => Promise<number | null>; identify(index) => id }requiredЗіставляє ідентичність із позицією і сам відповідає за свою чинність: locate (синхронно), locateAsync (запасний варіант для посторінкової галереї), identify (для запису). Для звичайної галереї за індексом розгорніть ...urlIndexKey(() => props.images.length) — він дає цей локатор разом із відповідним кодеком і обмежує ?photo=3 живою кількістю, тож застарілий ?photo=99 сам зникає з URL замість того, щоб відкрити слайд, якого ніхто не називав. Передавайте геттер, а не число: setup у Vue виконується один раз, і захоплена довжина застаріла б, поки посторінкова стрічка росте. Посторінкова стрічка або галерея з адресацією за ідентичністю передає власну узгоджену пару кодек + локатор.

useVueRouterUrlAdapter

A UrlAdapter на базі Vue Router. Передайте його як опцію adapter у useOverlayUrlState у застосунку з роутером, щоб роутер лишався єдиним джерелом правди про навігацію: запис history.pushState повз роутер лишає його місцеположення застарілим, і наступна навігація втрачає параметр. Запис торкається лише запиту, тож шлях, хеш і повторювані ключі на кшталт ?tag=a&tag=b лишаються недоторканими. Кожна зміна повідомляє, чи роутер додав запис на тій самій сторінці, замінив його чи пройшов історією, тож галерея, відкрита з <router-link>, закривається одним кроком назад.

Постачається з окремого підшляху, тож застосунок без роутера ніколи не тягне vue-router у свій бандл. vue-router — необов’язкова peer-залежність версії 4.1 або новішої: адаптер передає свою позначку власності через навігаційну опцію роутера state, яку старіші випуски ігнорують. Зі старішим роутером нічого не ламається — закриття просто прибирає параметр на місці замість кроку назад.

typescript
import { useVueRouterUrlAdapter } from '@reelkit/vue/vue-router-url-adapter';

const adapter = useVueRouterUrlAdapter();
const photo = useOverlayUrlState({
  param: 'photo',
  adapter,
  ...urlIndexKey(() => props.images.length),
});

toVueRef

Місток від сигналу ядра Subscribable (будь-який Signal from @reelkit/core) into a read-only Vue Ref. Беріть його щоразу, коли значення сигналу ядра має спричиняти перерендер у Vue — прямі читання signal.value у функціях рендерингу чи шаблонах не реактивні самі собою.

Підписка звільняється автоматично через onScopeDispose, so this must be called inside a Vue setup() чи інший контекст, обізнаний про область ефектів.

typescript
import { defineComponent, h } from 'vue';
import { toVueRef, useSoundState } from '@reelkit/vue';

export const MuteIcon = defineComponent({
  setup() {
    const sound = useSoundState();
    const muted = toVueRef(sound.muted); // Readonly<Ref<boolean>>

    return () => h('span', muted.value ? '🔇' : '🔊');
  },
});

asGenericPropKeys

Створює компонент, узагальнений за елементами, які він отримує, — так, як ReelPlayerOverlay і StoriesOverlay. Vue 3.3 приймає setup-функцію з параметром типу, defineComponent(<T>(props: Props<T>) => …, options), але зберігає цей параметр лише тоді, коли options.props перелічує назви пропсів. Передайте їй об’єкт пропсів — і Vue прочитає типи пропсів назад з об’єкта, тож T втрачається. asGenericPropKeys передає об’єкт пропсів без змін, а перевірка типів бачить список назв: T виводиться з того, що прив’язує батьківський компонент, а значення за замовчуванням, валідація й приведення boolean і далі працюють під час виконання.

Аргумент типу — це тип пропсів із базовим елементом, а компонент потребує Vue 3.3 або новішої. Слоти й події не можуть використовувати T: щоб типізувати область видимості слота, анотуйте її в шаблоні.

typescript
import { defineComponent, h, type PropType } from 'vue';
import { asGenericPropKeys } from '@reelkit/vue';

interface Item {
  id: string;
}

interface FeedProps<T extends Item> {
  items: T[];
  loop?: boolean;
}

const feedProps = {
  items: { type: Array as PropType<Item[]>, required: true as const },
  loop: { type: Boolean, default: false },
};

export const Feed = defineComponent(
  <T extends Item = Item>(props: FeedProps<T>) =>
    () =>
      h('ul', props.items.map((item) => h('li', item.id))),
  { name: 'Feed', props: asGenericPropKeys<FeedProps<Item>>(feedProps) },
);

hasRenderedNodes

hasRenderedNodes(nodes) визначає, чи результат слота щось виведе на сторінку, — для компонента, що повертається до власного рендерингу, коли батько лишає слот порожнім, як це роблять оверлеї. Слот, чий вміст стоїть за хибним v-if, однаково повертає вузол-коментар, тож перевірка довжини масиву вважала б його заповненим і відкинула б запасний варіант. hasRenderedNodes розгортає фрагменти, ігнорує вузли-коментарі й повертає false для null або undefined, тож hasRenderedNodes(slots.controls?.(scope)) — та перевірка, за якою варто розгалужуватися.

Accessibility

<Reel> рендериться як role="region" з aria-roledescription="carousel". Передайте aria-label (пропс має назву ariaLabel у TypeScript), щоб дати області назву для екранного читача. Ввічлива жива область оголошує «Слайд N з M» на кожну зміну слайда. Неактивні слайди отримують атрибут inert , тож фокус і навігація допоміжних технологій їх пропускають.

<ReelIndicator> рендериться як role="tablist" з рухомим tabindex на точках; стрілки переміщують фокус, а Enter або Space активує слайд.

Будуєте власне модальне вікно навколо <Reel>? captureFocusForReturn, createFocusTrap, та getFocusableElements — вони реекспортовані з @reelkit/vue для повернення й утримання фокуса.

Експорти пакета

Усі публічні експорти з @reelkit/vue:

typescript
// Components
import {
  Reel,
  ReelIndicator,
  SwipeToClose,
  SoundProvider,
  Observe,
} from '@reelkit/vue';

// Types
import type {
  ReelExpose,
  ReelContextValue,
  SwipeToCloseDirection,
  SwipeToCloseProps,
  UseFullscreenOptions,
  UseFullscreenReturn,
} from '@reelkit/vue';

// Context & composables
import {
  RK_REEL_KEY,
  useReelContext,
  RK_SOUND_KEY,
  useBodyLock,
  useFullscreen,
  useSoundState,
  toVueRef,
} from '@reelkit/vue';

// Generic components
import { asGenericPropKeys } from '@reelkit/vue';

// Utilities (re-exported from @reelkit/core)
import {
  createDefaultKeyExtractorForLoop,
  defaultRangeExtractor,
} from '@reelkit/vue';

// Core re-exports
import {
  // Signals & reactivity
  createSignal, createComputed, reaction, batch, createDeferred,

  // Transitions
  slideTransition, fadeTransition, flipTransition,
  cubeTransition, zoomTransition, getSlideProgress,

  // Content loading & preloading
  createContentLoadingController, createContentPreloader,
  observeMediaLoading,

  // Sound
  createSoundController, syncMutedToVideo,

  // Fullscreen
  fullscreenSignal, requestFullscreen, exitFullscreen,

  // DOM & cleanup
  observeDomEvent, createDisposableList, createBodyLock, sharedBodyLock,

  // Size detection
  observeElementSize, getViewportSize, observeViewportSize,
  isMobileWidth, fitAspectRatio, isTouchDevice,

  // Autoplay & download
  createTimerController, createSlideshowController, downloadFile,

  // Focus management
  captureFocusForReturn, createFocusTrap, getFocusableElements,

  // Gestures
  createGestureController,

  // Video
  captureFrame, createSharedVideo,

  // Animation
  animate,

  // Utilities
  noop, clamp, abs, first, last, extractRange,
  lerp, isNegative, generate,
} from '@reelkit/vue';