@symbiote-native/video 0.0.0-stage → 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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -2
  3. package/build/angular/index.d.ts +4 -0
  4. package/build/angular/index.js +5 -0
  5. package/build/angular/inject-video-player.d.ts +4 -0
  6. package/build/angular/inject-video-player.js +6 -0
  7. package/build/angular/video-airplay-button/index.d.ts +12 -0
  8. package/build/angular/video-airplay-button/index.js +78 -0
  9. package/build/angular/video-view/index.d.ts +17 -0
  10. package/build/angular/video-view/index.js +97 -0
  11. package/build/core/constants.d.ts +12 -0
  12. package/build/core/constants.js +13 -0
  13. package/build/core/index.d.ts +10 -0
  14. package/build/core/index.js +8 -0
  15. package/build/core/native-module.d.ts +10 -0
  16. package/build/core/native-module.js +3 -0
  17. package/build/core/player-types.d.ts +221 -0
  18. package/build/core/player-types.js +1 -0
  19. package/build/core/video-airplay-button.d.ts +4 -0
  20. package/build/core/video-airplay-button.js +29 -0
  21. package/build/core/video-module.d.ts +12 -0
  22. package/build/core/video-module.js +21 -0
  23. package/build/core/video-player-controller.d.ts +15 -0
  24. package/build/core/video-player-controller.js +21 -0
  25. package/build/core/video-player.d.ts +7 -0
  26. package/build/core/video-player.js +22 -0
  27. package/build/core/video-source.d.ts +3 -0
  28. package/build/core/video-source.js +20 -0
  29. package/build/core/video-thumbnail.d.ts +4 -0
  30. package/build/core/video-thumbnail.js +3 -0
  31. package/build/core/video-view.d.ts +18 -0
  32. package/build/core/video-view.js +63 -0
  33. package/build/core/view-types.d.ts +90 -0
  34. package/build/core/view-types.js +1 -0
  35. package/build/react/index.d.ts +4 -0
  36. package/build/react/index.js +4 -0
  37. package/build/react/use-video-player.d.ts +7 -0
  38. package/build/react/use-video-player.js +11 -0
  39. package/build/react/video-view.d.ts +13 -0
  40. package/build/react/video-view.js +10 -0
  41. package/build/solid/index.d.ts +3 -0
  42. package/build/solid/index.js +4 -0
  43. package/build/solid/use-video-player.d.ts +8 -0
  44. package/build/solid/use-video-player.js +11 -0
  45. package/build/solid/video-view.d.ts +33 -0
  46. package/build/solid/video-view.js +6 -0
  47. package/build/svelte/index.d.ts +5 -0
  48. package/build/svelte/index.js +5 -0
  49. package/build/svelte/use-video-player.svelte.d.ts +10 -0
  50. package/build/svelte/use-video-player.svelte.js +15 -0
  51. package/build/svelte/video-airplay-button.svelte +12 -0
  52. package/build/svelte/video-airplay-button.svelte.d.ts +4 -0
  53. package/build/svelte/video-view.svelte +25 -0
  54. package/build/svelte/video-view.svelte.d.ts +9 -0
  55. package/build/vue/index.d.ts +3 -0
  56. package/build/vue/index.js +4 -0
  57. package/build/vue/use-video-player.d.ts +8 -0
  58. package/build/vue/use-video-player.js +16 -0
  59. package/build/vue/video-view.d.ts +5 -0
  60. package/build/vue/video-view.js +14 -0
  61. package/build-ngc/angular/index.d.ts +4 -0
  62. package/build-ngc/angular/index.js +6 -0
  63. package/build-ngc/angular/index.js.map +1 -0
  64. package/build-ngc/angular/inject-video-player.d.ts +4 -0
  65. package/build-ngc/angular/inject-video-player.js +7 -0
  66. package/build-ngc/angular/inject-video-player.js.map +1 -0
  67. package/build-ngc/angular/video-airplay-button/index.d.ts +15 -0
  68. package/build-ngc/angular/video-airplay-button/index.js +37 -0
  69. package/build-ngc/angular/video-airplay-button/index.js.map +1 -0
  70. package/build-ngc/angular/video-view/index.d.ts +20 -0
  71. package/build-ngc/angular/video-view/index.js +56 -0
  72. package/build-ngc/angular/video-view/index.js.map +1 -0
  73. package/build-ngc/core/constants.d.ts +12 -0
  74. package/build-ngc/core/constants.js +14 -0
  75. package/build-ngc/core/constants.js.map +1 -0
  76. package/build-ngc/core/index.d.ts +10 -0
  77. package/build-ngc/core/index.js +9 -0
  78. package/build-ngc/core/index.js.map +1 -0
  79. package/build-ngc/core/native-module.d.ts +10 -0
  80. package/build-ngc/core/native-module.js +4 -0
  81. package/build-ngc/core/native-module.js.map +1 -0
  82. package/build-ngc/core/player-types.d.ts +221 -0
  83. package/build-ngc/core/player-types.js +2 -0
  84. package/build-ngc/core/player-types.js.map +1 -0
  85. package/build-ngc/core/video-airplay-button.d.ts +4 -0
  86. package/build-ngc/core/video-airplay-button.js +30 -0
  87. package/build-ngc/core/video-airplay-button.js.map +1 -0
  88. package/build-ngc/core/video-module.d.ts +12 -0
  89. package/build-ngc/core/video-module.js +22 -0
  90. package/build-ngc/core/video-module.js.map +1 -0
  91. package/build-ngc/core/video-player-controller.d.ts +15 -0
  92. package/build-ngc/core/video-player-controller.js +22 -0
  93. package/build-ngc/core/video-player-controller.js.map +1 -0
  94. package/build-ngc/core/video-player.d.ts +7 -0
  95. package/build-ngc/core/video-player.js +23 -0
  96. package/build-ngc/core/video-player.js.map +1 -0
  97. package/build-ngc/core/video-source.d.ts +3 -0
  98. package/build-ngc/core/video-source.js +21 -0
  99. package/build-ngc/core/video-source.js.map +1 -0
  100. package/build-ngc/core/video-thumbnail.d.ts +4 -0
  101. package/build-ngc/core/video-thumbnail.js +4 -0
  102. package/build-ngc/core/video-thumbnail.js.map +1 -0
  103. package/build-ngc/core/video-view.d.ts +18 -0
  104. package/build-ngc/core/video-view.js +64 -0
  105. package/build-ngc/core/video-view.js.map +1 -0
  106. package/build-ngc/core/view-types.d.ts +90 -0
  107. package/build-ngc/core/view-types.js +2 -0
  108. package/build-ngc/core/view-types.js.map +1 -0
  109. package/native-link.json +33 -0
  110. package/package.json +144 -3
  111. package/src/angular/index.ts +6 -0
  112. package/src/angular/inject-video-player.ts +20 -0
  113. package/src/angular/video-airplay-button/index.ts +38 -0
  114. package/src/angular/video-view/index.ts +59 -0
  115. package/src/core/constants.ts +16 -0
  116. package/src/core/index.ts +56 -0
  117. package/src/core/native-module.ts +15 -0
  118. package/src/core/player-types.ts +241 -0
  119. package/src/core/video-airplay-button.ts +45 -0
  120. package/src/core/video-module.ts +25 -0
  121. package/src/core/video-player-controller.ts +53 -0
  122. package/src/core/video-player.ts +38 -0
  123. package/src/core/video-source.ts +21 -0
  124. package/src/core/video-thumbnail.ts +7 -0
  125. package/src/core/video-view.ts +119 -0
  126. package/src/core/view-types.ts +114 -0
  127. package/src/react/index.ts +6 -0
  128. package/src/react/use-video-player.ts +22 -0
  129. package/src/react/video-view.ts +35 -0
  130. package/src/solid/index.ts +5 -0
  131. package/src/solid/use-video-player.ts +24 -0
  132. package/src/solid/video-view.ts +22 -0
  133. package/src/svelte/index.ts +7 -0
  134. package/src/svelte/svelte-ambient.d.ts +3 -0
  135. package/src/svelte/svelte-compile.test-helper.ts +6 -0
  136. package/src/svelte/use-video-player.svelte.ts +31 -0
  137. package/src/svelte/video-airplay-button.svelte +12 -0
  138. package/src/svelte/video-view.svelte +25 -0
  139. package/src/vue/index.ts +5 -0
  140. package/src/vue/use-video-player.ts +33 -0
  141. package/src/vue/video-view.ts +24 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 A. Prokopenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,241 @@
1
- # Temporary Holding Version
1
+ # @symbiote-native/video
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [`expo-video`](https://docs.expo.dev/versions/latest/sdk/video/) for **every**
4
+ [SymbioteNative](../../README.md) adapter: React, Vue, Svelte, Solid and Angular. The player, the
5
+ view, thumbnails, the video cache and the AirPlay button.
6
+
7
+ Built the same way as [`@symbiote-native/clipboard`](../clipboard)'s `ClipboardPasteButton`, an
8
+ `expo-modules-core` native view reached through `requireNativeViewManager` (see the
9
+ `symbiote-expo-native-module` project skill: why `expo-modules-core` is depended on directly and never
10
+ the `expo` meta-package, why the upstream JS is hand-ported into `core/`, and how autolinking finds the
11
+ native module). One render function in `core/` returns a descriptor and every adapter only turns it into
12
+ its own element.
13
+
14
+ ## Install
15
+
16
+ **New app:**
17
+
18
+ ```bash
19
+ npx @symbiote-native/cli new my-app --video
20
+ ```
21
+
22
+ **Existing SymbioteNative app:**
23
+
24
+ ```bash
25
+ npx @symbiote-native/cli add --video
26
+ ```
27
+
28
+ Either way: installs `@symbiote-native/video` and wires the native autolinking automatically,
29
+ see [`@symbiote-native/cli`](../cli).
30
+
31
+ <details>
32
+ <summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
33
+
34
+ ```bash
35
+ npm install @symbiote-native/video
36
+ ```
37
+
38
+ Depends on `expo-video` and `expo-modules-core` directly (regular dependencies, pinned to exact
39
+ versions, since this package's `core/` is hand-ported against one specific native API shape).
40
+ Never install `expo-video` yourself, and never add the `expo` package to this project: it bundles
41
+ its own Metro/Babel pipeline that conflicts with this project's own.
42
+
43
+ ### Required one-time step: native autolinking wiring
44
+
45
+ `expo-video`'s native code is discovered by `expo-modules-autolinking`, not by RN's own
46
+ `react-native.config.cjs` mechanism. Wire it into the native host app **once**, it covers this package
47
+ and every other `expo-modules-core` package with zero further changes. The steps and the
48
+ mechanics behind them are in the `symbiote-expo-native-module` skill and in
49
+ [`@symbiote-native/network`](../network)'s README; the reference app is `examples/expo-react`.
50
+
51
+ ### Background playback and Picture in Picture
52
+
53
+ The package writes nothing by default. For iOS add `audio` to `UIBackgroundModes` in `Info.plist`.
54
+ For Android choose the "Background video playback" bundle (the foreground service and its permissions),
55
+ and give the main activity `android:supportsPictureInPicture="true"` for Picture in Picture.
56
+
57
+ </details>
58
+
59
+ ## Shape
60
+
61
+ ```
62
+ src/core/ video-player.ts and video-player-controller.ts (the player and its lifecycle over
63
+ the engine's createJsonKeyedResourceController), video-view.ts
64
+ (createVideoView(getNode)), video-airplay-button.ts, video-source.ts,
65
+ video-module.ts (cache and Picture in Picture functions), video-thumbnail.ts.
66
+ src/react/ @symbiote-native/video/react - VideoView, useVideoPlayer
67
+ src/vue/ @symbiote-native/video/vue - VideoView, useVideoPlayer (a computed ref)
68
+ src/svelte/ @symbiote-native/video/svelte - VideoView, useVideoPlayer ({ current })
69
+ src/solid/ @symbiote-native/video/solid - VideoView, useVideoPlayer (an accessor)
70
+ src/angular/ @symbiote-native/video/angular - VideoView, injectVideoPlayer (a signal)
71
+ ```
72
+
73
+ `VideoView` is one component per platform (`VideoView` on iOS, `SurfaceVideoView` or `TextureVideoView` on
74
+ Android), and the view functions follow the surface the last render chose. `VideoAirPlayButton` is a plain
75
+ view off iOS. `useEvent` and `useEventListener` come from each adapter, not from this package.
76
+
77
+ ## Use it
78
+
79
+ ### React
80
+
81
+ ```tsx
82
+ import { VideoView, useVideoPlayer } from '@symbiote-native/video/react';
83
+
84
+ const player = useVideoPlayer('https://example.com/video.mp4', player => {
85
+ player.loop = true;
86
+ player.play();
87
+ });
88
+
89
+ <VideoView player={player} style={{ width: 320, height: 180 }} nativeControls />;
90
+ ```
91
+
92
+ ### Vue
93
+
94
+ ```vue
95
+ <script setup lang="ts">
96
+ import { VideoView, useVideoPlayer } from '@symbiote-native/video/vue';
97
+
98
+ const player = useVideoPlayer(
99
+ () => 'https://example.com/video.mp4',
100
+ instance => {
101
+ instance.loop = true;
102
+ instance.play();
103
+ },
104
+ );
105
+ </script>
106
+
107
+ <template>
108
+ <VideoView :player="player" :style="{ width: 320, height: 180 }" :nativeControls="true" />
109
+ </template>
110
+ ```
111
+
112
+ ### Angular
113
+
114
+ ```ts
115
+ import { Component } from '@angular/core';
116
+ import { VideoView, injectVideoPlayer } from '@symbiote-native/video/angular';
117
+
118
+ @Component({
119
+ standalone: true,
120
+ imports: [VideoView],
121
+ template: `
122
+ <VideoView [player]="player()" [style]="{ width: 320, height: 180 }" [nativeControls]="true" />
123
+ `,
124
+ })
125
+ export class Clip {
126
+ readonly player = injectVideoPlayer(
127
+ () => 'https://example.com/video.mp4',
128
+ instance => {
129
+ instance.loop = true;
130
+ instance.play();
131
+ },
132
+ );
133
+ }
134
+ ```
135
+
136
+ ### Svelte
137
+
138
+ ```svelte
139
+ <script lang="ts">
140
+ import { VideoView, useVideoPlayer } from '@symbiote-native/video/svelte';
141
+
142
+ const player = useVideoPlayer(
143
+ () => 'https://example.com/video.mp4',
144
+ instance => {
145
+ instance.loop = true;
146
+ instance.play();
147
+ },
148
+ );
149
+ </script>
150
+
151
+ <VideoView player={player.current} style={{ width: 320, height: 180 }} nativeControls />
152
+ ```
153
+
154
+ ### Solid
155
+
156
+ ```tsx
157
+ import { VideoView, useVideoPlayer } from '@symbiote-native/video/solid';
158
+
159
+ const player = useVideoPlayer(
160
+ () => 'https://example.com/video.mp4',
161
+ instance => {
162
+ instance.loop = true;
163
+ instance.play();
164
+ },
165
+ );
166
+
167
+ <VideoView player={player()} style={{ width: 320, height: 180 }} nativeControls />;
168
+ ```
169
+
170
+ ## API
171
+
172
+ ```ts
173
+ useVideoPlayer(source, setup?, options?): VideoPlayer // released on unmount, per adapter see Shape
174
+ createVideoPlayer(source, options?): VideoPlayer // you call player.release()
175
+
176
+ <VideoView player nativeControls? contentFit? surfaceType?={'surfaceView' | 'textureView'} // Android
177
+ allowsPictureInPicture? ... />
178
+ <VideoAirPlayButton ... /> // plain view off iOS
179
+
180
+ isPictureInPictureSupported(): boolean
181
+ setVideoCacheSizeAsync(sizeBytes): Promise<void> clearVideoCacheAsync(): Promise<void>
182
+ getCurrentVideoCacheSize(): number // all three work only while no player exists
183
+ ```
184
+
185
+ The player is the native `VideoPlayer` shared object, `{ uri, useCaching }` sources enable the cache.
186
+ Ported from upstream's `VideoPlayer.ts`, `VideoView.tsx`, `VideoAirPlayButton.tsx` and `index.ts`.
187
+
188
+ ## Notes
189
+
190
+ - **One player, one `VideoView` on Android.** Mounting several views with the same player does not
191
+ work there, a platform limitation. iOS accepts it. Create a player per visible view, or move the
192
+ player to the new view only after the old one is gone.
193
+ - **`useVideoPlayer` releases the player for you.** It disposes of it when the component unmounts,
194
+ and a changed source or options make a new one. A player from `createVideoPlayer` is yours:
195
+ call `release()` when you are done, or it leaks.
196
+ - **Android renders on a surface by default.** `surfaceType="surfaceView"` is the efficient choice,
197
+ `surfaceType="textureView"` composes like an ordinary view and costs more performance.
198
+ - **Caching is per source.** Set `useCaching: true` on the source object. The cache is persistent
199
+ and trimmed least-recently-used, 1 GB by default, and works offline for what it holds.
200
+ iOS cannot cache HLS, and DRM-protected video is not cached on either platform.
201
+ - **The cache functions work only while no player exists**, so call `setVideoCacheSizeAsync` and
202
+ `clearVideoCacheAsync` before you create one.
203
+ - **`useEvent` and `useEventListener` come from the adapter**, not from this package. See the aside
204
+ above.
205
+ - **Not ported.** The web build. `useEvent` / `useEventListener` ship with the `expo` package upstream, here the adapters export them for any emitter (`useEvent(player, 'statusChange')`, `injectEvent` in Angular, `@symbiote-native/svelte/runes/use-event` in Svelte). Upstream ships no tests, the suites here are written against its behavior.
206
+
207
+ ## Common questions
208
+
209
+ - **Black screen on Android.** One player in several `VideoView`s does not work there. Keep one view
210
+ per player and unmount the old view first.
211
+ - **Overlap or out of bounds on Android.** An ExoPlayer bug with `contentFit="cover"`. Set
212
+ `surfaceType="textureView"`.
213
+ - **`zIndex` ignored on Android.** The default surface draws above its surroundings. Try
214
+ `surfaceType="textureView"`.
215
+ - **Touch handlers do not fire on Android.** Put the handler on a wrapping view.
216
+ - **Not released.** `useVideoPlayer` releases on unmount, a player from `createVideoPlayer` needs
217
+ `player.release()`.
218
+ - **Fullscreen will not rotate on Android.** It follows the app's orientation lock, unlock it with
219
+ `@symbiote-native/screen-orientation`.
220
+ - **Caching.** `{ uri, useCaching: true }`. 1 GB by default, not for HLS on iOS or DRM. The cache
221
+ functions work only while no player exists.
222
+
223
+ Sources: [Expo docs: Video](https://docs.expo.dev/versions/latest/sdk/video/),
224
+ [expo/expo#35012](https://github.com/expo/expo/issues/35012),
225
+ [expo/expo#31248](https://github.com/expo/expo/issues/31248),
226
+ [expo/expo#31722](https://github.com/expo/expo/issues/31722),
227
+ [expo/expo#30275](https://github.com/expo/expo/issues/30275),
228
+ [expo/expo#34630](https://github.com/expo/expo/issues/34630),
229
+ [expo/expo#33804](https://github.com/expo/expo/issues/33804),
230
+ [expo/expo#9899](https://github.com/expo/expo/issues/9899).
231
+
232
+ ## Test it
233
+
234
+ No device is needed for the logic. The core tests (`src/core/*.test.ts`) replace `expo-modules-core`
235
+ (`requireNativeViewManager`, `Platform`) and assert the descriptor a render function returns. The
236
+ adapter tests (`src/{react,vue,solid,angular}/**/*.test.*`, `vitest`) render the real component over the
237
+ recording Fabric with an injected view config and assert the committed payload, and Svelte's
238
+ `*.smoke.test.ts` compile the `.svelte` files and mount them. Painting itself is verified on a device in
239
+ the six `examples/expo-*` canary apps (`examples/expo-react`, `examples/expo-vue-sfc`,
240
+ `examples/expo-vue-tsx`, `examples/expo-svelte`, `examples/expo-solid`, `examples/expo-angular`), see the
241
+ parent [README](../../README.md).
@@ -0,0 +1,4 @@
1
+ export { VideoView } from './video-view';
2
+ export { VideoAirPlayButton } from './video-airplay-button';
3
+ export { injectVideoPlayer } from './inject-video-player';
4
+ export * from '../core';
@@ -0,0 +1,5 @@
1
+ // @symbiote-native/video/angular: плеер, view, миниатюры, кэш и кнопка AirPlay на общем ядре
2
+ export { VideoView } from './video-view/index.js';
3
+ export { VideoAirPlayButton } from './video-airplay-button/index.js';
4
+ export { injectVideoPlayer } from './inject-video-player.js';
5
+ export * from '../core/index.js';
@@ -0,0 +1,4 @@
1
+ import type { Signal } from '@angular/core';
2
+ import type { IVideoPlayerBuilderOptions, IVideoSource, VideoPlayer } from '../core';
3
+ /** Released with the injection context, `setup` runs once on each new player */
4
+ export declare const injectVideoPlayer: (source: () => IVideoSource, setup?: (player: VideoPlayer) => void, options?: () => IVideoPlayerBuilderOptions | undefined) => Signal<VideoPlayer>;
@@ -0,0 +1,6 @@
1
+ // Angular twin of `useVideoPlayer`, `injectX` shape matching `injectAudioPlayer`
2
+ import { createResourceHook } from '@symbiote-native/angular';
3
+ import { createVideoPlayerController } from '../core/video-player-controller.js';
4
+ const injectPlayerResource = createResourceHook(createVideoPlayerController);
5
+ /** Released with the injection context, `setup` runs once on each new player */
6
+ export const injectVideoPlayer = (source, setup, options) => injectPlayerResource(() => [source(), options?.(), setup]);
@@ -0,0 +1,12 @@
1
+ import { NativeViewBase } from '@symbiote-native/angular';
2
+ import type { IDescriptor } from '@symbiote-native/components';
3
+ import type { IVideoAirPlayButtonProps } from '../../core';
4
+ declare const AIRPLAY_INPUTS: readonly ["tint", "activeTint", "prioritizeVideoDevices", "onBeginPresentingRoutes", "onEndPresentingRoutes"];
5
+ export interface VideoAirPlayButton extends Partial<Pick<IVideoAirPlayButtonProps, (typeof AIRPLAY_INPUTS)[number]>> {
6
+ }
7
+ /** Angular twin of `expo-video`'s `VideoAirPlayButton`, a plain view off iOS */
8
+ export declare class VideoAirPlayButton extends NativeViewBase {
9
+ protected readonly propNames: readonly ["tint", "activeTint", "prioritizeVideoDevices", "onBeginPresentingRoutes", "onEndPresentingRoutes"];
10
+ protected renderView(props: object): IDescriptor | null;
11
+ }
12
+ export {};
@@ -0,0 +1,78 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
36
+ import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
37
+ import { renderVideoAirPlayButton } from '../../core/index.js';
38
+ // One list is the inputs of the component and the props it hands to the native view
39
+ const AIRPLAY_INPUTS = [
40
+ 'tint',
41
+ 'activeTint',
42
+ 'prioritizeVideoDevices',
43
+ 'onBeginPresentingRoutes',
44
+ 'onEndPresentingRoutes',
45
+ ];
46
+ /** Angular twin of `expo-video`'s `VideoAirPlayButton`, a plain view off iOS */
47
+ let VideoAirPlayButton = (() => {
48
+ let _classDecorators = [Component({
49
+ selector: 'VideoAirPlayButton',
50
+ standalone: true,
51
+ imports: [DescriptorOutlet],
52
+ inputs: [...AIRPLAY_INPUTS],
53
+ changeDetection: ChangeDetectionStrategy.OnPush,
54
+ template: `@if (descriptor; as node) {
55
+ <symbiote-descriptor-outlet [node]="node" />
56
+ }`,
57
+ })];
58
+ let _classDescriptor;
59
+ let _classExtraInitializers = [];
60
+ let _classThis;
61
+ let _classSuper = NativeViewBase;
62
+ var VideoAirPlayButton = class extends _classSuper {
63
+ static { _classThis = this; }
64
+ static {
65
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
66
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
67
+ VideoAirPlayButton = _classThis = _classDescriptor.value;
68
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
69
+ __runInitializers(_classThis, _classExtraInitializers);
70
+ }
71
+ propNames = AIRPLAY_INPUTS;
72
+ renderView(props) {
73
+ return renderVideoAirPlayButton(props);
74
+ }
75
+ };
76
+ return VideoAirPlayButton = _classThis;
77
+ })();
78
+ export { VideoAirPlayButton };
@@ -0,0 +1,17 @@
1
+ import { NativeViewBase } from '@symbiote-native/angular';
2
+ import type { IDescriptor } from '@symbiote-native/components';
3
+ import type { IVideoViewProps } from '../../core';
4
+ declare const VIDEO_VIEW_INPUTS: readonly ["player", "nativeControls", "contentFit", "fullscreenOptions", "showsTimecodes", "requiresLinearPlayback", "buttonOptions", "surfaceType", "contentPosition", "onPictureInPictureStart", "onPictureInPictureStop", "allowsPictureInPicture", "startsPictureInPictureAutomatically", "allowsVideoFrameAnalysis", "onFullscreenEnter", "onFullscreenExit", "onFirstFrameRender", "useExoShutter"];
5
+ export interface VideoView extends Partial<Pick<IVideoViewProps, (typeof VIDEO_VIEW_INPUTS)[number]>> {
6
+ }
7
+ /** Angular twin of `expo-video`'s `VideoView` */
8
+ export declare class VideoView extends NativeViewBase {
9
+ private readonly view;
10
+ readonly enterFullscreen: () => Promise<void>;
11
+ readonly exitFullscreen: () => Promise<void>;
12
+ readonly startPictureInPicture: () => Promise<void>;
13
+ readonly stopPictureInPicture: () => Promise<void>;
14
+ protected readonly propNames: readonly ["player", "nativeControls", "contentFit", "fullscreenOptions", "showsTimecodes", "requiresLinearPlayback", "buttonOptions", "surfaceType", "contentPosition", "onPictureInPictureStart", "onPictureInPictureStop", "allowsPictureInPicture", "startsPictureInPictureAutomatically", "allowsVideoFrameAnalysis", "onFullscreenEnter", "onFullscreenExit", "onFirstFrameRender", "useExoShutter"];
15
+ protected renderView(props: object): IDescriptor | null;
16
+ }
17
+ export {};
@@ -0,0 +1,97 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
36
+ import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
37
+ import { createVideoView } from '../../core/index.js';
38
+ // One list is the inputs of the component and the props it hands to the native view
39
+ const VIDEO_VIEW_INPUTS = [
40
+ 'player',
41
+ 'nativeControls',
42
+ 'contentFit',
43
+ 'fullscreenOptions',
44
+ 'showsTimecodes',
45
+ 'requiresLinearPlayback',
46
+ 'buttonOptions',
47
+ 'surfaceType',
48
+ 'contentPosition',
49
+ 'onPictureInPictureStart',
50
+ 'onPictureInPictureStop',
51
+ 'allowsPictureInPicture',
52
+ 'startsPictureInPictureAutomatically',
53
+ 'allowsVideoFrameAnalysis',
54
+ 'onFullscreenEnter',
55
+ 'onFullscreenExit',
56
+ 'onFirstFrameRender',
57
+ 'useExoShutter',
58
+ ];
59
+ /** Angular twin of `expo-video`'s `VideoView` */
60
+ let VideoView = (() => {
61
+ let _classDecorators = [Component({
62
+ selector: 'VideoView',
63
+ standalone: true,
64
+ imports: [DescriptorOutlet],
65
+ inputs: [...VIDEO_VIEW_INPUTS],
66
+ changeDetection: ChangeDetectionStrategy.OnPush,
67
+ template: `@if (descriptor; as node) {
68
+ <symbiote-descriptor-outlet [node]="node" />
69
+ }`,
70
+ })];
71
+ let _classDescriptor;
72
+ let _classExtraInitializers = [];
73
+ let _classThis;
74
+ let _classSuper = NativeViewBase;
75
+ var VideoView = class extends _classSuper {
76
+ static { _classThis = this; }
77
+ static {
78
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
79
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
80
+ VideoView = _classThis = _classDescriptor.value;
81
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
82
+ __runInitializers(_classThis, _classExtraInitializers);
83
+ }
84
+ view = createVideoView(() => this.hostNode());
85
+ // The functions of the view are members of the component, a `@ViewChild` reaches them
86
+ enterFullscreen = this.view.handle.enterFullscreen;
87
+ exitFullscreen = this.view.handle.exitFullscreen;
88
+ startPictureInPicture = this.view.handle.startPictureInPicture;
89
+ stopPictureInPicture = this.view.handle.stopPictureInPicture;
90
+ propNames = VIDEO_VIEW_INPUTS;
91
+ renderView(props) {
92
+ return this.view.render(props);
93
+ }
94
+ };
95
+ return VideoView = _classThis;
96
+ })();
97
+ export { VideoView };
@@ -0,0 +1,12 @@
1
+ export declare const VIDEO_MODULE_NAME = "ExpoVideo";
2
+ /** Upstream's label for its `UnavailabilityError` */
3
+ export declare const VIDEO_PACKAGE_NAME = "expo-video";
4
+ export declare const VIDEO_VIEW_NAMES: {
5
+ /** The one iOS view */
6
+ readonly video: "VideoView";
7
+ /** The Android default, renders into a `SurfaceView` */
8
+ readonly surface: "SurfaceVideoView";
9
+ /** Android, for overlapping views */
10
+ readonly texture: "TextureVideoView";
11
+ readonly airPlayButton: "VideoAirPlayButtonView";
12
+ };
@@ -0,0 +1,13 @@
1
+ // Apart from `native-module`, which resolves the module on import: the views need the name too
2
+ export const VIDEO_MODULE_NAME = 'ExpoVideo';
3
+ /** Upstream's label for its `UnavailabilityError` */
4
+ export const VIDEO_PACKAGE_NAME = 'expo-video';
5
+ export const VIDEO_VIEW_NAMES = {
6
+ /** The one iOS view */
7
+ video: 'VideoView',
8
+ /** The Android default, renders into a `SurfaceView` */
9
+ surface: 'SurfaceVideoView',
10
+ /** Android, for overlapping views */
11
+ texture: 'TextureVideoView',
12
+ airPlayButton: 'VideoAirPlayButtonView',
13
+ };
@@ -0,0 +1,10 @@
1
+ export { VIDEO_MODULE_NAME } from './constants';
2
+ export type { IVideoAudioMixingMode, IVideoAudioTrack, IVideoBufferOptions, IVideoContentType, IVideoDrmOptions, IVideoDrmType, IVideoMetadata, IVideoPlayerBuilderOptions, IVideoPlayerError, IVideoPlayerEvents, IVideoPlayerStatus, IVideoRange, IVideoScrubbingModeOptions, IVideoSeekTolerance, IVideoSize, IVideoSource, IVideoSourceObject, IVideoSubtitleTrack, IVideoThumbnailOptions, IVideoTrack, VideoPlayer, } from './player-types';
3
+ export { createVideoPlayer } from './video-player';
4
+ export { createVideoPlayerController, type IVideoPlayerController, } from './video-player-controller';
5
+ export { clearVideoCacheAsync, getCurrentVideoCacheSize, isPictureInPictureSupported, setVideoCacheSizeAsync, } from './video-module';
6
+ export { parseSource } from './video-source';
7
+ export { VideoThumbnail } from './video-thumbnail';
8
+ export { createVideoView, type IVideoView, type IVideoViewHandle, } from './video-view';
9
+ export { renderVideoAirPlayButton, videoAirPlayButtonViewName, } from './video-airplay-button';
10
+ export type { IVideoAirPlayButtonProps, IVideoButtonOptions, IVideoContentFit, IVideoFullscreenOptions, IVideoFullscreenOrientation, IVideoKeepFullscreenOnPiPStop, IVideoSurfaceType, IVideoViewProps, } from './view-types';
@@ -0,0 +1,8 @@
1
+ export { VIDEO_MODULE_NAME } from './constants.js';
2
+ export { createVideoPlayer } from './video-player.js';
3
+ export { createVideoPlayerController, } from './video-player-controller.js';
4
+ export { clearVideoCacheAsync, getCurrentVideoCacheSize, isPictureInPictureSupported, setVideoCacheSizeAsync, } from './video-module.js';
5
+ export { parseSource } from './video-source.js';
6
+ export { VideoThumbnail } from './video-thumbnail.js';
7
+ export { createVideoView, } from './video-view.js';
8
+ export { renderVideoAirPlayButton, videoAirPlayButtonViewName, } from './video-airplay-button.js';
@@ -0,0 +1,10 @@
1
+ import type { VideoPlayer, VideoThumbnail } from './player-types';
2
+ export type INativeVideoModule = {
3
+ VideoPlayer: typeof VideoPlayer;
4
+ VideoThumbnail: typeof VideoThumbnail;
5
+ isPictureInPictureSupported(): boolean;
6
+ setVideoCacheSizeAsync(sizeBytes: number): Promise<void>;
7
+ clearVideoCacheAsync(): Promise<void>;
8
+ getCurrentVideoCacheSize(): number;
9
+ };
10
+ export declare const expoVideo: INativeVideoModule;
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ import { VIDEO_MODULE_NAME } from './constants.js';
3
+ export const expoVideo = requireNativeModule(VIDEO_MODULE_NAME);