Reel Player

Повноекранний компонент відеоплеєра у стилі Instagram Reels чи TikTok на основі @reelkit/react-reel-player.

Подивитися демо наживо →

Features

Вертикальний свайп
Дотик, перетягування, клавіатура, колесо
Автовідтворення відео
Грає, коли слайд видимий
Перемикач звуку
Безперервність на iOS
Multi-Media
Вкладені горизонтальні каруселі
Пам’ять позиції
Продовжує з місця, де зупинилися
Знімок кадру
Плавний перехід від постера до відео
Віртуалізований
Лише 3 слайди в DOM
Співвідношення сторін
9:16 на десктопі, на весь екран на мобільних
Навігація на десктопі
Кнопки-стрілки
Узагальнені типи
Власні моделі даних вмісту
Customizable
Render props для всього
Оверлей слайда
Автор, лайки, опис
Стан в URL
Посилання, якими можна ділитися й зберігати в закладки

Встановлення

bash

Не забудьте імпортувати стилі:

typescript
Icons
Стандартні елементи керування використовують lucide-react для іконок. Якщо ви віддаєте перевагу іншій бібліотеці іконок, скористайтеся renderControls та renderNavigation , щоб передати власні.

Швидкий старт

The ReelPlayerOverlay рендерить повноекранний оверлей плеєра. Передайте масив ContentItem і керуйте видимістю через isOpen.

tsx

Демо наживо

ReelPlayerPage.tsx

Натисніть мініатюру, щоб відкрити повноекранний плеєр. Escape або кнопка закриття повертають назад.

Customization

Узагальнений тип вмісту

Використовуйте власні типи даних, розширивши BaseContentItem:

tsx

Власний оверлей слайда

Замініть вбудований оверлей слайда власним вмістом для кожного слайда:

tsx

Слайди без медіа

Використовуйте renderSlide щоб вставити власний вміст (наприклад, картки із закликом до дії). Поверніть null щоб лишити стандартний:

tsx

Власні елементи керування

Складайте готові підкомпоненти разом із власними доповненнями:

tsx

Власний таймлайн

Замініть вбудовану смугу відтворення власним інтерфейсом перемотування через renderTimeline. Колбек спрацьовує лише тоді, коли за правилами показу оверлей вивів би стандартну смугу (та сама логіка timeline плюс timelineMinDurationSeconds ), тож переписувати її не доведеться. Використайте клас .rk-reel-timeline на своєму корені, щоб успадкувати притиснення до низу, відступи безпечної зони та проміжок для оверлея слайда на дотикових пристроях.

tsx

Власна навігація

tsx

Власна вкладена навігація

Замініть стрілки ліворуч і праворуч усередині мультимедійних слайдів (горизонтальна карусель) власною навігацією:

tsx

Власні вкладені слайди

Налаштуйте окремі слайди всередині мультимедійних каруселей через renderNestedSlide. Use props.defaultContent щоб загорнути стандартний ImageSlide чи VideoSlide або замінити його повністю:

tsx

Стан в URL

ReelPlayerUrlOverlay — окремий компонент, стан відкриття якого живе в адресному рядку. Побудуйте контролер через useOverlayUrlState from @reelkit/react і передайте його як controller: плеєр відкривається сам, коли параметр називає слайд, і закривається, коли параметр зникає. Посиланнями можна ділитися, а кнопка «назад» закриває плеєр, а не виводить зі сторінки.

Вбудовані клавіші
Слайди можна адресувати вбудованим ключем — розгорніть urlIndexKey (за позицією) або urlStableIdKey (за стабільним id) into the controller — both re-exported from @reelkit/react. See the посібник зі стану в URL та API ядра.
tsx

Full useOverlayUrlState опції — param, adapter, codec, locator — у довіднику API для React. Покроковий розбір — у посібнику для React.

  • Відкриття додає один запис в історію. Свайп стрічки замінює його, тож N свайпів не додають записів, і один крок назад завжди виходить із плеєра. «Назад» закриває, а не гортає слайди.
  • «Назад» закриває лише тоді, коли плеєр відкрили всередині застосунку — посилання додало запис. За надісланим посиланням у новій вкладці історії позаду немає, тож кнопка «назад» виведе із сайту; кнопка ✕ або Escape прибирає параметр на місці й лишає вас на сторінці.
  • Пряме посилання ?reel=3 відкриває плеєр одразу на цьому слайді.
  • Параметр, який не називає жодного слайда — застаріла закладка, змінене вручну значення, — прибирається з URL, а не лишає в адресному рядку слайд, який не відкриється.
  • Типово параметр адресує лише vertical допис (?reel=3). Opt into a two-axis key to also carry the inner media index of a multi-media carousel — see below.

Один ключ чи два — оберіть глибину URL

Той самий ReelPlayerUrlOverlay працює з обома формами; він розрізняє їх під час виконання за position контролера, тож жодного пропса режиму немає. Ключ обирайте, коли будуєте контролер:

KeyWireCarries
urlIndexKey(…)?reel=3Лише вертикальний допис.
urlIndexTwoAxisKey(…)?reel=3.2Допис та та індекс внутрішнього медіа каруселі.

Дві форми запису навмисно різні — двовісний ключ строго з крапкою (3.0, never a bare 3), so a bare one-axis link does not cross-decode. Switching an app between keys therefore invalidates any previously shared links. Pick one shape and keep it.

tsx

Застосунок із роутером — передайте адаптер. Writing history.pushState повз роутер лишає його місцеположення застарілим, і наступна навігація втрачає параметр:

tsx

Стабільні посилання. Індекс адресує за позицією, тож збережений у закладках ?reel=3 відкриє інший допис, щойно стрічку перевпорядкують — а для стрічки це радше правило, ніж виняток. urlStableIdKey адресує за стабільним id, scanning the live feed — one call covers the common case.

tsx

Pass hashCodec: base64UrlCodec щоб закодувати id в URL у base64url — оборотне маскування, а не криптографічний хеш.

Адресуєте за іншим полем ( slug), or page an infinite feed with locateAsync, and build the codec/locator самі. Дві окремі задачі: codec записує ідентичність в URL, locator знаходить, де ця ідентичність лежить.

tsx

Нескінченні стрічки. locate синхронний, тож відповідає лише за вже завантажені дописи — надіслане посилання на допис 400 у стрічці, де завантажено 20, нічого не знайде. locateAsync — запасний варіант, що викликається лише коли locate misses.

Shortcut
Keying by the item’s id? Не пишіть кодек і локатор вручну — передайте locateAsync просто в urlStableIdKey({ items, locateAsync }) (він вантажить дані, якщо не знайшов, і повертає індекс). Розгорнутий варіант нижче — для адресації за іншим полем або для повного контролю.
tsx
  • While locateAsync у процесі, плеєр лишається закритим, а параметр — недоторканим, тож пряме посилання переживає запит. null або відмова прибирає параметр.
  • Відповідь, що приходить після зміни URL, після закриття або після демонтажу, відкидається — повільний запит не відкриє слайд, якого ніхто не просив.
  • Поки триває очікування, нічого не рендериться: цей стан завантаження вже належить сторінці, тож малюйте власний скелетон.
  • Тайм-ауту немає — плеєр не може знати, яка стрічка завдовжки. Завершуйте значенням null коли сторінки скінчилися, інакше оверлей лишиться закритим назавжди.

Довідник API

Пропси ReelPlayerOverlayProps

ReelPlayerOverlayProps<T>

PropТипТипове значенняОпис
apiRefMutableRefObject<ReelApi>-Ref для доступу до API Reel
ariaLabelstring'Video player'Доступна назва області діалогу; екранні читачі оголошують її, коли оверлей відкривається
aspectRationumber9/16 (0.5625)Співвідношення ширини до висоти контейнера плеєра на десктопі. На мобільних плеєр завжди займає всю область перегляду.
contentT[]requiredМасив елементів вмісту (узагальнений тип, типово ContentItem)
initialIndexnumber0Початковий індекс слайда
initialInnerIndexnumber0Індекс внутрішнього медіа, з якого відкриватися, лише для початково видимого допису — дає змогу двовісному URL вести просто до потрібного зображення мультимедійного допису. Ігнорується, щойно плеєр відкрито й користувач починає гортати.
isOpenbooleanrequiredКерує видимістю оверлея. Для стану відкриття, керованого URL, беріть окремий ReelPlayerUrlOverlay — дивіться розділ про стан в URL нижче.
timeline'auto' | 'always' | 'never''auto'Правило показу вбудованої смуги таймлайну. 'auto' показує її лише для відео, довших за timelineMinDurationSeconds; 'always' — щойно на активному слайді є відео; 'never' вимикає вбудовану смугу (для повної заміни беріть renderTimeline).
timelineMinDurationSecondsnumber30Мінімальна тривалість відео (у секундах), за якої timeline='auto' показує вбудовану смугу. Короткі зациклені кліпи нижче цього порогу не показують її.
renderControls(props: ControlsRenderProps) => ReactNode-Власні елементи керування, замінюють стандартні кнопки закриття та звуку
renderError(props: { item: T; activeIndex: number }) => ReactNode-Власний індикатор помилки, замінює стандартний значок
renderLoading(props: { item: T; activeIndex: number }) => ReactNode-Власний індикатор завантаження, замінює стандартну хвилю
renderNavigation(props: NavigationRenderProps) => ReactNode-Власна навігація, замінює стандартні вертикальні стрілки
renderNestedNavigation(props: NavigationRenderProps) => ReactNode-Власна навігація для вкладеного горизонтального слайдера (мультимедійні дописи), замінює стандартні стрілки ліворуч і праворуч
renderNestedSlide(props: NestedSlideRenderProps) => ReactNode-Власний рендерер слайдів вкладеного горизонтального слайдера. Через props.defaultContent можна загорнути або вбудувати стандартний ImageSlide чи VideoSlide. На відміну від renderSlide, null тут не означає повернення до стандартного.
renderSlide(props: SlideRenderProps) => ReactNode | null-Власний рендеринг слайда. Поверніть null, щоб лишити стандартний. Через props.defaultContent можна загорнути або вбудувати стандартний слайд.
renderSlideOverlay(item, index, isActive) => ReactNode-Власний оверлей для кожного слайда, замінює стандартний SlideOverlay. Поверніть null, щоб сховати.
renderTimeline(props: TimelineRenderProps) => ReactNode-Власна смуга таймлайну відтворення. Викликається лише тоді, коли за правилами показу вивелася б стандартна смуга (та сама логіка auto/always/never плюс timelineMinDurationSeconds). Через props.defaultContent можна загорнути вбудований <TimelineBar />; поверніть null, щоб сховати.

Пропси ReelPlayerUrlOverlay

ReelPlayerUrlOverlayProps<T>

Приймає всі візуальні та поведінкові пропси вище, крім isOpen, replaced by a controller. initialIndex ігнорується — слайд обирає position контролера, тож передане поруч значення перезаписується на кожному відкритті.

PropТипТипове значенняОпис
controllerUrlStateControllerrequiredКонтролер із useOverlayUrlState. Його position вирішує, чи оверлей відкритий і який слайд показує; оверлей записує через нього назад на зміну слайда та на закриття.

Колбеки

PropТипОпис
onClose() => voidВикликається, коли плеєр закривається. Обов’язковий у ReelPlayerOverlay (стан відкриття ваш, тож закриття обробляєте ви); необов’язковий у ReelPlayerUrlOverlay, де закриттям керує URL — передавайте лише щоб зреагувати після закриття.
onSlideChange(index: number) => voidВикликається після зміни слайда
onInnerSlideChange(outerIndex: number, innerIndex: number) => voidВикликається, коли змінюється індекс внутрішнього медіа активного допису — під час навігації всередині мультимедійного допису й під час активації зовнішнього, повідомляючи поточний внутрішній індекс активованого допису (0 для допису з одним медіа).

Пропси Reel (передані далі)

Ці пропси передаються далі в Reel component.

PropТипТипове значенняОпис
enableNavKeysbooleantrueВмикає навігацію з клавіатури
enableWheelbooleantrueВмикає навігацію колесом миші
loopbooleanfalseВмикає нескінченний цикл
swipeDistanceFactornumber0.12Поріг свайпу (0–1)
transitionDurationnumber300Тривалість анімації переходу (мс)
wheelDebounceMsnumber200Тривалість дебаунсу колеса (мс)

Types

BaseContentItem

Тип-обмеження для узагальнення. Розширюйте його, щоб використовувати власні типи даних із ReelPlayerOverlay.

typescript

ContentItem

typescript

MediaItem

typescript

MediaType

typescript

ControlsRenderProps<T>

typescript
typescript

SlideRenderProps<T>

typescript

NestedSlideRenderProps

typescript

SlideOverlayProps

typescript

ImageSlideProps

typescript

VideoSlideProps

typescript

CloseButtonProps

typescript

SoundButtonProps

typescript

TimelineBarProps

typescript

TimelineRenderProps<T>

typescript

Sub-Components

Повторно використовувані блоки, експортовані для складання власних render props:

CloseButton

Окрема кнопка закриття зі стандартними стилями плеєра. Використовуйте всередині renderControls.

tsx

SoundButton

Окремий перемикач звуку. Має бути всередині SoundProvider (ReelPlayerOverlay додає його автоматично).

tsx

TimelineBar

Стандартна смуга перемотування. Читає з найближчого TimelineProvider (автоматично монтується всередині ReelPlayerOverlay) and renders the track, buffered ranges, progress fill, and scrub pill. Theme via the --rk-reel-timeline-* власними властивостями або замініть через renderTimeline.

tsx

SlideOverlay

Стандартний градієнтний оверлей з автором, описом і лайками. Показується автоматично, коли у вмісті є потрібні поля. Через renderSlideOverlay його можна замінити або сховати.

tsx

ImageSlide

Слайд-зображення з лінивим завантаженням і object-fit: cover за замовчуванням. Використовуйте всередині renderSlide щоб складати власні слайди-зображення зі своїми стилями.

tsx

VideoSlide

Слайд-відео зі спільним елементом <video> заради безперервності звуку на iOS, з постерами, пам’яттю позиції та індикатором завантаження. Має бути всередині SoundProvider (ReelPlayerOverlay додає його автоматично).

tsx
Складання власних слайдів
Використовуйте renderSlide з ImageSlide / VideoSlide щоб змінити рендеринг медіа, зберігши всю вбудовану поведінку (автовідтворення, знімок постера, синхронізацію звуку).
tsx

Завантаження вмісту та обробка помилок

Плеєр стежить за станом завантаження й помилок кожного слайда. Поки вміст вантажиться, показується хвильовий індикатор; для зіпсованого медіа — значок помилки. URL з помилками кешуються, тож повторний перехід одразу показує помилку без нової спроби.

Колбеки життєвого циклу

Якщо ви використовуєте renderSlide, call these callbacks to control the loading indicator:

КолбекКоли викликати
onReadyЗображення завантажилося або відео почало грати. Скидає стани завантаження й помилки.
onWaitingВідео буферизується посеред відтворення. Показує індикатор завантаження.
onErrorВміст не завантажився. Показує оверлей помилки й кешує URL як зіпсований.
tsx

Власний інтерфейс завантаження та помилок

Замініть стандартний хвильовий індикатор і значок помилки власними компонентами:

tsx

Таймлайн

Оверлей показує вбудовану смугу таймлайну відтворення над активним відео. Пропс timeline визначає, коли її показувати:

  • 'auto' (типово): показується, коли активне медіа — відео, тривалість якого перевищує timelineMinDurationSeconds (типово 30). Працює і для слайдів з одним відео, і для мультимедійних каруселей; смуга слідує за активним вкладеним елементом і ховається на зображеннях.
  • 'always': показується, щойно на активному слайді є відео.
  • 'never': не показується ніколи. Власну смугу будуйте через renderTimeline.
tsx

Тему задавайте через власні властивості CSS --rk-reel-timeline-* (висота, кольори, розмір повзунка). Для повністю власної смуги перемотування, таймкоду чи індикатора прогресу беріть renderTimeline; the callback receives a timelineState на основі TimelineController.

Контекст звуку

Для власних реалізацій доступ до стану звуку відкритий:

tsx

Класи CSS

Усі класи CSS звичайні (не CSS-модулі), тож їх можна перекрити селекторами вищої специфічності в таблиці стилів, підключеній після @reelkit/react-reel-player/styles.css. Для змін кольору, розміру та z-index краще беріть власні властивості CSS, описані в розділі Theming нижче — вони саме для цього й зроблені.

ClassComponentОпис
.rk-reel-overlayOverlayФіксоване повноекранне тло (фон, z-index)
.rk-reel-containerOverlayКонтейнер плеєра (позиція, переповнення)
.rk-reel-loaderOverlayОверлей хвильової анімації завантаження
.rk-reel-media-errorOverlayОверлей стану помилки (значок і текст по центру)
.rk-reel-media-error-textOverlayТекст повідомлення про помилку
.rk-reel-buttonControlsСпільна кругла кнопка з іконкою (закриття, звук, стрілки)
.rk-reel-close-btnControlsКнопка закриття
.rk-reel-sound-btnControlsКнопка перемикання звуку
.rk-reel-nav-arrowsНавігаціяКонтейнер стрілок лише для десктопа (прихований до 768px)
.rk-reel-nav-buttonНавігаціяОкрема стрілка вперед або назад
.rk-reel-slide-wrapperSlideОбгортка навколо медіа та оверлея
.rk-reel-slide-overlaySlideOverlayКонтейнер градієнтного оверлея
.rk-reel-slide-overlay-authorSlideOverlayРядок автора (аватар та ім’я)
.rk-reel-slide-overlay-avatarSlideOverlayЗображення аватара автора
.rk-reel-slide-overlay-nameSlideOverlayТекст імені автора
.rk-reel-slide-overlay-descriptionSlideOverlayТекст опису
.rk-reel-slide-overlay-likesSlideOverlayРядок лайків (сердечко й лічильник)
.rk-reel-video-containerVideoSlideОбгортка відео (фон, переповнення)
.rk-reel-video-elementVideoSlideThe <video> element
.rk-reel-video-posterVideoSlideПостер (зникає з початком відтворення)
.rk-reel-video-poster.rk-visibleVideoSlideМодифікатор стану постера, поки відео на паузі або вантажиться
.rk-reel-nested-indicatorNestedSliderПагінація точками під мультимедійними слайдами (позиція різна на десктопі й на дотикових пристроях)
.rk-reel-nested-navNestedSliderСтрілки горизонтальної каруселі (приховані до 768px)
.rk-reel-nested-nav-nextNestedSliderПозиція вкладеної стрілки вперед
.rk-reel-nested-nav-prevNestedSliderПозиція вкладеної стрілки назад
.rk-reel-timelineTimelineBarОбгортка смуги перемотування. Використовуйте на власних коренях `renderTimeline`, щоб успадкувати притиснення до низу, відступи безпечної зони та проміжок для оверлея слайда на дотикових пристроях.
.rk-reel-timeline-trackTimelineBarДоріжка (невідтворена частина)
.rk-reel-timeline-bufferedTimelineBarШар буферизованих сегментів
.rk-reel-timeline-fillTimelineBarЗаповнення відтвореного прогресу
.rk-reel-timeline-cursorTimelineBarПовзунок перемотування (плаває над доріжкою)

Theming

Кожен колір, розмір, z-index і перехід живе у власній властивості CSS. Перевизначайте одну чи кілька на :root (або на будь-якому предку оверлея), щоб змінити тему, не чіпаючи код компонентів.

TokenТипове значенняControls
--rk-reel-overlay-bg#000Full-screen backdrop color
--rk-reel-overlay-z1000Overlay z-index
--rk-reel-button-bgrgba(0, 0, 0, 0.5)Default circular button background
--rk-reel-button-bg-hoverrgba(255, 255, 255, 0.1)Nav arrow background (and base hover state)
--rk-reel-button-bg-hover-strongrgba(255, 255, 255, 0.2)Nav arrow hover background
--rk-reel-button-fg#fffButton icon color
--rk-reel-button-size44pxButton width / height
--rk-reel-button-radius50%Button border-radius
--rk-reel-ui-z10Close / sound / nav z-index
--rk-reel-edge-padding16pxEdge inset for close / sound / nav arrows
--rk-reel-nav-gap8pxSpacing between stacked nav arrows
--rk-reel-transition0.2sHover transition duration
--rk-reel-loader-colorrgba(255, 255, 255, 0.12)Wave loader gradient color
--rk-reel-loader-duration1.8sWave loader animation duration
--rk-reel-error-fgrgba(255, 255, 255, 0.4)Error icon and text color
--rk-reel-error-text-size13pxError message font size
--rk-reel-slide-overlay-bglinear-gradient(transparent, rgba(0, 0, 0, 0.7))Caption scrim gradient
--rk-reel-slide-overlay-padding48px 16px 16pxCaption inner padding
--rk-reel-slide-overlay-name-color#fffAuthor name color
--rk-reel-slide-overlay-description-colorrgba(255, 255, 255, 0.9)Description text color
--rk-reel-slide-overlay-likes-colorrgba(255, 255, 255, 0.8)Likes row text color
--rk-reel-video-bg#000Letterbox background behind <video>
--rk-reel-nested-button-bgrgba(0, 0, 0, 0.5)Nested arrow background
--rk-reel-nested-button-bg-hoverrgba(255, 255, 255, 0.2)Nested arrow hover background
--rk-reel-nested-button-size36pxNested arrow size
--rk-reel-nested-edge-padding12pxNested arrow edge inset
--rk-reel-timeline-trackrgba(255, 255, 255, 0.22)Track background (unplayed region)
--rk-reel-timeline-bufferedrgba(255, 255, 255, 0.4)Buffered segments color
--rk-reel-timeline-fill#fffPlayed-progress fill color
--rk-reel-timeline-cursor#fffScrub-handle pill color
--rk-reel-timeline-height3pxTrack height at rest
--rk-reel-timeline-height-active6pxTrack height on hover / focus / scrub
--rk-reel-timeline-cursor-width10pxScrub-pill width at rest
--rk-reel-timeline-cursor-width-active14pxScrub-pill width while scrubbing
--rk-reel-timeline-cursor-height24pxScrub-pill height at rest
--rk-reel-timeline-cursor-height-active32pxScrub-pill height while scrubbing
--rk-reel-timeline-hitbox16pxExtra pointer hit-area above the track
--rk-reel-timeline-transition0.15s ease-outTrack + pill grow/shrink animation
--rk-reel-timeline-z11Timeline z-index (above the default UI layer)

Вставте фрагмент нижче в таблицю стилів, підключену після @reelkit/react-reel-player/styles.css.

css

Accessibility

Корінь оверлея — модальний діалог (role="dialog", aria-modal="true"). Set ariaLabel щоб змінити оголошення для екранного читача; типове значення — «Video player». Кожен слайд несе role="group", aria-roledescription="slide", and an aria-label="Слайд N з M", so swiping announces position in the sequence.

Оверлей захоплює фокус під час відкриття й повертає його на елемент-тригер після закриття. Tab і Shift+Tab циклічно проходять фокусовані елементи всередині; фокус, що вислизнув (клік поза оверлеєм, програмна установка), повертається назад. Реалізовано через captureFocusForReturn та createFocusTrap from @reelkit/core.

Клавіатурні скорочення

KeyAction
ArrowUpPrevious slide
ArrowDownNext slide
ArrowLeftPrevious media (in nested slider)
ArrowRightNext media (in nested slider)
EscapeClose player