Referência da API para Vue
Referência completa dos componentes, dos composables e dos utilitários de @reelkit/vue.
Reel
Tag: <Reel>
Props
ReelProps
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
count | number | obrigatório | Número total de slides |
direction | 'vertical' | 'horizontal' | 'vertical' | Direção do deslocamento |
size | [number, number] | undefined | undefined | Largura e altura, na forma [largura, altura]. Sem esta prop, o tamanho é medido pelo ResizeObserver |
initialIndex | number | 0 | Índice do slide inicial |
loop | boolean | false | Liga o ciclo infinito |
transition | TransitionTransformFn | slideTransition | Função do efeito de transição. Prontas: slideTransition, fadeTransition, flipTransition, cubeTransition, zoomTransition |
transitionDuration | number | 300 | Duração da animação em ms |
swipeDistanceFactor | number | 0.12 | Limiar do deslize (0-1) |
enableGestures | boolean | true | Liga a navegação por arrasto de toque ou mouse |
enableNavKeys | boolean | true | Liga a navegação pelas setas do teclado |
enableWheel | boolean | false | Liga a navegação pela roda do mouse |
wheelDebounceMs | number | 200 | Debounce do evento de roda, em ms |
rangeExtractor | (index: number, count: number) => number[] | defaultRangeExtractor | Função própria para decidir quais índices são renderizados |
keyExtractor | (index: number, indexInRange: number) => string | index => index.toString() | Função de chave própria para a renderização dos slides (útil com loop) |
ariaLabel | string | undefined | Rótulo acessível da região do carrossel |
reelStyle | Record<string, string | number> | undefined | Estilos inline aplicados ao elemento contêiner raiz |
reelClass | string | Array | Object | undefined | Classe ou classes CSS aplicadas ao elemento contêiner raiz |
onNavKeyPress | (increment: -1 | 1) => void | undefined | Prop de callback que substitui a navegação padrão por ArrowUp/ArrowDown. Ao informá-la, a navegação passa a ser sua (chame reelRef.value.next(), por exemplo). Omita para manter o comportamento padrão. |
Eventos
| Evento | Carga | Descrição |
|---|---|---|
beforeChange | (index: number, nextIndex: number, indexInRange: number) | Emitido antes de a transição de slide começar |
afterChange | (index: number, indexInRange: number) | Emitido depois que a transição de slide termina |
slideDragStart | (index: number) | Emitido quando um gesto de arrasto começa |
slideDragEnd | (index: number) | Emitido quando um gesto de arrasto termina (dedo solto) |
slideDragCanceled | (index: number) | Emitido quando um gesto de arrasto é cancelado (o slide volta ao lugar) |
tap | (event: GestureCommonEvent) | Emitido em um gesto de toque único |
doubleTap | (event: GestureCommonEvent) | Emitido em um gesto de toque duplo |
longPress | (event: GestureCommonEvent) | Emitido quando um gesto de toque longo começa |
longPressEnd | (event: GestureEvent) | Emitido quando um gesto de toque longo termina |
Slots
<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 | Props com escopo | Descrição |
|---|---|---|
#item | { index: number, indexInRange: number, size: [number, number] } | Desenha cada slide visível. Chamado para cada índice do intervalo virtualizado |
default | nenhuma | Conteúdo sobreposto a todos os slides (indicadores, controles e afins) |
ReelExpose
API imperativa exposta por um ref de template:
<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>| Método | Tipo | Descrição |
|---|---|---|
next() | () => void | Vai para o próximo slide |
prev() | () => void | Vai para o slide anterior |
goTo(index, animate?) | (number, boolean?) => Promise<void> | Navega até um índice de slide específico |
adjust() | () => void | Recalcula as posições dos slides (útil depois de uma mudança de layout) |
observe() | () => void | Começa a escutar os eventos de gesto, teclado e roda |
unobserve() | () => void | Para de escutar os eventos de gesto, teclado e roda |
ReelIndicator
Tag: <ReelIndicator>
Props
ReelIndicatorProps
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
count | number | undefined | automático | Número total de itens. Vem sozinho do contexto do Reel que o envolve; passe explicitamente ao usar o indicador isolado |
active | number | undefined | automático | Índice ativo no momento. Vem sozinho do contexto do Reel que o envolve; passe explicitamente ao usar o indicador isolado |
direction | 'vertical' | 'horizontal' | 'vertical' | Orientação do indicador |
radius | number | 3 | Raio do ponto em pixels |
visible | number | 5 | Máximo de pontos em tamanho normal visíveis ao mesmo tempo |
gap | number | 4 | Espaço entre os pontos em pixels |
activeColor | string | '#fff' | Cor do ponto ativo |
inactiveColor | string | 'rgba(255, 255, 255, 0.5)' | Cor dos pontos inativos |
edgeScale | number | 0.5 | Fator de escala dos pontos que transbordam nas bordas |
onDotClick | (index: number) => void | undefined | Tratador de clique próprio. Dentro de um Reel, sem esta prop, o clique navega até o ponto escolhido |
indicatorClass | string | Array | Object | undefined | Classe ou classes CSS aplicadas ao elemento raiz do tablist |
indicatorStyle | CSSProperties | undefined | Estilos inline mesclados ao elemento raiz do tablist |
Eventos
| Evento | Carga | Descrição |
|---|---|---|
dotClick | (index: number) | Emitido quando um ponto é clicado; entrega o índice do ponto |
SwipeToClose
Tag: <SwipeToClose> — envolve o slot padrão em um contêiner sensível ao toque, que dá para dispensar com um deslize.
Props
SwipeToCloseProps
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
direction | 'up' | 'down' | obrigatório | Direção do deslize que fecha. Use "up" para dispensar a galeria, "down" para dispensar os stories |
enabled | boolean | true | Se o gesto de deslizar para fechar está ativo |
threshold | number | 0.2 | Fração da altura da tela necessária para fechar (0-1) |
Eventos
| Evento | Carga | Descrição |
|---|---|---|
close | () | Emitido quando o deslize passa do limiar e a animação de fechamento termina |
Slots
| Slot | Descrição |
|---|---|
default | Conteúdo a envolver com o gesto de deslizar para fechar |
Observe
Tag: <Observe :signals="[…]"> — re-renderiza o seu slot padrão sempre que um dos sinais muda, e nada ao redor.
Ler um sinal do core numa função de render ou num template não inscreve você nele. A resposta de sempre é toVueRef, mas ele amarra o sinal ao componente que o chamou, então um sinal que muda com frequência re-renderiza o componente inteiro. Observe é a fronteira mais estreita: coloque-o em volta da parte que mostra o valor e o resto do componente fica parado. É assim que o player de stories repinta o cabeçalho e a barra de progresso sem redesenhar nenhum dos sliders.
| Prop | Tipo | Descrição |
|---|---|---|
signals | readonly Subscribable[] | Sinais a acompanhar. Um conjunto diferente troca a inscrição; o mesmo conjunto a mantém. Tudo é liberado na desmontagem. |
O tipo das props é exportado como ObserveProps.
<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>Use toVueRef quando o componente inteiro acompanha o sinal, e Observe quando só um pedaço dele acompanha.
SoundProvider
Tag: <SoundProvider> — provedor de contexto que cria uma instância de SoundController e a entrega aos descendentes por RK_SOUND_KEY. Renderiza o slot padrão de forma transparente.
<template>
<SoundProvider>
<Reel :count="items.length">
<template #item="{ index }">
<VideoSlide :index="index" />
</template>
<MuteButton />
</Reel>
</SoundProvider>
</template>RK_REEL_KEY e useReelContext
Uma InjectionKey<ReelContextValue> que o <Reel> fornece aos seus descendentes. Usada internamente pelo <ReelIndicator> para se ligar sozinho. Use useReelContext() em componentes seus que precisem do contexto do slider.
<script setup lang="ts">
import { useReelContext } from '@reelkit/vue';
const ctx = useReelContext();
function jump(index: number) {
ctx?.goTo(index, true);
}
</script>| Propriedade | Tipo | Descrição |
|---|---|---|
index | Signal<number> | Índice reativo do slide atual |
count | Signal<number> | Contagem reativa do total de itens |
goTo | (index: number, animate?: boolean) => Promise<void> | Navega até um slide por código |
Composables
useBodyLock
Trava a rolagem do corpo do documento enquanto o valor informado for true. Usa contagem de referências, então vários chamadores simultâneos travam e destravam de forma independente. Destrava sozinho na desmontagem.
import { ref } from 'vue';
import { useBodyLock } from '@reelkit/vue';
const isOpen = ref(false);
useBodyLock(isOpen);
// Also accepts a static boolean
useBodyLock(true);| Parâmetro | Tipo | Descrição |
|---|---|---|
locked | Ref<boolean> | boolean | Se a rolagem do corpo deve ficar travada. Aceita um ref reativo ou um booleano fixo |
useFullscreen
UseFullscreenOptions → UseFullscreenReturn
Composable para lidar com a Fullscreen API com suporte entre navegadores. Sai da tela cheia sozinho na desmontagem.
import { ref } from 'vue';
import { useFullscreen } from '@reelkit/vue';
const containerRef = ref<HTMLElement | null>(null);
const { isFullscreen, request, exit, toggle } = useFullscreen({
elementRef: containerRef,
});| Retorno | Tipo | Descrição |
|---|---|---|
isFullscreen | Signal<boolean> | Sinal do core que reflete o estado atual de tela cheia (leia .value) |
request | () => Promise<void> | Pede tela cheia no elemento referenciado. Se outro elemento já estiver em tela cheia, ele sai primeiro (com espera). |
exit | () => Promise<void> | Sai da tela cheia |
toggle | () => Promise<void> | Alterna o estado de tela cheia |
useSoundState
Alcança o SoundController atual pelo contexto. Precisa ser chamado dentro de um <SoundProvider>. Lança erro se for chamado fora.
import { useSoundState } from '@reelkit/vue';
// Inside a SoundProvider descendant
const sound = useSoundState();
sound.muted; // Signal<boolean>
sound.toggle(); // Toggle muted stateuseOverlayUrlState
OverlayUrlStateOptions
Monta um controlador de estado na URL para o overlay, que você entrega a um <LightboxUrlOverlay> pela prop :controller.
Veja Estado na URL no guia para Vue para o passo a passo e os exemplos.
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
param | string | obrigatório | Parâmetro de consulta que carrega o slide ativo, por exemplo "photo". |
adapter | UrlAdapter | History API | Sistema de navegação por onde ler e escrever. Em um app com rotas, passe um adaptador ligado ao roteador para que a localização dele não fique desatualizada. |
codec | { decode(raw) => Id | null; encode(id) => string } | obrigatório | Formato do fio: texto do parâmetro ↔ identidade estável, sem enxergar a coleção. Anda junto do locator como par combinado que divide o mesmo Id — espalhe ...urlIndexKey(() => props.images.length) para a galeria padrão endereçada por índice em ?photo=3, ou forneça o seu (base64, slug) para que um favorito sobreviva à galeria mudar de ordem. |
locator | { locate(id) => number | null; locateAsync?(id) => Promise<number | null>; identify(index) => id } | obrigatório | Liga a identidade a uma posição e responde pela própria validade: locate (síncrono), locateAsync (plano B assíncrono de uma galeria paginada) e identify (nas escritas). Em uma galeria simples por índice, espalhe ...urlIndexKey(() => props.images.length) — ele fornece este locator mais o codec correspondente e limita ?photo=3 pela contagem atual, então um ?photo=99 velho se cura saindo da URL em vez de abrir um slide que ninguém nomeou. Passe um getter, e não um número, porque o setup do Vue roda uma única vez e um comprimento capturado envelheceria conforme o feed paginado cresce. Um feed paginado ou uma galeria endereçada por identidade fornece o próprio par de codec e locator. |
useVueRouterUrlAdapter
Um UrlAdapter apoiado no Vue Router. Passe-o na opção adapter de useOverlayUrlState em um app com rotas, para que o roteador siga sendo a única fonte de verdade da navegação — escrever history.pushState por trás dele deixa sua localização desatualizada, e a navegação seguinte derruba o parâmetro. As escritas mexem apenas na consulta, então o caminho, o hash e chaves repetidas como ?tag=a&tag=b seguem intactos. Cada mudança informa se o roteador empilhou na mesma página, substituiu ou andou pelo histórico, de modo que uma galeria aberta por um <router-link> fecha com um único passo para trás.
Vem de um subcaminho próprio, então um app sem roteador nunca puxa vue-router para o bundle. vue-router é uma peer dependency opcional, da versão 4.1 em diante: o adaptador leva seu carimbo de propriedade pela opção de navegação state do roteador, que as versões mais antigas ignoram. Em um roteador antigo nada quebra — fechar apenas limpa o parâmetro no lugar, em vez de dar um passo para trás.
import { useVueRouterUrlAdapter } from '@reelkit/vue/vue-router-url-adapter';
const adapter = useVueRouterUrlAdapter();
const photo = useOverlayUrlState({
param: 'photo',
adapter,
...urlIndexKey(() => props.images.length),
});toVueRef
Faz a ponte de um Subscribable do core (qualquer Signal de @reelkit/core) para um Ref somente leitura do Vue. Use sempre que o valor de um sinal do core precisar provocar uma nova renderização no Vue — ler signal.value direto em funções de renderização ou em templates não é reativo por si só.
A assinatura é descartada sozinha por onScopeDispose, então isto precisa ser chamado dentro de um setup() do Vue ou de outro contexto com escopo de efeito.
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
Cria um componente genérico em relação aos itens que recebe, como ReelPlayerOverlay e StoriesOverlay. O Vue 3.3 aceita uma função setup com parâmetro de tipo, defineComponent(<T>(props: Props<T>) => …, options), mas só mantém esse parâmetro quando options.props lista nomes de props. Passe um objeto de props e o Vue lê os tipos das props de volta a partir do objeto, então T se perde. asGenericPropKeys repassa o objeto de props intacto enquanto o verificador de tipos vê uma lista de nomes: T é inferido do que o componente pai vincula, e os valores padrão, a validação e a conversão de booleanos continuam valendo em tempo de execução.
O argumento de tipo é o tipo das props com o item base, e o componente precisa do Vue 3.3 ou mais recente. Slots e eventos não podem usar T: para tipar o escopo de um slot, anote-o no template.
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) diz se o resultado de um slot vai colocar algo na página, para um componente que volta à própria renderização quando o pai deixa um slot vazio, como fazem os overlays. Um slot cujo conteúdo está atrás de um v-if falso ainda devolve um nó de comentário, então checar o tamanho do array o trataria como preenchido e descartaria o fallback. hasRenderedNodes desembrulha fragmentos, ignora nós de comentário e devolve false para null ou undefined, então hasRenderedNodes(slots.controls?.(scope)) é o teste em que se basear.
Acessibilidade
<Reel> é renderizado como role="region" com aria-roledescription="carousel". Passe aria-label (no TypeScript a prop é ariaLabel) para dar à região um nome que o leitor de tela anuncie. Uma live region educada anuncia "Slide N de M" a cada troca. Os slides inativos recebem o atributo inert, então o foco e a navegação por tecnologia assistiva passam por cima deles.
<ReelIndicator> é renderizado como role="tablist", com tabindex móvel nos pontos; as setas movem o foco e Enter ou Espaço ativa o slide.
Montando um modal próprio em volta de <Reel>? captureFocusForReturn, createFocusTrap e getFocusableElements são reexportados por @reelkit/vue para devolver e prender o foco.
Exports do pacote
Todos os exports públicos de @reelkit/vue:
// 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';