ts-video-player 0.1.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 (251) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +438 -0
  3. package/dist/cdn.d.ts +10 -0
  4. package/dist/cdn.d.ts.map +1 -0
  5. package/dist/cdn.min.js +1046 -0
  6. package/dist/cdn.min.js.map +54 -0
  7. package/dist/cdn.test.d.ts +2 -0
  8. package/dist/cdn.test.d.ts.map +1 -0
  9. package/dist/chunk-36x4yhjn.js +765 -0
  10. package/dist/chunk-36x4yhjn.js.map +12 -0
  11. package/dist/chunk-eajts2jv.js +4243 -0
  12. package/dist/chunk-eajts2jv.js.map +42 -0
  13. package/dist/chunk-z1ehbz9f.js +380 -0
  14. package/dist/chunk-z1ehbz9f.js.map +19 -0
  15. package/dist/config.d.ts +9 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/core/audio-gain.d.ts +67 -0
  18. package/dist/core/audio-gain.d.ts.map +1 -0
  19. package/dist/core/caption-styles.d.ts +121 -0
  20. package/dist/core/caption-styles.d.ts.map +1 -0
  21. package/dist/core/chapters.d.ts +150 -0
  22. package/dist/core/chapters.d.ts.map +1 -0
  23. package/dist/core/error-overlay.d.ts +71 -0
  24. package/dist/core/error-overlay.d.ts.map +1 -0
  25. package/dist/core/events.d.ts +119 -0
  26. package/dist/core/events.d.ts.map +1 -0
  27. package/dist/core/features.d.ts +64 -0
  28. package/dist/core/features.d.ts.map +1 -0
  29. package/dist/core/i18n.d.ts +132 -0
  30. package/dist/core/i18n.d.ts.map +1 -0
  31. package/dist/core/index.d.ts +37 -0
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/live.d.ts +130 -0
  34. package/dist/core/live.d.ts.map +1 -0
  35. package/dist/core/media-session.d.ts +38 -0
  36. package/dist/core/media-session.d.ts.map +1 -0
  37. package/dist/core/orientation.d.ts +22 -0
  38. package/dist/core/orientation.d.ts.map +1 -0
  39. package/dist/core/popover.d.ts +42 -0
  40. package/dist/core/popover.d.ts.map +1 -0
  41. package/dist/core/remote-playback.d.ts +195 -0
  42. package/dist/core/remote-playback.d.ts.map +1 -0
  43. package/dist/core/settings-menu.d.ts +132 -0
  44. package/dist/core/settings-menu.d.ts.map +1 -0
  45. package/dist/core/spinner.d.ts +67 -0
  46. package/dist/core/spinner.d.ts.map +1 -0
  47. package/dist/core/state.d.ts +142 -0
  48. package/dist/core/state.d.ts.map +1 -0
  49. package/dist/core/text-tracks.d.ts +162 -0
  50. package/dist/core/text-tracks.d.ts.map +1 -0
  51. package/dist/core/themes.d.ts +213 -0
  52. package/dist/core/themes.d.ts.map +1 -0
  53. package/dist/core/thumbnails.d.ts +124 -0
  54. package/dist/core/thumbnails.d.ts.map +1 -0
  55. package/dist/core/tooltips.d.ts +100 -0
  56. package/dist/core/tooltips.d.ts.map +1 -0
  57. package/dist/elements/base.d.ts +3 -0
  58. package/dist/elements/base.d.ts.map +1 -0
  59. package/dist/elements/index.d.ts +33 -0
  60. package/dist/elements/index.d.ts.map +1 -0
  61. package/dist/elements/index.js +55 -0
  62. package/dist/elements/index.js.map +9 -0
  63. package/dist/elements/media-airplay-button.d.ts +13 -0
  64. package/dist/elements/media-airplay-button.d.ts.map +1 -0
  65. package/dist/elements/media-error-display.d.ts +13 -0
  66. package/dist/elements/media-error-display.d.ts.map +1 -0
  67. package/dist/elements/media-fullscreen-button.d.ts +13 -0
  68. package/dist/elements/media-fullscreen-button.d.ts.map +1 -0
  69. package/dist/elements/media-live-button.d.ts +13 -0
  70. package/dist/elements/media-live-button.d.ts.map +1 -0
  71. package/dist/elements/media-mute-button.d.ts +13 -0
  72. package/dist/elements/media-mute-button.d.ts.map +1 -0
  73. package/dist/elements/media-pip-button.d.ts +13 -0
  74. package/dist/elements/media-pip-button.d.ts.map +1 -0
  75. package/dist/elements/media-play-button.d.ts +14 -0
  76. package/dist/elements/media-play-button.d.ts.map +1 -0
  77. package/dist/elements/media-playback-rate-button.d.ts +10 -0
  78. package/dist/elements/media-playback-rate-button.d.ts.map +1 -0
  79. package/dist/elements/media-preview-time.d.ts +18 -0
  80. package/dist/elements/media-preview-time.d.ts.map +1 -0
  81. package/dist/elements/media-progress-bar.d.ts +16 -0
  82. package/dist/elements/media-progress-bar.d.ts.map +1 -0
  83. package/dist/elements/media-remote-playback-button.d.ts +16 -0
  84. package/dist/elements/media-remote-playback-button.d.ts.map +1 -0
  85. package/dist/elements/media-seek-button.d.ts +9 -0
  86. package/dist/elements/media-seek-button.d.ts.map +1 -0
  87. package/dist/elements/media-settings-menu.d.ts +32 -0
  88. package/dist/elements/media-settings-menu.d.ts.map +1 -0
  89. package/dist/elements/media-time-display.d.ts +21 -0
  90. package/dist/elements/media-time-display.d.ts.map +1 -0
  91. package/dist/elements/media-time-group.d.ts +22 -0
  92. package/dist/elements/media-time-group.d.ts.map +1 -0
  93. package/dist/elements/media-time-separator.d.ts +13 -0
  94. package/dist/elements/media-time-separator.d.ts.map +1 -0
  95. package/dist/elements/media-volume-slider.d.ts +16 -0
  96. package/dist/elements/media-volume-slider.d.ts.map +1 -0
  97. package/dist/elements/utils.d.ts +27 -0
  98. package/dist/elements/utils.d.ts.map +1 -0
  99. package/dist/elements/video-player.d.ts +23 -0
  100. package/dist/elements/video-player.d.ts.map +1 -0
  101. package/dist/elements/video-skin.d.ts +23 -0
  102. package/dist/elements/video-skin.d.ts.map +1 -0
  103. package/dist/features/captions.d.ts +8 -0
  104. package/dist/features/captions.d.ts.map +1 -0
  105. package/dist/features/create-player.d.ts +45 -0
  106. package/dist/features/create-player.d.ts.map +1 -0
  107. package/dist/features/fullscreen.d.ts +8 -0
  108. package/dist/features/fullscreen.d.ts.map +1 -0
  109. package/dist/features/gestures.d.ts +8 -0
  110. package/dist/features/gestures.d.ts.map +1 -0
  111. package/dist/features/index.d.ts +26 -0
  112. package/dist/features/index.d.ts.map +1 -0
  113. package/dist/features/index.js +31 -0
  114. package/dist/features/index.js.map +9 -0
  115. package/dist/features/keyboard.d.ts +8 -0
  116. package/dist/features/keyboard.d.ts.map +1 -0
  117. package/dist/features/pip.d.ts +8 -0
  118. package/dist/features/pip.d.ts.map +1 -0
  119. package/dist/features/playback.d.ts +8 -0
  120. package/dist/features/playback.d.ts.map +1 -0
  121. package/dist/features/quality.d.ts +8 -0
  122. package/dist/features/quality.d.ts.map +1 -0
  123. package/dist/features/types.d.ts +26 -0
  124. package/dist/features/types.d.ts.map +1 -0
  125. package/dist/features/volume.d.ts +8 -0
  126. package/dist/features/volume.d.ts.map +1 -0
  127. package/dist/index.d.ts +84 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +8149 -0
  130. package/dist/index.js.map +31 -0
  131. package/dist/layouts/index.d.ts +58 -0
  132. package/dist/layouts/index.d.ts.map +1 -0
  133. package/dist/player.d.ts +90 -0
  134. package/dist/player.d.ts.map +1 -0
  135. package/dist/plugins/ads.d.ts +311 -0
  136. package/dist/plugins/ads.d.ts.map +1 -0
  137. package/dist/plugins/analytics.d.ts +203 -0
  138. package/dist/plugins/analytics.d.ts.map +1 -0
  139. package/dist/plugins/end-screen.d.ts +184 -0
  140. package/dist/plugins/end-screen.d.ts.map +1 -0
  141. package/dist/plugins/index.d.ts +13 -0
  142. package/dist/plugins/index.d.ts.map +1 -0
  143. package/dist/plugins/index.js +20 -0
  144. package/dist/plugins/index.js.map +9 -0
  145. package/dist/plugins/skip-segments.d.ts +159 -0
  146. package/dist/plugins/skip-segments.d.ts.map +1 -0
  147. package/dist/plugins/watermark.d.ts +157 -0
  148. package/dist/plugins/watermark.d.ts.map +1 -0
  149. package/dist/providers/base.d.ts +56 -0
  150. package/dist/providers/base.d.ts.map +1 -0
  151. package/dist/providers/dash.d.ts +94 -0
  152. package/dist/providers/dash.d.ts.map +1 -0
  153. package/dist/providers/hls.d.ts +182 -0
  154. package/dist/providers/hls.d.ts.map +1 -0
  155. package/dist/providers/html5.d.ts +64 -0
  156. package/dist/providers/html5.d.ts.map +1 -0
  157. package/dist/providers/index.d.ts +41 -0
  158. package/dist/providers/index.d.ts.map +1 -0
  159. package/dist/providers/vimeo.d.ts +157 -0
  160. package/dist/providers/vimeo.d.ts.map +1 -0
  161. package/dist/providers/youtube.d.ts +134 -0
  162. package/dist/providers/youtube.d.ts.map +1 -0
  163. package/dist/stx/index.d.ts +59 -0
  164. package/dist/stx/index.d.ts.map +1 -0
  165. package/dist/stx/index.js +480 -0
  166. package/dist/stx/index.js.map +11 -0
  167. package/dist/types.d.ts +724 -0
  168. package/dist/types.d.ts.map +1 -0
  169. package/dist/ui/components.d.ts +121 -0
  170. package/dist/ui/components.d.ts.map +1 -0
  171. package/dist/ui/index.d.ts +9 -0
  172. package/dist/ui/index.d.ts.map +1 -0
  173. package/dist/ui/index.js +16 -0
  174. package/dist/ui/index.js.map +9 -0
  175. package/package.json +109 -0
  176. package/src/cdn.test.ts +10 -0
  177. package/src/cdn.ts +60 -0
  178. package/src/config.ts +25 -0
  179. package/src/core/audio-gain.ts +171 -0
  180. package/src/core/caption-styles.ts +568 -0
  181. package/src/core/chapters.ts +551 -0
  182. package/src/core/error-overlay.ts +354 -0
  183. package/src/core/events.ts +552 -0
  184. package/src/core/features.ts +287 -0
  185. package/src/core/i18n.ts +590 -0
  186. package/src/core/index.ts +249 -0
  187. package/src/core/live.ts +472 -0
  188. package/src/core/media-session.ts +137 -0
  189. package/src/core/orientation.ts +57 -0
  190. package/src/core/popover.ts +143 -0
  191. package/src/core/remote-playback.ts +661 -0
  192. package/src/core/settings-menu.ts +630 -0
  193. package/src/core/spinner.ts +310 -0
  194. package/src/core/state.ts +476 -0
  195. package/src/core/text-tracks.ts +599 -0
  196. package/src/core/themes.ts +607 -0
  197. package/src/core/thumbnails.ts +457 -0
  198. package/src/core/tooltips.ts +370 -0
  199. package/src/elements/base.ts +2 -0
  200. package/src/elements/index.ts +82 -0
  201. package/src/elements/media-airplay-button.ts +78 -0
  202. package/src/elements/media-error-display.ts +47 -0
  203. package/src/elements/media-fullscreen-button.ts +72 -0
  204. package/src/elements/media-live-button.ts +65 -0
  205. package/src/elements/media-mute-button.ts +69 -0
  206. package/src/elements/media-pip-button.ts +66 -0
  207. package/src/elements/media-play-button.ts +69 -0
  208. package/src/elements/media-playback-rate-button.ts +59 -0
  209. package/src/elements/media-preview-time.ts +75 -0
  210. package/src/elements/media-progress-bar.ts +200 -0
  211. package/src/elements/media-remote-playback-button.ts +108 -0
  212. package/src/elements/media-seek-button.ts +50 -0
  213. package/src/elements/media-settings-menu.ts +302 -0
  214. package/src/elements/media-time-display.ts +99 -0
  215. package/src/elements/media-time-group.ts +41 -0
  216. package/src/elements/media-time-separator.ts +35 -0
  217. package/src/elements/media-volume-slider.ts +140 -0
  218. package/src/elements/utils.ts +82 -0
  219. package/src/elements/video-player.ts +175 -0
  220. package/src/elements/video-skin.ts +127 -0
  221. package/src/features/captions.ts +56 -0
  222. package/src/features/create-player.ts +91 -0
  223. package/src/features/fullscreen.ts +44 -0
  224. package/src/features/gestures.ts +44 -0
  225. package/src/features/index.ts +44 -0
  226. package/src/features/keyboard.ts +89 -0
  227. package/src/features/pip.ts +47 -0
  228. package/src/features/playback.ts +68 -0
  229. package/src/features/quality.ts +19 -0
  230. package/src/features/types.ts +28 -0
  231. package/src/features/volume.ts +46 -0
  232. package/src/index.ts +635 -0
  233. package/src/layouts/index.ts +672 -0
  234. package/src/player.ts +821 -0
  235. package/src/plugins/ads.ts +1045 -0
  236. package/src/plugins/analytics.ts +673 -0
  237. package/src/plugins/end-screen.ts +793 -0
  238. package/src/plugins/index.ts +61 -0
  239. package/src/plugins/skip-segments.ts +537 -0
  240. package/src/plugins/watermark.ts +537 -0
  241. package/src/providers/base.ts +197 -0
  242. package/src/providers/dash.ts +588 -0
  243. package/src/providers/hls.ts +624 -0
  244. package/src/providers/html5.ts +473 -0
  245. package/src/providers/index.ts +97 -0
  246. package/src/providers/vimeo.ts +533 -0
  247. package/src/providers/youtube.ts +542 -0
  248. package/src/stx/index.ts +606 -0
  249. package/src/types.ts +874 -0
  250. package/src/ui/components.ts +910 -0
  251. package/src/ui/index.ts +29 -0
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/state.ts", "../src/core/events.ts", "../src/core/features.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * ts-video-player State Management\n *\n * Simple reactive state system for the video player.\n *\n * @module core/state\n */\n\nimport type { PlayerState } from '../types'\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Shallow equality comparison for plain objects.\n * Returns true if both objects have the same keys with === equal values.\n * Used to optimize selector subscriptions — skip notifications when\n * derived state hasn't meaningfully changed.\n */\nexport function shallowEqual<T extends Record<string, unknown>>(a: T, b: T): boolean {\n if (a === b) return true\n if (!a || !b) return false\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n\n if (keysA.length !== keysB.length) return false\n\n for (const key of keysA) {\n if (a[key] !== b[key]) return false\n }\n\n return true\n}\n\n// =============================================================================\n// Reactive Signal System\n// =============================================================================\n\n// eslint-disable-next-line pickier/no-unused-vars\ntype Listener<T> = (_value: T, _prev: T) => void\ntype Unsubscribe = () => void\n\n/**\n * Create a reactive signal\n */\nexport function createSignal<T>(initial: T): [() => T, (value: T | ((prev: T) => T)) => void] {\n let value = initial\n const listeners = new Set<Listener<T>>()\n\n const get = () => value\n\n const set = (newValue: T | ((prev: T) => T)) => {\n const prev = value\n value = typeof newValue === 'function' ? (newValue as (prev: T) => T)(prev) : newValue\n if (value !== prev) {\n listeners.forEach((listener) => listener(value, prev))\n }\n }\n\n // Attach subscribe method to getter\n ;(get as any).subscribe = (listener: Listener<T>): Unsubscribe => {\n listeners.add(listener)\n return () => listeners.delete(listener)\n }\n\n return [get, set]\n}\n\n/**\n * Create a computed value from signals\n */\nexport function computed<T>(fn: () => T, deps: Array<() => unknown>): () => T {\n let value: T\n let dirty = true\n\n // Subscribe to all dependencies\n deps.forEach((dep) => {\n if ((dep as any).subscribe) {\n (dep as any).subscribe(() => {\n dirty = true\n })\n }\n })\n\n return () => {\n if (dirty) {\n value = fn()\n dirty = false\n }\n return value\n }\n}\n\n// =============================================================================\n// Player State Store\n// =============================================================================\n\n/**\n * Default player state\n */\nexport function createDefaultState(): PlayerState {\n return {\n // Source\n src: null,\n sources: [],\n currentSourceIndex: 0,\n mediaType: 'unknown',\n streamType: 'unknown',\n providerType: 'unknown',\n\n // Loading\n loadingState: 'idle',\n preload: 'metadata',\n canPlay: false,\n canPlayThrough: false,\n error: null,\n\n // Playback\n playbackState: 'idle',\n paused: true,\n playing: false,\n started: false,\n ended: false,\n seeking: false,\n waiting: false,\n currentTime: 0,\n duration: 0,\n playbackRate: 1,\n loop: false,\n autoplay: false,\n playsinline: true,\n\n // Volume\n muted: false,\n volume: 1,\n\n // Buffering\n buffered: [],\n bufferedAmount: 0,\n seekable: [],\n\n // Dimensions\n videoWidth: 0,\n videoHeight: 0,\n aspectRatio: 16 / 9,\n\n // Tracks\n qualities: [],\n autoQuality: true,\n audioTracks: [],\n textTracks: [],\n\n // Fullscreen/PiP\n fullscreen: false,\n pictureInPicture: false,\n canFullscreen: false,\n canPictureInPicture: false,\n\n // Feature Availability\n volumeAvailability: 'unavailable',\n fullscreenAvailability: 'unavailable',\n pipAvailability: 'unavailable',\n\n // UI\n controlsVisible: true,\n userActive: true,\n pointerOver: false,\n\n // Metadata\n title: '',\n poster: '',\n }\n}\n\n/**\n * State store for the player\n *\n * Uses microtask-coalesced notifications: multiple rapid set() calls within\n * the same microtask are batched into a single notification cycle. This prevents\n * redundant re-renders when many state fields change in quick succession\n * (e.g., timeupdate + progress + buffered all firing together).\n */\nexport class StateStore {\n private state: PlayerState\n private listeners = new Map<keyof PlayerState | '*', Set<(state: PlayerState, key?: keyof PlayerState) => void>>()\n private _pendingKeys: Set<keyof PlayerState> | null = null\n private _flushScheduled = false\n\n constructor(initial?: Partial<PlayerState>) {\n this.state = { ...createDefaultState(), ...initial }\n }\n\n /**\n * Get the current state\n */\n getState(): Readonly<PlayerState> {\n return this.state\n }\n\n /**\n * Get a specific state value\n */\n get<K extends keyof PlayerState>(key: K): PlayerState[K] {\n return this.state[key]\n }\n\n /**\n * Set a single state value. Notifications are coalesced via microtask.\n */\n set<K extends keyof PlayerState>(key: K, value: PlayerState[K]): void {\n if (this.state[key] === value) return\n\n this.state = { ...this.state, [key]: value }\n this.scheduleNotify(key)\n }\n\n /**\n * Batch update multiple state values. Notifications are coalesced via microtask.\n */\n batch(updates: Partial<PlayerState>): void {\n for (const [key, value] of Object.entries(updates)) {\n if (this.state[key as keyof PlayerState] !== value) {\n ;(this.state as any)[key] = value\n this.scheduleNotify(key as keyof PlayerState)\n }\n }\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(\n // eslint-disable-next-line pickier/no-unused-vars\n keyOrListener: keyof PlayerState | '*' | ((_state: PlayerState, _key?: keyof PlayerState) => void),\n // eslint-disable-next-line pickier/no-unused-vars\n listener?: (_state: PlayerState, _key?: keyof PlayerState) => void,\n ): Unsubscribe {\n if (typeof keyOrListener === 'function') {\n // Subscribe to all changes\n const key = '*'\n if (!this.listeners.has(key)) {\n this.listeners.set(key, new Set())\n }\n this.listeners.get(key)!.add(keyOrListener)\n return () => this.listeners.get(key)?.delete(keyOrListener)\n }\n\n // Subscribe to specific key\n const key = keyOrListener\n if (!listener) return () => {}\n\n if (!this.listeners.has(key)) {\n this.listeners.set(key, new Set())\n }\n this.listeners.get(key)!.add(listener)\n return () => this.listeners.get(key)?.delete(listener)\n }\n\n /**\n * Reset state to defaults\n */\n reset(): void {\n this.state = createDefaultState()\n this._pendingKeys = null\n this._flushScheduled = false\n this.notifyAll()\n }\n\n /**\n * Force synchronous flush of pending notifications.\n * Useful in tests or when immediate consistency is required.\n */\n flush(): void {\n if (this._pendingKeys) {\n const keys = this._pendingKeys\n this._pendingKeys = null\n this._flushScheduled = false\n for (const key of keys) {\n this.notifyKey(key)\n }\n this.notifyAll()\n }\n }\n\n private scheduleNotify(key: keyof PlayerState): void {\n if (!this._pendingKeys) {\n this._pendingKeys = new Set()\n }\n this._pendingKeys.add(key)\n\n if (!this._flushScheduled) {\n this._flushScheduled = true\n queueMicrotask(() => this.flush())\n }\n }\n\n private notifyKey(key: keyof PlayerState): void {\n this.listeners.get(key)?.forEach((listener) => listener(this.state, key))\n }\n\n private notifyAll(): void {\n this.listeners.get('*')?.forEach((listener) => listener(this.state))\n }\n}\n\n// =============================================================================\n// State Selectors (Computed Values)\n// =============================================================================\n\n/**\n * Calculate buffered percentage\n */\nexport function selectBufferedAmount(state: PlayerState): number {\n if (state.duration === 0 || state.buffered.length === 0) return 0\n\n let buffered = 0\n for (const range of state.buffered) {\n buffered += range.end - range.start\n }\n return Math.min(buffered / state.duration, 1)\n}\n\n/**\n * Calculate progress percentage\n */\nexport function selectProgress(state: PlayerState): number {\n if (state.duration === 0) return 0\n return Math.min(state.currentTime / state.duration, 1)\n}\n\n/**\n * Get remaining time\n */\nexport function selectRemainingTime(state: PlayerState): number {\n return Math.max(state.duration - state.currentTime, 0)\n}\n\n/**\n * Check if player is in idle state\n */\nexport function selectIsIdle(state: PlayerState): boolean {\n return state.loadingState === 'idle' && state.playbackState === 'idle'\n}\n\n/**\n * Check if player is loading\n */\nexport function selectIsLoading(state: PlayerState): boolean {\n return state.loadingState === 'loading' || state.waiting\n}\n\n/**\n * Check if live stream\n */\nexport function selectIsLive(state: PlayerState): boolean {\n return state.streamType.includes('live')\n}\n\n/**\n * Check if DVR enabled\n */\nexport function selectIsDVR(state: PlayerState): boolean {\n return state.streamType === 'live:dvr'\n}\n\n/**\n * Get current quality\n */\nexport function selectCurrentQuality(state: PlayerState): string | null {\n const selected = state.qualities.find((q) => q.selected)\n if (!selected) return state.autoQuality ? 'auto' : null\n return `${selected.height}p`\n}\n\n/**\n * Get current text track\n */\nexport function selectCurrentTextTrack(state: PlayerState): string | null {\n const showing = state.textTracks.find((t) => t.mode === 'showing')\n return showing?.label || null\n}\n\n/**\n * Get current audio track\n */\nexport function selectCurrentAudioTrack(state: PlayerState): string | null {\n const selected = state.audioTracks.find((t) => t.selected)\n return selected?.label || null\n}\n\n// =============================================================================\n// Deprecated Selectors (use availability states instead)\n// =============================================================================\n\n/** @deprecated Use `state.fullscreenAvailability === 'available'` instead */\nexport function selectCanFullscreen(state: PlayerState): boolean {\n return state.fullscreenAvailability === 'available'\n}\n\n/** @deprecated Use `state.pipAvailability === 'available'` instead */\nexport function selectCanPiP(state: PlayerState): boolean {\n return state.pipAvailability === 'available'\n}\n\n/** @deprecated Use `state.volumeAvailability === 'available'` instead */\nexport function selectCanSetVolume(state: PlayerState): boolean {\n return state.volumeAvailability === 'available'\n}\n\n// =============================================================================\n// Storage Integration\n// =============================================================================\n\nconst STORAGE_KEY = 'ts-video-player'\n\ninterface StoredState {\n volume: number\n muted: boolean\n playbackRate: number\n captions: boolean\n quality: string\n}\n\n/**\n * Load persisted state from storage\n */\nexport function loadPersistedState(storage: Storage = localStorage): Partial<StoredState> {\n try {\n const data = storage.getItem(STORAGE_KEY)\n if (data) {\n return JSON.parse(data)\n }\n } catch {\n // Ignore storage errors\n }\n return {}\n}\n\n/**\n * Save state to storage\n */\nexport function savePersistedState(state: Partial<StoredState>, storage: Storage = localStorage): void {\n try {\n const existing = loadPersistedState(storage)\n storage.setItem(STORAGE_KEY, JSON.stringify({ ...existing, ...state }))\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Create storage sync for state store\n */\nexport function createStorageSync(\n store: StateStore,\n keys: (keyof StoredState)[] = ['volume', 'muted', 'playbackRate'],\n storage: Storage = localStorage,\n): Unsubscribe {\n // Load initial values\n const persisted = loadPersistedState(storage)\n if (persisted.volume !== undefined) store.set('volume', persisted.volume)\n if (persisted.muted !== undefined) store.set('muted', persisted.muted)\n if (persisted.playbackRate !== undefined) store.set('playbackRate', persisted.playbackRate)\n\n // Subscribe to changes\n const unsubscribes = keys.map((key) =>\n store.subscribe(key as keyof PlayerState, (state) => {\n const value = state[key as keyof PlayerState]\n savePersistedState({ [key]: value } as Partial<StoredState>, storage)\n }),\n )\n\n return () => unsubscribes.forEach((unsub) => unsub())\n}\n",
6
+ "/**\n * ts-video-player Event System\n *\n * Event emitter and media event normalization.\n *\n * @module core/events\n */\n\nimport type { ProviderEventMap, MediaError, TimeRange } from '../types'\n\n/**\n * Type-safe event emitter\n */\nexport class EventEmitter<T extends { [K in keyof T]: (...args: any[]) => void }> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>()\n private onceListeners = new Map<keyof T, Set<T[keyof T]>>()\n\n /**\n * Add an event listener\n */\n on<K extends keyof T>(event: K, handler: T[K]): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set())\n }\n this.listeners.get(event)!.add(handler)\n\n return () => this.off(event, handler)\n }\n\n /**\n * Add a one-time event listener\n */\n once<K extends keyof T>(event: K, handler: T[K]): () => void {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set())\n }\n this.onceListeners.get(event)!.add(handler)\n\n return () => this.onceListeners.get(event)?.delete(handler)\n }\n\n /**\n * Remove an event listener\n */\n off<K extends keyof T>(event: K, handler: T[K]): void {\n this.listeners.get(event)?.delete(handler)\n this.onceListeners.get(event)?.delete(handler)\n }\n\n /**\n * Emit an event\n */\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n // Call regular listeners\n this.listeners.get(event)?.forEach((handler) => {\n try {\n ;(handler as (...args: any[]) => void)(...args)\n } catch (error) {\n console.error(`[ts-video-player] Error in event handler for \"${String(event)}\":`, error)\n }\n })\n\n // Call and remove once listeners\n const onceHandlers = this.onceListeners.get(event)\n if (onceHandlers) {\n onceHandlers.forEach((handler) => {\n try {\n ;(handler as (...args: any[]) => void)(...args)\n } catch (error) {\n console.error(`[ts-video-player] Error in once handler for \"${String(event)}\":`, error)\n }\n })\n onceHandlers.clear()\n }\n }\n\n /**\n * Remove all listeners for an event (or all events)\n */\n removeAllListeners(event?: keyof T): void {\n if (event) {\n this.listeners.delete(event)\n this.onceListeners.delete(event)\n } else {\n this.listeners.clear()\n this.onceListeners.clear()\n }\n }\n\n /**\n * Get listener count for an event\n */\n listenerCount(event: keyof T): number {\n return (this.listeners.get(event)?.size || 0) + (this.onceListeners.get(event)?.size || 0)\n }\n}\n\n// =============================================================================\n// Media Events Normalizer\n// =============================================================================\n\n/**\n * Normalize HTMLMediaElement events to our event system\n */\nexport class MediaEventsNormalizer {\n private media: HTMLMediaElement\n private emitter: EventEmitter<ProviderEventMap>\n private listeners: Array<() => void> = []\n\n constructor(media: HTMLMediaElement, emitter: EventEmitter<ProviderEventMap>) {\n this.media = media\n this.emitter = emitter\n this.attachListeners()\n }\n\n private attachListeners(): void {\n const on = (event: string, handler: (e: Event) => void) => {\n this.media.addEventListener(event, handler)\n this.listeners.push(() => this.media.removeEventListener(event, handler))\n }\n\n // Loading events\n on('loadstart', () => this.emitter.emit('loadstart'))\n on('loadedmetadata', () => this.emitter.emit('loadedmetadata'))\n on('loadeddata', () => this.emitter.emit('loadeddata'))\n on('canplay', () => this.emitter.emit('canplay'))\n on('canplaythrough', () => this.emitter.emit('canplaythrough'))\n\n // Playback events\n on('play', () => this.emitter.emit('play'))\n on('pause', () => this.emitter.emit('pause'))\n on('playing', () => this.emitter.emit('playing'))\n on('waiting', () => this.emitter.emit('waiting'))\n on('ended', () => this.emitter.emit('ended'))\n\n // Seeking events\n on('seeking', () => this.emitter.emit('seeking'))\n on('seeked', () => this.emitter.emit('seeked'))\n\n // Time/duration events\n on('timeupdate', () => this.emitter.emit('timeupdate', this.media.currentTime))\n on('durationchange', () => this.emitter.emit('durationchange', this.media.duration))\n\n // Volume events\n on('volumechange', () => this.emitter.emit('volumechange', this.media.volume, this.media.muted))\n\n // Rate events\n on('ratechange', () => this.emitter.emit('ratechange', this.media.playbackRate))\n\n // Progress events\n on('progress', () => {\n const buffered = this.getTimeRanges(this.media.buffered)\n this.emitter.emit('progress', buffered)\n })\n\n // Error events\n on('error', () => {\n const error = this.normalizeError(this.media.error)\n this.emitter.emit('error', error)\n })\n }\n\n private getTimeRanges(ranges: TimeRanges): TimeRange[] {\n const result: TimeRange[] = []\n for (let i = 0; i < ranges.length; i++) {\n result.push({\n start: ranges.start(i),\n end: ranges.end(i),\n })\n }\n return result\n }\n\n private normalizeError(error: globalThis.MediaError | null): MediaError {\n if (!error) {\n return { code: 0, message: 'Unknown error' }\n }\n\n const messages: Record<number, string> = {\n 1: 'The fetching of the media resource was aborted by the user agent.',\n 2: 'A network error occurred while fetching the media resource.',\n 3: 'An error occurred while decoding the media resource.',\n 4: 'The media resource is not supported.',\n }\n\n return {\n code: error.code,\n message: messages[error.code] || error.message || 'Unknown error',\n }\n }\n\n /**\n * Destroy the normalizer\n */\n destroy(): void {\n this.listeners.forEach((remove) => remove())\n this.listeners = []\n }\n}\n\n// =============================================================================\n// Fullscreen Events\n// =============================================================================\n\n/**\n * Normalize fullscreen change events\n */\nexport function onFullscreenChange(handler: (fullscreen: boolean) => void): () => void {\n const events = ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange']\n\n const listener = () => {\n const fullscreen = !!(\n document.fullscreenElement ||\n (document as any).webkitFullscreenElement ||\n (document as any).mozFullScreenElement ||\n (document as any).msFullscreenElement\n )\n handler(fullscreen)\n }\n\n events.forEach((event) => document.addEventListener(event, listener))\n\n return () => {\n events.forEach((event) => document.removeEventListener(event, listener))\n }\n}\n\n// =============================================================================\n// Picture-in-Picture Events\n// =============================================================================\n\n/**\n * Normalize PiP change events\n */\nexport function onPiPChange(video: HTMLVideoElement, handler: (pip: boolean) => void): () => void {\n const enterHandler = () => handler(true)\n const leaveHandler = () => handler(false)\n\n video.addEventListener('enterpictureinpicture', enterHandler)\n video.addEventListener('leavepictureinpicture', leaveHandler)\n\n return () => {\n video.removeEventListener('enterpictureinpicture', enterHandler)\n video.removeEventListener('leavepictureinpicture', leaveHandler)\n }\n}\n\n// =============================================================================\n// Keyboard Events\n// =============================================================================\n\n/**\n * Default keyboard shortcuts\n */\nexport const DEFAULT_KEYBOARD_SHORTCUTS: Record<string, string> = {\n ' ': 'togglePlay',\n k: 'togglePlay',\n m: 'toggleMute',\n f: 'toggleFullscreen',\n i: 'togglePiP',\n c: 'toggleCaptions',\n ArrowLeft: 'seekBackward',\n ArrowRight: 'seekForward',\n j: 'seekBackward',\n l: 'seekForward',\n ArrowUp: 'volumeUp',\n ArrowDown: 'volumeDown',\n '>': 'speedUp',\n '<': 'speedDown',\n Home: 'seekStart',\n End: 'seekEnd',\n '0': 'seek0',\n '1': 'seek10',\n '2': 'seek20',\n '3': 'seek30',\n '4': 'seek40',\n '5': 'seek50',\n '6': 'seek60',\n '7': 'seek70',\n '8': 'seek80',\n '9': 'seek90',\n}\n\n/**\n * Action handlers for keyboard shortcuts\n */\nexport interface KeyboardActions {\n togglePlay(): void\n toggleMute(): void\n toggleFullscreen(): void\n togglePiP(): void\n toggleCaptions(): void\n seekBackward(): void\n seekForward(): void\n volumeUp(): void\n volumeDown(): void\n speedUp(): void\n speedDown(): void\n seekStart(): void\n seekEnd(): void\n seekPercent(percent: number): void\n}\n\n/**\n * Create keyboard event handler\n */\nexport function createKeyboardHandler(\n actions: KeyboardActions,\n options: { seekStep?: number; volumeStep?: number; speedStep?: number } = {},\n): (event: KeyboardEvent) => void {\n const { seekStep: _seekStep = 5, volumeStep: _volumeStep = 0.1, speedStep: _speedStep = 0.25 } = options\n\n return (event: KeyboardEvent) => {\n // Ignore if in input field\n if (\n event.target instanceof HTMLInputElement ||\n event.target instanceof HTMLTextAreaElement ||\n event.target instanceof HTMLSelectElement ||\n (event.target as HTMLElement)?.isContentEditable\n ) {\n return\n }\n\n const key = event.key\n const action = DEFAULT_KEYBOARD_SHORTCUTS[key]\n\n if (!action) return\n\n // Prevent default for handled keys\n event.preventDefault()\n\n switch (action) {\n case 'togglePlay':\n actions.togglePlay()\n break\n case 'toggleMute':\n actions.toggleMute()\n break\n case 'toggleFullscreen':\n actions.toggleFullscreen()\n break\n case 'togglePiP':\n actions.togglePiP()\n break\n case 'toggleCaptions':\n actions.toggleCaptions()\n break\n case 'seekBackward':\n actions.seekBackward()\n break\n case 'seekForward':\n actions.seekForward()\n break\n case 'volumeUp':\n actions.volumeUp()\n break\n case 'volumeDown':\n actions.volumeDown()\n break\n case 'speedUp':\n actions.speedUp()\n break\n case 'speedDown':\n actions.speedDown()\n break\n case 'seekStart':\n actions.seekStart()\n break\n case 'seekEnd':\n actions.seekEnd()\n break\n default:\n // Handle number keys for percentage seeking\n if (action.startsWith('seek')) {\n const percent = parseInt(action.replace('seek', ''), 10)\n if (!isNaN(percent)) {\n actions.seekPercent(percent)\n }\n }\n }\n }\n}\n\n// =============================================================================\n// User Activity Detection\n// =============================================================================\n\n/**\n * Create user activity detector\n */\nexport function createActivityDetector(\n element: HTMLElement,\n options: { timeout?: number; onActive?: () => void; onInactive?: () => void } = {},\n): () => void {\n const { timeout = 3000, onActive, onInactive } = options\n\n let timer: ReturnType<typeof setTimeout> | null = null\n let active = true\n\n const setActive = () => {\n if (!active) {\n active = true\n onActive?.()\n }\n resetTimer()\n }\n\n const setInactive = () => {\n if (active) {\n active = false\n onInactive?.()\n }\n }\n\n const resetTimer = () => {\n if (timer) clearTimeout(timer)\n timer = setTimeout(setInactive, timeout)\n }\n\n // Events that indicate activity\n const events = ['mousemove', 'mouseenter', 'mouseleave', 'mousedown', 'keydown', 'touchstart', 'touchmove']\n\n events.forEach((event) => element.addEventListener(event, setActive))\n\n // Start timer\n resetTimer()\n\n // Return cleanup function\n return () => {\n if (timer) clearTimeout(timer)\n events.forEach((event) => element.removeEventListener(event, setActive))\n }\n}\n\n// =============================================================================\n// Gesture Detection\n// =============================================================================\n\nexport interface GestureHandlers {\n onTap?: (x: number, y: number) => void\n onDoubleTap?: (x: number, y: number) => void\n onSwipeLeft?: () => void\n onSwipeRight?: () => void\n onSwipeUp?: () => void\n onSwipeDown?: () => void\n onScrub?: (progress: number) => void\n onScrubEnd?: () => void\n}\n\n/**\n * Create touch gesture detector\n */\nexport function createGestureDetector(element: HTMLElement, handlers: GestureHandlers): () => void {\n let startX = 0\n let startY = 0\n let startTime = 0\n let lastTap = 0\n let isScrubbing = false\n let cachedRect: DOMRect | null = null\n\n const SWIPE_THRESHOLD = 50\n const TAP_THRESHOLD = 200\n const DOUBLE_TAP_THRESHOLD = 300\n\n const onTouchStart = (e: TouchEvent) => {\n const touch = e.touches[0]\n startX = touch.clientX\n startY = touch.clientY\n startTime = Date.now()\n isScrubbing = false\n cachedRect = element.getBoundingClientRect()\n }\n\n const onTouchMove = (e: TouchEvent) => {\n if (!startTime) return\n\n const touch = e.touches[0]\n const deltaX = touch.clientX - startX\n const deltaY = touch.clientY - startY\n\n // Horizontal scrubbing\n if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 20) {\n isScrubbing = true\n const rect = cachedRect || element.getBoundingClientRect()\n const progress = Math.max(0, Math.min(1, (touch.clientX - rect.left) / rect.width))\n handlers.onScrub?.(progress)\n }\n }\n\n const onTouchEnd = (e: TouchEvent) => {\n const endTime = Date.now()\n const duration = endTime - startTime\n\n if (isScrubbing) {\n handlers.onScrubEnd?.()\n isScrubbing = false\n startTime = 0\n return\n }\n\n const touch = e.changedTouches[0]\n const deltaX = touch.clientX - startX\n const deltaY = touch.clientY - startY\n\n // Check for swipe\n if (duration < 500) {\n if (Math.abs(deltaX) > SWIPE_THRESHOLD && Math.abs(deltaX) > Math.abs(deltaY)) {\n if (deltaX > 0) {\n handlers.onSwipeRight?.()\n } else {\n handlers.onSwipeLeft?.()\n }\n startTime = 0\n return\n }\n\n if (Math.abs(deltaY) > SWIPE_THRESHOLD && Math.abs(deltaY) > Math.abs(deltaX)) {\n if (deltaY > 0) {\n handlers.onSwipeDown?.()\n } else {\n handlers.onSwipeUp?.()\n }\n startTime = 0\n return\n }\n }\n\n // Check for tap\n if (duration < TAP_THRESHOLD && Math.abs(deltaX) < 10 && Math.abs(deltaY) < 10) {\n const now = Date.now()\n if (now - lastTap < DOUBLE_TAP_THRESHOLD) {\n handlers.onDoubleTap?.(touch.clientX, touch.clientY)\n lastTap = 0\n } else {\n handlers.onTap?.(touch.clientX, touch.clientY)\n lastTap = now\n }\n }\n\n startTime = 0\n }\n\n element.addEventListener('touchstart', onTouchStart, { passive: true })\n element.addEventListener('touchmove', onTouchMove, { passive: true })\n element.addEventListener('touchend', onTouchEnd, { passive: true })\n\n return () => {\n element.removeEventListener('touchstart', onTouchStart)\n element.removeEventListener('touchmove', onTouchMove)\n element.removeEventListener('touchend', onTouchEnd)\n }\n}\n",
7
+ "/**\n * ts-video-player Feature Availability Detection\n *\n * Detects platform capabilities for volume, fullscreen, and PiP.\n *\n * @module core/features\n */\n\nimport type { FeatureAvailability } from '../types'\n\n// =============================================================================\n// Platform Detection Helpers\n// =============================================================================\n\n/**\n * Detect iOS Safari (including iPadOS Safari)\n */\nexport function isIOSSafari(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent\n // iPhone/iPad/iPod with Safari\n if (/iPad|iPhone|iPod/.test(ua) && !(window as any).MSStream) return true\n // iPadOS reports as Mac but has touch\n if (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) return true\n return false\n}\n\n/**\n * Detect Safari browser (desktop or mobile)\n */\nexport function isSafari(): boolean {\n if (typeof navigator === 'undefined') return false\n return /^(?:(?!chrome|android).)*safari/i.test(navigator.userAgent)\n}\n\n/**\n * Detect standalone PWA mode\n */\nexport function isStandalonePWA(): boolean {\n if (typeof window === 'undefined') return false\n return (navigator as any).standalone === true\n || window.matchMedia('(display-mode: standalone)').matches\n}\n\n// =============================================================================\n// Volume Availability\n// =============================================================================\n\n/**\n * Detect volume control availability.\n * iOS Safari silently ignores programmatic volume changes on media elements.\n */\nexport function detectVolumeAvailability(\n media?: HTMLMediaElement | null,\n): FeatureAvailability {\n if (isIOSSafari()) return 'unsupported'\n if (!media) return 'unavailable'\n return 'available'\n}\n\n/**\n * Async volume probe: attempts to set volume and reads it back.\n * This is the authoritative check - the sync check is a fast heuristic.\n */\nexport async function probeVolumeAvailability(\n media: HTMLMediaElement,\n): Promise<FeatureAvailability> {\n const original = media.volume\n try {\n const testValue = original === 1 ? 0.5 : 1\n media.volume = testValue\n // Some browsers apply volume asynchronously\n await new Promise((r) => setTimeout(r, 0))\n const changed = media.volume !== original\n media.volume = original\n return changed ? 'available' : 'unsupported'\n } catch {\n try { media.volume = original } catch { /* ignore */ }\n return 'unsupported'\n }\n}\n\n// =============================================================================\n// Fullscreen Availability\n// =============================================================================\n\ninterface WebKitDocument extends Document {\n webkitFullscreenEnabled?: boolean\n webkitFullscreenElement?: Element\n webkitExitFullscreen?: () => Promise<void>\n webkitCancelFullScreen?: () => Promise<void>\n mozFullScreenEnabled?: boolean\n msFullscreenEnabled?: boolean\n}\n\ninterface WebKitVideoElement extends HTMLVideoElement {\n webkitEnterFullscreen?: () => void\n webkitExitFullscreen?: () => void\n webkitSupportsFullscreen?: boolean\n webkitDisplayingFullscreen?: boolean\n webkitPresentationMode?: string\n webkitSetPresentationMode?: (mode: string) => void\n webkitSupportsPresentationMode?: (mode: string) => boolean\n}\n\ninterface WebKitFullscreenElement extends HTMLElement {\n webkitRequestFullscreen?: () => Promise<void>\n webkitRequestFullScreen?: () => Promise<void>\n}\n\n/**\n * Detect fullscreen API availability.\n */\nexport function detectFullscreenAvailability(\n container?: HTMLElement | null,\n videoElement?: HTMLVideoElement | null,\n): FeatureAvailability {\n const doc = typeof document !== 'undefined' ? document as WebKitDocument : null\n if (!doc) return 'unsupported'\n\n // Standard API or WebKit prefix\n if (doc.fullscreenEnabled || doc.webkitFullscreenEnabled) return 'available'\n // Moz/MS prefixes\n if (doc.mozFullScreenEnabled || doc.msFullscreenEnabled) return 'available'\n\n // iOS Safari: video-only fullscreen via webkitEnterFullscreen\n if (videoElement) {\n const video = videoElement as WebKitVideoElement\n if (video.webkitSupportsFullscreen === true) return 'available'\n if (typeof video.webkitEnterFullscreen === 'function') return 'available'\n }\n\n if (!container && !videoElement) return 'unavailable'\n return 'unsupported'\n}\n\n/**\n * Whether this environment only supports video-element fullscreen (iOS Safari),\n * not container-level fullscreen.\n */\nexport function isVideoOnlyFullscreen(): boolean {\n if (typeof document === 'undefined') return false\n const doc = document as WebKitDocument\n return isIOSSafari()\n && !doc.fullscreenEnabled\n && !doc.webkitFullscreenEnabled\n}\n\n/**\n * Enter fullscreen with cross-browser support including iOS Safari.\n */\nexport async function enterFullscreen(\n container: HTMLElement | null,\n media: HTMLMediaElement | null,\n): Promise<void> {\n const video = media as WebKitVideoElement | null\n\n // Try container first (standard and WebKit APIs)\n if (container) {\n const el = container as WebKitFullscreenElement\n if (typeof el.requestFullscreen === 'function') return el.requestFullscreen()\n if (typeof el.webkitRequestFullscreen === 'function') return el.webkitRequestFullscreen()\n if (typeof el.webkitRequestFullScreen === 'function') return el.webkitRequestFullScreen()\n }\n\n // Fall back to video element (iOS Safari)\n if (video && typeof video.webkitEnterFullscreen === 'function') {\n video.webkitEnterFullscreen()\n return\n }\n\n // Last resort: try media element with standard API\n if (media && typeof media.requestFullscreen === 'function') {\n return media.requestFullscreen()\n }\n}\n\n/**\n * Exit fullscreen with cross-browser support.\n */\nexport async function exitFullscreen(media?: HTMLMediaElement | null): Promise<void> {\n const doc = document as WebKitDocument\n const video = media as WebKitVideoElement | null\n\n if (typeof doc.exitFullscreen === 'function') return doc.exitFullscreen()\n if (typeof doc.webkitExitFullscreen === 'function') return doc.webkitExitFullscreen()\n if (typeof doc.webkitCancelFullScreen === 'function') return doc.webkitCancelFullScreen()\n\n // iOS Safari video fullscreen\n if (video && typeof video.webkitExitFullscreen === 'function') {\n video.webkitExitFullscreen()\n }\n}\n\n// =============================================================================\n// Picture-in-Picture Availability\n// =============================================================================\n\n/**\n * Detect Picture-in-Picture availability.\n */\nexport function detectPipAvailability(\n videoElement?: HTMLVideoElement | null,\n): FeatureAvailability {\n if (!videoElement) return 'unavailable'\n\n // Standard PiP API\n if ('requestPictureInPicture' in videoElement) {\n if (typeof document !== 'undefined' && document.pictureInPictureEnabled === false) {\n return 'unavailable'\n }\n // Safari PWAs have the API but it doesn't work\n if (isSafari() && isStandalonePWA()) return 'unavailable'\n return 'available'\n }\n\n // iOS Safari WebKit presentation mode\n const video = videoElement as WebKitVideoElement\n if (typeof video.webkitSetPresentationMode === 'function') {\n if (isStandalonePWA()) return 'unavailable'\n if (typeof video.webkitSupportsPresentationMode === 'function') {\n return video.webkitSupportsPresentationMode('picture-in-picture')\n ? 'available'\n : 'unsupported'\n }\n return 'available'\n }\n\n return 'unsupported'\n}\n\n/**\n * Enter Picture-in-Picture with cross-browser support.\n */\nexport async function enterPiP(media: HTMLMediaElement): Promise<void> {\n const video = media as HTMLVideoElement & WebKitVideoElement\n\n // Standard PiP API\n if (typeof video.requestPictureInPicture === 'function') {\n await video.requestPictureInPicture()\n return\n }\n\n // iOS Safari WebKit presentation mode\n if (typeof video.webkitSetPresentationMode === 'function') {\n video.webkitSetPresentationMode('picture-in-picture')\n }\n}\n\n/**\n * Exit Picture-in-Picture with cross-browser support.\n */\nexport async function exitPiP(media?: HTMLMediaElement | null): Promise<void> {\n // Standard PiP API\n if (document.pictureInPictureElement && typeof document.exitPictureInPicture === 'function') {\n await document.exitPictureInPicture()\n return\n }\n\n // iOS Safari WebKit presentation mode\n if (media) {\n const video = media as WebKitVideoElement\n if (video.webkitPresentationMode === 'picture-in-picture'\n && typeof video.webkitSetPresentationMode === 'function') {\n video.webkitSetPresentationMode('inline')\n }\n }\n}\n\n// =============================================================================\n// Aggregate Detection\n// =============================================================================\n\n/**\n * Detect all feature availabilities at once.\n */\nexport function detectAllFeatures(\n container?: HTMLElement | null,\n videoElement?: HTMLVideoElement | null,\n mediaElement?: HTMLMediaElement | null,\n): Record<'volume' | 'fullscreen' | 'pip', FeatureAvailability> {\n return {\n volume: detectVolumeAvailability(mediaElement),\n fullscreen: detectFullscreenAvailability(container, videoElement),\n pip: detectPipAvailability(videoElement),\n }\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "24A95575AA67786364756E2164756E21",
11
+ "names": []
12
+ }