@vkontakte/videoplayer 1.1.98-beta.0 → 1.1.98-dev.652aecfe7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/es2015.cjs +10 -10
  2. package/es2015.esm.js +10 -10
  3. package/esnext.cjs +10 -10
  4. package/esnext.esm.js +9 -9
  5. package/evergreen.esm.js +10 -10
  6. package/package.json +8 -8
  7. package/types/VKVideoPlayer/index.svelte.d.ts +4 -0
  8. package/types/components/Controls/useControlInLayout.svelte.d.ts +20 -0
  9. package/types/components/Controls/useControlVariant.svelte.d.ts +13 -0
  10. package/types/config.d.ts +0 -1
  11. package/types/index.d.ts +2 -0
  12. package/types/store/composition.d.ts +2 -1
  13. package/types/store/modules/controlsLayoutStore/config/controls.config.d.ts +21 -0
  14. package/types/store/modules/controlsLayoutStore/config/features.config.d.ts +33 -0
  15. package/types/store/modules/controlsLayoutStore/config/index.d.ts +10 -0
  16. package/types/store/modules/controlsLayoutStore/config/positions.d.ts +28 -0
  17. package/types/store/modules/controlsLayoutStore/config/priority.d.ts +11 -0
  18. package/types/store/modules/controlsLayoutStore/config/resolver.d.ts +20 -0
  19. package/types/store/modules/controlsLayoutStore/config/utils.d.ts +32 -0
  20. package/types/store/modules/controlsLayoutStore/controlsLayoutStore.module.d.ts +3 -0
  21. package/types/store/modules/controlsLayoutStore/controlsLayoutStore.store.d.ts +54 -0
  22. package/types/store/modules/controlsLayoutStore/controlsLayoutStore.token.d.ts +6 -0
  23. package/types/store/modules/controlsLayoutStore/index.d.ts +10 -0
  24. package/types/store/modules/controlsLayoutStore/types.d.ts +140 -0
  25. package/types/store/modules/controlsLayoutStore/variants.d.ts +15 -0
  26. package/types/store/modules/index.d.ts +3 -0
  27. package/types/store/types.d.ts +5 -0
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@vkontakte/videoplayer",
3
- "version": "1.1.98-beta.0",
4
- "author": "vk.ru",
5
- "description": "Videoplayer based on the vk.ru platform",
6
- "homepage": "https://vk.ru",
3
+ "version": "1.1.98-dev.652aecfe7.0",
4
+ "author": "vk.com",
5
+ "description": "Videoplayer based on the vk.com platform",
6
+ "homepage": "https://vk.com",
7
7
  "license": "GPL-3.0",
8
8
  "main": "./esnext.cjs",
9
9
  "module": "./esnext.esm.js",
@@ -43,9 +43,9 @@
43
43
  ],
44
44
  "dependencies": {
45
45
  "@adtech/rbadman": "2.2.57",
46
- "@vkontakte/videoplayer-core": "2.0.167-beta.0",
47
- "@vkontakte/videoplayer-interactive": "1.0.73-beta.0",
48
- "@vkontakte/videoplayer-shared": "1.0.96-beta.0",
49
- "@vkontakte/videoplayer-statistics": "1.0.113-beta.0"
46
+ "@vkontakte/videoplayer-core": "2.0.167-dev.652aecfe7.0",
47
+ "@vkontakte/videoplayer-interactive": "1.0.73-dev.652aecfe7.0",
48
+ "@vkontakte/videoplayer-shared": "1.0.96-dev.652aecfe7.0",
49
+ "@vkontakte/videoplayer-statistics": "1.0.113-dev.652aecfe7.0"
50
50
  }
51
51
  }
@@ -9,6 +9,7 @@ import { ThinOneStat } from "@vkontakte/videoplayer-statistics";
9
9
  import { AnnotationsApi } from "../utils/webAPI/annotationsApi/annotationsApi";
10
10
  import type { AdditionalContextMenuItem, AdditionalSettingsMenuItem, MenuItemHighlight, RootMenuId } from "../components/Menus/subMenuTabs/types";
11
11
  import type { AdditionalButton } from "../components/Controls/types";
12
+ import type { ExternalControlConfig } from "../store/modules/controlsLayoutStore/types";
12
13
  import { SlotsApi } from "../utils/webAPI/slotsApi";
13
14
  import { HTMLElement } from "./HTMLElement";
14
15
  export declare class VKVideoPlayer extends HTMLElement {
@@ -192,6 +193,9 @@ export declare class VKVideoPlayer extends HTMLElement {
192
193
  updateAdditionalButton(itemId: string, fields: Partial<Omit<AdditionalButton, "id" | "type">>): void;
193
194
  addAdditionalButton(newButton: AdditionalButton): void;
194
195
  removeAdditionalButton(itemId: string): void;
196
+ addExternalControl(control: ExternalControlConfig): void;
197
+ updateExternalControl(id: string, fields: Partial<Omit<ExternalControlConfig, "id">>): void;
198
+ removeExternalControl(id: string): void;
195
199
  updateStatContext(statContext: Partial<IStatContext | ThinOneStat.IStatContext>): void;
196
200
  handleTimerNextVideo(state: boolean): void;
197
201
  togglePictureInPicture(): void;
@@ -0,0 +1,20 @@
1
+ import { type Readable } from "svelte/store";
2
+ import type { ControlId } from "../../store/modules/controlsLayoutStore/types";
3
+ /**
4
+ * Регистрирует контрол в менеджере layout'а и возвращает реактивный
5
+ * store с финальным вердиктом «показывать или нет».
6
+ *
7
+ * @param id идентификатор контрола из конфига
8
+ * @param requested геттер бизнес-условия — функция, читающая реактивные
9
+ * источники (runes-state, props, derived и т.п.).
10
+ * По умолчанию () => true — контрол всегда «хочет» быть на экране.
11
+ *
12
+ * @example
13
+ * const visible$ = useControlInLayout(
14
+ * 'rewind',
15
+ * () => !isLive.value || hasDvr.value,
16
+ * );
17
+ *
18
+ * {#if $visible$}<button>...</button>{/if}
19
+ */
20
+ export declare function useControlInLayout(id: ControlId, requested?: () => boolean): Readable<boolean>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Хук для получения текущего варианта контрола
3
+ *
4
+ * Используется внутри компонента контрола, который уже отрендерен
5
+ * по решению useControlInLayout.
6
+ */
7
+ import { type Readable } from "svelte/store";
8
+ import type { ControlWithVariants, VariantOf } from "../../store/modules/controlsLayoutStore/variants";
9
+ /**
10
+ * Возвращает текущий variant контрола, выбранный резолвером
11
+ * для актуального breakpoint и режима плеера.
12
+ */
13
+ export declare function useControlVariant<Id extends ControlWithVariants>(id: Id): Readable<VariantOf<Id>>;
package/types/config.d.ts CHANGED
@@ -11,7 +11,6 @@ export declare enum LogoType {
11
11
  VK_VIDEO = "vk_video",
12
12
  APP_STORE = "app_store",
13
13
  PLAY_MARKET = "play_market",
14
- RU_STORE = "ru_store",
15
14
  VK_VIDEO_MOBILE = "vk_video_mobile"
16
15
  }
17
16
  /**
package/types/index.d.ts CHANGED
@@ -8,6 +8,8 @@ export { VERSION } from "./env";
8
8
  export declare const registerPlayerWebComponent: () => void;
9
9
  export { type AdditionalSettingsMenuItem, MenuItemType, type AdditionalClickSettingsMenuItem, type AdditionalSwitchSettingsMenuItem, type AdditionalContextMenuItem, RootMenuId, SubMenuId, SETTINGS_MENU_ID } from "./components/Menus/subMenuTabs/types";
10
10
  export { type AdditionalButton, ControlButtonType } from "./components/Controls/types";
11
+ export { Priority } from "./store/modules/controlsLayoutStore/config";
12
+ export type { ExternalControlConfig } from "./store/modules/controlsLayoutStore/types";
11
13
  export type { VKVideoPlayer, IVKVideoPlayerConfig, IUpdatableVKVideoPlayerConfig, IControlInfo, ITimelinePreviewThumbsData, IUpcomingLiveViewControlInfo, IVKVideoPlayerCallbacks, IVideoData, AdsParams, HotKeyMapData, HotKeyMapItem, HotKeyMapGroup, ISources, IDashSource, URLSource, RawSource, URLSourceWithSeek, LanguagePack, LanguageConfig, Milliseconds, IVideoLive, IInteractiveData, AdditionalButtonDeprecated, QualityLimits, IAdsConfig, IVideoEpisode, IDpipConfig, IQoeConfig, IQoeButtonOnlyConfig, IQoePoll, IQoeResult, IQoeQuestion, IQoeCallbacks, QoePollTranslations, ISDKConfig, VideoPlayerView, IAdmanInitParamsExternalApi, VKLogoType };
12
14
  export { GridTypes } from "./constans";
13
15
  export { PlayerPhase } from "./types";
@@ -2,7 +2,7 @@ import type { IUIConfig } from "../config";
2
2
  import type { IVKVideoPlayerConfig } from "../types";
3
3
  import type { IUIStatistics } from "../services/statistics";
4
4
  import type { IStore } from "./index";
5
- import type { FakeIsPlayingStore, GraphIsOpenedStore, HighlightedMenuItemsStore, InteractiveControlsOpacityStore, LanguageStore, NotificationsStore, PictureInPictureStore, IQoeStore, SeekToInteractiveDisabledTooltipStore, ShowInteractiveTimeIndicatorTooltipStore, SubtitlesStore, QualityStore, PlaybackRateStore } from "./modules";
5
+ import type { FakeIsPlayingStore, GraphIsOpenedStore, HighlightedMenuItemsStore, InteractiveControlsOpacityStore, LanguageStore, NotificationsStore, PictureInPictureStore, IQoeStore, SeekToInteractiveDisabledTooltipStore, ShowInteractiveTimeIndicatorTooltipStore, SubtitlesStore, QualityStore, PlaybackRateStore, ControlsLayoutStore } from "./modules";
6
6
  import type { AppTracer, ITracer } from "@vkontakte/videoplayer-shared";
7
7
  import type { Interactives } from "@vkontakte/videoplayer-interactive";
8
8
  export interface ICompositionParams {
@@ -29,6 +29,7 @@ export interface ICompositionResult {
29
29
  subtitlesStore: SubtitlesStore;
30
30
  qualityStore: QualityStore;
31
31
  playbackRateStore: PlaybackRateStore;
32
+ controlsLayoutStore: ControlsLayoutStore;
32
33
  };
33
34
  /** Очистка ресурсов */
34
35
  destroy(): void;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Декларативный конфиг контролов
3
+ *
4
+ * Определяет position, priority, breakpoints, modes, platforms для каждого контрола.
5
+ */
6
+ import type { ControlLayoutConfig, Platform } from "../types";
7
+ /**
8
+ * Конфигурация всех контролов
9
+ *
10
+ * priority: выше число = важнее контрол, остаётся при сжатии
11
+ * breakpoints: { min, max } — диапазон breakpoint'ов для видимости
12
+ * modes: массив режимов, в которых контрол актуален
13
+ * platforms: массив платформ, на которых контрол показывается
14
+ *
15
+ * Контролы отсортированы по position (порядок слева направо).
16
+ */
17
+ export declare const controlsConfig: ControlLayoutConfig[];
18
+ /**
19
+ * Вместимость ряда по платформе и GridTypes
20
+ */
21
+ export declare const rowCapacity: Record<Platform, Record<string, number>>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Фича-конфиг для переопределения контролов
3
+ *
4
+ * Когда фича = true, записи из массива мержатся со статичным конфигом по id.
5
+ * Переопределяются только указанные поля, остальные сохраняются.
6
+ */
7
+ import type { BreakpointRange, PlayerMode, Platform } from "../types";
8
+ /**
9
+ * Вариант контрола для фича-переопределения
10
+ */
11
+ type VariantEntry = {
12
+ name: string;
13
+ breakpoints?: BreakpointRange;
14
+ modes?: PlayerMode[];
15
+ platforms?: Platform[];
16
+ };
17
+ /**
18
+ * Частичный конфиг контрола для фича-переопределения
19
+ */
20
+ export type FeatureControlOverride = {
21
+ id: string;
22
+ position?: number;
23
+ priority?: number | Record<string, number>;
24
+ breakpoints?: BreakpointRange | Partial<Record<PlayerMode, BreakpointRange>>;
25
+ modes?: PlayerMode[];
26
+ platforms?: Platform[];
27
+ variant?: VariantEntry[];
28
+ };
29
+ /**
30
+ * Фича-конфиг: ключ = название фичи, значение = массив переопределений
31
+ */
32
+ export declare const featuresConfig: Record<string, FeatureControlOverride[]>;
33
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Экспорты конфигурации контролов
3
+ */
4
+ export { Position } from "./positions";
5
+ export { Priority } from "./priority";
6
+ export { controlsConfig, rowCapacity } from "./controls.config";
7
+ export { featuresConfig } from "./features.config";
8
+ export { resolveRow } from "./resolver";
9
+ export { mergeConfigWithFeatures, convertWeightToPosition, convertLegacyButtonToExternal, isBuiltInControlId, builtInControlIds } from "./utils";
10
+ export type { ResolveRowParams } from "./resolver";
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Позиции контролов в ряду
3
+ *
4
+ * Числа определяют порядок слева направо.
5
+ * Группы: левая (воспроизведение), центр (прогресс), правая (настройки).
6
+ */
7
+ export declare enum Position {
8
+ Prev = 100,
9
+ Replay = 125,
10
+ Play = 150,
11
+ Next = 200,
12
+ PlayPrevChapter = 225,
13
+ InteractiveGraph = 250,
14
+ SeekToInteractive = 250,
15
+ Episodes = 300,
16
+ Time = 400,
17
+ LiveIndicator = 550,
18
+ VkLogo = 600,
19
+ Volume = 700,
20
+ AutoplayNext = 725,
21
+ Qoe = 750,
22
+ Subtitles = 775,
23
+ Settings = 800,
24
+ Context = 825,
25
+ Pip = 850,
26
+ Fullscreen = 875,
27
+ Cast = 900
28
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Приоритет контролов
3
+ *
4
+ * Выше приоритет = важнее контрол, остаётся при сжатии ряда.
5
+ */
6
+ export declare enum Priority {
7
+ Permanent = 500,
8
+ Important = 400,
9
+ Normal = 300,
10
+ Cosmetic = 200
11
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Resolver для видимости контролов
3
+ *
4
+ * Фильтрует, сортирует и отсекает контролы по capacity.
5
+ */
6
+ import type { ControlId, PlayerMode, Platform, ResolvableControlConfig, ResolvedRow } from "../types";
7
+ import type { GridTypes } from "../../../../constans";
8
+ export interface ResolveRowParams {
9
+ /** Конфиг контролов (встроенные + external) */
10
+ config: ResolvableControlConfig[];
11
+ /** Запрошенные встроенные контролы */
12
+ requested: Partial<Record<ControlId, boolean>>;
13
+ mode: PlayerMode;
14
+ breakpoint: GridTypes;
15
+ platform: Platform;
16
+ }
17
+ /**
18
+ * Разрешает список видимых контролов для заданных условий
19
+ */
20
+ export declare function resolveRow(params: ResolveRowParams): ResolvedRow;
@@ -0,0 +1,32 @@
1
+ import type { AdditionalDesktopControlPanelButton } from "../../../../components/Controls/types";
2
+ import type { ControlLayoutConfig, ExternalControlConfig } from "../types";
3
+ import type { AdditionalButtonDeprecated } from "../../../../types";
4
+ /**
5
+ * Множество id встроенных контролов (из controlsConfig)
6
+ */
7
+ export declare const builtInControlIds: Set<string>;
8
+ /**
9
+ * Проверяет, является ли id встроенным контролом
10
+ */
11
+ export declare const isBuiltInControlId: (id: string) => id is string;
12
+ /**
13
+ * Конвертирует weight в position
14
+ *
15
+ * - При точном совпадении возвращает значение из таблицы
16
+ * - При несовпадении интерполирует между соседями
17
+ * Например: weight=350 — между VOLUME(300→700) и SUBTITLES(400→775),
18
+ * результат: 700 + 0.5 * (775 - 700) = 738
19
+ */
20
+ export declare function convertWeightToPosition(weight: number): number;
21
+ /**
22
+ * Конвертирует legacy AdditionalDesktopControlPanelButton в ExternalControlConfig
23
+ */
24
+ export declare function convertLegacyButtonToExternal(button: AdditionalDesktopControlPanelButton | AdditionalButtonDeprecated, fallbackIndex: number): ExternalControlConfig;
25
+ /**
26
+ * Мержит статичный конфиг с фича-переопределениями
27
+ *
28
+ * @param baseConfig Базовый конфиг контролов
29
+ * @param features Объект с фича-флагами (ключи должны совпадать с ключами в featuresConfig)
30
+ * @returns Модифицированный конфиг с применёнными переопределениями
31
+ */
32
+ export declare function mergeConfigWithFeatures(baseConfig: ControlLayoutConfig[], features: Record<string, boolean>): ControlLayoutConfig[];
@@ -0,0 +1,3 @@
1
+ import { type ControlsLayoutStore } from "./controlsLayoutStore.store";
2
+ import type { Module } from "../utils";
3
+ export declare const controlsLayoutModule: Module<ControlsLayoutStore>;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Controls Layout Store
3
+ *
4
+ * Управляет layout'ом контролов на основе breakpoint, режима и бизнес-условий.
5
+ */
6
+ import type { Readable } from "svelte/store";
7
+ import type { Subscription } from "@vkontakte/videoplayer-shared";
8
+ import type { IVideoEpisode } from "../../../types";
9
+ import type { GridTypes } from "../../../constans";
10
+ import type { ControlId, ExternalControlConfig, ResolvedRow } from "./types";
11
+ export interface ControlsLayoutStoreDeps {
12
+ /** isMobile из ui */
13
+ isMobile: Readable<boolean>;
14
+ /** Текущий тип сетки */
15
+ currentGridType$: Readable<GridTypes>;
16
+ /** Является ли видео интерактивным (статическое значение) */
17
+ isInteractive: boolean;
18
+ /** isLive$ из state */
19
+ isLive$: Readable<boolean | undefined>;
20
+ /** videoEpisodes$ из state */
21
+ videoEpisodes$: Readable<IVideoEpisode[] | undefined>;
22
+ /** Фича-флаг для responsive UI в интерактивах */
23
+ interactiveResponsiveUi: boolean;
24
+ /** Фича-флаг для логотипа VK Video на bottom controls */
25
+ mobileVkLogoViewOnBottomControls: boolean;
26
+ /** Подписка для очистки */
27
+ subscription: Subscription;
28
+ /** Внешние контролы, добавленные через API */
29
+ externalControls$: Readable<ExternalControlConfig[]>;
30
+ }
31
+ export interface ControlsLayoutStoreState {
32
+ /** Полный результат резолва */
33
+ resolved$: Readable<ResolvedRow>;
34
+ /** Левые контролы (воспроизведение) */
35
+ left$: Readable<ControlId[]>;
36
+ /** Правые контролы (настройки) */
37
+ right$: Readable<ControlId[]>;
38
+ /** Карта external controls по id */
39
+ externalById$: Readable<Map<string, ExternalControlConfig>>;
40
+ /** Проверить, виден ли контрол (кэшированный derived) */
41
+ isVisible: (id: ControlId) => Readable<boolean>;
42
+ }
43
+ export interface ControlsLayoutStoreActions {
44
+ /** Зарегистрировать запрос на показ контрола */
45
+ registerRequest: (id: ControlId, requested$: Readable<boolean>) => () => void;
46
+ }
47
+ export interface ControlsLayoutStore {
48
+ state: ControlsLayoutStoreState;
49
+ actions: ControlsLayoutStoreActions;
50
+ }
51
+ /**
52
+ * Создаёт store layout'а контролов
53
+ */
54
+ export declare const createControlsLayoutStore: (deps: ControlsLayoutStoreDeps) => ControlsLayoutStore;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * InjectionToken для ControlsLayoutStore
3
+ */
4
+ import { InjectionToken } from "@vkontakte/videoplayer-shared";
5
+ import type { ControlsLayoutStore } from "./controlsLayoutStore.store";
6
+ export declare const CONTROLS_LAYOUT_STORE_TOKEN: InjectionToken<ControlsLayoutStore>;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ControlsLayoutStore Module
3
+ *
4
+ * Управляет layout'ом контролов на основе breakpoint, режима и бизнес-условий.
5
+ */
6
+ export type { BreakpointRange, ControlId, ControlLayoutConfig, ExternalControlConfig, ModePriority, PlayerMode, Platform, ResolvableControlConfig } from "./types";
7
+ export type { ControlsLayoutStore, ControlsLayoutStoreState, ControlsLayoutStoreActions, ControlsLayoutStoreDeps } from "./controlsLayoutStore.store";
8
+ export { controlsLayoutModule } from "./controlsLayoutStore.module";
9
+ export { CONTROLS_LAYOUT_STORE_TOKEN } from "./controlsLayoutStore.token";
10
+ export { Position, Priority, controlsConfig, resolveRow, rowCapacity } from "./config";
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Типы для системы видимости контролов
3
+ */
4
+ import type { Readable } from "svelte/store";
5
+ import type { GridTypes } from "../../../constans";
6
+ import type { ControlWithVariants, VariantOf } from "./variants";
7
+ import type { Priority } from "./config/priority";
8
+ /**
9
+ * Режим плеера, влияющий на видимость контролов
10
+ */
11
+ export type PlayerMode = "default" | "live" | "episodes" | "interactive";
12
+ /**
13
+ * Платформа
14
+ */
15
+ export type Platform = "desktop" | "mobile";
16
+ /**
17
+ * Идентификаторы контролов
18
+ * Соответствуют ключам IPlayerControlsRef и DesktopButtons*Ids
19
+ */
20
+ export type ControlId = "prevButton" | "playButton" | "replayButton" | "nextButton" | "playPrevChapterButton" | "seekToInteractiveButton" | "interactiveGraphButton" | "liveButton" | "time" | "episodes" | "vkLogo" | "autoplayNext" | "qoe" | "volume" | "subtitles" | "settings" | "context" | "fullscreen" | "chromecast" | "pip";
21
+ /**
22
+ * Диапазон breakpoint'ов для видимости контрола
23
+ */
24
+ export type BreakpointRange = {
25
+ min?: GridTypes;
26
+ max?: GridTypes;
27
+ };
28
+ /**
29
+ * Breakpoints с поддержкой разных режимов
30
+ *
31
+ * Варианты:
32
+ * - { min: GridTypes.M } — для всех modes
33
+ * - { interactive: { min: GridTypes.M } } — только для interactive, остальные без ограничений
34
+ * - { default: { min: GridTypes.S }, interactive: { min: GridTypes.M } } — разное для разных modes
35
+ */
36
+ export type ModeBreakpoints = BreakpointRange | (Partial<Record<PlayerMode, BreakpointRange>> & {
37
+ default?: BreakpointRange;
38
+ });
39
+ /**
40
+ * Приоритет контрола с поддержкой разных режимов
41
+ */
42
+ export type ModePriority = {
43
+ default: number;
44
+ } & Partial<Record<PlayerMode, number>>;
45
+ /**
46
+ * Конфигурация варианта контрола
47
+ */
48
+ export type VariantConfig<Id extends ControlWithVariants> = {
49
+ name: VariantOf<Id>;
50
+ breakpoints?: BreakpointRange;
51
+ modes?: PlayerMode[];
52
+ platforms?: Platform[];
53
+ };
54
+ /**
55
+ * Конфигурация контрола для layout-системы
56
+ */
57
+ export type ControlLayoutConfig<Id extends string = ControlId> = {
58
+ /** Идентификатор контрола */
59
+ id: Id;
60
+ /** Позиция в ряду (для сортировки) */
61
+ position: number;
62
+ /** Приоритет (выше = важнее, остаётся при нехватке места) */
63
+ priority: number | ModePriority;
64
+ /** Группа: левая (воспроизведение) или правая (настройки) */
65
+ group?: "left" | "right";
66
+ /** Диапазон breakpoint'ов, на которых контрол виден */
67
+ breakpoints?: ModeBreakpoints;
68
+ /** Режимы, в которых контрол доступен */
69
+ modes?: PlayerMode[];
70
+ /** Платформы, на которых контрол доступен */
71
+ platforms?: Platform[];
72
+ /** Визуальные варианты (только для контролов из ControlVariants) */
73
+ variant?: Id extends ControlWithVariants ? Array<VariantConfig<Id>> : never;
74
+ };
75
+ /**
76
+ * Конфиг контрола для резолва (упрощённый, без strict variant)
77
+ */
78
+ export type ResolvableControlConfig = {
79
+ id: string;
80
+ position: number;
81
+ priority: number | ModePriority;
82
+ group?: "left" | "right";
83
+ breakpoints?: ModeBreakpoints;
84
+ modes?: PlayerMode[];
85
+ platforms?: Platform[];
86
+ variant?: Array<{
87
+ name: string;
88
+ breakpoints?: BreakpointRange;
89
+ modes?: PlayerMode[];
90
+ platforms?: Platform[];
91
+ }>;
92
+ };
93
+ /**
94
+ * Конфигурация внешнего контрола (добавляется через API)
95
+ *
96
+ * В отличие от ControlLayoutConfig, содержит данные для рендеринга (icon, onClick).
97
+ */
98
+ export interface ExternalControlConfig {
99
+ /** Уникальный идентификатор */
100
+ id: string;
101
+ /** Позиция в ряду (для сортировки) */
102
+ position: number;
103
+ /** Приоритет (выше = важнее, остаётся при нехватке места) */
104
+ priority: Priority;
105
+ /** Группа: левая (воспроизведение) или правая (настройки). По умолчанию 'right' */
106
+ group?: "left" | "right";
107
+ /** Иконка (URL или SVG-строка) */
108
+ icon: string;
109
+ /** ARIA-метка для доступности */
110
+ ariaLabel: string;
111
+ /** Текст tooltip'а */
112
+ tooltipText?: string;
113
+ /** Data-testid для тестов */
114
+ testId?: string;
115
+ /** Отключён ли контрол */
116
+ disabled?: boolean;
117
+ /** Обработчик клика */
118
+ onClick?: () => void;
119
+ /** Диапазон breakpoint'ов, на которых контрол виден */
120
+ breakpoints?: ModeBreakpoints;
121
+ /** Платформы, на которых контрол доступен */
122
+ platforms?: Platform[];
123
+ /** Режимы, в которых контрол доступен */
124
+ modes?: PlayerMode[];
125
+ }
126
+ /**
127
+ * Результат резолва ряда
128
+ */
129
+ export type ResolvedRow = {
130
+ /** ID контролов, видимых в inline */
131
+ inline: string[];
132
+ /** ID контролов, не поместившихся в capacity */
133
+ overflow: string[];
134
+ /** Визуальные варианты для контролов */
135
+ variantById: Partial<Record<ControlId, string>>;
136
+ };
137
+ /**
138
+ * Store для requested-стейта контролов
139
+ */
140
+ export type ControlRequestsStore = Readable<Map<ControlId, Readable<boolean>>>;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Реестр контролов, имеющих несколько визуальных вариантов.
3
+ */
4
+ export type ControlVariants = {
5
+ /** time: отображение времени */
6
+ time: "compact" | "full";
7
+ /** episodes: кнопка эпизодов */
8
+ episodes: "icon-only" | "icon-counter" | "icon-title";
9
+ /** vkLogo: логотип VK Video */
10
+ vkLogo: "short" | "full";
11
+ /** volume: регулятор громкости */
12
+ volume: "vertical" | "horizontal";
13
+ };
14
+ export type ControlWithVariants = keyof ControlVariants;
15
+ export type VariantOf<Id extends ControlWithVariants> = ControlVariants[Id];
@@ -27,3 +27,6 @@ export type { QualityStoreDeps, QualityStoreState, QualityStore } from "./qualit
27
27
  export { qualityModule, QUALITY_STORE_TOKEN } from "./qualityStore";
28
28
  export type { PlaybackRateStoreDeps, PlaybackRateStoreState, PlaybackRateStoreActions, PlaybackRateStore } from "./playbackRateStore";
29
29
  export { playbackRateModule, PLAYBACK_RATE_STORE_TOKEN } from "./playbackRateStore";
30
+ export type { ControlsLayoutStore, ControlsLayoutStoreState, ControlsLayoutStoreActions, ControlsLayoutStoreDeps } from "./controlsLayoutStore";
31
+ export { controlsLayoutModule, CONTROLS_LAYOUT_STORE_TOKEN } from "./controlsLayoutStore";
32
+ export type { BreakpointRange, ControlId, ControlLayoutConfig, ModePriority, PlayerMode, Platform } from "./controlsLayoutStore";
@@ -8,6 +8,7 @@ import type { AdmanWrapper } from "../components/Ads/admanWrapper";
8
8
  import type { QualitySettingsAppliesTo } from "../utils/userSettings";
9
9
  import type { GridTypes, PlayPrevChapterDisabledTooltipKey } from "../constans";
10
10
  import type { AdditionalButton, AdditionalDesktopControlPanelButton } from "../components/Controls/types";
11
+ import type { ExternalControlConfig } from "./modules/controlsLayoutStore/types";
11
12
  import type { AdditionalContextMenuItem, AdditionalSettingsMenuItem, ContextMenuItem, SettingsMenuItem } from "../components/Menus/subMenuTabs/types";
12
13
  import type { SlotsApi } from "../utils/webAPI/slotsApi";
13
14
  import type { FocusManager } from "../utils/webAPI/focusManager";
@@ -102,6 +103,7 @@ export interface IUIState {
102
103
  interactiveHideMobileControls: Writable<boolean>;
103
104
  additionalButtonsDeprecated$: Readable<AdditionalButtonDeprecated[]>;
104
105
  additionalDesktopControlPanelRightButtons$: Readable<AdditionalDesktopControlPanelButton[]>;
106
+ externalControls$: Readable<ExternalControlConfig[]>;
105
107
  additionalSettingsMenuItems$: Readable<SettingsMenuItem[]>;
106
108
  additionalContextMenuItems$: Readable<ContextMenuItem[]>;
107
109
  overlayContainer$: Writable<HTMLDivElement | undefined>;
@@ -280,6 +282,9 @@ export interface IStoreExternalActions {
280
282
  updateAdditionalButton: (itemId: string, fields: Partial<Omit<AdditionalButton, "id" | "type">>) => void;
281
283
  addAdditionalButton: (newButton: AdditionalButton) => void;
282
284
  removeAdditionalButton: (itemId: string) => void;
285
+ addExternalControl: (control: ExternalControlConfig) => void;
286
+ updateExternalControl: (id: string, fields: Partial<Omit<ExternalControlConfig, "id">>) => void;
287
+ removeExternalControl: (id: string) => void;
283
288
  setLiveLowLatency: (isLowLatency: boolean) => void;
284
289
  hideControls: () => void;
285
290
  showControls: () => void;