Lightbox

@reelkit/react-lightbox से बना फ़ुलस्क्रीन इमेज और वीडियो गैलरी lightbox कंपोनेंट।

लाइव डेमो देखें →

फ़ीचर

इमेज और वीडियो
वीडियो स्लाइड का बिल्ट-इन सपोर्ट
टच जेस्चर
स्वाइप करके आगे-पीछे जाएँ
स्वाइप करके बंद करें
हटाने के लिए ऊपर स्वाइप करें
कीबोर्ड नेविगेशन
तीर वाली कुंजियाँ + Escape
फ़ुलस्क्रीन
सभी ब्राउज़र में चलने वाला API
ट्रांज़िशन
Slide, fade, flip, zoom-in
पहले से लोडिंग
आसपास की इमेज पहले से fetch होती हैं
साउंड टॉगल
हर स्लाइड पर mute/unmute
लोडिंग स्टेट
Spinner + कस्टम रेंडर
एरर हैंडलिंग
एरर आइकन + कस्टम रेंडर
Render props
कस्टमाइज़ होने वाले 6 रेंडर हिस्से
Hooks
useVideoSlideRenderer + useFullscreen
URL स्टेट
शेयर और bookmark करने लायक लिंक
स्लाइडशो
play/pause के साथ opt-in अपने-आप आगे बढ़ना
डाउनलोड
सक्रिय आइटम सेव करने वाला opt-in बटन

इंस्टॉलेशन

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

styles import करना न भूलें:

typescript
import '@reelkit/react-lightbox/styles.css';
आइकन

डिफ़ॉल्ट कंट्रोल आइकन के लिए lucide-react इस्तेमाल करते हैं। अगर आप कोई और आइकन लाइब्रेरी पसंद करते हैं, तो अपने कंट्रोल देने के लिए renderControls और renderNavigation इस्तेमाल करें।

क्विक स्टार्ट

LightboxOverlay कंपोनेंट इमेज फ़ुलस्क्रीन में दिखाता है। LightboxItem objects का array पास करें और null हो सकने वाले index से दिखना नियंत्रित करें।

tsx
import { useState } from 'react';
import { LightboxOverlay, type LightboxItem } from '@reelkit/react-lightbox';
import '@reelkit/react-lightbox/styles.css';

const images: LightboxItem[] = [
  {
    src: 'https://example.com/image1.jpg',
    title: 'Sunset',
    description: 'Beautiful sunset over the ocean',
  },
  {
    src: 'https://example.com/image2.jpg',
    title: 'Mountains',
  },
];

function App() {
  const [index, setIndex] = useState<number | null>(null);

  return (
    <>
      {images.map((img, i) => (
        <img
          key={i}
          src={img.src}
          onClick={() => setIndex(i)}
        />
      ))}
      <LightboxOverlay
        isOpen={index !== null}
        images={images}
        initialIndex={index ?? 0}
        onClose={() => setIndex(null)}
      />
    </>
  );
}
LightboxPage.tsx
import { useState } from 'react';
import {
  LightboxOverlay,
  flipTransition,
  lightboxFadeTransition,
  lightboxZoomTransition,
  slideTransition,
  type LightboxItem,
} from '@reelkit/react-lightbox';
import type { TransitionTransformFn } from '@reelkit/react';
import '@reelkit/react-lightbox/styles.css';

const images: LightboxItem[] = [
  {
    src: '/cdn/samples/images/image-01.jpg',
    title: 'Mountain River',
    description: 'A beautiful mountain river flowing through the forest',
    width: 1600,
    height: 1000,
  },
  {
    src: '/cdn/samples/images/image-02.jpg',
    title: 'Snowy Peaks',
    description: 'Majestic snow-capped mountains reaching for the sky',
    width: 1000,
    height: 1600,
  },
  {
    src: '/cdn/samples/images/image-03.jpg',
    title: 'Foggy Forest',
    description: 'Misty morning in the dense forest',
    width: 1600,
    height: 900,
  },
  {
    src: '/cdn/samples/images/image-04.jpg',
    title: 'Ocean Waves',
    description: 'Powerful ocean waves crashing against the rocky shore',
    width: 900,
    height: 1400,
  },
  {
    src: '/cdn/samples/images/image-05.jpg',
    title: 'Autumn Path',
    description: 'A winding path through the autumn forest',
    width: 1600,
    height: 1067,
  },
  {
    src: '/cdn/samples/images/image-06.jpg',
    title: 'Coastal Cliffs',
    description: 'Dramatic coastal cliffs overlooking the deep blue sea',
    width: 1600,
    height: 1067,
  },
];

const transitions: { label: string; fn: TransitionTransformFn }[] = [
  { label: 'slide', fn: slideTransition },
  { label: 'fade', fn: lightboxFadeTransition },
  { label: 'flip', fn: flipTransition },
  { label: 'zoom-in', fn: lightboxZoomTransition },
];

export default function App() {
  const [index, setIndex] = useState<number | null>(null);
  const [transitionFn, setTransitionFn] = useState<TransitionTransformFn>(
    () => slideTransition,
  );

  return (
    <div style={{ padding: 16, background: '#f8fafc', minHeight: '100vh' }}>
      {/* Transition picker */}
      <div style={{ display: 'flex', gap: 6, marginBottom: 12 }}>
        {transitions.map((t) => (
          <button
            key={t.label}
            onClick={() => setTransitionFn(() => t.fn)}
            style={{
              padding: '6px 14px', borderRadius: 8, border: 'none', cursor: 'pointer',
              fontSize: 13, fontWeight: 500,
              background: transitionFn === t.fn ? '#6366f1' : '#e2e8f0',
              color: transitionFn === t.fn ? '#fff' : '#334155',
            }}
          >
            {t.label}
          </button>
        ))}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 6 }}>
        {images.map((img, i) => (
          <button
            key={i}
            onClick={() => setIndex(i)}
            style={{
              position: 'relative', aspectRatio: '4 / 3', borderRadius: 8,
              overflow: 'hidden', border: 'none', padding: 0, cursor: 'pointer',
              background: '#e2e8f0',
            }}
          >
            <img
              src={img.src}
              alt={img.title}
              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
            />
          </button>
        ))}
      </div>
      <LightboxOverlay
        isOpen={index !== null}
        images={images}
        initialIndex={index ?? 0}
        onClose={() => setIndex(null)}
        transitionFn={transitionFn}
      />
    </div>
  );
}

गैलरी को स्लाइडशो की तरह चलाने और हर फ़ोटो की मूल फ़ाइल सेव करने के लिए गैलरी स्लाइडशो रेसिपी देखें।

वीडियो स्लाइड (opt-in)

वीडियो सपोर्ट पूरी तरह opt-in और tree-shake होने लायक है — सिर्फ़ इमेज इस्तेमाल करने पर बंडल पर कोई अतिरिक्त भार नहीं पड़ता। useVideoSlideRenderer import करें और उसकी लौटाई values को LightboxOverlay से जोड़ें। Hook लोडिंग स्टेट, साउंड प्रबंधन और वीडियो lifecycle अपने-आप संभालता है।

tsx
import {
  LightboxOverlay,
  useVideoSlideRenderer,
  type LightboxItem,
} from '@reelkit/react-lightbox';
import '@reelkit/react-lightbox/styles.css';

const items: LightboxItem[] = [
  { src: '/photo.jpg', title: 'Photo' },
  {
    src: '/clip.mp4',
    type: 'video',
    poster: '/clip-thumb.jpg',
    title: 'Video Clip',
  },
];

function Gallery() {
  const [index, setIndex] = useState<number | null>(null);
  const isOpen = index !== null;
  const { renderSlide, renderControls, SoundProvider } =
    useVideoSlideRenderer(items);

  return (
    <SoundProvider>
      {/* thumbnails… */}
      <LightboxOverlay
        isOpen={isOpen}
        images={items}
        initialIndex={index ?? 0}
        onClose={() => setIndex(null)}
        renderSlide={renderSlide}
        renderControls={renderControls}
      />
    </SoundProvider>
  );
}
यह कैसे काम करता है
  • Hook SoundProvider लौटाता है — mute/unmute काम करे, इसके लिए अपने overlay को इसमें लपेटें
  • स्लाइड सक्रिय होने पर वीडियो अपने-आप चलते हैं (डिफ़ॉल्ट रूप से muted)
  • iOS पर आवाज़ बनी रहे, इसके लिए स्लाइडों के बीच एक साझा वीडियो एलिमेंट दोबारा इस्तेमाल होता है
  • वीडियो स्लाइड पर reactive mute टॉगल वाला साउंड बटन अपने-आप दिखता है
  • type: 'video' के बिना आइटम इमेज के रूप में रेंडर होते हैं (पुराने कोड के साथ संगत)

कस्टमाइज़ेशन

कस्टम कंट्रोल

डिफ़ॉल्ट बंद करने का बटन, काउंटर और फ़ुलस्क्रीन टॉगल बदलने के लिए renderControls इस्तेमाल करें। export किए गए sub-components से जोड़ें:

tsx
import {
  LightboxOverlay,
  CloseButton,
  Counter,
  FullscreenButton,
} from '@reelkit/react-lightbox';

<LightboxOverlay
  isOpen={isOpen}
  images={images}
  onClose={handleClose}
  renderControls={({ onClose, activeIndex, count, isFullscreen, onToggleFullscreen }) => (
    <div style={{ position: 'absolute', top: 12, left: 16, right: 16, display: 'flex', justifyContent: 'space-between', zIndex: 10 }}>
      <Counter currentIndex={activeIndex} count={count} />
      <div>
        <FullscreenButton isFullscreen={isFullscreen} onToggle={onToggleFullscreen} />
        <CloseButton onClick={onClose} />
      </div>
    </div>
  )}
/>

कस्टम जानकारी overlay

डिफ़ॉल्ट शीर्षक/विवरण gradient बदलने के लिए renderInfo इस्तेमाल करें, या उसे पूरी तरह छिपाने के लिए renderInfo={() => null} पास करें:

tsx
<LightboxOverlay
  isOpen={isOpen}
  images={images}
  onClose={handleClose}
  renderInfo={({ item, index }) => (
    <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: 16, background: 'linear-gradient(transparent, rgba(0,0,0,0.8))', color: '#fff', zIndex: 10 }}>
      <h3>{item.title}</h3>
      <p>{item.description}</p>
    </div>
  )}
/>

कस्टम नेविगेशन

डिफ़ॉल्ट prev/next तीरों को बदलने के लिए renderNavigation इस्तेमाल करें:

tsx
<LightboxOverlay
  isOpen={isOpen}
  images={images}
  onClose={handleClose}
  renderNavigation={({ onPrev, onNext, activeIndex, count }) => (
    <div style={{ position: 'absolute', bottom: 24, left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: 12, zIndex: 10 }}>
      <button onClick={onPrev} disabled={activeIndex === 0}>Prev</button>
      <span>{activeIndex + 1} / {count}</span>
      <button onClick={onNext} disabled={activeIndex === count - 1}>Next</button>
    </div>
  )}
/>

कस्टम स्लाइड

पूरी तरह कस्टम स्लाइड कंटेंट के लिए renderSlide इस्तेमाल करें। डिफ़ॉल्ट इमेज स्लाइड पर लौटने के लिए null लौटाएँ:

tsx
<LightboxOverlay
  isOpen={isOpen}
  images={images}
  onClose={handleClose}
  renderSlide={({ item, index, size, isActive, onReady, onError }) => {
    // Custom CTA on last slide
    if (index === images.length - 1) {
      return (
        <div style={{ width: size[0], height: size[1], display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>
          <h2>View all photos</h2>
        </div>
      );
    }
    return null; // default image slide
  }}
/>

कंटेंट लोडिंग और एरर हैंडलिंग

Lightbox हर स्लाइड की लोडिंग और एरर स्टेट ट्रैक करता है। कंटेंट लोड होते समय spinner दिखता है; फ़ेल हुए मीडिया पर टूटी इमेज का आइकन दिखता है। एरर वाले URL cache हो जाते हैं, इसलिए दोबारा आने पर बिना फिर से कोशिश किए तुरंत एरर दिखता है।

Lifecycle callbacks

renderSlide इस्तेमाल करते समय लोडिंग इंडिकेटर नियंत्रित करने के लिए ये callbacks कॉल करें:

Callbackकब कॉल करें
onReadyइमेज लोड हुई या वीडियो चलने लगा। लोडिंग और एरर स्टेट साफ़ करता है।
onWaitingवीडियो चलते-चलते buffer हो रहा है। लोडिंग इंडिकेटर दिखाता है।
onErrorकंटेंट लोड नहीं हुआ। एरर overlay दिखाता है और URL को टूटा हुआ cache करता है।
tsx
// Inside renderSlide — wire callbacks to your custom media
renderSlide={({ item, index, size, isActive, onReady, onWaiting, onError }) => (
  <div style={{ width: size[0], height: size[1] }}>
    {item.type === 'video' ? (
      <video
        src={item.src}
        poster={item.poster}
        autoPlay={isActive}
        onCanPlay={onReady}
        onWaiting={onWaiting}
        onError={onError}
        style={{ width: '100%', height: '100%', objectFit: 'contain' }}
      />
    ) : (
      <img
        src={item.src}
        onLoad={onReady}
        onError={onError}
        style={{ width: '100%', height: '100%', objectFit: 'contain' }}
      />
    )}
  </div>
)}

कस्टम लोडिंग और एरर UI

डिफ़ॉल्ट spinner और एरर आइकन की जगह अपने कंपोनेंट लगाएँ:

tsx
<LightboxOverlay
  isOpen={isOpen}
  images={images}
  onClose={() => setIsOpen(false)}
  renderLoading={({ item, activeIndex }) => (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 10,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      color: '#fff', fontSize: 14,
    }}>
      Loading image {activeIndex + 1}...
    </div>
  )}
  renderError={({ item, activeIndex }) => (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 10,
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center',
      gap: 12, color: 'rgba(255,255,255,0.5)',
    }}>
      <span style={{ fontSize: 48 }}>!</span>
      <span>Failed to load content</span>
    </div>
  )}
/>

URL स्टेट

लाइव डेमो देखें →

LightboxUrlOverlay एक अलग कंपोनेंट है जिसकी खुले होने की स्टेट address bar में रहती है। @reelkit/react के useOverlayUrlState से कंट्रोलर बनाएँ और उसे controller के रूप में दें: जब parameter किसी स्लाइड का नाम लेता है तो गैलरी खुद खुलती है, और उसके हटते ही बंद हो जाती है। लिंक शेयर किए जा सकते हैं, और back बटन पेज छोड़ने के बजाय गैलरी बंद करता है।

बिल्ट-इन keys

आप बिल्ट-इन key से स्लाइडों को पहचान सकते हैं — कंट्रोलर में urlIndexKey (स्थिति से) या urlStableIdKey (स्थिर id से) spread करें — दोनों @reelkit/react से भी export होते हैं। URL स्टेट गाइड और Core API देखें।

tsx
import { useOverlayUrlState, urlIndexKey, urlStableIdKey } from '@reelkit/react';
import { LightboxUrlOverlay } from '@reelkit/react-lightbox';
import { Link } from 'react-router-dom';

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

// Opening is a link — the href is the open action. No open flag, no handler:
// the overlay reads the URL and opens itself.
{images.map((image, i) => (
  <Link key={image.src} to={`?photo=${i}`}>
    <img src={image.src} />
  </Link>
))}

<LightboxUrlOverlay controller={photo} images={images} />

Hook विकल्पों का एक object लेता है और UrlStateController (set, index, value के साथ) लौटाता है। प्रोग्राम से नियंत्रण के लिए इसे रखें: set वह निचले स्तर का write है जो overlay अंदर से इस्तेमाल करता है (स्लाइड बदलना, और बंद करने के लिए set(null))। यह overlay को प्रोग्राम से भी चलाता है — set(index) उसे खोलता है, बिल्कुल parameter पर जाने की तरह। फिर भी खोलने के लिए लिंक को प्राथमिकता दें: href शेयर किया जा सकता है, नए tab में खुलता है, और back बटन उसे बंद करता है — सब मुफ़्त में, बिना किसी हैंडलर के।

useOverlayUrlState के सारे विकल्प (param, adapter, codec, locator): React API रेफ़रेंस देखें।

LightboxUrlOverlay खुद सिर्फ़ controller (ज़रूरी), वैकल्पिक onClose, और LightboxOverlay के सारे दिखावट और व्यवहार वाले props (images, ariaLabel, transitionFn, render props वगैरह) लेता है — लेकिन isOpen नहीं।

  • खोलने पर history की एक entry लगती है। स्लाइड बदलना उसे बदल देता है, इसलिए सौ स्वाइप भी कोई entry नहीं जोड़ते — back का एक कदम हमेशा गैलरी छोड़ देता है। Back बंद करता है; फ़ोटो में पीछे नहीं जाता।
  • ?photo=3 जैसा शेयर किया गया लिंक गैलरी को उसी स्लाइड पर खोलता है। पेज के साथ आए लिंक को बंद करना आपकी साइट से बाहर जाने के बजाय parameter को उसी जगह हटाता है।
  • Back सिर्फ़ तब बंद करता है जब आपने ऐप के अंदर से खोला हो — लिंक ने entry जोड़ी, इसलिए back गैलरी पर लौटता है। नए tab में सीधे खोले गए शेयर किए गए लिंक के पीछे कोई history नहीं होती, इसलिए ब्राउज़र का back साइट छोड़ देता है; बंद करने का बटन या Escape parameter को उसी जगह हटाकर आपको गैलरी पर रखता है। पैकेज के साथ आने वाले router adapters उसी पेज पर लिंक के push की पुष्टि करते हैं; जो कस्टम adapter नहीं बता सकता कि entry कैसे आई, उसे भी उसी जगह बंद होना मिलता है, जिससे history में पेज की एक नकल रह जाती है — तब back का एक कदम ऐसा लगता है जैसे कुछ हुआ ही नहीं, लेकिन कुछ दोबारा नहीं खुलता।
  • किसी स्लाइड का नाम न लेने वाला parameter — पुराना bookmark, हाथ से बदली value — URL से हटा दिया जाता है, ताकि address bar ऐसी स्लाइड का दावा न करता रहे जो खुल ही नहीं सकती।

Routing वाले ऐप में adapter पास करें। history में सीधे लिखने से router की अपनी location पुरानी पड़ जाती है, और उसका अगला नेविगेशन parameter गिरा देता है।

tsx
import { useReactRouterUrlAdapter } from '@reelkit/react/react-router-url-adapter';

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

<LightboxUrlOverlay controller={photo} images={images} />

खोलना एक लिंक है। खुली स्टेट URL में रहती है, इसलिए थंबनेल एक साधारण लिंक है — कोई click हैंडलर नहीं — और ब्राउज़र का अपना व्यवहार मुफ़्त मिलता है: नए tab में खोलना, पता कॉपी करना, hover पर प्रीव्यू। Routing वाले ऐप में router का लिंक इस्तेमाल करें, ताकि सब क्लाइंट साइड पर ही रहे।

tsx
import { Link } from 'react-router-dom';

// The href is the open action — no onClick, no open flag.
{images.map((image, i) => (
  <Link key={image.src} to={`?photo=${i}`}>
    <img src={image.src} />
  </Link>
))}

<LightboxUrlOverlay controller={photo} images={images} />

शेयर होने वाले लिंक के लिए स्थिर पहचान चुनें। Index स्थिति पर आधारित है, इसलिए सूची का क्रम बदलते ही bookmark किया गया ?photo=3 कोई दूसरी इमेज खोलता है। urlStableIdKey हर आइटम की स्थिर id से key बनाता है और मौजूदा सूची में ढूँढता है — आम मामले के लिए एक कॉल काफ़ी है।

tsx
const photo = useOverlayUrlState({
  param: 'photo',
  ...urlStableIdKey({ items: () => images }),
});

<LightboxUrlOverlay controller={photo} images={images} />

URL में id को base64url में encode करने के लिए hashCodec: base64UrlCodec पास करें — वापस पढ़ा जा सकने वाला छिपाव, cryptographic hash नहीं।

किसी दूसरे field (slug) से key बनाएँ, या locateAsync से अनंत फ़ीड के पेज लोड करें, और codec/locator खुद बनाएँ:

tsx
const photo = useOverlayUrlState({
  param: 'photo',
  codec: { decode: (raw) => raw, encode: (id) => id },
  locator: {
    locate: (id) => images.findIndex((x) => x.slug === id),
    identify: (index) => images[index].slug,
  },
});

<LightboxUrlOverlay controller={photo} images={images} />

अनंत या पेज वाली गैलरी। synchronous locate सिर्फ़ लोड हो चुकी इमेज के लिए जवाब दे सकता है — जिस फ़ीड में 20 इमेज लोड हुई हैं, उसकी इमेज 400 का शेयर किया गया लिंक खाली लौटता है। locateAsync विकल्प है, जो सिर्फ़ locate के न मिलने पर कॉल होता है।

छोटा रास्ता

आइटम की id से key बना रहे हैं? अपना codec और locator लिखना छोड़ें — locateAsync सीधे urlStableIdKey({ items, locateAsync }) को पास करें (न मिलने पर यह fetch करता है, फिर index लौटाता है)। नीचे का पूरा रूप किसी दूसरे field से key बनाने या पूरे नियंत्रण के लिए है।

tsx
const photo = useOverlayUrlState({
  param: 'photo',
  codec: { decode: (raw) => raw, encode: (id) => id },
  locator: {
    locate: (id) => images.findIndex((x) => x.id === id),
    identify: (index) => 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 image
      setImages(loaded); // commit — the overlay renders from this state
      return loaded.findIndex((x) => x.id === id); // wherever it landed
    },
  },
});

<LightboxUrlOverlay controller={photo} images={images} />
  • लोड कैसे करना है, यह आप पर है — लक्ष्य तक लगातार पेज fetch करें, या सिर्फ़ वही एक इमेज fetch करके जोड़ दें। URL स्थिति से नहीं, पहचान से key बनाता है, इसलिए आइटम जहाँ भी पहुँचे, findIndex वही लौटाता है।
  • locateAsync के pending रहने तक lightbox बंद रहता है और parameter को छुआ नहीं जाता, इसलिए सीधा लिंक fetch के बाद भी बना रहता है। null या rejection parameter हटा देता है।
  • URL आगे बढ़ जाने, बंद होने या unmount के बाद आया जवाब फेंक दिया जाता है — धीमा fetch ऐसी स्लाइड नहीं खोल सकता जो किसी ने माँगी ही नहीं।
  • pending रहने के दौरान कुछ भी रेंडर नहीं होता; लोडिंग की वह स्टेट पेज के पास पहले से है, इसलिए अपना skeleton रेंडर करें।
  • कोई timeout नहीं है — lightbox नहीं जान सकता कि गैलरी कितनी लंबी है। पेज ख़त्म होने पर null से निपटाएँ, नहीं तो overlay हमेशा बंद रहेगा।
  • locateAsync जो भी लौटाए, वही अंतिम है — अभी fetch किए डेटा का index, images दोबारा पढ़े बिना जैसा है वैसा लिया जाता है।

अपने-आप आगे बढ़ना

खुलते ही गैलरी को स्लाइडशो की तरह चलाने के लिए autoAdvance सेट करें। यह डिफ़ॉल्ट रूप से बंद है, इसलिए मौजूदा lightbox पहले की तरह ही रेंडर होता और चलता है।

tsx
import { LightboxOverlay } from '@reelkit/react-lightbox';

<LightboxOverlay
  isOpen={index !== null}
  images={images}
  initialIndex={index ?? 0}
  onClose={() => setIndex(null)}
  autoAdvance
  autoAdvanceInterval={4000}
/>;
  • इमेज autoAdvanceInterval (डिफ़ॉल्ट 5000 ms) तक रहती हैं, जो इमेज लोड होने के पल से गिना जाता है, इसलिए धीमी इमेज किसी के देखने से पहले कभी नहीं छूटती। जो इमेज लोड नहीं हो पाती, उसकी गिनती उसके error से होती है।
  • वीडियो loop की जगह एक बार चलते हैं और ख़त्म होने पर आगे बढ़ते हैं। useVideoSlideRenderer के साथ यह आपके लिए जुड़ा हुआ है; कस्टम renderSlide अपने props से autoAdvance पढ़ता है और अंत की सूचना onEnded से देता है।
  • यह रुका रहता है जब माउस किसी कंट्रोल (बटन, लिंक या कैप्शन) पर टिका हो, swipe के दौरान, और जब पेज छिपा हो, फिर वहीं से आगे चलता है जहाँ रुका था।
  • हाथ से आगे बढ़ना (तीर, keys, wheel, swipe) नई स्लाइड का interval शून्य से शुरू करता है; स्लाइडशो चालू रहता है।
  • आख़िरी स्लाइड पर यह रुक जाता है, जब तक loop सेट न हो। कंट्रोल में play/pause बटन स्टेट दिखाता है और दर्शक को इसे बदलने देता है।

कस्टम renderControls को isAutoAdvancing मिलता है और, सिर्फ़ autoAdvance चालू होने पर, onToggleAutoAdvance — जब यह मौजूद हो तो PlayPauseButton रेंडर करें। टाइमिंग ख़ुद @reelkit/core का createSlideshowController है; अपने प्लेयर में यही व्यवहार बनाने के लिए ऑटोप्ले गाइड देखें, और इसके मेथड के लिए Core API।

डाउनलोड

कंट्रोल में डाउनलोड बटन जोड़ने के लिए showDownload सेट करें। यह सक्रिय आइटम को उसके downloadUrl से सेव करता है, जो न हो तो src से, उसके downloadName नाम से, जो न हो तो URL के आख़िरी हिस्से के नाम से।

tsx
import { LightboxOverlay, type LightboxItem } from '@reelkit/react-lightbox';

const images: LightboxItem[] = [
  {
    src: 'https://cdn.example.com/beach-1600.jpg',
    // Save the original rather than the resized preview
    downloadUrl: 'https://cdn.example.com/beach-original.jpg',
    downloadName: 'beach.jpg',
  },
];

<LightboxOverlay
  isOpen={index !== null}
  images={images}
  initialIndex={index ?? 0}
  onClose={() => setIndex(null)}
  showDownload
/>;

फ़ाइल fetch करके सेव की जाती है, क्योंकि ब्राउज़र cross-origin लिंक पर download attribute को नज़रअंदाज़ करता है और फ़ाइल को खोल देता। जब fetch विफल हो — आम तौर पर दूसरे origin का ऐसा सर्वर जो CORS headers नहीं भेजता — तो फ़ाइल नए टैब में खुलती है, जहाँ दर्शक उसे फिर भी सेव कर सकता है। एक क्लिक में सेव के लिए फ़ाइलें Access-Control-Allow-Origin के साथ serve करें। डाउनलोड चलते समय बटन disabled रहता है।

कस्टम renderControls को isDownloading मिलता है और, सिर्फ़ showDownload चालू होने पर, onDownload — जब यह मौजूद हो तो DownloadButton रेंडर करें। helper @reelkit/core का downloadFile है; डाउनलोड गाइड देखें।

API रेफ़रेंस

LightboxOverlay के props

LightboxOverlayProps

Propटाइपडिफ़ॉल्टविवरण
isOpenbooleanज़रूरीlightbox का दिखना नियंत्रित करता है। URL से चलने वाली खुली स्टेट के लिए इसकी जगह अलग LightboxUrlOverlay इस्तेमाल करें — नीचे URL स्टेट देखें।
imagesLightboxItem[]ज़रूरीदिखाई जाने वाली इमेज का array
ariaLabelstring'Image gallery'dialog क्षेत्र का सुलभ लेबल; lightbox खुलने पर स्क्रीन रीडर इसे बोलते हैं
initialIndexnumber0शुरुआती इमेज index
transitionFnTransitionTransformFnslideTransitionस्लाइड ट्रांज़िशन फ़ंक्शन। कोई बिल्ट-इन (slideTransition, flipTransition, lightboxFadeTransition, lightboxZoomTransition) import करें या अपना पास करें। छोड़ने पर slideTransition लगता है।
autoAdvancebooleanfalseगैलरी को स्लाइडशो की तरह चलाएँ। अपने-आप आगे बढ़ना देखें।
autoAdvanceIntervalnumber5000स्लाइडशो के दौरान हर इमेज कितनी देर रहती है, मिलीसेकंड में, लोड होने के बाद से गिना जाता है
showDownloadbooleanfalseसक्रिय आइटम के लिए डाउनलोड बटन जोड़ें। डाउनलोड देखें।
apiRefMutableRefObject<ReelApi>-Reel API तक पहुँचने के लिए ref
renderControls(props: ControlsRenderProps) => ReactNode-कस्टम कंट्रोल, डिफ़ॉल्ट बंद करने के बटन, काउंटर और फ़ुलस्क्रीन टॉगल की जगह लेते हैं
renderNavigation(props: NavigationRenderProps) => ReactNode-कस्टम नेविगेशन, डिफ़ॉल्ट prev/next तीरों की जगह लेता है
renderInfo(props: InfoRenderProps) => ReactNode-कस्टम जानकारी overlay, डिफ़ॉल्ट शीर्षक + विवरण gradient की जगह लेता है। छिपाने के लिए null लौटाएँ।
renderSlide(props: SlideRenderProps) => ReactNode | null-कस्टम स्लाइड रेंडरिंग। { item, index, size, isActive, autoAdvance, onReady, onWaiting, onError, onEnded } मिलता है। डिफ़ॉल्ट पर लौटने के लिए null लौटाएँ।
renderLoading(props: { item: LightboxItem; activeIndex: number }) => ReactNode-कस्टम लोडिंग इंडिकेटर, डिफ़ॉल्ट spinner की जगह लेता है
renderError(props: { item: LightboxItem; activeIndex: number }) => ReactNode-कस्टम एरर इंडिकेटर, डिफ़ॉल्ट एरर आइकन की जगह लेता है

LightboxUrlOverlay के props

LightboxUrlOverlayProps

ऊपर के सारे दिखावट और व्यवहार वाले props लेता है, सिवाय isOpen के, जिसकी जगह controller आता है। यहाँ initialIndex अनदेखा होता है — स्लाइड कंट्रोलर की स्थिति चुनती है, इसलिए साथ में दी गई value हर बार खुलने पर बदल दी जाती।

Propटाइपडिफ़ॉल्टविवरण
controllerUrlStateControllerज़रूरीuseOverlayUrlState से मिला कंट्रोलर। इसकी स्थिति तय करती है कि overlay खुला है या नहीं और कौन-सी स्लाइड दिखती है; स्लाइड बदलने और बंद होने पर overlay इसी के ज़रिए वापस लिखता है।

Callbacks

Propटाइपविवरण
onClose() => voidlightbox बंद होने पर कॉल होता है। LightboxOverlay पर ज़रूरी (खुली स्टेट आपके पास है, इसलिए बंद करना आपको संभालना होगा); LightboxUrlOverlay पर वैकल्पिक, जहाँ बंद करना URL चलाता है — इसे सिर्फ़ बंद होने के बाद कुछ करने के लिए पास करें।
onSlideChange(index: number) => voidस्लाइड बदलने के बाद कॉल होता है

Reel के props (आगे भेजे गए)

ये props अंदर के Reel कंपोनेंट को आगे भेजे जाते हैं। इनका टाइप ReelProxyProps है, Reel props का वह हिस्सा जो overlay आगे भेजता है; इन्हें आगे भेजने वाले wrapper को टाइप करने के लिए इसका इस्तेमाल करें।

Propटाइपडिफ़ॉल्टविवरण
loopbooleanfalseअनंत लूप चालू करता है
enableNavKeysbooleantrueकीबोर्ड नेविगेशन चालू करता है
enableWheelbooleantrueमाउस व्हील से नेविगेशन चालू करता है
wheelDebounceMsnumber200व्हील debounce की अवधि (ms)
transitionDurationnumber300ट्रांज़िशन एनिमेशन की अवधि (ms)
swipeDistanceFactornumber0.12स्वाइप की सीमा (0-1)
swipeToCloseDirection'up' | 'down''up'मोबाइल पर स्वाइप करके बंद करने वाले जेस्चर की दिशा

टाइप

LightboxItem

typescript
interface LightboxItem {
  src: string;
  type?: 'image' | 'video';  // defaults to 'image'
  poster?: string;            // thumbnail for video items
  title?: string;
  description?: string;
  width?: number;
  height?: number;
  downloadUrl?: string;       // what the download button saves; defaults to src
  downloadName?: string;      // file name; defaults to the URL's last segment
}

ControlsRenderProps

typescript
interface ControlsRenderProps {
  item: LightboxItem;
  activeIndex: number;
  count: number;
  isFullscreen: boolean;
  isAutoAdvancing: boolean;
  isDownloading: boolean;
  onClose: () => void;
  onToggleFullscreen: () => void;
  onToggleAutoAdvance?: () => void; // only with autoAdvance
  onDownload?: () => void;          // only with showDownload
}
typescript
interface NavigationRenderProps {
  item: LightboxItem;
  activeIndex: number;
  count: number;
  onPrev: () => void;
  onNext: () => void;
}

SlideRenderProps

typescript
interface SlideRenderProps {
  item: LightboxItem;
  index: number;
  size: [number, number];
  isActive: boolean;
  autoAdvance: boolean; // a video should play once, not loop
  onReady: () => void;
  onWaiting: () => void;
  onError: () => void;
  onEnded: () => void;  // a video played to its end
}

InfoRenderProps

typescript
interface InfoRenderProps {
  item: LightboxItem;
  index: number;
}

सब-कंपोनेंट

renderControls के ज़रिए कस्टम कंट्रोल बनाने के लिए दोबारा इस्तेमाल होने वाले sub-components।

CloseButton

डिफ़ॉल्ट X बंद करने का बटन। Props (CloseButtonProps): onClick, वैकल्पिक className और style।

tsx
import { CloseButton } from '@reelkit/react-lightbox';

<CloseButton onClick={onClose} />

Counter

"1 / 3" दिखाने वाली इमेज काउंटर pill। Props (CounterProps): currentIndex (शून्य से शुरू), count, वैकल्पिक className और style।

tsx
import { Counter } from '@reelkit/react-lightbox';

<Counter currentIndex={activeIndex} count={count} />

FullscreenButton

फ़ुलस्क्रीन टॉगल बटन (Maximize/Minimize आइकन)। Props (FullscreenButtonProps): isFullscreen, onToggle, वैकल्पिक className और style।

tsx
import { FullscreenButton } from '@reelkit/react-lightbox';

<FullscreenButton isFullscreen={isFullscreen} onToggle={onToggleFullscreen} />

SoundButton

वीडियो स्लाइड के लिए mute/unmute टॉगल बटन (Volume2/VolumeX आइकन)। useVideoSlideRenderer से मिले renderControls में अपने-आप शामिल है। कस्टम कंट्रोल के अंदर अलग से इस्तेमाल के लिए useSoundState से साउंड स्टेट तक पहुँचें। Props (SoundButtonProps): isMuted, onToggle, वैकल्पिक className और style।

tsx
import { SoundButton } from '@reelkit/react-lightbox';
import { useSoundState } from '@reelkit/react';

// Inside a component wrapped in SoundProvider:
function CustomControls({ onClose }) {
  const soundState = useSoundState();

  return (
    <div>
      <SoundButton
        isMuted={soundState.muted.value}
        onToggle={soundState.toggle}
      />
      <button onClick={onClose}>Close</button>
    </div>
  );
}

PlayPauseButton

स्लाइडशो टॉगल (Play/Pause आइकन, चलते समय aria-pressed)। Props (PlayPauseButtonProps): isPlaying, onToggle, वैकल्पिक className और style। autoAdvance चालू होने पर डिफ़ॉल्ट कंट्रोल इसे दिखाते हैं।

tsx
import {
  LightboxOverlay,
  PlayPauseButton,
  CloseButton,
} from '@reelkit/react-lightbox';

<LightboxOverlay
  autoAdvance
  renderControls={({ isAutoAdvancing, onToggleAutoAdvance, onClose }) => (
    <>
      {onToggleAutoAdvance && (
        <PlayPauseButton
          isPlaying={isAutoAdvancing}
          onToggle={onToggleAutoAdvance}
        />
      )}
      <CloseButton onClick={onClose} />
    </>
  )}
  {...props}
/>;

DownloadButton

डाउनलोड बटन (Download आइकन), isDownloading के दौरान disabled। Props (DownloadButtonProps): isDownloading, onClick, वैकल्पिक className और style। showDownload चालू होने पर डिफ़ॉल्ट कंट्रोल इसे दिखाते हैं।

tsx
import {
  LightboxOverlay,
  DownloadButton,
  CloseButton,
} from '@reelkit/react-lightbox';

<LightboxOverlay
  showDownload
  renderControls={({ isDownloading, onDownload, onClose }) => (
    <>
      {onDownload && (
        <DownloadButton isDownloading={isDownloading} onClick={onDownload} />
      )}
      <CloseButton onClick={onClose} />
    </>
  )}
  {...props}
/>;

Hooks

useVideoSlideRenderer

opt-in वीडियो सपोर्ट का hook। renderSlide, renderControls और SoundProvider लौटाता है — overlay को SoundProvider में लपेटें और रेंडर फ़ंक्शन पास करें। लौटाया गया टाइप UseVideoSlideRendererResult है, जिसमें hasVideo भी है; किसी भी आइटम का type: 'video' होने पर यह true होता है।

इसका renderSlide वीडियो आइटम LightboxVideoSlide से बनाता है, यानी ऐसी वीडियो स्लाइड जो एक साझा <video> एलिमेंट से चलती है, ताकि iOS पर साउंड काम करता रहे, और हर वीडियो की स्थिति याद रखती है। इसे ख़ुद सिर्फ़ कस्टम renderSlide से रेंडर करें। इसके props (LightboxVideoSlideProps) हैं src, poster, isActive, size, slideKey (सहेजी गई स्थिति और लिए गए फ़्रेम की key), loop (डिफ़ॉल्ट true) और onPlaying, onWaiting, onError, onEnded callbacks।

typescript
import { useVideoSlideRenderer } from '@reelkit/react-lightbox';

const { renderSlide, renderControls, SoundProvider, hasVideo } =
  useVideoSlideRenderer(items);

// SoundProvider  — wrap LightboxOverlay in this for mute/unmute support
// renderSlide    — pass to LightboxOverlay's renderSlide prop
// renderControls — pass to LightboxOverlay's renderControls prop
//                  (includes Counter, FullscreenButton, SoundButton, CloseButton)
// hasVideo       — true if items contain at least one video

useFullscreen

सभी ब्राउज़र के सपोर्ट के साथ फ़ुलस्क्रीन स्टेट संभालने का hook।

tsx
import { useRef } from 'react';
import { useFullscreen } from '@reelkit/react';

function CustomLightbox() {
  const containerRef = useRef<HTMLDivElement>(null);
  const [isFullscreen, requestFullscreen, exitFullscreen, toggleFullscreen] =
    useFullscreen({ ref: containerRef });

  return (
    <div ref={containerRef}>
      <button onClick={toggleFullscreen}>
        {isFullscreen.value ? 'Exit Fullscreen' : 'Enter Fullscreen'}
      </button>
    </div>
  );
}

ट्रांज़िशन

transitionFn prop के ज़रिए कोई भी TransitionTransformFn पास करें। सिर्फ़ इस्तेमाल होने वाला ट्रांज़िशन import करने से bundler बाकी को tree-shake कर देता है। छोड़ने पर slideTransition लगता है।

फ़ंक्शनकहाँ सेविवरण
slideTransition@reelkit/react-lightboxसामान्य हॉरिज़ॉन्टल स्लाइड (डिफ़ॉल्ट)
lightboxFadeTransition@reelkit/react-lightboxइमेज के बीच crossfade
flipTransition@reelkit/react-lightbox3D कार्ड पलटने का इफ़ेक्ट
lightboxZoomTransition@reelkit/react-lightboxछोटे से सामान्य आकार तक zoom in
tsx
import {
  LightboxOverlay,
  lightboxFadeTransition,
} from '@reelkit/react-lightbox';

<LightboxOverlay
  isOpen={isOpen}
  images={images}
  initialIndex={0}
  onClose={handleClose}
  transitionFn={lightboxFadeTransition}
/>

कस्टम ट्रांज़िशन फ़ंक्शन

अपना TransitionTransformFn लिखें और transitionFn के ज़रिए पास करें। इसका signature core स्लाइडर ट्रांज़िशन जैसा ही है।

tsx
import { LightboxOverlay } from '@reelkit/react-lightbox';
import type { TransitionTransformFn } from '@reelkit/react';

const customFade: TransitionTransformFn = (offset, size) => ({
  transform: `translate3d(${offset * size[0]}px, 0, 0)`,
  opacity: 1 - Math.min(Math.abs(offset), 1),
});

<LightboxOverlay
  isOpen={isOpen}
  images={images}
  transitionFn={customFade}
  onClose={() => setIsOpen(false)}
/>

CSS क्लास

सारे UI एलिमेंट साधारण CSS क्लास इस्तेमाल करते हैं (CSS modules नहीं), जिन्हें @reelkit/react-lightbox/styles.css के बाद लोड होने वाली stylesheet में ज़्यादा specificity वाले selectors से निशाना बनाया जा सकता है। रंग, आकार और z-index बदलने के लिए नीचे थीमिंग हिस्से में बताई CSS custom properties को प्राथमिकता दें।

क्लासकंपोनेंटविवरण
.rk-lightbox-overlayOverlayRoot कंटेनर (फ़ुलस्क्रीन backdrop)
.rk-lightbox-spinnerOverlayडिफ़ॉल्ट लोडिंग spinner
.rk-lightbox-img-errorOverlayएरर स्टेट का कंटेनर (टूटी इमेज/वीडियो)
.rk-lightbox-img-error-textOverlayएरर स्टेट का टेक्स्ट लेबल
.rk-lightbox-swipe-hintOverlayमोबाइल पर स्वाइप का संकेत
.rk-lightbox-controls-leftControlsऊपर-बाएँ कंट्रोल का कंटेनर
.rk-lightbox-btnControlsकंट्रोल बटन (फ़ुलस्क्रीन वगैरह)
.rk-lightbox-play-pauseControlsस्लाइडशो play/pause बटन (.rk-lightbox-btn के साथ)
.rk-lightbox-downloadControlsडाउनलोड बटन (.rk-lightbox-btn के साथ)
.rk-lightbox-closeControlsबंद करने का बटन
.rk-lightbox-counterControlsइमेज काउंटर chip
.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वीडियो स्लाइड कंटेनर (opt-in)
.rk-lightbox-video-elementVideoSlideवीडियो एलिमेंट (opt-in)
.rk-lightbox-video-posterVideoSlideवीडियो की poster इमेज (opt-in)

थीमिंग

हर रंग, आकार, z-index और ट्रांज़िशन एक CSS custom property में है। कंपोनेंट का source छुए बिना थीम बदलने के लिए :root (या lightbox के किसी भी ancestor) पर एक या कई override करें।

Tokenडिफ़ॉल्टक्या नियंत्रित करता है
--rk-lightbox-overlay-bg#000फ़ुलस्क्रीन backdrop का रंग
--rk-lightbox-overlay-z9999Overlay का z-index
--rk-lightbox-top-shade-height80pxऊपर के gradient की ऊँचाई
--rk-lightbox-top-shade-bglinear-gradient(rgba(0,0,0,0.6), transparent)ऊपर के gradient का रंग
--rk-lightbox-edge-padding16pxबंद / नेविगेशन / ऊपर-बाएँ कंट्रोल की किनारे से दूरी
--rk-lightbox-controls-gap12pxऊपर-बाएँ कंट्रोल के बीच की दूरी
--rk-lightbox-transition0.2sबटन hover ट्रांज़िशन की अवधि
--rk-lightbox-blur8pxबटन / chips के backdrop blur का radius
--rk-lightbox-btn-bgrgba(0, 0, 0, 0.5)बंद, नेविगेशन और छोटे बटन का डिफ़ॉल्ट background
--rk-lightbox-btn-bg-hoverrgba(255, 255, 255, 0.2)बंद, नेविगेशन और छोटे बटन का hover background
--rk-lightbox-btn-fg#fffबंद, नेविगेशन और छोटे बटन के आइकन का रंग
--rk-lightbox-btn-size36pxछोटे बटन का आकार (फ़ुलस्क्रीन टॉगल वगैरह)
--rk-lightbox-btn-disabled-opacity0.5disabled छोटे बटन की opacity (डाउनलोड चलते समय)
--rk-lightbox-close-size40pxबंद करने के बटन का आकार
--rk-lightbox-nav-size48pxprev/next तीर का आकार
--rk-lightbox-nav-opacity0.7आराम की हालत में prev/next तीरों की opacity
--rk-lightbox-counter-fg#fffकाउंटर के टेक्स्ट का रंग
--rk-lightbox-counter-bgrgba(0, 0, 0, 0.5)काउंटर chip का background
--rk-lightbox-counter-size14pxकाउंटर का font size
--rk-lightbox-counter-padding6px 12pxकाउंटर chip की padding
--rk-lightbox-counter-radius20pxकाउंटर chip का border-radius
--rk-lightbox-spinner-size28pxडिफ़ॉल्ट spinner की चौड़ाई/ऊँचाई
--rk-lightbox-spinner-trackrgba(255, 255, 255, 0.2)spinner track का रंग
--rk-lightbox-spinner-fg#fffspinner इंडिकेटर का रंग
--rk-lightbox-spinner-duration0.8sspinner के घूमने की अवधि
--rk-lightbox-error-fgrgba(255, 255, 255, 0.4)एरर आइकन + टेक्स्ट का रंग
--rk-lightbox-error-text-size13pxएरर संदेश का font size
--rk-lightbox-info-bglinear-gradient(transparent, rgba(0,0,0,0.8))कैप्शन के पीछे का gradient
--rk-lightbox-info-padding24pxकैप्शन की अंदरूनी padding
--rk-lightbox-title-size18pxशीर्षक का font size
--rk-lightbox-description-size14pxविवरण का font size
--rk-lightbox-info-fg#fffकैप्शन के टेक्स्ट का रंग
--rk-lightbox-hint-fgrgba(255, 255, 255, 0.5)स्वाइप संकेत के टेक्स्ट का रंग
--rk-lightbox-hint-bgrgba(0, 0, 0, 0.3)स्वाइप संकेत chip का background
--rk-lightbox-hint-duration3sस्वाइप संकेत के दिखने/छिपने की कुल अवधि
--rk-lightbox-video-bg#000<video> के पीछे letterbox background

नीचे का snippet @reelkit/react-lightbox/styles.css के बाद लोड होने वाली stylesheet में डालें।

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

सुलभता

Overlay का root एक modal dialog है (role="dialog", aria-modal="true")। स्क्रीन रीडर की घोषणा बदलने के लिए ariaLabel सेट करें; डिफ़ॉल्ट "Image gallery" है। हर स्लाइड पर role="group", aria-roledescription="slide" और aria-label="Image N of M" होते हैं।

Lightbox खुलने पर फ़ोकस पकड़ता है और बंद होने पर उसे trigger पर लौटा देता है। Tab और Shift+Tab अंदर के फ़ोकस होने वाले एलिमेंट में घूमते हैं; बाहर निकला फ़ोकस (बाहर क्लिक, प्रोग्राम से फ़ोकस) वापस खींच लिया जाता है। यह @reelkit/core के captureFocusForReturn और createFocusTrap से बना है।

कीबोर्ड शॉर्टकट

कुंजीक्रिया
ArrowLeftपिछली इमेज
ArrowRightअगली इमेज
Escapelightbox बंद करें (या चालू हो तो फ़ुलस्क्रीन से बाहर आएँ)