Angular Lightbox
Galeria de imagens e vídeos em tela cheia para Angular, construída sobre @reelkit/angular-lightbox.
Recursos
Instalação
npm install @reelkit/angular-lightbox @reelkit/angular lucide-angularRegistre a folha de estilos uma única vez:
// Anywhere that runs at startup — main.ts, app.config.ts, a component file.
import '@reelkit/angular-lightbox/styles.css';
// Or, if you keep CSS out of TypeScript, from your global stylesheet:
// @import '@reelkit/angular-lightbox/styles.css';
// Or register it in angular.json:
// "styles": ["node_modules/@reelkit/angular-lightbox/styles.css"]Ícones
Os controles padrão usam lucide-angular para os ícones. Se você prefere outra biblioteca de ícones, use os slots de template rkLightboxControls e rkLightboxNavigation para fornecer os seus.
Início rápido
Importe os estilos e o componente standalone RkLightboxOverlayComponent no array imports do seu componente.
import { Component } from '@angular/core';
import {
RkLightboxOverlayComponent,
type LightboxItem,
} from '@reelkit/angular-lightbox';
import '@reelkit/angular-lightbox/styles.css';
const images: LightboxItem[] = [
{
src: '/cdn/samples/images/image-01.jpg',
title: 'Mountain River',
description: 'A beautiful mountain river',
},
{
src: '/cdn/samples/images/image-02.jpg',
title: 'Snowy Peaks',
},
{
src: '/cdn/samples/images/image-03.jpg',
title: 'Misty Forest',
description: 'Morning fog over the forest canopy',
},
{
src: '/cdn/samples/images/image-04.jpg',
title: 'Autumn Trail',
},
{
src: '/cdn/samples/images/image-05.jpg',
title: 'Ocean Cliff',
description: 'Dramatic cliffs above the Pacific',
},
{
src: '/cdn/samples/images/image-06.jpg',
title: 'Desert Dunes',
},
];
@Component({
selector: 'app-root',
standalone: true,
imports: [RkLightboxOverlayComponent],
template: `
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px">
@for (img of images; track img.src; let i = $index) {
<button (click)="openIndex = i" style="aspect-ratio:4/3;cursor:pointer">
<img [src]="img.src" style="width:100%;height:100%;object-fit:cover" />
</button>
}
</div>
<rk-lightbox-overlay
[isOpen]="openIndex !== null"
[items]="images"
[initialIndex]="openIndex ?? 0"
(closed)="openIndex = null"
/>
`,
})
export class AppComponent {
images = images;
openIndex: number | null = null;
}Onde o overlay é renderizado
Ao contrário dos lightboxes de React e Vue, que movem o overlay para o fim de document.body, o rk-lightbox-overlay é renderizado onde você o coloca e cobre a tela com position: fixed. Mantenha-o fora de qualquer ancestral com transform, perspective, filter ou will-change: transform: esse ancestral vira o bloco de contenção do overlay, então o lightbox assume o tamanho dele em vez da viewport e é cortado pelo seu overflow. Um ancestral que cria o próprio contexto de empilhamento também limita o quanto --rk-lightbox-overlay-z consegue elevar o lightbox. Em troca, os tokens --rk-lightbox-* definidos em qualquer ancestral chegam ao lightbox.
Slots de template
Quatro diretivas de slot de template permitem personalizar por completo a interface do overlay, sem precisar copiar o componente. Cada slot recebe um objeto de contexto fortemente tipado.
| Diretiva | Tipo do contexto | Descrição |
|---|---|---|
| [rkLightboxControls] | LightboxControlsContext | Substitui a barra de controles do topo (botão de fechar, contador, botão de tela cheia) |
| [rkLightboxNavigation] | LightboxNavContext | Substitui as setas de avançar e voltar |
| [rkLightboxInfo] | LightboxInfoContext | Substitui o gradiente de título e descrição na base |
| [rkLightboxSlide] | LightboxSlideContext | Substitui o conteúdo de cada slide (necessário para slides de vídeo) |
| [rkLightboxLoading] | LightboxLoadingContext | Indicador de carregamento próprio; a classe da diretiva é RkLightboxLoadingDirective |
| [rkLightboxError] | LightboxErrorContext | Indicador de erro próprio; a classe da diretiva é RkLightboxErrorDirective |
import {
RkLightboxOverlayComponent,
RkLightboxControlsDirective,
RkLightboxNavigationDirective,
RkLightboxInfoDirective,
RkCloseButtonComponent,
RkCounterComponent,
RkFullscreenButtonComponent,
type LightboxItem,
type LightboxControlsContext,
type LightboxNavContext,
} from '@reelkit/angular-lightbox';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RkLightboxOverlayComponent,
RkLightboxControlsDirective,
RkLightboxNavigationDirective,
RkLightboxInfoDirective,
RkCloseButtonComponent,
RkCounterComponent,
RkFullscreenButtonComponent,
],
template: `
<rk-lightbox-overlay [isOpen]="isOpen" [items]="images" (closed)="isOpen = false">
<!-- Custom controls bar -->
<ng-template rkLightboxControls
let-onClose="onClose"
let-activeIndex="activeIndex"
let-count="count"
let-isFullscreen="isFullscreen"
let-onToggleFullscreen="onToggleFullscreen">
<div style="position:absolute;top:0;left:0;right:0;padding:12px;
display:flex;align-items:center;justify-content:space-between">
<rk-close-button (clicked)="onClose()" />
<rk-counter [currentIndex]="activeIndex + 1" [count]="count" />
<rk-fullscreen-button
[isFullscreen]="isFullscreen"
(toggled)="onToggleFullscreen()" />
</div>
</ng-template>
<!-- Custom navigation -->
<ng-template rkLightboxNavigation
let-onPrev="onPrev"
let-onNext="onNext"
let-activeIndex="activeIndex"
let-count="count">
<button (click)="onPrev()" [disabled]="activeIndex === 0">←</button>
<button (click)="onNext()" [disabled]="activeIndex === count - 1">→</button>
</ng-template>
<!-- Custom info overlay -->
<ng-template rkLightboxInfo let-item let-index="index">
<div style="position:absolute;bottom:0;left:0;right:0;padding:16px;
background:linear-gradient(transparent,rgba(0,0,0,0.6))">
<h3 style="color:#fff">{{ item.title }}</h3>
<p style="color:rgba(255,255,255,0.7)">{{ item.description }}</p>
</div>
</ng-template>
</rk-lightbox-overlay>
`,
})
export class AppComponent {
images: LightboxItem[] = [];
isOpen = false;
}Suporte a vídeo
Para ter slides de vídeo é preciso optar por eles, pelo slot de template rkLightboxSlide e pelo RkLightboxVideoSlideComponent. Esse desenho evita embutir o player de vídeo em galerias que só precisam de imagens.
O botão de som embutido só aparece quando um SoundStateService é fornecido acima de <rk-lightbox-overlay>: é essa instância compartilhada que faz o toque chegar ao vídeo, já que o slide vem do seu template. Sem ela, controle o elemento direto com setLightboxVideoMuted.
import {
RkLightboxOverlayComponent,
RkLightboxSlideDirective,
RkLightboxVideoSlideComponent,
type LightboxItem,
type LightboxSlideContext,
} from '@reelkit/angular-lightbox';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RkLightboxOverlayComponent,
RkLightboxSlideDirective,
RkLightboxVideoSlideComponent,
],
template: `
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
<ng-template rkLightboxSlide
let-item
let-index="index"
let-size="size"
let-isActive="isActive"
let-autoAdvance="autoAdvance"
let-onReady="onReady"
let-onEnded="onEnded">
@if (item.type === 'video') {
<!-- With autoAdvance the video plays once and reports its end -->
<rk-lightbox-video-slide
[src]="item.src"
[poster]="item.poster"
[slideKey]="'lightbox-' + index"
[size]="size"
[isActive]="isActive"
[loop]="!autoAdvance"
[onReady]="onReady"
[onEnded]="onEnded"
/>
} @else {
<img [src]="item.src"
[style.width.px]="size[0]"
[style.height.px]="size[1]"
style="object-fit:contain" />
}
</ng-template>
</rk-lightbox-overlay>
`,
})
export class AppComponent {
isOpen = false;
items: LightboxItem[] = [
{ src: '/photo.jpg', title: 'Photo' },
{ src: '/clip.mp4', type: 'video', poster: '/clip-thumb.jpg', title: 'Video' },
];
}Tela cheia
Use fullscreenSignal, requestFullscreen e exitFullscreen, de @reelkit/angular, para observar ou alternar o estado de tela cheia.
import { fullscreenSignal, requestFullscreen, exitFullscreen } from '@reelkit/angular';
@Component({ ... })
export class AppComponent {
readonly isFullscreen = fullscreenSignal();
toggle(container: HTMLElement): void {
if (this.isFullscreen()) {
exitFullscreen();
} else {
requestFullscreen(container);
}
}
}Estado na URL
Ver demonstração ao vivo →RkLightboxUrlOverlayComponent é um componente à parte cujo estado aberto vive na barra de endereços. Monte um controlador com createOverlayUrlState e entregue-o como [controller]: a galeria se abre quando o parâmetro nomeia um slide e se fecha quando ele some. Os links dão para compartilhar, e o botão voltar fecha a galeria em vez de sair da página.
Chaves prontas
Você pode endereçar os slides com uma chave pronta — espalhe urlIndexKey (por posição) ou urlStableIdKey (por um id estável) no controlador — as duas reexportadas por @reelkit/angular. Veja o guia de estado na URL e a API do core.
import { RkLightboxUrlOverlayComponent } from '@reelkit/angular-lightbox';
import { createOverlayUrlState, urlIndexKey, urlStableIdKey } from '@reelkit/angular';
@Component({
imports: [RkLightboxUrlOverlayComponent, RouterLink],
template: `
@for (image of images(); track image.src; let i = $index) {
<a [routerLink]="[]" [queryParams]="{ photo: i }">
<img [src]="image.src" alt="" />
</a>
}
<rk-lightbox-url-overlay [controller]="photo" [items]="images()" />
`,
})
export class GalleryComponent {
protected readonly images = signal(photos);
protected readonly photo = createOverlayUrlState({
param: 'photo',
...urlIndexKey(() => this.images().length),
});
}Chame-o em um contexto de injeção — na inicialização de um campo ou no construtor. Ele se liga na hora e se solta pelo DestroyRef, então um componente destruído com a galeria aberta não deixa nenhuma escuta para trás. As opções completas estão na referência da API para Angular.
- Abrir empilha uma entrada no histórico. Percorrer os slides substitui essa entrada, então N passos não acrescentam nenhuma e um único passo para trás sempre sai da galeria.
- Voltar só fecha quando a galeria foi aberta de dentro do app — foi o link que empilhou a entrada. Um link compartilhado aberto direto em uma aba nova não tem histórico atrás de si, então o voltar do navegador sai do site; o botão ✕ ou o Escape removem o parâmetro ali mesmo e você continua na página.
- Um parâmetro que não nomeia slide nenhum — um favorito velho, um valor editado à mão — é retirado da URL, em vez de ficar afirmando um slide que não abre.
- Os slots de template funcionam sem mudança: o componente de URL faz ele mesmo as seis consultas de slot e repassa cada template à galeria, então
rkLightboxControlse seus irmãos ficam dentro dele exatamente como ficariam dentro derk-lightbox-overlay. - Em uma aplicação com rotas, passe um adaptador construído sobre o
Router. Escrever no histórico por trás do Router deixa a localização dele desatualizada, e a navegação seguinte derruba o parâmetro.
Em um app com rotas, passe um adaptador. Escrever no histórico por trás do Router deixa a localização dele desatualizada, e a navegação seguinte derruba o parâmetro; então construa um adaptador sobre o Router e passe-o como adapter:
import { createRouterUrlAdapter } from '@reelkit/angular/ng-router-url-adapter';
const adapter = createRouterUrlAdapter();
const photo = createOverlayUrlState({
param: 'photo',
adapter,
...urlIndexKey(() => this.images().length),
});Links estáveis. O índice é posicional — um ?photo=3 favoritado abre outra imagem assim que a lista muda de ordem. urlStableIdKey usa o id estável de cada item, varrendo a lista atual — uma chamada resolve o caso comum.
const photo = createOverlayUrlState({
param: 'photo',
...urlStableIdKey({ items: () => this.images() }),
});Passe hashCodec: base64UrlCodec para escrever o id em base64url na URL — é um disfarce reversível, não um hash criptográfico.
Quer endereçar por outro campo (um slug), ou paginar um feed infinito com locateAsync? Monte o codec (o fio) e o locator (a busca) você mesmo:
const photo = createOverlayUrlState({
param: 'photo',
codec: { decode: (raw) => raw, encode: (id) => id },
locator: {
locate: (id) => this.images().findIndex((x) => x.id === id),
identify: (index) => this.images()[index].id,
},
});Galerias infinitas ou paginadas. locate é síncrono, então só responde pelas imagens já carregadas — um link compartilhado para a imagem 400 de um feed que carregou 20 volta vazio. locateAsync é o plano B, chamado somente quando locate falha: carregue as páginas necessárias e devolva o índice que a identidade acabou tendo. Enquanto a busca corre, a galeria fica fechada e o parâmetro é deixado em paz, então o link direto sobrevive; um null ou uma rejeição derrubam o parâmetro.
Atalho
Vai endereçar pelo id do item? Dispense o codec e o locator escritos à mão — passe locateAsync direto para urlStableIdKey({ items, locateAsync }) (ele busca quando falha e então devolve o índice). A versão mais completa abaixo serve para endereçar por outro campo, ou para ter controle total.
const photo = createOverlayUrlState({
param: 'photo',
codec: { decode: (raw) => raw, encode: (id) => id },
locator: {
locate: (id) => this.images().findIndex((x) => x.id === id),
identify: (index) => this.images()[index].id,
locateAsync: async (id) => {
const loaded = await loadById(id); // or loadUntil(id) — fetch just that one, or page up to it
if (!loaded) return null; // exhausted — link names no item
this.images.set(loaded); // commit; the overlay renders from this
return loaded.findIndex((x) => x.id === id); // wherever it landed
},
},
});Avanço automático
Defina [autoAdvance]="true" para tocar a galeria como uma apresentação assim que ela abre. Vem desligado, então uma galeria que já existe renderiza e se comporta como antes.
- Imagens ficam por
autoAdvanceInterval(5000 ms por padrão), contados a partir do momento em que a imagem carregou, então uma imagem lenta nunca é pulada antes de alguém vê-la. Uma imagem que falha ao carregar conta a partir do erro. - Vídeos tocam uma vez em vez de repetir e passam adiante quando terminam. Num template
rkLightboxSlide, ligue[loop]="!autoAdvance"e[onEnded]="onEnded"emrk-lightbox-video-slide, como em Suporte a vídeo. - Ela espera enquanto o mouse repousa sobre um controle (um botão, um link ou a legenda), durante um deslize e enquanto a página está oculta, e depois continua de onde parou.
- Navegar à mão (setas, teclas, roda do mouse, deslize) começa o intervalo do novo slide do zero; a apresentação continua ligada.
- No último slide ela para, a menos que
loopesteja definido. O botão de play/pause nos controles mostra o estado e deixa quem assiste alterná-lo.
A apresentação roda fora da zone do Angular, então seus frames de animação não disparam detecção de mudanças. Um template rkLightboxControls próprio recebe isAutoAdvancing e, só quando autoAdvance está ligado, onToggleAutoAdvance — renderize rk-play-pause-button quando ele estiver lá. A temporização em si é o createSlideshowController de @reelkit/core; veja o guia de reprodução automática e a API do core.
import { Component } from '@angular/core';
import {
RkCloseButtonComponent,
RkLightboxControlsDirective,
RkLightboxOverlayComponent,
RkPlayPauseButtonComponent,
type LightboxItem,
} from '@reelkit/angular-lightbox';
@Component({
selector: 'app-gallery',
imports: [
RkLightboxOverlayComponent,
RkLightboxControlsDirective,
RkPlayPauseButtonComponent,
RkCloseButtonComponent,
],
template: `
<rk-lightbox-overlay
[isOpen]="isOpen"
[items]="items"
[autoAdvance]="true"
[autoAdvanceInterval]="4000"
(closed)="isOpen = false"
>
<!-- Optional: a custom bar shows the toggle only when its handler is there -->
<ng-template rkLightboxControls let-ctx>
@if (ctx.onToggleAutoAdvance) {
<rk-play-pause-button
[playing]="ctx.isAutoAdvancing"
(toggled)="ctx.onToggleAutoAdvance()"
/>
}
<rk-close-button (clicked)="ctx.onClose()" />
</ng-template>
</rk-lightbox-overlay>
`,
})
export class GalleryComponent {
isOpen = false;
items: LightboxItem[] = [{ src: '/beach.jpg' }, { src: '/forest.jpg' }];
}Download
Defina [showDownload]="true" para acrescentar um botão de download aos controles. Ele salva o item ativo a partir do seu downloadUrl, ou de src na falta dele, com o nome downloadName, ou com o último segmento da URL na falta dele.
O arquivo é buscado e salvo, porque o navegador ignora o atributo download num link de outra origem e abriria o arquivo em vez de salvá-lo. Quando a busca falha — em geral um servidor de outra origem que não envia cabeçalhos CORS — o arquivo abre numa nova aba, onde quem assiste ainda pode salvá-lo. Sirva os arquivos com Access-Control-Allow-Origin para salvar com um clique. O botão fica desativado enquanto um download está em andamento.
Um template rkLightboxControls próprio recebe isDownloading e, só quando showDownload está ligado, onDownload — renderize rk-download-button quando ele estiver lá. O helper é o downloadFile de @reelkit/core; veja o guia de download.
import { Component } from '@angular/core';
import {
RkCloseButtonComponent,
RkDownloadButtonComponent,
RkLightboxControlsDirective,
RkLightboxOverlayComponent,
type LightboxItem,
} from '@reelkit/angular-lightbox';
@Component({
selector: 'app-gallery',
imports: [
RkLightboxOverlayComponent,
RkLightboxControlsDirective,
RkDownloadButtonComponent,
RkCloseButtonComponent,
],
template: `
<rk-lightbox-overlay
[isOpen]="isOpen"
[items]="items"
[showDownload]="true"
(closed)="isOpen = false"
>
<!-- Optional: a custom bar shows the button only when its handler is there -->
<ng-template rkLightboxControls let-ctx>
@if (ctx.onDownload) {
<rk-download-button
[downloading]="ctx.isDownloading"
(pressed)="ctx.onDownload()"
/>
}
<rk-close-button (clicked)="ctx.onClose()" />
</ng-template>
</rk-lightbox-overlay>
`,
})
export class GalleryComponent {
isOpen = false;
items: LightboxItem[] = [
{
src: '/beach-1600.jpg',
// Save the original rather than the resized preview
downloadUrl: '/beach-original.jpg',
downloadName: 'beach.jpg',
},
];
}Botões de controle
| Componente | Seletor | Inputs / outputs | Descrição |
|---|---|---|---|
RkPlayPauseButtonComponent | rk-play-pause-button | [playing], (toggled) | Alternador da apresentação (ícone Play/Pause, aria-pressed enquanto toca). Mostrado pelos controles padrão com autoAdvance. |
RkDownloadButtonComponent | rk-download-button | [downloading], (pressed) | Botão de download, desativado enquanto downloading. Mostrado pelos controles padrão com showDownload. |
RkSoundButtonComponent | rk-sound-button | [muted], (toggled) | Botão de mudo para itens de vídeo. Mostrado pelos controles padrão num slide de vídeo; coloque-o no seu próprio template rkLightboxControls para mantê-lo. |
Inputs do RkLightboxUrlOverlayComponent
Aceita todos os inputs de rk-lightbox-overlay, menos isOpen, substituído por um controlador. Os outputs são os mesmos, closed e slideChange; quem fecha é a URL, então closed é um aviso, não o mecanismo.
| Input | Tipo | Padrão | Descrição |
|---|---|---|---|
controller | UrlStateController | obrigatório | Controlador vindo de createOverlayUrlState. A posição dele decide se a galeria está aberta e qual slide aparece; o componente escreve de volta por ele na troca de slide e no fechamento. |
Inputs do RkLightboxOverlayComponent
| Input | Tipo | Padrão | Descrição |
|---|---|---|---|
isOpen | boolean | obrigatório | Controla a visibilidade; com false, o overlay sai do DOM |
items | LightboxItem[] | obrigatório | Array de itens da galeria (imagens ou vídeos) |
initialIndex | number | 0 | Índice, começando em zero, do item visível no início |
transitionFn | TransitionTransformFn | slideTransition | Função da transição entre slides. Importe uma das prontas (slideTransition, flipTransition, lightboxFadeTransition, lightboxZoomTransition) ou passe a sua. Sem este input, vale slideTransition. |
showInfo | boolean | true | Se a camada de título e descrição aparece |
showControls | boolean | true | Se a barra de controles do topo aparece (fechar, contador, tela cheia) |
showNavigation | boolean | true | Se as setas de avançar e voltar aparecem |
transitionDuration | number | 300 | Duração da animação do slide em ms |
swipeDistanceFactor | number | 0.12 | Fração mínima da distância de deslize (0–1) para trocar de slide |
swipeToCloseDirection | 'up' | 'down' | 'up' | Direção do gesto de deslizar para fechar no celular |
loop | boolean | false | Se o slider passa do último slide de volta ao primeiro |
enableNavKeys | boolean | true | Liga a navegação pelas setas do teclado |
enableWheel | boolean | true | Liga a navegação pela roda do mouse |
wheelDebounceMs | number | 200 | Duração do debounce dos eventos de roda em ms |
autoAdvance | boolean | false | Toca a galeria como uma apresentação. Veja Avanço automático. |
autoAdvanceInterval | number | 5000 | Quanto tempo cada imagem fica durante a apresentação, em ms, contado a partir do momento em que carregou |
showDownload | boolean | false | Acrescenta um botão de download para o item ativo. Veja Download. |
ariaLabel | string | 'Image gallery' | Rótulo acessível da região do diálogo |
Os inputs do slider acima (transitionDuration, swipeDistanceFactor, loop, enableNavKeys, enableWheel, wheelDebounceMs) são tipados por ReelProxyProps. Use-o para tipar um componente wrapper que os repassa ao lightbox.
Outputs do RkLightboxOverlayComponent
| Output | Tipo | Descrição |
|---|---|---|
closed | EventEmitter<void> | Emitido quando o leitor fecha a galeria |
slideChange | EventEmitter<number> | Emitido quando o índice do slide ativo muda |
Interface LightboxItem
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
src | string | sim | URL da imagem ou do vídeo |
type | 'image' | 'video' | não | Tipo do item. O padrão é 'image' |
poster | string | não | Imagem de miniatura dos itens de vídeo |
title | string | não | Título mostrado na camada de informações |
description | string | não | Descrição mostrada abaixo do título |
width | number | não | Largura original da imagem em pixels |
height | number | não | Altura original da imagem em pixels |
downloadUrl | string | não | O que o botão de download salva. O padrão é src |
downloadName | string | não | Nome do arquivo salvo. O padrão é o último segmento do caminho da URL |
Tipos de contexto dos slots de template
| Tipo | Campos |
|---|---|
LightboxControlsContext | { item, activeIndex, count, isFullscreen, isAutoAdvancing, isDownloading, onClose, onToggleFullscreen, onToggleAutoAdvance?, onDownload? } |
LightboxNavContext | { item, onPrev, onNext, activeIndex, count } |
LightboxInfoContext | { $implicit: LightboxItem, index } |
LightboxSlideContext | { $implicit: LightboxItem, index, size: [number, number], isActive, autoAdvance, onReady, onWaiting, onError, onEnded } |
LightboxLoadingContext | { $implicit: activeIndex, item } — o que o template rkLightboxLoading recebe |
LightboxErrorContext | { $implicit: activeIndex, item } — o que o template rkLightboxError recebe |
Transições
Passe qualquer TransitionTransformFn pelo input transitionFn. Importar apenas a transição que você usa deixa o bundler descartar as outras. Sem este input, vale slideTransition.
| Função | De onde vem | Descrição |
|---|---|---|
slideTransition | @reelkit/angular-lightbox | Deslizamento horizontal comum (padrão) |
lightboxFadeTransition | @reelkit/angular-lightbox | Esmaecimento cruzado entre as imagens |
flipTransition | @reelkit/angular-lightbox | Efeito de virada de carta em 3D |
lightboxZoomTransition | @reelkit/angular-lightbox | Aproximação, do menor até o tamanho normal |
import {
RkLightboxOverlayComponent,
lightboxFadeTransition,
} from '@reelkit/angular-lightbox';
@Component({
imports: [RkLightboxOverlayComponent],
template: `
<rk-lightbox-overlay
[isOpen]="isOpen"
[items]="images"
[transitionFn]="lightboxFadeTransition"
(closed)="isOpen = false"
/>
`,
})
export class GalleryComponent {
protected readonly lightboxFadeTransition = lightboxFadeTransition;
}Carregamento de conteúdo e tratamento de erros
Ao usar o slot de template rkLightboxSlide, três callbacks de ciclo de vida ficam disponíveis no contexto para informar o estado de carregamento. A galeria acompanha o estado de cada slide e mostra o girador ou o ícone de erro conforme o caso. Um pré-carregador guarda em cache as URLs quebradas, então voltar a um slide que falhou pula a nova tentativa.
Callbacks de ciclo de vida
| Callback | Tipo | Descrição |
|---|---|---|
onReady | () => void | Avisa que o conteúdo do slide carregou (a imagem foi decodificada, por exemplo) |
onWaiting | () => void | Avisa que o conteúdo do slide está carregando (mostra o girador) |
onError | () => void | Avisa que o conteúdo do slide não carregou (mostra o ícone de erro) |
Ligando os callbacks no rkLightboxSlide
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
<ng-template rkLightboxSlide
let-item
let-size="size"
let-isActive="isActive"
let-onReady="onReady"
let-onWaiting="onWaiting"
let-onError="onError">
@if (item.type === 'video') {
<rk-lightbox-video-slide
[item]="item"
[size]="size"
[isActive]="isActive"
/>
} @else {
<img [src]="item.src"
[style.width.px]="size[0]"
[style.height.px]="size[1]"
style="object-fit:contain"
(load)="onReady()"
(error)="onError()" />
}
</ng-template>
</rk-lightbox-overlay>Template de carregamento próprio
Use a diretiva rkLightboxLoading para substituir o girador padrão.
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
<ng-template rkLightboxLoading let-index let-item="item">
<div style="display:flex;flex-direction:column;align-items:center;color:#fff">
<span>Loading image {{ index + 1 }}...</span>
<span style="opacity:0.6">{{ item.title }}</span>
</div>
</ng-template>
</rk-lightbox-overlay>Template de erro próprio
Use a diretiva rkLightboxError para substituir o ícone de erro padrão.
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
<ng-template rkLightboxError let-index let-item="item">
<div style="display:flex;flex-direction:column;align-items:center;color:#ef4444">
<span>Failed to load</span>
<span style="opacity:0.6">{{ item.title ?? item.src }}</span>
</div>
</ng-template>
</rk-lightbox-overlay>Classes CSS
Todas as classes CSS são simples (sem escopo), então dá para alcançá-las com seletores de especificidade maior em uma folha de estilo carregada depois de @reelkit/angular-lightbox/styles.css. Para mudar cor, tamanho e z-index, prefira as propriedades CSS documentadas na seção Temas, abaixo.
| Classe | Componente | Descrição |
|---|---|---|
.rk-lightbox-overlay | Overlay | Contêiner raiz (fundo em tela cheia) |
.rk-lightbox-top-shade | Overlay | Gradiente do topo, atrás dos controles |
.rk-lightbox-spinner | Overlay | Girador de carregamento padrão |
.rk-lightbox-img-error | Overlay | Contêiner do estado de erro (imagem quebrada) |
.rk-lightbox-img-error-text | Overlay | Texto do estado de erro |
.rk-lightbox-swipe-hint | Overlay | Dica de deslize no celular |
.rk-lightbox-empty | Overlay | Texto do estado vazio |
.rk-lightbox-controls-left | Controls | Contêiner dos controles no canto superior esquerdo |
.rk-lightbox-btn | Controls | Botão de controle (tela cheia e afins) |
.rk-lightbox-play-pause | Controls | Botão de play/pause da apresentação (com .rk-lightbox-btn) |
.rk-lightbox-download | Controls | Botão de download (com .rk-lightbox-btn) |
.rk-lightbox-close | Controls | Botão de fechar |
.rk-lightbox-counter | Controls | Etiqueta contadora de imagens |
.rk-lightbox-nav | Navigation | Seta de navegação (avançar e voltar) |
.rk-lightbox-nav-prev | Navigation | Seta de voltar |
.rk-lightbox-nav-next | Navigation | Seta de avançar |
.rk-lightbox-info | Info | Contêiner de título e descrição |
.rk-lightbox-title | Info | Título da imagem |
.rk-lightbox-description | Info | Descrição da imagem |
.rk-lightbox-slide | Slide | Contêiner do slide |
.rk-lightbox-img | Slide | Elemento de imagem |
.rk-lightbox-video-container | VideoSlide | Contêiner do slide de vídeo (opcional) |
.rk-lightbox-video-element | VideoSlide | Elemento de vídeo (opcional) |
.rk-lightbox-video-poster | VideoSlide | Imagem de pôster do vídeo (opcional) |
.rk-lightbox-video-error | VideoSlide | Contêiner do estado de erro do vídeo |
Temas
Cada cor, tamanho, z-index e transição vive em uma propriedade CSS. Sobrescreva uma ou várias em :root (ou em qualquer ancestral da galeria) para trocar o tema sem mexer no código dos componentes. Os tokens são os mesmos do lightbox do React, então as sobrescritas valem para os dois bindings.
| Token | Padrão | O que controla |
|---|---|---|
--rk-lightbox-overlay-bg | #000 | Cor do fundo em tela cheia |
--rk-lightbox-overlay-z | 9999 | z-index do overlay |
--rk-lightbox-top-shade-height | 80px | Altura do gradiente do topo |
--rk-lightbox-top-shade-bg | linear-gradient(rgba(0,0,0,0.6), transparent) | Cor do gradiente do topo |
--rk-lightbox-edge-padding | 16px | Recuo da borda para fechar, navegação e controles do canto superior esquerdo |
--rk-lightbox-controls-gap | 12px | Espaço entre os controles do canto superior esquerdo |
--rk-lightbox-transition | 0.2s | Duração da transição dos botões ao passar o mouse |
--rk-lightbox-blur | 8px | Raio do desfoque atrás de botões e etiquetas |
--rk-lightbox-btn-bg | rgba(0, 0, 0, 0.5) | Fundo padrão dos botões de fechar, navegação e dos pequenos |
--rk-lightbox-btn-bg-hover | rgba(255, 255, 255, 0.2) | Fundo desses botões ao passar o mouse |
--rk-lightbox-btn-fg | #fff | Cor do ícone desses botões |
--rk-lightbox-btn-size | 36px | Tamanho dos botões pequenos (tela cheia e afins) |
--rk-lightbox-btn-disabled-opacity | 0.5 | Opacidade de um botão pequeno desativado (download em andamento) |
--rk-lightbox-close-size | 40px | Tamanho do botão de fechar |
--rk-lightbox-nav-size | 48px | Tamanho das setas de avançar e voltar |
--rk-lightbox-nav-opacity | 0.7 | Opacidade das setas em repouso |
--rk-lightbox-counter-fg | #fff | Cor do texto do contador |
--rk-lightbox-counter-bg | rgba(0, 0, 0, 0.5) | Fundo da etiqueta do contador |
--rk-lightbox-counter-size | 14px | Tamanho da fonte do contador |
--rk-lightbox-counter-padding | 6px 12px | Respiro interno da etiqueta do contador |
--rk-lightbox-counter-radius | 20px | Arredondamento da etiqueta do contador |
--rk-lightbox-spinner-size | 28px | Largura e altura do girador padrão |
--rk-lightbox-spinner-duration | 0.8s | Duração de uma volta do girador |
--rk-lightbox-error-fg | rgba(255, 255, 255, 0.4) | Cor do ícone e do texto de erro |
--rk-lightbox-info-bg | linear-gradient(transparent, rgba(0,0,0,0.8)) | Gradiente que escurece o fundo da legenda |
--rk-lightbox-info-padding | 24px | Respiro interno da legenda |
--rk-lightbox-title-size | 18px | Tamanho da fonte do título |
--rk-lightbox-description-size | 14px | Tamanho da fonte da descrição |
--rk-lightbox-hint-fg | rgba(255, 255, 255, 0.5) | Cor do texto da dica de deslize |
--rk-lightbox-hint-bg | rgba(0, 0, 0, 0.3) | Fundo da etiqueta da dica de deslize |
--rk-lightbox-video-bg | #000 | Cor das faixas em volta do <video> |
Cole o trecho abaixo em uma folha de estilo carregada depois de @reelkit/angular-lightbox/styles.css.
/* Brand the lightbox */
:root {
--rk-lightbox-overlay-bg: #0f172a;
--rk-lightbox-btn-bg: rgba(99, 102, 241, 0.65);
--rk-lightbox-btn-bg-hover: rgba(168, 85, 247, 0.85);
--rk-lightbox-nav-size: 56px;
--rk-lightbox-counter-bg: rgba(99, 102, 241, 0.65);
--rk-lightbox-info-bg: linear-gradient(
transparent,
rgba(99, 102, 241, 0.55) 60%,
rgba(168, 85, 247, 0.85)
);
}Acessibilidade
A raiz do overlay é um diálogo modal (role="dialog", aria-modal="true"). Defina o input ariaLabel para mudar o que o leitor de tela anuncia; o padrão é "Image gallery". Cada slide carrega role="group", aria-roledescription="slide" e um aria-label derivado do título da imagem e da posição.
A galeria captura o foco ao abrir e o devolve ao gatilho ao fechar. Tab e Shift+Tab percorrem os elementos focáveis lá dentro; um foco que escapa (clique fora, foco por código) é trazido de volta. Implementado com captureFocusForReturn e createFocusTrap, de @reelkit/core.
Atalhos de teclado
| Tecla | Ação |
|---|---|
ArrowLeft | Imagem anterior |
ArrowRight | Próxima imagem |
Escape | Fecha a galeria (ou sai da tela cheia, se estiver nela) |