Angular Lightbox

@reelkit/angular-lightbox で作られた、Angular 用のフルスクリーンの画像と動画のギャラリーです。

ライブデモを見る →

機能

画像と動画
動画スライドを標準でサポート
タッチジェスチャー
スワイプで移動
スワイプで閉じる
上にスワイプして閉じる
キーボード操作
矢印キーと Escape
フルスクリーン
ブラウザー間で動く API
トランジション
スライド、フェード、フリップ、ズームイン
先読み
隣の画像を事前に取得
サウンド切り替え
スライドごとのミュート
読み込み状態
スピナーと独自のスロット
エラー処理
エラーアイコンと独自のスロット
テンプレートスロット
カスタマイズできる 6 つのスロット領域
OnPush
Angular のシグナルと OnPush
URL の状態
共有もブックマークもできるリンク
スライドショー
オプトインの自動送り、再生と一時停止に対応
ダウンロード
アクティブなアイテムを保存するオプトインのボタン

インストール

bash
npm install @reelkit/angular-lightbox @reelkit/angular lucide-angular

スタイルシートを一度だけ登録します:

typescript
// 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"]
アイコン

デフォルトのコントロールはアイコンに lucide-angular を使います。別のアイコンライブラリを使いたい場合は、rkLightboxControls と rkLightboxNavigation のテンプレートスロットで独自のものを渡してください。

クイックスタート

スタイルとスタンドアロンの RkLightboxOverlayComponent を、コンポーネントの imports 配列にインポートします。

gallery.component.ts
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;
}
オーバーレイが描画される場所

オーバーレイを document.body の末尾へ移す React と Vue の lightbox と違い、rk-lightbox-overlay は置いた場所に描画され、position: fixed で画面を覆います。transform、perspective、filter、will-change: transform を持つ祖先の中には置かないでください。その祖先がオーバーレイの包含ブロックになり、lightbox はビューポートではなくその祖先の大きさになり、祖先の overflow で切り取られます。独自のスタッキングコンテキストを作る祖先も、--rk-lightbox-overlay-z で lightbox をどこまで持ち上げられるかを制限します。その代わり、どの祖先に設定した --rk-lightbox-* トークンも lightbox に届きます。

テンプレートスロット

4 つのテンプレートスロットのディレクティブで、コンポーネントを複製せずにオーバーレイの UI を自由にカスタマイズできます。各スロットは厳密に型付けされたコンテキストのオブジェクトを受け取ります。

ディレクティブコンテキストの型説明
[rkLightboxControls]LightboxControlsContext上部のコントロールバー(閉じるボタン、カウンター、フルスクリーン切り替え)を置き換えます
[rkLightboxNavigation]LightboxNavContext前後のナビゲーション矢印を置き換えます
[rkLightboxInfo]LightboxInfoContext下部のタイトルと説明のグラデーションのオーバーレイを置き換えます
[rkLightboxSlide]LightboxSlideContext個々のスライドの内容を置き換えます(動画スライドに必要)
[rkLightboxLoading]LightboxLoadingContext独自の読み込み表示。ディレクティブのクラスは RkLightboxLoadingDirective です
[rkLightboxError]LightboxErrorContext独自のエラー表示。ディレクティブのクラスは RkLightboxErrorDirective です
typescript
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">&#8592;</button>
        <button (click)="onNext()" [disabled]="activeIndex === count - 1">&#8594;</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;
}

動画のサポート

動画スライドを使うには、rkLightboxSlide のテンプレートスロットと RkLightboxVideoSlideComponent でオプトインする必要があります。画像だけでよいギャラリーに動画プレイヤーをバンドルしないための設計です。

組み込みのサウンドボタンは、SoundStateService が <rk-lightbox-overlay> の上で提供されているときだけ表示されます。スライドはあなたのテンプレートから描画されるので、その共有インスタンスだけが切り替えを動画まで届けます。ないときは setLightboxVideoMuted で要素を直接操作してください。

typescript
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' },
  ];
}

フルスクリーン

フルスクリーンの状態を監視したり切り替えたりするには、@reelkit/angular の fullscreenSignal、requestFullscreen、exitFullscreen を使います。

typescript
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);
    }
  }
}

URL の状態

ライブデモを見る →

RkLightboxUrlOverlayComponent は、開閉状態をアドレスバーに持つ別のコンポーネントです。createOverlayUrlState でコントローラーを作り、[controller] として渡します。パラメーターがスライドを指すとギャラリーは自分で開き、なくなると閉じます。リンクは共有でき、戻るボタンはページを離れる代わりにギャラリーを閉じます。

組み込みのキー

スライドは組み込みのキーで指せます。urlIndexKey(位置で指す)か urlStableIdKey(安定した id で指す)をコントローラーに展開してください。どちらも @reelkit/angular から再エクスポートされています。URL の状態のガイド と Core API を参照してください。

typescript
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),
  });
}

インジェクションコンテキスト(フィールドの初期化子かコンストラクター)の中で呼んでください。すぐに接続し、DestroyRef で解放されるので、ギャラリーが開いたままコンポーネントが破棄されてもリスナーは残りません。すべてのオプションは Angular API リファレンス にあります。

  • 開くと履歴エントリーを 1 つ 積みます。スライドを送るとそれを 置き換え るので、N 回移動してもエントリーは増えず、1 回戻れば必ずギャラリーから出られます。
  • 戻るで閉じるのは、アプリ内からギャラリーを開いた場合だけです(リンクがエントリーを積んだ場合)。新しいタブで直接開いた共有リンクには前の履歴がないので、ブラウザーの戻るではサイトを離れます。✕ ボタンか Escape なら、その場でパラメーターを取り除いてページにとどまります。
  • どのスライドも指さないパラメーター(古いブックマークや手で書き換えた値)は、開けないスライドを指したままにならないよう、URL から取り除かれます。
  • テンプレートスロットはそのまま使えます。URL のコンポーネントが 6 つのスロットの問い合わせを自分で行い、それぞれのテンプレートをギャラリーへ渡すので、rkLightboxControls などは rk-lightbox-overlay の中と同じように置けます。
  • ルーティングを使うアプリケーションでは、Router の上に作ったアダプターを渡してください。Router の裏で履歴を書くと、その位置情報が古くなり、次のナビゲーションでパラメーターが消えます。

ルーターを使うアプリでは、アダプターを渡します。 Router の裏で履歴を書くと、その位置情報が古くなり、次のナビゲーションでパラメーターが消えます。Router の上にアダプターを作り、adapter として渡してください:

typescript
import { createRouterUrlAdapter } from '@reelkit/angular/ng-router-url-adapter';

const adapter = createRouterUrlAdapter();

const photo = createOverlayUrlState({
  param: 'photo',
  adapter,
  ...urlIndexKey(() => this.images().length),
});

安定したリンク。 インデックスは位置なので、ブックマークした ?photo=3 はリストが並べ替えられると別の画像を開きます。urlStableIdKey は各アイテムの安定した id で指し、現在のリストを走査します。よくあるケースは 1 回の呼び出しで済みます。

typescript
const photo = createOverlayUrlState({
  param: 'photo',
  ...urlStableIdKey({ items: () => this.images() }),
});

hashCodec: base64UrlCodec を渡すと、URL の id を base64url でエンコードします。元に戻せる難読化で、暗号学的ハッシュではありません。

別のフィールド(slug)で指したい場合や、locateAsync で無限フィードをページングしたい場合は、codec(通信形式)と locator(検索)を自分で作ります:

typescript
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,
  },
});

無限またはページングされたギャラリー。 locate は同期なので、読み込み済みの画像にしか答えません。20 件を読み込んだフィードの 400 番目の画像への共有リンクは見つかりません。locateAsync はフォールバックで、locate が見つけられなかったときだけ呼ばれます。必要なページを読み込み、その識別子が最終的に持ったインデックスを返してください。保留中のあいだギャラリーは閉じたままで、パラメーターはそのまま残るので、ディープリンクは取得のあいだも失われません。null か reject でパラメーターは取り除かれます。

近道

アイテムの id で指すなら、codec と locator を手書きする必要はありません。locateAsync をそのまま urlStableIdKey({ items, locateAsync }) に渡してください(見つからなければ取得してからインデックスを返します)。下のより完全な例は、別のフィールドで指す場合や、すべてを自分で制御したい場合のものです。

typescript
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
    },
  },
});

自動送り

[autoAdvance]="true" を指定すると、ギャラリーが開いたときにスライドショーとして再生します。デフォルトではオフなので、既存の Lightbox の描画と動作は変わりません。

  • 画像は autoAdvanceInterval(デフォルトは 5000 ms)のあいだ表示されます。画像の読み込みが終わった時点から数えるので、遅い画像が誰にも見られないまま飛ばされることはありません。読み込みに失敗した画像は、そのエラーの時点から数えます。
  • 動画はループせずに 1 回だけ再生し、終わると次へ進みます。rkLightboxSlide テンプレートでは、動画のサポートのように rk-lightbox-video-slide に [loop]="!autoAdvance" と [onEnded]="onEnded" をバインドしてください。
  • 待機するのは、マウスがコントロール(ボタン、リンク、キャプション)の上にあるあいだ、スワイプ中、ページが非表示のあいだです。そのあとは止まったところから続けます。
  • 手で移動すると(矢印、キー、ホイール、スワイプ)、新しいスライドの間隔は 0 から始まります。スライドショーはオンのままです。
  • 最後のスライドでは、loop が指定されていない限り止まります。コントロールの再生/一時停止ボタンが状態を示し、閲覧者が切り替えられます。

スライドショーは Angular のゾーンの外で動くので、そのアニメーションフレームは変更検知を起こしません。独自の rkLightboxControls テンプレートは isAutoAdvancing を受け取り、autoAdvance がオンのときだけ onToggleAutoAdvance も受け取ります。それがあるときは rk-play-pause-button を描画してください。タイミング自体は @reelkit/core の createSlideshowController です。自動再生ガイドと Core API を参照してください。

typescript
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' }];
}

ダウンロード

[showDownload]="true" を指定すると、コントロールにダウンロードボタンが加わります。アクティブなアイテムを downloadUrl(なければ src)から、downloadName(なければ URL の最後の部分)という名前で保存します。

ファイルは fetch してから保存します。別オリジンのリンクでは、ブラウザーは download 属性を無視してファイルを開いてしまうからです。fetch が失敗したとき(よくあるのは CORS ヘッダーを送らない別オリジンのサーバーです)は、ファイルを新しいタブで開くので、閲覧者はそこから保存できます。ワンクリックで保存できるようにするには、ファイルを Access-Control-Allow-Origin 付きで配信してください。ダウンロード中はボタンが無効になります。

独自の rkLightboxControls テンプレートは isDownloading を受け取り、showDownload がオンのときだけ onDownload も受け取ります。それがあるときは rk-download-button を描画してください。ヘルパーは @reelkit/core の downloadFile です。ダウンロードガイドを参照してください。

typescript
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',
    },
  ];
}

コントロールのボタン

コンポーネントセレクター入力/出力説明
RkPlayPauseButtonComponentrk-play-pause-button[playing], (toggled)スライドショーの切り替えボタン(Play/Pause のアイコン、再生中は aria-pressed)。autoAdvance のときにデフォルトのコントロールが表示します。
RkDownloadButtonComponentrk-download-button[downloading], (pressed)ダウンロードボタン。downloading のあいだは無効になります。showDownload のときにデフォルトのコントロールが表示します。
RkSoundButtonComponentrk-sound-button[muted], (toggled)動画の要素向けのミュート切り替え。動画スライドではデフォルトのコントロールが表示します。残すには、独自の rkLightboxControls テンプレートに置きます。

RkLightboxUrlOverlayComponent の入力

rk-lightbox-overlay の入力をすべて受け取りますが、isOpen の代わりにコントローラーを使います。出力は同じ closed と slideChange です。閉じるのは URL が行うので、closed は仕組みではなく通知です。

入力型デフォルト説明
controllerUrlStateController必須createOverlayUrlState のコントローラー。その位置で、ギャラリーが開いているかどうかと、どのスライドを表示するかが決まります。コンポーネントはスライドの切り替え時と閉じるときに、これを通じて書き戻します。

RkLightboxOverlayComponent の入力

入力型デフォルト説明
isOpenboolean必須表示を制御します。false のときオーバーレイは DOM から取り除かれます
itemsLightboxItem[]必須ギャラリーのアイテム(画像または動画)の配列
initialIndexnumber0最初に表示するアイテムの 0 始まりのインデックス
transitionFnTransitionTransformFnslideTransitionスライドのトランジション関数。組み込みのもの(slideTransition、flipTransition、lightboxFadeTransition、lightboxZoomTransition)をインポートするか、独自のものを渡します。省略すると slideTransition になります。
showInfobooleantrueタイトルと説明の情報オーバーレイを描画するかどうか
showControlsbooleantrue上部のコントロールバー(閉じる、カウンター、フルスクリーン)を描画するかどうか
showNavigationbooleantrue前後のナビゲーション矢印を描画するかどうか
transitionDurationnumber300スライドのアニメーションの長さ(ms)
swipeDistanceFactornumber0.12スライドを切り替えるのに必要なスワイプ距離の最小の割合(0–1)
swipeToCloseDirection'up' | 'down''up'モバイルでスワイプして閉じるジェスチャーの方向
loopbooleanfalse最後のスライドから最初のスライドへ戻るかどうか
enableNavKeysbooleantrueキーボードの矢印キーによる操作を有効にします
enableWheelbooleantrueマウスホイールでの操作を有効にします
wheelDebounceMsnumber200ホイールイベントのデバウンス時間(ms)
autoAdvancebooleanfalseギャラリーをスライドショーとして再生します。自動送りを参照してください。
autoAdvanceIntervalnumber5000スライドショーで各画像を表示しておく長さ(ms)。読み込みが終わった時点から数えます
showDownloadbooleanfalseアクティブなアイテムのダウンロードボタンを加えます。ダウンロードを参照してください。
ariaLabelstring'Image gallery'ダイアログ領域のアクセシブルなラベル

上のスライダーの入力(transitionDuration、swipeDistanceFactor、loop、enableNavKeys、enableWheel、wheelDebounceMs)の型は ReelProxyProps です。それらを Lightbox に転送するラッパーコンポーネントの型付けに使います。

RkLightboxOverlayComponent の出力

出力型説明
closedEventEmitter<void>ユーザーがギャラリーを閉じたときに発行されます
slideChangeEventEmitter<number>アクティブなスライドのインデックスが変わったときに発行されます

LightboxItem インターフェース

フィールド型必須説明
srcstringはい画像または動画の URL
type'image' | 'video'いいえアイテムの種類。デフォルトは 'image' です
posterstringいいえ動画アイテムのサムネイル画像
titlestringいいえ情報オーバーレイに表示するタイトル
descriptionstringいいえタイトルの下に表示する説明
widthnumberいいえ画像の本来の幅(ピクセル)
heightnumberいいえ画像の本来の高さ(ピクセル)
downloadUrlstringいいえダウンロードボタンが保存するもの。デフォルトは src
downloadNamestringいいえ保存するファイル名。デフォルトは URL のパスの最後の部分

テンプレートスロットのコンテキスト型

型フィールド
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 }。rkLightboxLoading テンプレートが受け取るもの
LightboxErrorContext{ $implicit: activeIndex, item }。rkLightboxError テンプレートが受け取るもの

トランジション

任意の TransitionTransformFn を transitionFn 入力で渡します。使うトランジションだけをインポートすれば、残りはバンドラーがツリーシェイキングします。省略すると slideTransition になります。

関数提供元説明
slideTransition@reelkit/angular-lightbox標準的な横方向のスライド(デフォルト)
lightboxFadeTransition@reelkit/angular-lightbox画像どうしをクロスフェード
flipTransition@reelkit/angular-lightbox3D でカードをめくる効果
lightboxZoomTransition@reelkit/angular-lightbox小さいサイズから通常のサイズへズームイン
typescript
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;
}

コンテンツの読み込みとエラー処理

rkLightboxSlide のテンプレートスロットを使う場合、読み込み状態を報告するための 3 つのライフサイクルのコールバックがコンテキストで使えます。ギャラリーはスライドごとの状態を追跡し、それに応じてスピナーかエラーアイコンを表示します。コンテンツのプリローダーは壊れた URL をキャッシュするので、失敗したスライドを再訪しても再試行はしません。

ライフサイクルのコールバック

コールバック型説明
onReady() => voidスライドの内容の読み込みに成功したことを伝えます(たとえば画像のデコードが終わった)
onWaiting() => voidスライドの内容が読み込み中またはバッファリング中であることを伝えます(スピナーを表示)
onError() => voidスライドの内容の読み込みに失敗したことを伝えます(エラーアイコンを表示)

rkLightboxSlide でコールバックをつなぐ

html
<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>

独自の読み込みテンプレート

rkLightboxLoading ディレクティブで、デフォルトのスピナーを置き換えます。

html
<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>

独自のエラーテンプレート

rkLightboxError ディレクティブで、デフォルトのエラーアイコンを置き換えます。

html
<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>

CSS クラス

CSS クラスはすべて通常のクラス(スコープなし)なので、@reelkit/angular-lightbox/styles.css のあとに読み込むスタイルシートで、詳細度の高いセレクターを使って指定できます。色、サイズ、z-index を変えるなら、下の テーマ設定 で説明している CSS カスタムプロパティを使ってください。

クラスコンポーネント説明
.rk-lightbox-overlayOverlayルートのコンテナー(フルスクリーンの背景)
.rk-lightbox-top-shadeOverlayコントロールの後ろの上部のグラデーション
.rk-lightbox-spinnerOverlayデフォルトの読み込みスピナー
.rk-lightbox-img-errorOverlayエラー状態のコンテナー(壊れた画像)
.rk-lightbox-img-error-textOverlayエラー状態のテキストラベル
.rk-lightbox-swipe-hintOverlayモバイルでのスワイプのヒント
.rk-lightbox-emptyOverlay空の状態のテキスト
.rk-lightbox-controls-leftControls左上のコントロールのコンテナー
.rk-lightbox-btnControlsコントロールのボタン(フルスクリーンなど)
.rk-lightbox-play-pauseControlsスライドショーの再生/一時停止ボタン(.rk-lightbox-btn と併用)
.rk-lightbox-downloadControlsダウンロードボタン(.rk-lightbox-btn と併用)
.rk-lightbox-closeControls閉じるボタン
.rk-lightbox-counterControls画像のカウンターのチップ
.rk-lightbox-navNavigationナビゲーションの矢印(前へ・次への両方)
.rk-lightbox-nav-prevNavigation前へ の矢印
.rk-lightbox-nav-nextNavigation次へ の矢印
.rk-lightbox-infoInfoタイトルと説明のコンテナー
.rk-lightbox-titleInfo画像のタイトル
.rk-lightbox-descriptionInfo画像の説明
.rk-lightbox-slideSlideスライドのコンテナー
.rk-lightbox-imgSlide画像要素
.rk-lightbox-video-containerVideoSlide動画スライドのコンテナー(オプトイン)
.rk-lightbox-video-elementVideoSlide動画要素(オプトイン)
.rk-lightbox-video-posterVideoSlide動画のポスター画像(オプトイン)
.rk-lightbox-video-errorVideoSlide動画のエラー状態のコンテナー

テーマ設定

色、サイズ、z-index、トランジションはすべて CSS カスタムプロパティにあります。:root(またはギャラリーの任意の祖先)で 1 つでも複数でも上書きすれば、コンポーネントのソースに触れずにテーマを変えられます。トークンは React のギャラリーと共通なので、上書きはバインディング間でそのまま使えます。

トークンデフォルト制御するもの
--rk-lightbox-overlay-bg#000フルスクリーンの背景色
--rk-lightbox-overlay-z9999オーバーレイの z-index
--rk-lightbox-top-shade-height80px上部のグラデーションの高さ
--rk-lightbox-top-shade-bglinear-gradient(rgba(0,0,0,0.6), transparent)上部のグラデーションの色
--rk-lightbox-edge-padding16px閉じる、ナビゲーション、左上のコントロールの端からの距離
--rk-lightbox-controls-gap12px左上のコントロールの間隔
--rk-lightbox-transition0.2sボタンのホバーのトランジションの長さ
--rk-lightbox-blur8pxボタンやチップの背景のぼかしの半径
--rk-lightbox-btn-bgrgba(0, 0, 0, 0.5)閉じる、ナビゲーション、小さいボタンのデフォルトの背景
--rk-lightbox-btn-bg-hoverrgba(255, 255, 255, 0.2)閉じる、ナビゲーション、小さいボタンのホバー時の背景
--rk-lightbox-btn-fg#fff閉じる、ナビゲーション、小さいボタンのアイコンの色
--rk-lightbox-btn-size36px小さいボタンの大きさ(フルスクリーン切り替えなど)
--rk-lightbox-btn-disabled-opacity0.5無効になった小さいボタンの不透明度(ダウンロード中)
--rk-lightbox-close-size40px閉じるボタンの大きさ
--rk-lightbox-nav-size48px前後の矢印の大きさ
--rk-lightbox-nav-opacity0.7前後の矢印の通常時の不透明度
--rk-lightbox-counter-fg#fffカウンターのテキストの色
--rk-lightbox-counter-bgrgba(0, 0, 0, 0.5)カウンターのチップの背景
--rk-lightbox-counter-size14pxカウンターの文字サイズ
--rk-lightbox-counter-padding6px 12pxカウンターのチップの余白
--rk-lightbox-counter-radius20pxカウンターのチップの角丸
--rk-lightbox-spinner-size28pxデフォルトのスピナーの幅と高さ
--rk-lightbox-spinner-duration0.8sスピナーの回転の長さ
--rk-lightbox-error-fgrgba(255, 255, 255, 0.4)エラーアイコンとテキストの色
--rk-lightbox-info-bglinear-gradient(transparent, rgba(0,0,0,0.8))キャプションの背景のグラデーション
--rk-lightbox-info-padding24pxキャプションの内側の余白
--rk-lightbox-title-size18pxタイトルの文字サイズ
--rk-lightbox-description-size14px説明の文字サイズ
--rk-lightbox-hint-fgrgba(255, 255, 255, 0.5)スワイプのヒントのテキストの色
--rk-lightbox-hint-bgrgba(0, 0, 0, 0.3)スワイプのヒントのチップの背景
--rk-lightbox-video-bg#000<video> の後ろのレターボックスの背景

下のスニペットを、@reelkit/angular-lightbox/styles.css のあとに読み込むスタイルシートに入れてください。

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)
  );
}

アクセシビリティ

オーバーレイのルートはモーダルダイアログ(role="dialog"、aria-modal="true")です。ariaLabel 入力を指定すると、スクリーンリーダーの読み上げが変わります。デフォルトは「Image gallery」です。各スライドは role="group"、aria-roledescription="slide"、そして画像のタイトルと位置から作られる aria-label を持ちます。

ギャラリーは開くとフォーカスを取り込み、閉じるとトリガーに戻します。Tab と Shift+Tab は中のフォーカス可能な要素を循環し、外へ出たフォーカス(外側のクリック、プログラムからのフォーカス)は引き戻されます。@reelkit/core の captureFocusForReturn と createFocusTrap で実装されています。

キーボードショートカット

キー動作
ArrowLeft前の画像
ArrowRight次の画像
Escapeギャラリーを閉じる(フルスクリーン中ならフルスクリーンを終了)