Reel Player для Angular
Повноекранний вертикальний медіаплеєр у стилі Instagram чи TikTok для Angular на основі @reelkit/angular-reel-player.
Features
Встановлення
npm install @reelkit/angular-reel-player @reelkit/angular lucide-angularЗареєструйте таблицю стилів один раз:
// Anywhere that runs at startup — main.ts, app.config.ts, a component file.
import '@reelkit/angular-reel-player/styles.css';
// Or, if you keep CSS out of TypeScript, from your global stylesheet:
// @import '@reelkit/angular-reel-player/styles.css';
// Or register it in angular.json:
// "styles": ["node_modules/@reelkit/angular-reel-player/styles.css"]Icons
Стандартні елементи керування використовують lucide-angular для іконок (закриття, звук, стрілки навігації). Якщо ви віддаєте перевагу іншій бібліотеці іконок, скористайтеся слотами rkPlayerControls та rkPlayerNavigation щоб передати власні.
Швидкий старт
Імпортуйте таблицю стилів і автономний RkReelPlayerOverlayComponent у imports array.
import { Component, signal } from '@angular/core';
import {
RkReelPlayerOverlayComponent,
type ContentItem,
} from '@reelkit/angular-reel-player';
import '@reelkit/angular-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 content',
},
{
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-02.mp4',
poster: '/cdn/samples/videos/video-poster-02.jpg',
aspectRatio: 16 / 9,
}],
author: { name: 'Mike Chen', avatar: '/cdn/samples/avatars/avatar-03.jpg' },
likes: 3456,
description: 'Adventure awaits',
},
];
@Component({
selector: 'app-root',
standalone: true,
imports: [RkReelPlayerOverlayComponent],
template: `
<!-- Grid thumbnail view -->
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px">
@for (item of content; track item.id; let i = $index) {
<button
(click)="openAt(i)"
style="aspect-ratio:9/16;cursor:pointer;overflow:hidden"
>
<img
[src]="item.media[0].poster || item.media[0].src"
style="width:100%;height:100%;object-fit:cover"
/>
</button>
}
</div>
<rk-reel-player-overlay
[isOpen]="isOpen()"
[content]="content"
[initialIndex]="startIndex()"
(closed)="isOpen.set(false)"
/>
`,
})
export class AppComponent {
readonly content = content;
readonly isOpen = signal(false);
readonly startIndex = signal(0);
openAt(index: number): void {
this.startIndex.set(index);
this.isOpen.set(true);
}
}Де рендериться оверлей
На відміну від плеєрів React і Vue, які переносять свій оверлей у кінець document.body, rk-reel-player-overlay рендериться там, де ви його розмістили, і накриває екран через position: fixed. Не кладіть його всередину предка з transform, perspective, filter або will-change: transform: такий предок стає блоком-контейнером оверлея, тож плеєр отримує розмір предка замість вікна й обрізається його overflow. Предок, що створює власний контекст накладання, також обмежує, наскільки високо --rk-reel-overlay-z може підняти плеєр. Натомість токени --rk-reel-*, задані на будь-якому предку, доходять до плеєра.
Шаблонні слоти
Шість директив шаблонних слотів дають налаштувати будь-яку частину інтерфейсу плеєра. Кожна отримує строго типізований об’єкт контексту. Задавайте лише ті слоти, які хочете перекрити — для решти лишиться стандартний вигляд.
| Directive | Тип контексту | Опис |
|---|---|---|
| [rkPlayerControls] | PlayerControlsContext<T> | Власна загальна смуга керування (закриття, перемикач звуку тощо); клас директиви — RkPlayerControlsDirective |
| [rkPlayerError] | PlayerErrorContext | Шаблонний слот власного індикатора помилки; клас директиви — RkPlayerErrorDirective |
| [rkPlayerLoading] | PlayerLoadingContext | Шаблонний слот власного індикатора завантаження; клас директиви — RkPlayerLoadingDirective |
| [rkPlayerNavigation] | PlayerNavigationContext | Власні стрілки навігації вперед і назад; клас директиви — RkPlayerNavigationDirective |
| [rkPlayerNestedNavigation] | PlayerNestedNavigationContext | Власні стрілки навігації для внутрішнього горизонтального слайдера; клас директиви — RkPlayerNestedNavigationDirective |
| [rkPlayerNestedSlide] | PlayerNestedSlideContext | Власний вміст кожного слайда всередині внутрішнього горизонтального слайдера; клас директиви — RkPlayerNestedSlideDirective |
| [rkPlayerSlide] | PlayerSlideContext<T> | Повністю власний вміст слайда, що замінює стандартний медіаслайд; клас директиви — RkPlayerSlideDirective |
| [rkPlayerSlideOverlay] | PlayerSlideOverlayContext<T> | Оверлей для кожного слайда (дані автора, лайки, опис тощо); клас директиви — RkPlayerSlideOverlayDirective |
| [rkPlayerTimeline] | PlayerTimelineContext<T> | Власна смуга таймлайну відтворення. Показується лише тоді, коли за правилом (режим timeline плюс мінімальна тривалість) вивелася б стандартна смуга — логіка auto/always/never та сама. Клас директиви — RkPlayerTimelineDirective |
PLAYER_TEMPLATE_SLOT_DIRECTIVES збирає всі ці директиви, тож компонент може одним махом розгорнути їх у свої imports.
import {
RkReelPlayerOverlayComponent,
RkPlayerSlideOverlayDirective,
RkPlayerControlsDirective,
RkPlayerNavigationDirective,
RkCloseButtonComponent,
RkSoundButtonComponent,
type ContentItem,
type PlayerSlideOverlayContext,
type PlayerControlsContext,
type PlayerNavigationContext,
} from '@reelkit/angular-reel-player';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RkReelPlayerOverlayComponent,
RkPlayerSlideOverlayDirective,
RkPlayerControlsDirective,
RkPlayerNavigationDirective,
RkCloseButtonComponent,
RkSoundButtonComponent,
],
template: `
<rk-reel-player-overlay
[isOpen]="isOpen"
[content]="content"
(closed)="isOpen = false"
>
<!-- Custom per-slide overlay: author + likes -->
<ng-template rkPlayerSlideOverlay let-item let-isActive="isActive">
@if (isActive) {
<div style="position:absolute;bottom:80px;left:16px;color:#fff">
<div style="display:flex;align-items:center;gap:8px">
<img [src]="item.author.avatar" style="width:40px;height:40px;border-radius:50%" />
<span style="font-weight:600">{{ item.author.name }}</span>
</div>
<p style="margin-top:8px">{{ item.description }}</p>
</div>
}
</ng-template>
<!-- Custom global controls -->
<ng-template rkPlayerControls
let-onClose
let-soundState="soundState">
<div style="position:absolute;top:16px;right:16px;display:flex;gap:8px">
<rk-sound-button [soundState]="soundState" />
<rk-close-button (click)="onClose()" />
</div>
</ng-template>
<!-- Custom navigation -->
<ng-template rkPlayerNavigation
let-onPrev
let-onNext="onNext"
let-activeIndex="activeIndex"
let-count="count">
<div style="position:absolute;right:16px;top:50%;transform:translateY(-50%)">
<button (click)="onPrev()" [disabled]="activeIndex === 0">▲</button>
<button (click)="onNext()" [disabled]="activeIndex === count - 1">▼</button>
</div>
</ng-template>
<!-- Custom playback timeline -->
<ng-template rkPlayerTimeline let-state="timelineState">
<div class="rk-reel-timeline" style="padding:0 16px"
(pointerdown)="bindTrack(track, state); track.focus()">
<div #track
role="slider"
[attr.aria-valuenow]="state.currentTime()"
style="height:6px;background:rgba(255,255,255,0.2);border-radius:999px">
<div [style.width.%]="state.progress() * 100"
style="height:100%;background:linear-gradient(90deg,#6366f1,#ec4899);border-radius:999px"></div>
</div>
</div>
</ng-template>
</rk-reel-player-overlay>
`,
})
export class AppComponent {
isOpen = false;
content: ContentItem[] = [];
private _trackDispose: (() => void) | null = null;
/** Wire pointer + keyboard scrub onto your custom track element. */
bindTrack(el: HTMLElement, state: PlayerTimelineState) {
this._trackDispose?.();
this._trackDispose = state.bindInteractions(el);
}
}Стандартні компоненти слайда
Частини, з яких складено стандартний слайд. Кожна — самостійний компонент; використайте його у власному шаблоні, щоб зберегти частину стандартного вигляду.
| Компонент | Селектор | Опис |
|---|---|---|
RkMediaSlideComponent | rk-media-slide | Стандартний слайд. Рендерить rk-image-slide, rk-video-slide або rk-nested-slider залежно від media елемента вмісту; використайте його в шаблоні rkPlayerSlide, щоб зберегти стандартне медіа й додати поверх власний шар. |
RkImageSlideComponent | rk-image-slide | Одне зображення з object-fit: cover: показує свій poster, доки завантажується, і викликає onReady, onWaiting або onError. |
RkVideoSlideComponent | rk-video-slide | Одне відео на спільному елементі <video>. Потребує SoundStateService, який надає оверлей, тож рендерте його лише всередині плеєра. |
RkNestedSliderComponent | rk-nested-slider | Горизонтальний слайдер з точками-індикаторами для елемента вмісту з кількома записами media. |
RkSlideOverlayComponent | rk-slide-overlay | Стандартний нижній оверлей: аватар та ім’я автора, опис і лайки з його входів author, description і likes. Використайте його в шаблоні rkPlayerSlideOverlay, щоб зберегти стандартний вигляд. |
Власний таймлайн
The rkPlayerTimeline викликається лише тоді, коли за правилами показу оверлей вивів би стандартну смугу (та сама логіка timeline плюс timelineMinDurationSeconds), so you don't re-implement it. Reuse the .rk-reel-timeline на своєму корені, щоб успадкувати притиснення до низу, відступи безпечної зони та проміжок на дотикових пристроях. Викличте state.bindInteractions(el) на своїй доріжці перемотування, щоб підключити перемотування вказівником і клавіатурою.
Вкладений слайдер (мультимедійні елементи)
Коли ContentItem містить кілька записів media , плеєр показує їх у вкладеному горизонтальному слайдері (як карусель Instagram). Через слот rkPlayerNestedSlide можна налаштувати вміст внутрішнього слайда.
const carouselItem: ContentItem = {
id: '3',
media: [
{ id: 'img-a', type: 'image', src: '/photo-a.jpg', aspectRatio: 2 / 3 },
{ id: 'img-b', type: 'image', src: '/photo-b.jpg', aspectRatio: 3 / 4 },
{ id: 'img-c', type: 'image', src: '/photo-c.jpg', aspectRatio: 1 },
],
author: { name: 'Emma Davis', avatar: '/avatar3.jpg' },
likes: 8901,
description: 'Travel moments',
};Завантаження вмісту та обробка помилок
Плеєр стежить за станом завантаження й помилок кожного слайда. Поки вміст вантажиться, показується хвильовий індикатор; для зіпсованого медіа — значок помилки. URL з помилками кешуються, тож повторний перехід одразу показує помилку без нової спроби.
Колбеки життєвого циклу
Коли використовуєте слот rkPlayerSlide , керуйте індикатором завантаження через колбеки контексту:
| Колбек | Коли викликати |
|---|---|
onReady | Зображення завантажилося або відео почало грати. Скидає стани завантаження й помилки. |
onWaiting | Відео буферизується посеред відтворення. Показує індикатор завантаження. |
onError | Вміст не завантажився. Показує оверлей помилки й кешує URL як зіпсований. |
<!-- Wire lifecycle callbacks in a custom slide template -->
<rk-reel-player-overlay [isOpen]="isOpen" [content]="items" (closed)="isOpen = false">
<ng-template rkPlayerSlide
let-item
let-size="size"
let-isActive="isActive"
let-onReady="onReady"
let-onWaiting="onWaiting"
let-onError="onError"
>
@if (item.media[0].type === 'image') {
<img
[src]="item.media[0].src"
(load)="onReady()"
(error)="onError()"
[style.width.px]="size[0]"
[style.height.px]="size[1]"
style="object-fit: cover"
/>
} @else {
<video
[src]="item.media[0].src"
[autoplay]="isActive"
(canplay)="onReady()"
(waiting)="onWaiting()"
(error)="onError()"
[style.width.px]="size[0]"
[style.height.px]="size[1]"
style="object-fit: cover"
/>
}
</ng-template>
</rk-reel-player-overlay>Власний інтерфейс завантаження та помилок
Замініть стандартний хвильовий індикатор і значок помилки власними шаблонами:
<rk-reel-player-overlay [isOpen]="isOpen" [content]="items" (closed)="isOpen = false">
<ng-template rkPlayerLoading let-index let-item="item">
<div style="
position: absolute; inset: 0; z-index: 10;
display: flex; align-items: center; justify-content: center;
color: #fff; font-size: 14px;
">
Loading slide {{ index + 1 }}...
</div>
</ng-template>
<ng-template rkPlayerError let-index let-item="item">
<div style="
position: absolute; inset: 0; z-index: 10;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
gap: 12px; color: rgba(255,255,255,0.5);
">
<span style="font-size: 48px">!</span>
<span>Failed to load media</span>
</div>
</ng-template>
</rk-reel-player-overlay>Таймлайн
Оверлей показує вбудовану смугу таймлайну відтворення над активним відео. Керуйте показом через пропс timeline : 'auto' (типово) показує її, коли активне медіа — відео, довше за timelineMinDurationSeconds (default 30), 'always' щойно активне відео, 'never' вимикає її. Для повністю власної смуги перемотування беріть слот rkPlayerTimeline ; його контекст відкриває timelineState на основі TimelineController.
<rk-reel-player-overlay
[isOpen]="isOpen()"
[content]="items"
timeline="auto"
[timelineMinDurationSeconds]="30"
(closed)="isOpen.set(false)"
/>Тему задавайте через власні властивості CSS --rk-reel-timeline-* власними властивостями CSS. Для прямого керування у власних компонентах-споживачах впроваджуйте TimelineStateService.
RkTimelineBarComponent
Стандартний компонент смуги перемотування. Використовує TimelineStateService (його надає RkReelPlayerOverlayComponent) and renders the track, buffered ranges, progress fill, and scrub pill. Selector: rk-timeline-bar. Входи: class?: string, style?: Record<string, string>. Використовуйте всередині шаблону rkPlayerTimeline щоб загорнути або доповнити стандартну смугу; окремо — лише всередині споживача, який надає цей сервіс.
import { RkTimelineBarComponent } from '@reelkit/angular-reel-player';
@Component({
standalone: true,
imports: [RkReelPlayerOverlayComponent, RkTimelineBarComponent],
template: `
<rk-reel-player-overlay [isOpen]="isOpen()" [content]="items">
<!-- Wrap or augment the default bar: -->
<ng-template rkPlayerTimeline>
<my-timecode />
<rk-timeline-bar />
</ng-template>
</rk-reel-player-overlay>
`,
})
export class AppComponent {}SoundStateService
Надається на рівні RkReelPlayerOverlayComponent . Впроваджується стандартною кнопкою звуку й відкривається в контексті шаблонного слота елементів керування. Можна впровадити у власні елементи керування, що є children оверлея, для прямого доступу.
import { inject } from '@angular/core';
import { SoundStateService } from '@reelkit/angular-reel-player';
@Component({ ... })
export class AppComponent {
readonly soundState = inject(SoundStateService);
// Use in template:
// [class.muted]="soundState.muted()"
// [disabled]="soundState.disabled()"
// (click)="soundState.toggle()"
}| Член | Тип | Опис |
|---|---|---|
muted() | Signal<boolean> | Чи вимкнено звук просто зараз |
disabled() | Signal<boolean> | True, коли на активному слайді немає відео або триває перехід |
toggle() | () => void | Перемикає стан звуку |
Стан в URL
Подивитися демо наживо →RkReelPlayerUrlOverlayComponent — окремий компонент, стан відкриття якого живе в адресному рядку. Побудуйте контролер через createOverlayUrlState у контексті впровадження й передайте його як [controller]: плеєр відкривається, коли параметр називає слайд, і закривається, коли параметр зникає. Посиланнями можна ділитися, а кнопка «назад» закриває плеєр. RkReelPlayerOverlayComponent stays [isOpen], тож кожен компонент має рівно один драйвер стану відкриття.
Вбудовані клавіші
Слайди можна адресувати вбудованим ключем — розгорніть urlIndexKey (за позицією) або urlStableIdKey (за стабільним id) into the controller — both re-exported from @reelkit/angular. See the посібник зі стану в URL та API ядра.
Застосунок із роутером передає адаптер на базі Router, щоб той лишався єдиним джерелом правди про навігацію: запис в історію повз нього лишає його місцеположення застарілим і втрачає параметр на наступній навігації. createRouterUrlAdapter from @reelkit/angular/ng-router-url-adapter — готовий адаптер.
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import {
RkReelPlayerUrlOverlayComponent,
type ContentItem,
} from '@reelkit/angular-reel-player';
import { createOverlayUrlState, urlIndexKey, urlStableIdKey } from '@reelkit/angular';
import { createRouterUrlAdapter } from '@reelkit/angular/ng-router-url-adapter';
import '@reelkit/angular-reel-player/styles.css';
@Component({
standalone: true,
imports: [RkReelPlayerUrlOverlayComponent, RouterLink],
template: `
@for (post of content; track post.id; let i = $index) {
<a [routerLink]="[]" [queryParams]="{ reel: i }">{{ post.id }}</a>
}
<rk-reel-player-url-overlay [controller]="reel" [content]="content" />
`,
})
export class FeedComponent {
content: ContentItem[] = [/* ... */];
protected readonly reel = createOverlayUrlState({
param: 'reel',
adapter: createRouterUrlAdapter(),
...urlIndexKey(() => this.content.length),
});
}- Відкриття додає один запис в історію. Свайп стрічки замінює його, тож N свайпів не додають записів, і один крок назад завжди виходить із плеєра. «Назад» закриває, а не гортає слайди.
- «Назад» закриває лише тоді, коли плеєр відкрили всередині застосунку — посилання додало запис. За надісланим посиланням у новій вкладці історії позаду немає, тож кнопка «назад» виведе із сайту; кнопка ✕ або Escape прибирає параметр на місці й лишає вас на сторінці.
- Пряме посилання
?reel=3відкриває плеєр одразу на цьому слайді. - Параметр, який не називає жодного слайда — застаріла закладка, змінене вручну значення, — прибирається з URL, а не лишає в адресному рядку слайд, який не відкриється.
- Глибина URL залежить від ключа контролера: одна вісь для самого допису або дві (
urlIndexTwoAxisKey) to also carry a multi-media post’s inner image index. Pick one key per app; the shapes do not cross-decode.
Full createOverlayUrlState опції — у довіднику API для Angular.
Один ключ чи два — оберіть глибину URL
Той самий RkReelPlayerUrlOverlayComponent працює з обома формами; він розрізняє їх під час виконання за position контролера, тож жодного входу режиму немає. Ключ обирайте, коли будуєте контролер:
| Key | Wire | Carries |
|---|---|---|
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.
import { createOverlayUrlState, urlIndexTwoAxisKey } from '@reelkit/angular';
protected readonly reel = createOverlayUrlState({
param: 'reel',
...urlIndexTwoAxisKey({
outerCount: () => this.content.length,
innerCounts: () => this.content.map((post) => post.media.length),
}),
});
// A link now names both axes: post 3, inner media 2 — ?reel=3.2Стабільні посилання. Індекс адресує за позицією, тож збережений у закладках ?reel=3 відкриє інший допис, щойно стрічку перевпорядкують — а для стрічки це радше правило. urlStableIdKey адресує за стабільним id, scanning the live feed — one call covers the common case.
protected readonly reel = createOverlayUrlState({
param: 'reel',
...urlStableIdKey({ items: () => this.loaded() }),
});Pass hashCodec: base64UrlCodec щоб закодувати id в URL у base64url — оборотне маскування, а не криптографічний хеш.
Адресуєте за іншим полем ( slug), or page an infinite feed with locateAsync, and build the codec/locator самі. Дві окремі задачі: codec записує ідентичність в URL, locator знаходить, де ця ідентичність лежить.
protected readonly reel = createOverlayUrlState({
param: 'reel',
codec: { decode: (raw) => raw, encode: (id) => id },
locator: {
locate: (id) => this.loaded().findIndex((x) => x.id === id),
identify: (index) => this.loaded()[index].id,
},
});Нескінченні стрічки. locate синхронний, тож відповідає лише за вже завантажені дописи — надіслане посилання на допис 400 у стрічці, де завантажено 20, нічого не знайде. locateAsync — запасний варіант, що викликається лише коли locate не знаходить: завантажте потрібні сторінки й поверніть індекс, який ця ідентичність отримала.
Shortcut
Keying by the item’s id? Не пишіть кодек і локатор вручну — передайте locateAsync просто в urlStableIdKey({ items, locateAsync }) (він вантажить дані, якщо не знайшов, і повертає індекс). Розгорнутий варіант нижче — для адресації за іншим полем або для повного контролю.
protected readonly reel = createOverlayUrlState({
param: 'reel',
adapter: createRouterUrlAdapter(),
codec: { decode: (raw) => raw, encode: (id) => id },
locator: {
locate: (id) => this.loaded().findIndex((x) => x.id === id),
identify: (index) => this.loaded()[index].id,
locateAsync: async (id) => {
const page = await this.loadById(id); // or loadUntil(id) — fetch just that one, or page up to it
if (!page) return null; // exhausted — link names no post
this.loaded.set(page); // commit — the overlay renders from this state
return page.findIndex((x) => x.id === id);
},
},
});- While
locateAsyncу процесі, плеєр лишається закритим, а параметр — недоторканим, тож пряме посилання переживає запит.nullабо відмова прибирає параметр. - Відповідь, що приходить після зміни URL, після закриття або після демонтажу, відкидається — повільний запит не відкриє слайд, якого ніхто не просив.
- Поки триває очікування, нічого не рендериться: цей стан завантаження вже належить сторінці, тож малюйте власний скелетон.
- Тайм-ауту немає — плеєр не може знати, яка стрічка завдовжки. Завершуйте значенням
nullколи сторінки скінчилися, інакше оверлей лишиться закритим назавжди.
Власні типи даних
Extend BaseContentItem щоб узяти власну доменну модель. Компонент узагальнений: RkReelPlayerOverlayComponent<T extends BaseContentItem>.
import type { BaseContentItem } from '@reelkit/angular-reel-player';
interface MyPost extends BaseContentItem {
// id: string — from BaseContentItem
// media: MediaItem[] — from BaseContentItem
title: string;
tags: string[];
publishedAt: Date;
}
@Component({
imports: [RkReelPlayerOverlayComponent],
template: `
<rk-reel-player-overlay [isOpen]="isOpen" [content]="posts" (closed)="isOpen = false">
<ng-template rkPlayerSlideOverlay let-post let-isActive="isActive">
@if (isActive) {
<div style="position:absolute;bottom:80px;left:16px;color:#fff">
<h3>{{ post.title }}</h3>
@for (tag of post.tags; track tag) {
<span>#{{ tag }} </span>
}
</div>
}
</ng-template>
</rk-reel-player-overlay>
`,
})
export class AppComponent {
isOpen = false;
posts: MyPost[] = [];
}Входи RkReelPlayerOverlayComponent
| Input | Тип | Типове значення | Опис |
|---|---|---|---|
ariaLabel | string | 'Video player' | Доступна назва області діалогу |
aspectRatio | number | undefined | undefined | Співвідношення ширини до висоти контейнера на десктопі. Типово 9/16; це ж значення замінює нульове, від’ємне чи нескінченне. На ширині 768px і вужче плеєр займає всю область перегляду. |
content | T[] (extends BaseContentItem) | required | Масив елементів вмісту для показу в плеєрі |
enableNavKeys | boolean | true | Вмикає навігацію стрілками клавіатури |
enableWheel | boolean | true | Вмикає навігацію колесом миші |
initialIndex | number | 0 | Індекс початково видимого елемента, від нуля |
initialInnerIndex | number | 0 | Індекс внутрішнього медіа, з якого відкриватися, лише для початково видимого допису — дає змогу двовісному URL вести просто до потрібного зображення мультимедійного допису. Ігнорується, щойно користувач починає гортати. |
isOpen | boolean | required | Керує видимістю оверлея; якщо false, оверлей прибирається з DOM |
loop | boolean | false | Вмикає нескінченний цикл між слайдами |
swipeDistanceFactor | number | 0.12 | Мінімальна частка відстані свайпу, щоб змінити слайд |
timeline | TimelineMode ('auto' | 'always' | 'never') | 'auto' | Правило показу вбудованої смуги таймлайну. 'auto' показує її лише для відео, довших за timelineMinDurationSeconds; 'always' — щойно на активному слайді є відео; 'never' вимикає вбудовану смугу (для повної заміни беріть шаблонний слот rkPlayerTimeline). |
timelineMinDurationSeconds | number | 30 | Мінімальна тривалість відео (у секундах), за якої timeline='auto' показує вбудовану смугу. Короткі зациклені кліпи нижче цього порогу не показують її. |
transitionDuration | number | 300 | Тривалість анімації слайда в мілісекундах |
wheelDebounceMs | number | 200 | Тривалість дебаунсу подій колеса в мілісекундах |
Виходи RkReelPlayerOverlayComponent
| Output | Тип | Опис |
|---|---|---|
apiReady | EventEmitter<ReelApi> | Видається, коли слайдер готовий, і відкриває імперативний API |
closed | EventEmitter<void> | Видається, коли плеєр закрито |
slideChange | EventEmitter<number> | Видається, коли змінюється індекс активного слайда |
innerSlideChange | EventEmitter<{ outer: number; inner: number }> | Видається, коли змінюється індекс внутрішнього медіа активного допису — під час внутрішньої навігації та під час активації зовнішнього, повідомляючи поточний внутрішній індекс активованого допису (0 для допису з одним медіа). |
Входи RkReelPlayerUrlOverlayComponent
Приймає всі входи вище, крім isOpen та initialIndex, replaced by a controller position якого обирає слайд. Виходи closed та slideChange.
| Input | Тип | Типове значення | Опис |
|---|---|---|---|
controller | UrlStateController | required | Контролер із createOverlayUrlState. Its позицією вирішує, чи плеєр відкритий і який слайд показує; оверлей записує через нього назад на зміну слайда та на закриття. |
Інтерфейс MediaItem
| Field | Тип | Опис |
|---|---|---|
id | string | Унікальний ідентифікатор медіаелемента |
type | MediaType | Тип медіа: 'image' | 'video' |
src | string | URL медіафайлу |
poster | string? | URL мініатюри-постера для елементів-відео |
aspectRatio | number | співвідношення ширини до висоти. Значення < 1 означають вертикальне (cover), > 1 — горизонтальне (contain) |
Типи контексту шаблонних слотів
| Тип | Fields |
|---|---|
PlayerControlsContext<T> | { $implicit: onClose, activeIndex, content: T[], soundState: PlayerSoundState } |
PlayerNavigationContext | { $implicit: onPrev, onNext, activeIndex, count } |
PlayerNestedNavigationContext | { $implicit: onPrev, onNext, activeIndex, count } |
PlayerNestedSlideContext | { $implicit: MediaItem, index, size, isActive, isInnerActive, slideKey } |
PlayerSlideContext<T> | { $implicit: T, index, size: [number,number], isActive, slideKey, onReady, onWaiting, onError } |
PlayerSlideOverlayContext<T> | { $implicit: T, index, isActive } |
PlayerTimelineContext<T> | { $implicit: T, activeIndex, timelineState: PlayerTimelineState } |
PlayerTimelineState | { duration(), currentTime(), progress(), bufferedRanges(), isScrubbing(), seek(t), bindInteractions(el) } |
PlayerBufferedRange | { start, end } у секундах — один запис bufferedRanges() |
PlayerLoadingContext | { $implicit: activeIndex, item, innerActiveIndex } — що отримує шаблон rkPlayerLoading; innerActiveIndex дорівнює null поза вкладеним слайдером |
PlayerErrorContext | { $implicit: activeIndex, item, innerActiveIndex } — що отримує шаблон rkPlayerError |
Класи CSS
Усі класи CSS звичайні (не scoped), тож їх можна перекрити селекторами вищої специфічності в таблиці стилів, підключеній після @reelkit/angular-reel-player/styles.css. Для змін кольору, розміру та z-index краще беріть власні властивості CSS, описані в розділі Theming нижче — вони саме для цього й зроблені.
| Class | Component | Опис |
|---|---|---|
.rk-reel-overlay | Overlay | Фіксоване повноекранне тло (фон, z-index) |
.rk-reel-container | Overlay | Конт ейнер плеєра (позиція, переповнення) |
.rk-reel-loader | Overlay | Оверлей хвильової анімації завантаження |
.rk-reel-media-error | Overlay | Оверлей стану помилки (значок і текст по центру) |
.rk-reel-media-error-text | Overlay | Текст повідомлення про помилку |
.rk-reel-button | Controls | Спільна кругла кнопка з іконкою (закриття, звук, стрілки) |
.rk-reel-close-btn | Controls | Кнопка закриття |
.rk-reel-sound-btn | Controls | Кнопка перемикання звуку |
.rk-reel-nav-arrows | Навігація | Контейнер стрілок лише для десктопа (прихований на ширині 768px і вужче) |
.rk-reel-nav-btn | Навігація | Окрема стрілка вперед або назад |
.rk-reel-slide-wrapper | Slide | Обгортка навколо медіа та оверлея |
.rk-reel-slide-overlay | SlideOverlay | Контейнер градієнтного оверлея |
.rk-reel-slide-overlay-author | SlideOverlay | Рядок автора (аватар та ім’я) |
.rk-reel-slide-overlay-avatar | SlideOverlay | Зображення аватара автора |
.rk-reel-slide-overlay-name | SlideOverlay | Текст імені автора |
.rk-reel-slide-overlay-description | SlideOverlay | Текст опису |
.rk-reel-slide-overlay-likes | SlideOverlay | Рядок лайків (сердечко й лічильник) |
.rk-reel-video-container | VideoSlide | Обгортка відео (фон, переповнення) |
.rk-reel-video-element | VideoSlide | Елемент <video> |
.rk-reel-video-poster | VideoSlide | Постер (зникає з початком відтворення) |
.rk-reel-video-loader | VideoSlide | Хвильова анімація завантаження |
.rk-reel-video-poster.rk-visible | VideoSlide | Модифікатор стану постера, поки відео на паузі або вантажиться |
.rk-reel-nested-indicator | NestedSlider | Пагінація точками під мультимедійними слайдами (позиція різна на десктопі й на дотикових пристроях) |
.rk-reel-nested-nav | NestedSlider | Стрілки горизонтальної каруселі (приховані на ширині 768px і вужче) |
.rk-reel-nested-nav-next | NestedSlider |