Reel Player

@reelkit/react-reel-player से बना, Instagram Reel/TikTok जैसा फ़ुलस्क्रीन वीडियो प्लेयर कंपोनेंट।

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

फ़ीचर

वर्टिकल स्वाइप
टच, खींचना, कीबोर्ड, व्हील
वीडियो autoplay
दिखते ही चलता है
साउंड टॉगल
iOS पर आवाज़ बनी रहती है
मल्टी-मीडिया
हॉरिज़ॉन्टल nested carousels
स्थिति याद रखना
जहाँ छोड़ा था, वहीं से शुरू
फ़्रेम कैप्चर
poster से वीडियो तक crossfade
वर्चुअलाइज़्ड
DOM में सिर्फ़ 3 स्लाइड
Aspect ratio
डेस्कटॉप पर 9:16, मोबाइल पर पूरी स्क्रीन
डेस्कटॉप नेविगेशन
तीर वाले बटन
Generic टाइप
कंटेंट के कस्टम डेटा मॉडल
कस्टमाइज़ करने लायक
हर चीज़ के लिए render props
स्लाइड overlay
लेखक, लाइक, विवरण
URL स्टेट
शेयर और bookmark करने लायक लिंक

इंस्टॉलेशन

bash
npm install @reelkit/react-reel-player @reelkit/react lucide-react

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

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

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

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

ReelPlayerOverlay कंपोनेंट फ़ुलस्क्रीन प्लेयर overlay रेंडर करता है। ContentItem objects का array पास करें और isOpen से दिखना नियंत्रित करें।

tsx
import { useState } from 'react';
import { ReelPlayerOverlay, type ContentItem } from '@reelkit/react-reel-player';
import '@reelkit/react-reel-player/styles.css';

const content: ContentItem[] = [
  {
    id: '1',
    media: [{
      id: 'v1',
      type: 'video',
      src: 'https://example.com/video.mp4',
      poster: 'https://example.com/poster.jpg',
      aspectRatio: 9 / 16,
    }],
    author: { name: 'John Doe', avatar: 'https://example.com/avatar.jpg' },
    likes: 1234,
    description: 'Amazing video!',
  },
];

function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Open Player</button>
      <ReelPlayerOverlay
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        content={content}
      />
    </>
  );
}
ReelPlayerPage.tsx
import { useState } from 'react';
import { ReelPlayerOverlay, type ContentItem } from '@reelkit/react-reel-player';
import '@reelkit/react-reel-player/styles.css';

const content: ContentItem[] = [
  {
    id: '1',
    media: [{
      id: 'v1',
      type: 'video',
      src: '/cdn/samples/videos/video-01.mp4',
      poster: '/cdn/samples/videos/video-poster-01.jpg',
      aspectRatio: 16 / 9,
    }],
    author: { name: 'Alex Johnson', avatar: '/cdn/samples/avatars/avatar-01.jpg' },
    likes: 1234,
    description: 'Amazing sunset vibes',
  },
  {
    id: '2',
    media: [{
      id: 'img1',
      type: 'image',
      src: '/cdn/samples/images/image-01.jpg',
      aspectRatio: 2 / 3,
    }],
    author: { name: 'Sarah Miller', avatar: '/cdn/samples/avatars/avatar-02.jpg' },
    likes: 5678,
    description: 'Nature at its finest',
  },
  {
    id: '3',
    media: [{
      id: 'v2',
      type: 'video',
      src: '/cdn/samples/videos/video-04.mp4',
      poster: '/cdn/samples/videos/video-poster-04.jpg',
      aspectRatio: 16 / 9,
    }],
    author: { name: 'James Wilson', avatar: '/cdn/samples/avatars/avatar-03.jpg' },
    likes: 3456,
    description: 'City life adventures',
  },
  {
    id: '4',
    media: [
      { id: 'img2', type: 'image', src: '/cdn/samples/images/image-02.jpg', aspectRatio: 2 / 3 },
      { id: 'img3', type: 'image', src: '/cdn/samples/images/image-03.jpg', aspectRatio: 3 / 4 },
    ],
    author: { name: 'Emma Davis', avatar: '/cdn/samples/avatars/avatar-04.jpg' },
    likes: 8901,
    description: 'Travel moments',
  },
  {
    id: '5',
    media: [{
      id: 'img4',
      type: 'image',
      src: '/cdn/samples/images/image-04.jpg',
      aspectRatio: 2 / 3,
    }],
    author: { name: 'Michael Brown', avatar: '/cdn/samples/avatars/avatar-05.jpg' },
    likes: 2345,
    description: 'Golden hour magic',
  },
  {
    id: '6',
    media: [{
      id: 'v3',
      type: 'video',
      src: '/cdn/samples/videos/video-05.mp4',
      poster: '/cdn/samples/videos/video-poster-05.jpg',
      aspectRatio: 16 / 9,
    }],
    author: { name: 'Alex Johnson', avatar: '/cdn/samples/avatars/avatar-01.jpg' },
    likes: 7890,
    description: 'Living the moment',
  },
];

export default function App() {
  const [isOpen, setIsOpen] = useState(false);
  const [initialIndex, setInitialIndex] = useState(0);

  return (
    <div style={{ padding: 16, background: '#0f172a', minHeight: '100vh' }}>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 6 }}>
        {content.map((item, i) => (
          <button
            key={item.id}
            onClick={() => { setInitialIndex(i); setIsOpen(true); }}
            style={{
              position: 'relative', aspectRatio: '9 / 16', borderRadius: 8,
              overflow: 'hidden', border: 'none', padding: 0, cursor: 'pointer',
              background: '#1e293b',
            }}
          >
            <img
              src={item.media[0].poster || item.media[0].src}
              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
            />
          </button>
        ))}
      </div>

      <ReelPlayerOverlay
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        content={content}
        initialIndex={initialIndex}
      />
    </div>
  );
}

पूरे फ़्लो के लिए, यानी थंबनेल ग्रिड जो प्लेयर खोलता है और दर्शक को वहीं लौटाता है जहाँ वह रुका था, ग्रिड से प्लेयर तक रेसिपी देखें।

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

Generic कंटेंट टाइप

BaseContentItem को extend करके कस्टम डेटा टाइप इस्तेमाल करें:

tsx
import { ReelPlayerOverlay, type BaseContentItem } from '@reelkit/react-reel-player';

interface MyItem extends BaseContentItem {
  title: string;
  username: string;
}

const items: MyItem[] = [
  {
    id: '1',
    media: [{ id: 'v1', type: 'video', src: '/video.mp4', aspectRatio: 9/16 }],
    title: 'My Video',
    username: '@user',
  },
];

<ReelPlayerOverlay<MyItem>
  isOpen={isOpen}
  onClose={handleClose}
  content={items}
  renderSlideOverlay={(item) => (
    <div style={{ position: 'absolute', bottom: 16, left: 16, color: '#fff' }}>
      <strong>{item.username}</strong>
      <p>{item.title}</p>
    </div>
  )}
/>

कस्टम स्लाइड overlay

बिल्ट-इन स्लाइड overlay की जगह हर स्लाइड पर अपना कंटेंट दिखाएँ:

tsx
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderSlideOverlay={(item, index, isActive) => (
    <div style={{
      position: 'absolute',
      bottom: 0,
      left: 0,
      right: 0,
      padding: 16,
      background: 'linear-gradient(transparent, rgba(0,0,0,0.8))',
      color: '#fff',
    }}>
      <h3>{item.author.name}</h3>
      <p>{item.description}</p>
      <span>Slide {index + 1} {isActive ? '(active)' : ''}</span>
    </div>
  )}
/>

बिना मीडिया वाली स्लाइड

कस्टम कंटेंट (जैसे CTA कार्ड) डालने के लिए renderSlide इस्तेमाल करें। डिफ़ॉल्ट पर लौटने के लिए null लौटाएँ:

tsx
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderSlide={({ index, size }) => {
    // CTA card on last slide
    if (index === content.length - 1) {
      return (
        <div style={{
          width: size[0],
          height: size[1],
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          background: 'linear-gradient(135deg, #667eea, #764ba2)',
          color: '#fff',
        }}>
          <div style={{ textAlign: 'center' }}>
            <h2>Follow for more!</h2>
            <button>Subscribe</button>
          </div>
        </div>
      );
    }
    // Fall back to default MediaSlide + overlay
    return null;
  }}
/>

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

दोबारा इस्तेमाल होने वाले sub-components को अपनी चीज़ों के साथ जोड़ें:

tsx
import {
  ReelPlayerOverlay,
  CloseButton,
  SoundButton,
} from '@reelkit/react-reel-player';

<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderControls={({ onClose, content, activeIndex }) => (
    <>
      <CloseButton onClick={onClose} />
      <SoundButton />
      <button
        onClick={() => share(content[activeIndex])}
        style={{
          position: 'absolute',
          bottom: 60,
          right: 16,
          zIndex: 10,
        }}
      >
        Share
      </button>
    </>
  )}
/>

कस्टम टाइमलाइन

renderTimeline के ज़रिए बिल्ट-इन प्लेबैक बार की जगह अपना scrub UI लगाएँ। Callback सिर्फ़ तब चलता है जब overlay के नियम डिफ़ॉल्ट बार रेंडर करते (वही timeline मोड + timelineMinDurationSeconds logic), इसलिए आपको इसे दोबारा नहीं लिखना पड़ता। नीचे से सटी स्थिति, safe-area padding और टच डिवाइस पर स्लाइड overlay से दूरी पाने के लिए अपने root पर .rk-reel-timeline class दोबारा इस्तेमाल करें।

tsx
import { useRef, useEffect } from 'react';
import { ReelPlayerOverlay } from '@reelkit/react-reel-player';
import { Observe } from '@reelkit/react';

function CustomTimelineBar({ timelineState }) {
  const trackRef = useRef(null);
  useEffect(() => {
    if (!trackRef.current) return;
    // Pointer + keyboard scrub wiring, same as the built-in bar.
    return timelineState.bindInteractions(trackRef.current);
  }, [timelineState]);

  return (
    <div className="rk-reel-timeline" style={{ padding: '0 16px' }}>
      <Observe signals={[timelineState.progress, timelineState.currentTime]}>
        {() => (
          <div
            ref={trackRef}
            role="slider"
            aria-valuenow={timelineState.currentTime.value}
            style={{ height: 6, background: 'rgba(255,255,255,0.2)' }}
          >
            <div style={{
              width: `${timelineState.progress.value * 100}%`,
              height: '100%',
              background: 'linear-gradient(90deg, #6366f1, #ec4899)',
            }} />
          </div>
        )}
      </Observe>
    </div>
  );
}

<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  timeline="always"
  renderTimeline={({ timelineState }) => (
    <CustomTimelineBar timelineState={timelineState} />
  )}
/>

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

tsx
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderNavigation={({ onPrev, onNext, activeIndex, count }) => (
    <div style={{ position: 'absolute', right: 16, top: '50%', transform: 'translateY(-50%)' }}>
      <button onClick={onPrev} disabled={activeIndex === 0}>Up</button>
      <span>{activeIndex + 1}/{count}</span>
      <button onClick={onNext} disabled={activeIndex === count - 1}>Down</button>
    </div>
  )}
/>

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

मल्टी-मीडिया स्लाइड (हॉरिज़ॉन्टल carousel) के अंदर बाएँ/दाएँ तीरों की जगह अपना नेविगेशन लगाएँ:

tsx
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderNestedNavigation={({ onPrev, onNext, activeIndex, count }) => (
    <div style={{
      position: 'absolute',
      bottom: 48,
      left: 0,
      right: 0,
      display: 'flex',
      justifyContent: 'center',
      gap: 8,
      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>
  )}
/>

कस्टम nested स्लाइड

renderNestedSlide से मल्टी-मीडिया carousels के अंदर की अलग-अलग स्लाइड कस्टमाइज़ करें। डिफ़ॉल्ट ImageSlide/VideoSlide को लपेटने के लिए props.defaultContent इस्तेमाल करें, या उसे पूरी तरह बदल दें:

tsx
// Wrap default slides with rounded corners
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderNestedSlide={({ defaultContent }) => (
    <div style={{ borderRadius: 16, overflow: 'hidden' }}>
      {defaultContent}
    </div>
  )}
/>

// Fully custom nested slide for images
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderNestedSlide={({ item, size, isActive, slideKey, onVideoRef, defaultContent }) => {
    if (item.type === 'video') return defaultContent; // keep default video
    return (
      <ImageSlide
        src={item.src}
        size={size}
        imgStyle={{ objectFit: 'contain' }}
        style={{ backgroundColor: '#111' }}
      />
    );
  }}
/>

URL स्टेट

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

ReelPlayerUrlOverlay एक अलग कंपोनेंट है जिसकी खुले होने की स्टेट 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 { ReelPlayerUrlOverlay } from '@reelkit/react-reel-player';
import { Link } from 'react-router-dom';

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

// Opening is a link — the overlay reads the URL and opens itself.
{content.map((item, i) => (
  <Link key={item.id} to={`?reel=${i}`}>
    <img src={getThumbnail(item)} />
  </Link>
))}

<ReelPlayerUrlOverlay controller={reel} content={content} />

useOverlayUrlState के सारे विकल्प — param, adapter, codec, locator — React API रेफ़रेंस में हैं। पूरी जानकारी React गाइड में है।

  • खोलने पर history में एक entry जुड़ती है। फ़ीड स्वाइप करना उसे बदल देता है, इसलिए N स्वाइप कोई entry नहीं जोड़ते और back का एक कदम हमेशा प्लेयर छोड़ देता है। Back बंद करता है; स्लाइड नहीं बदलता।
  • Back सिर्फ़ तब बंद करता है जब प्लेयर ऐप के अंदर से खोला गया हो — लिंक ने entry जोड़ी हो। नए tab में सीधे खोले गए शेयर किए गए लिंक के पीछे कोई history नहीं होती, इसलिए ब्राउज़र का back साइट छोड़ देता है; ✕ बटन या Escape parameter को उसी जगह हटाकर पेज पर बना रहता है।
  • सीधा लिंक ?reel=3 लोड होते ही प्लेयर को उसी स्लाइड पर खोलता है।
  • किसी स्लाइड का नाम न लेने वाला parameter — पुराना bookmark, हाथ से बदली value — URL से हटा दिया जाता है, ताकि address bar ऐसी स्लाइड का दावा न करता रहे जो खुल ही नहीं सकती।
  • डिफ़ॉल्ट रूप से parameter सिर्फ़ वर्टिकल पोस्ट को पहचानता है (?reel=3)। मल्टी-मीडिया carousel का अंदरूनी मीडिया index भी रखने के लिए दो-अक्ष वाली key चुनें — नीचे देखें।

एक key या दो — URL की गहराई चुनें

वही ReelPlayerUrlOverlay दोनों रूप चलाता है; यह चलते समय कंट्रोलर की स्थिति से फ़र्क पहचानता है, इसलिए कोई mode prop नहीं है। कंट्रोलर बनाते समय key चुनें:

KeyWireक्या रखता है
urlIndexKey(…)?reel=3सिर्फ़ वर्टिकल पोस्ट।
urlIndexTwoAxisKey(…)?reel=3.2पोस्ट और carousel का अंदरूनी मीडिया index।

दोनों wire जानबूझकर अलग हैं — दो-अक्ष वाली key सख़्ती से बिंदु वाली है (3.0, कभी अकेला 3 नहीं), इसलिए एक-अक्ष वाला साधारण लिंक दूसरे रूप में decode नहीं होता। इसलिए ऐप में key बदलने से पहले शेयर किए गए सारे लिंक बेकार हो जाते हैं। एक रूप चुनें और उसी पर टिके रहें।

tsx
import { useOverlayUrlState, urlIndexTwoAxisKey } from '@reelkit/react';

const reel = useOverlayUrlState({
  param: 'reel',
  ...urlIndexTwoAxisKey({
    outerCount: () => content.length,
    innerCounts: () => content.map((post) => post.media.length),
  }),
});

// A link now names both axes: post 3, inner media 2.
<Link to="?reel=3.2">…</Link>
<ReelPlayerUrlOverlay controller={reel} content={content} />

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

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

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

<ReelPlayerUrlOverlay controller={reel} content={content} />

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

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

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

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

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

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

छोटा रास्ता

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

tsx
const reel = useOverlayUrlState({
  param: 'reel',
  codec: { decode: (raw) => raw, encode: (id) => id },
  locator: {
    locate: (id) => content.findIndex((x) => x.id === id),
    identify: (index) => content[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 post
      setContent(loaded); // commit — the overlay renders from this state
      return loaded.findIndex((x) => x.id === id); // wherever it landed
    },
  },
});
  • locateAsync के pending रहने तक प्लेयर बंद रहता है और parameter को छुआ नहीं जाता, इसलिए सीधा लिंक fetch के बाद भी बना रहता है। null या rejection parameter हटा देता है।
  • URL आगे बढ़ जाने, बंद होने या unmount के बाद आया जवाब फेंक दिया जाता है — धीमा fetch ऐसी स्लाइड नहीं खोल सकता जो किसी ने माँगी ही नहीं।
  • pending रहने के दौरान कुछ भी रेंडर नहीं होता; लोडिंग की वह स्टेट पेज के पास पहले से है, इसलिए अपना skeleton रेंडर करें।
  • कोई timeout नहीं है — प्लेयर नहीं जान सकता कि फ़ीड कितनी लंबी है। पेज ख़त्म होने पर null से निपटाएँ, नहीं तो overlay हमेशा बंद रहेगा।

API रेफ़रेंस

ReelPlayerOverlayProps के props

ReelPlayerOverlayProps<T>

ReelPlayerOverlayProps, ReelPlayerOverlayBaseProps (दोनों overlay के साझा दिखावट और व्यवहार वाले props) और ReelPlayerControlledProps (isOpen और onClose) को मिलाकर बनता है। किसी भी overlay को रेंडर करने वाले wrapper को टाइप करने के लिए base टाइप इस्तेमाल करें।

Propटाइपडिफ़ॉल्टविवरण
apiRefMutableRefObject<ReelApi>-Reel API तक पहुँचने के लिए ref
ariaLabelstring'Video player'dialog क्षेत्र का सुलभ लेबल; overlay खुलने पर स्क्रीन रीडर इसे बोलते हैं
aspectRationumber9/16 (0.5625)डेस्कटॉप पर प्लेयर कंटेनर का चौड़ाई/ऊँचाई अनुपात। 768px या उससे कम चौड़ाई पर प्लेयर हमेशा पूरा viewport लेता है। शून्य, ऋणात्मक या non-finite मान होने पर 9/16 इस्तेमाल होता है।
contentT[]ज़रूरीकंटेंट आइटम का array (generic, डिफ़ॉल्ट ContentItem)
initialIndexnumber0शुरुआती स्लाइड index
initialInnerIndexnumber0अंदरूनी मीडिया index जिस पर खोलना है, सिर्फ़ शुरू में दिखने वाली पोस्ट के लिए — इससे दो-अक्ष वाला URL मल्टी-मीडिया पोस्ट की किसी खास इमेज पर सीधे ले जा सकता है। प्लेयर खुलने और यूज़र के नेविगेट करने के बाद अनदेखा होता है।
isOpenbooleanज़रूरीoverlay का दिखना नियंत्रित करता है। URL से चलने वाली खुली स्टेट के लिए इसकी जगह अलग ReelPlayerUrlOverlay इस्तेमाल करें — नीचे URL स्टेट देखें।
timeline'auto' | 'always' | 'never''auto'बिल्ट-इन प्लेबैक टाइमलाइन बार दिखाने का नियम। 'auto' सिर्फ़ timelineMinDurationSeconds से लंबे वीडियो पर रेंडर करता है; 'always' जब भी सक्रिय स्लाइड में वीडियो हो; 'never' बिल्ट-इन बार बंद करता है (पूरी तरह कस्टम बार के लिए renderTimeline इस्तेमाल करें)।
timelineMinDurationSecondsnumber30timeline='auto' में बिल्ट-इन बार दिखाने के लिए वीडियो की न्यूनतम अवधि (सेकंड)। इससे छोटी लूप होने वाली क्लिप पर बार नहीं दिखता।
renderControls(props: ControlsRenderProps) => ReactNode-कस्टम कंट्रोल, डिफ़ॉल्ट बंद + साउंड बटन की जगह लेते हैं
renderError(props: { item: T; activeIndex: number }) => ReactNode-कस्टम एरर इंडिकेटर, डिफ़ॉल्ट एरर आइकन की जगह लेता है
renderLoading(props: { item: T; activeIndex: number }) => ReactNode-कस्टम लोडिंग इंडिकेटर, डिफ़ॉल्ट wave loader की जगह लेता है
renderNavigation(props: NavigationRenderProps) => ReactNode-कस्टम नेविगेशन, डिफ़ॉल्ट वर्टिकल तीरों की जगह लेता है
renderNestedNavigation(props: NavigationRenderProps) => ReactNode-nested हॉरिज़ॉन्टल स्लाइडर (मल्टी-मीडिया पोस्ट) का कस्टम नेविगेशन, डिफ़ॉल्ट बाएँ/दाएँ तीरों की जगह लेता है
renderNestedSlide(props: NestedSlideRenderProps) => ReactNode-nested हॉरिज़ॉन्टल स्लाइडर के आइटम का कस्टम स्लाइड renderer। डिफ़ॉल्ट ImageSlide/VideoSlide को लपेटने या अंदर रखने के लिए props.defaultContent इस्तेमाल करें। renderSlide के उलट, null को डिफ़ॉल्ट पर लौटना नहीं माना जाता।
renderSlide(props: SlideRenderProps) => ReactNode | null-कस्टम स्लाइड रेंडरिंग। डिफ़ॉल्ट पर लौटने के लिए null लौटाएँ। डिफ़ॉल्ट स्लाइड को लपेटने या अंदर रखने के लिए props.defaultContent इस्तेमाल करें।
renderSlideOverlay(item, index, isActive) => ReactNode-हर स्लाइड का कस्टम overlay, डिफ़ॉल्ट SlideOverlay की जगह लेता है। छिपाने के लिए null लौटाएँ।
renderTimeline(props: TimelineRenderProps) => ReactNode-कस्टम प्लेबैक टाइमलाइन बार। सिर्फ़ तब चलता है जब नियम डिफ़ॉल्ट बार रेंडर करते (वही auto/always/never + timelineMinDurationSeconds logic)। बिल्ट-इन <TimelineBar /> को लपेटने के लिए props.defaultContent इस्तेमाल करें; छिपाने के लिए null लौटाएँ।

ReelPlayerUrlOverlay के props

ReelPlayerUrlOverlayProps<T>

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

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

Callbacks

Propटाइपविवरण
onClose() => voidप्लेयर बंद होने पर कॉल होता है। ReelPlayerOverlay पर ज़रूरी (खुली स्टेट आपके पास है, इसलिए बंद करना आपको संभालना होगा); ReelPlayerUrlOverlay पर वैकल्पिक, जहाँ बंद करना URL चलाता है — इसे सिर्फ़ बंद होने के बाद कुछ करने के लिए पास करें।
onSlideChange(index: number) => voidस्लाइड बदलने के बाद कॉल होता है
onInnerSlideChange(outerIndex: number, innerIndex: number) => voidसक्रिय पोस्ट का अंदरूनी मीडिया index बदलने पर कॉल होता है — मल्टी-मीडिया पोस्ट के अंदर नेविगेशन पर, और बाहरी सक्रियता पर, सक्रिय हुई पोस्ट का मौजूदा अंदरूनी index बताते हुए (एक मीडिया वाली पोस्ट के लिए 0)।

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

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

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

टाइप

BaseContentItem

generic की सीमा तय करने वाला टाइप। ReelPlayerOverlay के साथ कस्टम डेटा टाइप इस्तेमाल करने के लिए इसे extend करें।

typescript
interface BaseContentItem {
  id: string;
  media: MediaItem[];
}

ContentItem

typescript
interface ContentItem extends BaseContentItem {
  author: {
    name: string;
    avatar: string;
  };
  likes: number;
  description: string;
}

MediaItem

typescript
interface MediaItem {
  id: string;
  type: 'image' | 'video';
  src: string;
  poster?: string;
  aspectRatio: number;
}

MediaType

typescript
type MediaType = 'image' | 'video';

ControlsRenderProps<T>

typescript
interface ControlsRenderProps<T extends BaseContentItem> {
  onClose: () => void;
  soundState: SoundState;
  activeIndex: number;
  content: T[];
}
typescript
interface NavigationRenderProps {
  onPrev: () => void;
  onNext: () => void;
  activeIndex: number;
  count: number;
}

SlideRenderProps<T>

typescript
interface SlideRenderProps<T extends BaseContentItem> {
  item: T;
  index: number;
  size: [number, number];
  isActive: boolean;
  slideKey: string;
  onVideoRef?: (ref: HTMLVideoElement | null) => void;
  innerSliderRef: MutableRefObject<ReelApi | null>;
  onActiveMediaTypeChange?: (type: 'image' | 'video') => void;
  renderNestedNavigation?: (props: NavigationRenderProps) => ReactNode;
  enableWheel?: boolean;
  defaultContent: ReactNode;
}

NestedSlideRenderProps

typescript
interface NestedSlideRenderProps {
  item: MediaItem;
  index: number;
  size: [number, number];
  isActive: boolean;
  isInnerActive: boolean;
  slideKey: string;
  onVideoRef?: (ref: HTMLVideoElement | null) => void;
  defaultContent: ReactNode;
}

SlideOverlayProps

typescript
interface SlideOverlayProps {
  author?: { name: string; avatar: string };
  description?: string;
  likes?: number;
}

ImageSlideProps

typescript
interface ImageSlideProps {
  src: string;
  size: [number, number];
  className?: string;
  style?: CSSProperties;
  imgClassName?: string;
  imgStyle?: CSSProperties;
}

VideoSlideProps

typescript
interface VideoSlideProps {
  src: string;
  poster?: string;
  aspectRatio: number;
  size: [number, number];
  isActive: boolean;
  isInnerActive?: boolean;   // default: true
  slideKey: string;
  onVideoRef?: (ref: HTMLVideoElement | null) => void;
  className?: string;
  style?: CSSProperties;
}

CloseButtonProps

typescript
interface CloseButtonProps {
  onClick: () => void;
  className?: string;
  style?: React.CSSProperties;
}

SoundButtonProps

typescript
interface SoundButtonProps {
  disabled?: boolean;
  className?: string;
  style?: React.CSSProperties;
}

TimelineBarProps

typescript
interface TimelineBarProps {
  className?: string;
  style?: React.CSSProperties;
}

TimelineRenderProps<T>

typescript
interface TimelineRenderProps<T extends BaseContentItem> {
  item: T;
  activeIndex: number;
  timelineState: TimelineController;
  defaultContent: ReactNode;
}

सब-कंपोनेंट

कस्टम render props में जोड़कर इस्तेमाल करने के लिए export किए गए, दोबारा इस्तेमाल होने वाले हिस्से:

CloseButton

reel प्लेयर की डिफ़ॉल्ट styling वाला अलग बंद करने का बटन। renderControls के अंदर इस्तेमाल करें।

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

<CloseButton onClick={onClose} />
<CloseButton onClick={onClose} className="my-close-btn" style={{ top: 24, right: 24 }} />

SoundButton

अलग साउंड टॉगल। SoundProvider के अंदर होना ज़रूरी है (ReelPlayerOverlay इसे अपने-आप देता है)।

tsx
import { SoundButton } from '@reelkit/react-reel-player';

<SoundButton />
<SoundButton disabled className="my-sound-btn" />

TimelineBar

डिफ़ॉल्ट प्लेबैक scrub bar। सबसे पास के TimelineProvider (जो ReelPlayerOverlay के अंदर अपने-आप mount होता है) से पढ़ता है और track, buffered ranges, प्रोग्रेस भराव और scrub pill रेंडर करता है। --rk-reel-timeline-* custom properties से थीम करें, या renderTimeline से बदल दें।

tsx
import { TimelineBar } from '@reelkit/react-reel-player';

// Inside renderTimeline — wrap or augment the default bar:
<ReelPlayerOverlay
  renderTimeline={({ defaultContent }) => (
    <>
      <MyTimecode />
      {defaultContent}
    </>
  )}
/>

// Or render standalone inside a custom TimelineProvider tree:
<TimelineBar className="my-timeline" />

SlideOverlay

लेखक, विवरण और लाइक दिखाने वाला डिफ़ॉल्ट gradient overlay। कंटेंट में ज़रूरी fields होने पर अपने-आप रेंडर होता है। इसे बदलने या छिपाने के लिए renderSlideOverlay इस्तेमाल करें।

tsx
import { SlideOverlay } from '@reelkit/react-reel-player';

<SlideOverlay
  author={{ name: 'John', avatar: '/avatar.jpg' }}
  description="Amazing content"
  likes={12500}
/>

ImageSlide

lazy loading और डिफ़ॉल्ट object-fit: cover वाली इमेज स्लाइड। अपनी styles के साथ कस्टम इमेज स्लाइड बनाने के लिए renderSlide के अंदर इस्तेमाल करें।

tsx
import { ImageSlide } from '@reelkit/react-reel-player';

// Default usage
<ImageSlide src="/photo.jpg" size={[400, 700]} />

// Custom styles
<ImageSlide
  src="/photo.jpg"
  size={[400, 700]}
  className="my-image-slide"
  style={{ backgroundColor: '#1a1a1a', borderRadius: 12 }}
  imgStyle={{ objectFit: 'contain' }}
/>

VideoSlide

iOS पर आवाज़ बनाए रखने के लिए साझा <video> एलिमेंट, poster फ़्रेम, स्थिति याद रखने और लोडिंग इंडिकेटर वाली वीडियो स्लाइड। SoundProvider के अंदर होना ज़रूरी है (ReelPlayerOverlay इसे अपने-आप देता है)।

tsx
import { VideoSlide } from '@reelkit/react-reel-player';

<VideoSlide
  src="/video.mp4"
  poster="/thumb.jpg"
  aspectRatio={9 / 16}
  size={[400, 700]}
  isActive={true}
  slideKey="slide-1"
  style={{ borderRadius: 12 }}
/>
कस्टम स्लाइड बनाना

सारा बिल्ट-इन व्यवहार (autoplay, poster कैप्चर, साउंड sync) बनाए रखते हुए मीडिया रेंडरिंग कस्टमाइज़ करने के लिए ImageSlide / VideoSlide के साथ renderSlide इस्तेमाल करें।

tsx
import {
  ReelPlayerOverlay,
  ImageSlide,
  VideoSlide,
} from '@reelkit/react-reel-player';

<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={handleClose}
  content={content}
  renderSlide={({ item, size, isActive, slideKey, onVideoRef }) => {
    const media = item.media[0];
    if (media.type === 'image') {
      return (
        <ImageSlide
          src={media.src}
          size={size}
          imgStyle={{ objectFit: 'contain' }}
          style={{ backgroundColor: '#111' }}
        />
      );
    }
    if (media.type === 'video') {
      return (
        <VideoSlide
          src={media.src}
          poster={media.poster}
          aspectRatio={media.aspectRatio}
          size={size}
          isActive={isActive}
          slideKey={slideKey}
          onVideoRef={onVideoRef}
          style={{ borderRadius: 16 }}
        />
      );
    }
    return null; // fallback to default
  }}
/>

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

प्लेयर हर स्लाइड की लोडिंग और एरर स्टेट ट्रैक करता है। कंटेंट लोड होते समय wave loader दिखता है; टूटे मीडिया पर एरर आइकन दिखता है। एरर वाले 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, size, isActive, onReady, onWaiting, onError }) => (
  <div style={{ width: size[0], height: size[1] }}>
    {item.media[0].type === 'image' ? (
      <img
        src={item.media[0].src}
        onLoad={onReady}
        onError={onError}
        style={{ width: '100%', height: '100%', objectFit: 'cover' }}
      />
    ) : (
      <video
        src={item.media[0].src}
        autoPlay={isActive}
        onCanPlay={onReady}
        onWaiting={onWaiting}
        onError={onError}
        style={{ width: '100%', height: '100%', objectFit: 'cover' }}
      />
    )}
  </div>
)}

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

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

tsx
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  content={content}
  renderLoading={({ item, activeIndex }) => (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 10,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      color: '#fff', fontSize: 14,
    }}>
      Loading slide {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 media</span>
    </div>
  )}
/>

टाइमलाइन

Overlay सक्रिय वीडियो के ऊपर एक बिल्ट-इन प्लेबैक टाइमलाइन बार रेंडर करता है। TimelineMode टाइप वाला timeline prop रेंडरिंग तय करता है:

  • 'auto' (डिफ़ॉल्ट): तब रेंडर होता है जब सक्रिय मीडिया ऐसा वीडियो हो जिसकी अवधि timelineMinDurationSeconds (डिफ़ॉल्ट 30) से ज़्यादा हो। एक वीडियो वाली स्लाइड और मल्टी-मीडिया carousels दोनों पर काम करता है; बार सक्रिय nested आइटम के साथ चलता है और इमेज पर छिप जाता है।
  • 'always': जब भी सक्रिय स्लाइड में वीडियो हो, रेंडर होता है।
  • 'never': कभी रेंडर नहीं होता। renderTimeline से अपना बार बनाएँ।
tsx
<ReelPlayerOverlay
  isOpen={isOpen}
  onClose={close}
  content={items}
  timeline="auto"
  timelineMinDurationSeconds={30}
/>

--rk-reel-timeline-* CSS custom properties (ऊँचाई, रंग, cursor का आकार) से थीम करें। पूरी तरह कस्टम scrub bar, timecode या प्रोग्रेस इंडिकेटर के लिए renderTimeline इस्तेमाल करें; callback को अंदर के TimelineController पर आधारित timelineState मिलता है।

overlay के अंदर रेंडर हुआ कंपोनेंट यही कंट्रोलर ख़ुद भी पढ़ सकता है: useTimelineState() उसे सबसे पास वाले TimelineProvider (जिसे overlay लगाता है) से लौटाता है और उसके बाहर एरर देता है; useTimelineStateOptional() वहाँ null लौटाता है, उन कंपोनेंट के लिए जो प्लेयर के बाहर भी रेंडर हो सकते हैं।

साउंड context

कस्टम implementation के लिए आप साउंड स्टेट तक पहुँच सकते हैं:

tsx
import { SoundProvider, useSoundState } from '@reelkit/react';

// ReelPlayerOverlay wraps itself in a SoundProvider.
// Access sound state inside custom controls:
function CustomControls() {
  const soundState = useSoundState();

  return (
    <button onClick={soundState.toggle}>
      {soundState.muted.value ? 'Unmute' : 'Mute'}
    </button>
  );
}

CSS क्लास

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

क्लासकंपोनेंटविवरण
.rk-reel-overlayOverlayतय फ़ुलस्क्रीन backdrop (background, z-index)
.rk-reel-containerOverlayप्लेयर कंटेनर (position, overflow)
.rk-reel-loaderOverlaywave लोडिंग एनिमेशन का overlay
.rk-reel-media-errorOverlayएरर स्टेट का overlay (बीच में आइकन + टेक्स्ट)
.rk-reel-media-error-textOverlayएरर संदेश का टेक्स्ट
.rk-reel-buttonControlsसाझा गोल आइकन बटन (बंद, साउंड, नेविगेशन तीर)
.rk-reel-close-btnControlsबंद करने का बटन
.rk-reel-sound-btnControlsसाउंड टॉगल बटन
.rk-reel-nav-arrowsNavigationसिर्फ़ डेस्कटॉप वाला तीरों का कंटेनर (768px या उससे कम चौड़ाई पर छिपा)
.rk-reel-nav-buttonNavigationअलग prev/next नेविगेशन तीर
.rk-reel-slide-wrapperSlideमीडिया + overlay के चारों ओर का wrapper
.rk-reel-slide-overlaySlideOverlaygradient overlay का कंटेनर
.rk-reel-slide-overlay-authorSlideOverlayलेखक की पंक्ति (avatar + नाम)
.rk-reel-slide-overlay-avatarSlideOverlayलेखक की avatar इमेज
.rk-reel-slide-overlay-nameSlideOverlayलेखक के नाम का टेक्स्ट
.rk-reel-slide-overlay-descriptionSlideOverlayविवरण का टेक्स्ट
.rk-reel-slide-overlay-likesSlideOverlayलाइक की पंक्ति (दिल + गिनती)
.rk-reel-video-containerVideoSlideवीडियो wrapper (background, overflow)
.rk-reel-video-elementVideoSlide<video> एलिमेंट
.rk-reel-video-posterVideoSlideposter इमेज (चलने पर धुंधली होकर गायब)
.rk-reel-video-poster.rk-visibleVideoSlideवीडियो रुका/लोड होते समय poster पर लगने वाला स्टेट modifier
.rk-reel-nested-indicatorNestedSliderमल्टी-मीडिया स्लाइड के नीचे बिंदु वाला pagination (डेस्कटॉप और टच पर स्थिति अलग)
.rk-reel-nested-navNestedSliderहॉरिज़ॉन्टल carousel के तीर (768px या उससे कम चौड़ाई पर छिपे)
.rk-reel-nested-nav-nextNestedSlidernested अगले तीर की स्थिति
.rk-reel-nested-nav-prevNestedSlidernested पिछले तीर की स्थिति
.rk-reel-timelineTimelineBarscrub bar का wrapper। नीचे से सटी स्थिति, safe-area padding और टच डिवाइस पर स्लाइड overlay से दूरी पाने के लिए कस्टम `renderTimeline` roots पर दोबारा इस्तेमाल करें।
.rk-reel-timeline-trackTimelineBarTrack (न चला हुआ हिस्सा)
.rk-reel-timeline-bufferedTimelineBarbuffered हिस्सों की परत
.rk-reel-timeline-fillTimelineBarचले हुए हिस्से का भराव
.rk-reel-timeline-cursorTimelineBarscrub handle की pill (track के ऊपर तैरती)

थीमिंग

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

Tokenडिफ़ॉल्टक्या नियंत्रित करता है
--rk-reel-overlay-bg#000फ़ुलस्क्रीन backdrop का रंग
--rk-reel-overlay-z1000Overlay का z-index
--rk-reel-button-bgrgba(0, 0, 0, 0.5)डिफ़ॉल्ट गोल बटन का background
--rk-reel-button-bg-hoverrgba(255, 255, 255, 0.1)नेविगेशन तीर का background (और hover की मूल स्टेट)
--rk-reel-button-bg-hover-strongrgba(255, 255, 255, 0.2)नेविगेशन तीर का hover background
--rk-reel-button-fg#fffबटन आइकन का रंग
--rk-reel-button-size44pxबटन की चौड़ाई / ऊँचाई
--rk-reel-button-radius50%बटन का border-radius
--rk-reel-ui-z10बंद / साउंड / नेविगेशन का z-index
--rk-reel-edge-padding16pxबंद / साउंड / नेविगेशन तीरों की किनारे से दूरी
--rk-reel-nav-gap8pxएक के ऊपर एक रखे नेविगेशन तीरों के बीच की दूरी
--rk-reel-transition0.2shover ट्रांज़िशन की अवधि
--rk-reel-loader-colorrgba(255, 255, 255, 0.12)wave loader के gradient का रंग
--rk-reel-loader-duration1.8swave loader एनिमेशन की अवधि
--rk-reel-error-fgrgba(255, 255, 255, 0.4)एरर आइकन और टेक्स्ट का रंग
--rk-reel-error-text-size13pxएरर संदेश का font size
--rk-reel-slide-overlay-bglinear-gradient(transparent, rgba(0, 0, 0, 0.7))कैप्शन के पीछे का gradient
--rk-reel-slide-overlay-padding48px 16px 16pxकैप्शन की अंदरूनी padding
--rk-reel-slide-overlay-name-color#fffलेखक के नाम का रंग
--rk-reel-slide-overlay-description-colorrgba(255, 255, 255, 0.9)विवरण के टेक्स्ट का रंग
--rk-reel-slide-overlay-likes-colorrgba(255, 255, 255, 0.8)लाइक वाली पंक्ति के टेक्स्ट का रंग
--rk-reel-video-bg#000<video> के पीछे letterbox background
--rk-reel-nested-button-bgrgba(0, 0, 0, 0.5)nested तीर का background
--rk-reel-nested-button-bg-hoverrgba(255, 255, 255, 0.2)nested तीर का hover background
--rk-reel-nested-button-size36pxnested तीर का आकार
--rk-reel-nested-edge-padding12pxnested तीर की किनारे से दूरी
--rk-reel-timeline-trackrgba(255, 255, 255, 0.22)Track का background (न चला हुआ हिस्सा)
--rk-reel-timeline-bufferedrgba(255, 255, 255, 0.4)buffered हिस्सों का रंग
--rk-reel-timeline-fill#fffचले हुए हिस्से के भराव का रंग
--rk-reel-timeline-cursor#fffscrub handle की pill का रंग
--rk-reel-timeline-height3pxआराम की हालत में track की ऊँचाई
--rk-reel-timeline-height-active6pxhover / फ़ोकस / scrub पर track की ऊँचाई
--rk-reel-timeline-cursor-width10pxआराम की हालत में scrub pill की चौड़ाई
--rk-reel-timeline-cursor-width-active14pxscrub करते समय scrub pill की चौड़ाई
--rk-reel-timeline-cursor-height24pxआराम की हालत में scrub pill की ऊँचाई
--rk-reel-timeline-cursor-height-active32pxscrub करते समय scrub pill की ऊँचाई
--rk-reel-timeline-hitbox16pxtrack के ऊपर pointer के लिए अतिरिक्त छूने की जगह
--rk-reel-timeline-transition0.15s ease-outtrack + pill के बढ़ने/घटने का एनिमेशन
--rk-reel-timeline-z11टाइमलाइन का z-index (डिफ़ॉल्ट UI परत के ऊपर)

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

css
/* Brand the reel-player overlay */
:root {
  --rk-reel-overlay-bg: #0f172a;
  --rk-reel-button-bg: rgba(99, 102, 241, 0.65);
  --rk-reel-button-bg-hover-strong: rgba(168, 85, 247, 0.85);
  --rk-reel-edge-padding: 24px;
  --rk-reel-button-size: 52px;

  /* Timeline bar: brand-matched, beefier on desktop */
  --rk-reel-timeline-track: rgba(99, 102, 241, 0.25);
  --rk-reel-timeline-buffered: rgba(168, 85, 247, 0.45);
  --rk-reel-timeline-fill: #a855f7;
  --rk-reel-timeline-cursor: #a855f7;
  --rk-reel-timeline-height: 4px;
  --rk-reel-timeline-height-active: 8px;
  --rk-reel-timeline-cursor-width-active: 18px;
  --rk-reel-timeline-transition: 0.2s ease-out;
}

सुलभता

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

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

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

कुंजीक्रिया
ArrowUpपिछली स्लाइड
ArrowDownअगली स्लाइड
ArrowLeftपिछला मीडिया (nested स्लाइडर में)
ArrowRightअगला मीडिया (nested स्लाइडर में)
Escapeप्लेयर बंद करें