@venomousone/rn-videokit 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.
- package/LICENSE +20 -0
- package/README.md +248 -0
- package/lib/module/components/VideoKit.js +347 -0
- package/lib/module/components/VideoKit.js.map +1 -0
- package/lib/module/components/controls/FullscreenButton.js +38 -0
- package/lib/module/components/controls/FullscreenButton.js.map +1 -0
- package/lib/module/components/controls/Icon.js +71 -0
- package/lib/module/components/controls/Icon.js.map +1 -0
- package/lib/module/components/controls/PlayPauseButton.js +33 -0
- package/lib/module/components/controls/PlayPauseButton.js.map +1 -0
- package/lib/module/components/controls/Scrubber.js +146 -0
- package/lib/module/components/controls/Scrubber.js.map +1 -0
- package/lib/module/components/controls/SpeedButton.js +96 -0
- package/lib/module/components/controls/SpeedButton.js.map +1 -0
- package/lib/module/components/controls/TimeDisplay.js +28 -0
- package/lib/module/components/controls/TimeDisplay.js.map +1 -0
- package/lib/module/components/controls/VolumeButton.js +31 -0
- package/lib/module/components/controls/VolumeButton.js.map +1 -0
- package/lib/module/components/core/VideoPlayer.js +114 -0
- package/lib/module/components/core/VideoPlayer.js.map +1 -0
- package/lib/module/components/core/VideoPlayerContext.js +119 -0
- package/lib/module/components/core/VideoPlayerContext.js.map +1 -0
- package/lib/module/components/core/index.js +5 -0
- package/lib/module/components/core/index.js.map +1 -0
- package/lib/module/components/index.js +14 -0
- package/lib/module/components/index.js.map +1 -0
- package/lib/module/components/overlays/BufferingOverlay.js +24 -0
- package/lib/module/components/overlays/BufferingOverlay.js.map +1 -0
- package/lib/module/components/overlays/DoubleTapSeek.js +95 -0
- package/lib/module/components/overlays/DoubleTapSeek.js.map +1 -0
- package/lib/module/components/overlays/ErrorOverlay.js +60 -0
- package/lib/module/components/overlays/ErrorOverlay.js.map +1 -0
- package/lib/module/components/overlays/GestureIndicator.js +118 -0
- package/lib/module/components/overlays/GestureIndicator.js.map +1 -0
- package/lib/module/components/overlays/LoadingPoster.js +22 -0
- package/lib/module/components/overlays/LoadingPoster.js.map +1 -0
- package/lib/module/hooks/index.js +6 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/useVideoBrightness.js +33 -0
- package/lib/module/hooks/useVideoBrightness.js.map +1 -0
- package/lib/module/hooks/useVideoControls.js +64 -0
- package/lib/module/hooks/useVideoControls.js.map +1 -0
- package/lib/module/hooks/useVideoOrientation.js +24 -0
- package/lib/module/hooks/useVideoOrientation.js.map +1 -0
- package/lib/module/hooks/useVideoPlayer.js +59 -0
- package/lib/module/hooks/useVideoPlayer.js.map +1 -0
- package/lib/module/hooks/useVideoVolume.js +42 -0
- package/lib/module/hooks/useVideoVolume.js.map +1 -0
- package/lib/module/index.js +7 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types/index.js +4 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/utils/clamp.js +8 -0
- package/lib/module/utils/clamp.js.map +1 -0
- package/lib/module/utils/formatTime.js +12 -0
- package/lib/module/utils/formatTime.js.map +1 -0
- package/lib/module/utils/index.js +5 -0
- package/lib/module/utils/index.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/VideoKit.d.ts +3 -0
- package/lib/typescript/src/components/VideoKit.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/FullscreenButton.d.ts +6 -0
- package/lib/typescript/src/components/controls/FullscreenButton.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/Icon.d.ts +10 -0
- package/lib/typescript/src/components/controls/Icon.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/PlayPauseButton.d.ts +2 -0
- package/lib/typescript/src/components/controls/PlayPauseButton.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/Scrubber.d.ts +7 -0
- package/lib/typescript/src/components/controls/Scrubber.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/SpeedButton.d.ts +2 -0
- package/lib/typescript/src/components/controls/SpeedButton.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/TimeDisplay.d.ts +2 -0
- package/lib/typescript/src/components/controls/TimeDisplay.d.ts.map +1 -0
- package/lib/typescript/src/components/controls/VolumeButton.d.ts +2 -0
- package/lib/typescript/src/components/controls/VolumeButton.d.ts.map +1 -0
- package/lib/typescript/src/components/core/VideoPlayer.d.ts +14 -0
- package/lib/typescript/src/components/core/VideoPlayer.d.ts.map +1 -0
- package/lib/typescript/src/components/core/VideoPlayerContext.d.ts +48 -0
- package/lib/typescript/src/components/core/VideoPlayerContext.d.ts.map +1 -0
- package/lib/typescript/src/components/core/index.d.ts +3 -0
- package/lib/typescript/src/components/core/index.d.ts.map +1 -0
- package/lib/typescript/src/components/index.d.ts +6 -0
- package/lib/typescript/src/components/index.d.ts.map +1 -0
- package/lib/typescript/src/components/overlays/BufferingOverlay.d.ts +2 -0
- package/lib/typescript/src/components/overlays/BufferingOverlay.d.ts.map +1 -0
- package/lib/typescript/src/components/overlays/DoubleTapSeek.d.ts +5 -0
- package/lib/typescript/src/components/overlays/DoubleTapSeek.d.ts.map +1 -0
- package/lib/typescript/src/components/overlays/ErrorOverlay.d.ts +6 -0
- package/lib/typescript/src/components/overlays/ErrorOverlay.d.ts.map +1 -0
- package/lib/typescript/src/components/overlays/GestureIndicator.d.ts +9 -0
- package/lib/typescript/src/components/overlays/GestureIndicator.d.ts.map +1 -0
- package/lib/typescript/src/components/overlays/LoadingPoster.d.ts +6 -0
- package/lib/typescript/src/components/overlays/LoadingPoster.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +4 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideoBrightness.d.ts +5 -0
- package/lib/typescript/src/hooks/useVideoBrightness.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideoControls.d.ts +11 -0
- package/lib/typescript/src/hooks/useVideoControls.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideoOrientation.d.ts +6 -0
- package/lib/typescript/src/hooks/useVideoOrientation.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideoPlayer.d.ts +7 -0
- package/lib/typescript/src/hooks/useVideoPlayer.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideoVolume.d.ts +6 -0
- package/lib/typescript/src/hooks/useVideoVolume.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +96 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/clamp.d.ts +2 -0
- package/lib/typescript/src/utils/clamp.d.ts.map +1 -0
- package/lib/typescript/src/utils/formatTime.d.ts +2 -0
- package/lib/typescript/src/utils/formatTime.d.ts.map +1 -0
- package/lib/typescript/src/utils/index.d.ts +3 -0
- package/lib/typescript/src/utils/index.d.ts.map +1 -0
- package/package.json +191 -0
- package/src/components/VideoKit.tsx +415 -0
- package/src/components/controls/FullscreenButton.tsx +29 -0
- package/src/components/controls/Icon.tsx +71 -0
- package/src/components/controls/PlayPauseButton.tsx +25 -0
- package/src/components/controls/Scrubber.tsx +157 -0
- package/src/components/controls/SpeedButton.tsx +86 -0
- package/src/components/controls/TimeDisplay.tsx +21 -0
- package/src/components/controls/VolumeButton.tsx +23 -0
- package/src/components/core/VideoPlayer.tsx +148 -0
- package/src/components/core/VideoPlayerContext.tsx +133 -0
- package/src/components/core/index.ts +5 -0
- package/src/components/index.ts +25 -0
- package/src/components/overlays/BufferingOverlay.tsx +21 -0
- package/src/components/overlays/DoubleTapSeek.tsx +91 -0
- package/src/components/overlays/ErrorOverlay.tsx +49 -0
- package/src/components/overlays/GestureIndicator.tsx +114 -0
- package/src/components/overlays/LoadingPoster.tsx +21 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useVideoBrightness.ts +34 -0
- package/src/hooks/useVideoControls.ts +65 -0
- package/src/hooks/useVideoOrientation.ts +22 -0
- package/src/hooks/useVideoPlayer.ts +69 -0
- package/src/hooks/useVideoVolume.ts +36 -0
- package/src/index.ts +15 -0
- package/src/types/index.ts +137 -0
- package/src/utils/clamp.ts +4 -0
- package/src/utils/formatTime.ts +9 -0
- package/src/utils/index.ts +2 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mureyvenom
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# @venomousone/rn-videokit
|
|
2
|
+
|
|
3
|
+
A gesture-driven, composable video player kit for React Native.
|
|
4
|
+
|
|
5
|
+
Built on **react-native-video v6+**, **Reanimated 4**, and **Gesture Handler 2**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- ▶️ Play / pause with animated controls
|
|
12
|
+
- ⏩ Double-tap left/right to seek ±N seconds with ripple animation
|
|
13
|
+
- ⚡️ Long-press for 2× speed
|
|
14
|
+
- 🔆 Swipe up/down on left side to adjust brightness
|
|
15
|
+
- 🔊 Swipe up/down on right side to adjust volume
|
|
16
|
+
- ⛶ Fullscreen via button (Modal-based, no activity change)
|
|
17
|
+
- 📶 Buffered progress indicator on scrubber
|
|
18
|
+
- 🎨 Themeable accent colors
|
|
19
|
+
- 🧩 Headless `useVideoPlayer` hook for custom UIs
|
|
20
|
+
- 📦 100% TypeScript
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
yarn add @venomousone/rn-videokit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Peer dependencies
|
|
31
|
+
|
|
32
|
+
Install all peer dependencies in your app:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
yarn add react-native-video \
|
|
36
|
+
react-native-reanimated \
|
|
37
|
+
react-native-gesture-handler \
|
|
38
|
+
react-native-worklets \
|
|
39
|
+
react-native-orientation-locker \
|
|
40
|
+
react-native-volume-manager \
|
|
41
|
+
react-native-svg \
|
|
42
|
+
@reeq/react-native-device-brightness
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Then run pod install:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
cd ios && pod install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Native setup
|
|
52
|
+
|
|
53
|
+
**react-native-gesture-handler** — wrap your root component:
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
57
|
+
|
|
58
|
+
export default function App() {
|
|
59
|
+
return (
|
|
60
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
61
|
+
{/* your app */}
|
|
62
|
+
</GestureHandlerRootView>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**react-native-orientation-locker (iOS)** — add to `AppDelegate.swift`:
|
|
68
|
+
|
|
69
|
+
```swift
|
|
70
|
+
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
|
71
|
+
return Orientation.getOrientation()
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**react-native-orientation-locker (Android)** — add to `AndroidManifest.xml`:
|
|
76
|
+
|
|
77
|
+
```xml
|
|
78
|
+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
And in `MainActivity.kt`:
|
|
82
|
+
|
|
83
|
+
```kotlin
|
|
84
|
+
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
85
|
+
super.onConfigurationChanged(newConfig)
|
|
86
|
+
val intent = Intent("onConfigurationChanged")
|
|
87
|
+
intent.putExtra("newConfig", newConfig)
|
|
88
|
+
sendBroadcast(intent)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Usage
|
|
95
|
+
|
|
96
|
+
### Basic
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { VideoKit } from '@venomousone/rn-videokit';
|
|
100
|
+
|
|
101
|
+
<VideoKit
|
|
102
|
+
source={{ uri: 'https://example.com/video.m3u8' }}
|
|
103
|
+
poster="https://example.com/thumb.jpg"
|
|
104
|
+
autoPlay
|
|
105
|
+
style={{ width: '100%', aspectRatio: 16 / 9 }}
|
|
106
|
+
/>;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### With safe area (recommended for fullscreen)
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
113
|
+
|
|
114
|
+
function Player() {
|
|
115
|
+
const insets = useSafeAreaInsets();
|
|
116
|
+
return (
|
|
117
|
+
<VideoKit
|
|
118
|
+
source={{ uri: '...' }}
|
|
119
|
+
safeAreaInsets={insets}
|
|
120
|
+
onFullscreenChange={(isFullscreen) => {
|
|
121
|
+
// orientation is locked automatically by the library
|
|
122
|
+
console.log('fullscreen:', isFullscreen);
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Disable specific controls
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<VideoKit
|
|
133
|
+
source={{ uri: '...' }}
|
|
134
|
+
controls={{
|
|
135
|
+
speed: false, // hide speed button
|
|
136
|
+
volume: false, // hide mute button
|
|
137
|
+
}}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Theming
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
<VideoKit
|
|
145
|
+
source={{ uri: '...' }}
|
|
146
|
+
theme={{
|
|
147
|
+
accentColor: '#ff0000', // scrubber thumb and played track
|
|
148
|
+
controlsTint: '#ffffff', // icon color
|
|
149
|
+
overlayColor: 'rgba(0,0,0,0.6)',
|
|
150
|
+
}}
|
|
151
|
+
/>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Headless (custom UI)
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
import { VideoPlayerProvider, useVideoPlayer } from '@venomousone/rn-videokit';
|
|
158
|
+
|
|
159
|
+
function MyControls() {
|
|
160
|
+
const { play, pause, seek, status, currentTime, duration } = useVideoPlayer();
|
|
161
|
+
return (
|
|
162
|
+
// your own controls UI
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function MyPlayer() {
|
|
167
|
+
return (
|
|
168
|
+
<VideoPlayerProvider>
|
|
169
|
+
<MyVideoSurface />
|
|
170
|
+
<MyControls />
|
|
171
|
+
</VideoPlayerProvider>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Props
|
|
179
|
+
|
|
180
|
+
| Prop | Type | Default | Description |
|
|
181
|
+
| ---------------------- | ----------------------------------- | ------- | ---------------------------------------------- |
|
|
182
|
+
| `source` | `{ uri: string } \| number` | — | **Required.** Video URI or local `require()` |
|
|
183
|
+
| `poster` | `string` | — | Thumbnail shown before first frame |
|
|
184
|
+
| `autoPlay` | `boolean` | `false` | Start playing immediately on mount |
|
|
185
|
+
| `loop` | `boolean` | `false` | Loop playback |
|
|
186
|
+
| `muted` | `boolean` | `false` | Mute audio |
|
|
187
|
+
| `controls` | `VideoKitControlsConfig \| boolean` | `true` | Control which buttons render |
|
|
188
|
+
| `theme` | `VideoKitTheme` | — | Visual theming |
|
|
189
|
+
| `autoHideDelay` | `number` | `3000` | Ms before controls fade (while playing) |
|
|
190
|
+
| `doubleTapSeekSeconds` | `number` | `10` | Seconds to seek on double-tap |
|
|
191
|
+
| `safeAreaInsets` | `EdgeInsets` | — | Pass from `useSafeAreaInsets()` for fullscreen |
|
|
192
|
+
| `style` | `StyleProp<ViewStyle>` | — | Container style |
|
|
193
|
+
| `onProgress` | `(p: VideoProgress) => void` | — | Fires every 250ms during playback |
|
|
194
|
+
| `onEnd` | `() => void` | — | Fires when video ends |
|
|
195
|
+
| `onError` | `(e: Error) => void` | — | Fires on playback error |
|
|
196
|
+
| `onBuffer` | `(isBuffering: boolean) => void` | — | Fires on buffer state change |
|
|
197
|
+
| `onFullscreenChange` | `(isFullscreen: boolean) => void` | — | Fires on fullscreen toggle |
|
|
198
|
+
|
|
199
|
+
### `VideoKitControlsConfig`
|
|
200
|
+
|
|
201
|
+
| Key | Default |
|
|
202
|
+
| ------------ | ------- |
|
|
203
|
+
| `playPause` | `true` |
|
|
204
|
+
| `scrubber` | `true` |
|
|
205
|
+
| `time` | `true` |
|
|
206
|
+
| `volume` | `true` |
|
|
207
|
+
| `fullscreen` | `true` |
|
|
208
|
+
| `speed` | `true` |
|
|
209
|
+
|
|
210
|
+
### `VideoKitTheme`
|
|
211
|
+
|
|
212
|
+
| Key | Default |
|
|
213
|
+
| -------------- | -------------------- |
|
|
214
|
+
| `accentColor` | `'#ffffff'` |
|
|
215
|
+
| `controlsTint` | `'#ffffff'` |
|
|
216
|
+
| `overlayColor` | `'rgba(0,0,0,0.45)'` |
|
|
217
|
+
| `trackHeight` | `3` |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Gesture reference
|
|
222
|
+
|
|
223
|
+
| Gesture | Action |
|
|
224
|
+
| --------------------------- | -------------------- |
|
|
225
|
+
| Tap | Toggle controls |
|
|
226
|
+
| Double tap left (35% zone) | Seek −N seconds |
|
|
227
|
+
| Double tap right (35% zone) | Seek +N seconds |
|
|
228
|
+
| Long press | 2× speed while held |
|
|
229
|
+
| Swipe up/down — left half | Adjust brightness |
|
|
230
|
+
| Swipe up/down — right half | Adjust system volume |
|
|
231
|
+
| Swipe up | Enter fullscreen |
|
|
232
|
+
| Swipe down (in fullscreen) | Exit fullscreen |
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Roadmap
|
|
237
|
+
|
|
238
|
+
- [x] v0.1 — Core player, gestures, controls, fullscreen
|
|
239
|
+
- [ ] v0.\* — Quality selector, chapter markers
|
|
240
|
+
- [ ] v0.\* — Picture-in-Picture
|
|
241
|
+
- [ ] v0.\* — Subtitles / captions
|
|
242
|
+
- [ ] v0.\* — AirPlay / Chromecast
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT © [Oluwamurewa](https://github.com/mureyvenom)
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useMemo } from 'react';
|
|
4
|
+
import { StyleSheet, View, StatusBar, Modal, useWindowDimensions } from 'react-native';
|
|
5
|
+
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
|
|
6
|
+
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
7
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
8
|
+
import { useVideoStoreApi, VideoPlayerProvider } from "./core/VideoPlayerContext.js";
|
|
9
|
+
import { VideoPlayer } from "./core/VideoPlayer.js";
|
|
10
|
+
import { useVideoControls } from "../hooks/useVideoControls.js";
|
|
11
|
+
import { useVideoOrientation } from "../hooks/useVideoOrientation.js";
|
|
12
|
+
import { useVideoPlayerContext, useVideoStore } from "./core/VideoPlayerContext.js";
|
|
13
|
+
import { useVideoBrightness } from "../hooks/useVideoBrightness.js";
|
|
14
|
+
import { PlayPauseButton } from "./controls/PlayPauseButton.js";
|
|
15
|
+
import { Scrubber } from "./controls/Scrubber.js";
|
|
16
|
+
import { TimeDisplay } from "./controls/TimeDisplay.js";
|
|
17
|
+
import { VolumeButton } from "./controls/VolumeButton.js";
|
|
18
|
+
import { FullscreenButton } from "./controls/FullscreenButton.js";
|
|
19
|
+
import { SpeedButton } from "./controls/SpeedButton.js";
|
|
20
|
+
import { BufferingOverlay } from "./overlays/BufferingOverlay.js";
|
|
21
|
+
import { ErrorOverlay } from "./overlays/ErrorOverlay.js";
|
|
22
|
+
import { LoadingPoster } from "./overlays/LoadingPoster.js";
|
|
23
|
+
import { DoubleTapSeek } from "./overlays/DoubleTapSeek.js";
|
|
24
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
25
|
+
import { useVideoVolume } from "../hooks/useVideoVolume.js";
|
|
26
|
+
import { VolumeManager } from 'react-native-volume-manager';
|
|
27
|
+
|
|
28
|
+
// ─── Inner component (has access to context) ─────────────────────────────────
|
|
29
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
30
|
+
function VideoKitInner({
|
|
31
|
+
source,
|
|
32
|
+
poster,
|
|
33
|
+
autoPlay = false,
|
|
34
|
+
loop = false,
|
|
35
|
+
onProgress,
|
|
36
|
+
onEnd,
|
|
37
|
+
onError,
|
|
38
|
+
onBuffer,
|
|
39
|
+
onFullscreenChange,
|
|
40
|
+
autoHideDelay = 3000,
|
|
41
|
+
doubleTapSeekSeconds = 10,
|
|
42
|
+
style,
|
|
43
|
+
testID,
|
|
44
|
+
safeAreaInsets,
|
|
45
|
+
controls,
|
|
46
|
+
muted
|
|
47
|
+
}) {
|
|
48
|
+
const {
|
|
49
|
+
videoRef
|
|
50
|
+
} = useVideoPlayerContext();
|
|
51
|
+
const doubleTapRef = useRef(null);
|
|
52
|
+
const layoutWidth = useSharedValue(0);
|
|
53
|
+
const isFullscreen = useVideoStore(s => s.isFullscreen);
|
|
54
|
+
const {
|
|
55
|
+
height
|
|
56
|
+
} = useWindowDimensions();
|
|
57
|
+
useVideoOrientation();
|
|
58
|
+
const {
|
|
59
|
+
showControls,
|
|
60
|
+
keepControlsVisible,
|
|
61
|
+
toggleControls
|
|
62
|
+
} = useVideoControls(autoHideDelay);
|
|
63
|
+
const {
|
|
64
|
+
adjustBrightness
|
|
65
|
+
} = useVideoBrightness();
|
|
66
|
+
const {
|
|
67
|
+
adjustVolume
|
|
68
|
+
} = useVideoVolume();
|
|
69
|
+
const controlsVisible = useVideoStore(s => s.controlsVisible);
|
|
70
|
+
const {
|
|
71
|
+
currentTime,
|
|
72
|
+
duration,
|
|
73
|
+
setSpeed,
|
|
74
|
+
setStatus,
|
|
75
|
+
setError,
|
|
76
|
+
setMuted,
|
|
77
|
+
setFullscreen
|
|
78
|
+
} = useVideoStoreApi().getState();
|
|
79
|
+
const resolvedControls = useMemo(() => {
|
|
80
|
+
if (controls === false) return null;
|
|
81
|
+
if (controls === true || controls === undefined) {
|
|
82
|
+
return {
|
|
83
|
+
playPause: true,
|
|
84
|
+
scrubber: true,
|
|
85
|
+
time: true,
|
|
86
|
+
volume: true,
|
|
87
|
+
fullscreen: true,
|
|
88
|
+
speed: true
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
playPause: true,
|
|
93
|
+
scrubber: true,
|
|
94
|
+
time: true,
|
|
95
|
+
volume: true,
|
|
96
|
+
fullscreen: true,
|
|
97
|
+
speed: true,
|
|
98
|
+
...controls
|
|
99
|
+
};
|
|
100
|
+
}, [controls]);
|
|
101
|
+
|
|
102
|
+
// ── Seek helper (JS thread) ──────────────────────────────────────────────
|
|
103
|
+
const seekBy = useCallback(seconds => {
|
|
104
|
+
const next = Math.max(0, Math.min(currentTime + seconds, duration));
|
|
105
|
+
videoRef?.current?.seek(next);
|
|
106
|
+
}, [videoRef, currentTime, duration]);
|
|
107
|
+
const handleDoubleTap = useCallback(side => {
|
|
108
|
+
doubleTapRef.current?.show(side, doubleTapSeekSeconds);
|
|
109
|
+
seekBy(side === 'left' ? -doubleTapSeekSeconds : doubleTapSeekSeconds);
|
|
110
|
+
showControls();
|
|
111
|
+
}, [doubleTapSeekSeconds, seekBy, showControls]);
|
|
112
|
+
const handleLongPressStart = useCallback(() => {
|
|
113
|
+
setSpeed(2);
|
|
114
|
+
}, [setSpeed]);
|
|
115
|
+
const handleLongPressEnd = useCallback(() => {
|
|
116
|
+
setSpeed(1);
|
|
117
|
+
}, [setSpeed]);
|
|
118
|
+
|
|
119
|
+
// ── Gestures ────────────────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
const panGesture = Gesture.Pan().minDistance(10).onEnd(e => {
|
|
122
|
+
'worklet';
|
|
123
|
+
|
|
124
|
+
// vertical swipe — not a brightness/volume gesture
|
|
125
|
+
if (Math.abs(e.translationY) > Math.abs(e.translationX) * 1.5) {
|
|
126
|
+
const isSignificantSwipe = Math.abs(e.translationY) > 60;
|
|
127
|
+
if (isSignificantSwipe) {
|
|
128
|
+
if (e.translationY < 0) {
|
|
129
|
+
// swipe up → enter fullscreen
|
|
130
|
+
scheduleOnRN(() => setFullscreen(true));
|
|
131
|
+
} else if (e.translationY > 0) {
|
|
132
|
+
// swipe down → exit fullscreen
|
|
133
|
+
scheduleOnRN(() => setFullscreen(false));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}).activeOffsetY([-10, 10]) // only vertical pans
|
|
138
|
+
.failOffsetX([-10, 10]) // horizontal movement cancels it
|
|
139
|
+
.onUpdate(e => {
|
|
140
|
+
'worklet';
|
|
141
|
+
|
|
142
|
+
const delta = -(e.translationY / height) / 3; // negative because swipe up = brighter
|
|
143
|
+
const isLeftSide = e.x < layoutWidth.value / 2;
|
|
144
|
+
if (isLeftSide) {
|
|
145
|
+
scheduleOnRN(adjustBrightness, delta);
|
|
146
|
+
} else {
|
|
147
|
+
scheduleOnRN(adjustVolume, delta);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
const doubleTap = Gesture.Tap().numberOfTaps(2).maxDuration(250).onEnd(e => {
|
|
151
|
+
'worklet';
|
|
152
|
+
|
|
153
|
+
const leftZone = layoutWidth.value * 0.35;
|
|
154
|
+
const rightZone = layoutWidth.value * 0.65;
|
|
155
|
+
if (e.x < leftZone) {
|
|
156
|
+
scheduleOnRN(handleDoubleTap, 'left');
|
|
157
|
+
} else if (e.x > rightZone) {
|
|
158
|
+
scheduleOnRN(handleDoubleTap, 'right');
|
|
159
|
+
} else {
|
|
160
|
+
// scheduleOnRN(toggleControls);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const singleTap = Gesture.Tap()
|
|
164
|
+
// .maxDuration(250)
|
|
165
|
+
.onEnd(() => {
|
|
166
|
+
'worklet';
|
|
167
|
+
|
|
168
|
+
scheduleOnRN(toggleControls);
|
|
169
|
+
});
|
|
170
|
+
const longPress = Gesture.LongPress().minDuration(400).onStart(() => {
|
|
171
|
+
'worklet';
|
|
172
|
+
|
|
173
|
+
scheduleOnRN(handleLongPressStart);
|
|
174
|
+
}).onEnd(() => {
|
|
175
|
+
'worklet';
|
|
176
|
+
|
|
177
|
+
scheduleOnRN(handleLongPressEnd);
|
|
178
|
+
});
|
|
179
|
+
const taps = Gesture.Exclusive(doubleTap, singleTap);
|
|
180
|
+
const composed = Gesture.Simultaneous(taps, longPress, panGesture);
|
|
181
|
+
|
|
182
|
+
// ── Controls animated opacity ────────────────────────────────────────────
|
|
183
|
+
const controlsStyle = useAnimatedStyle(() => ({
|
|
184
|
+
opacity: withTiming(controlsVisible ? 1 : 0, {
|
|
185
|
+
duration: 200
|
|
186
|
+
})
|
|
187
|
+
}));
|
|
188
|
+
const handleRetry = useCallback(() => {
|
|
189
|
+
setStatus('loading');
|
|
190
|
+
setError(null);
|
|
191
|
+
}, [setStatus, setError]);
|
|
192
|
+
const insets = isFullscreen ? {
|
|
193
|
+
paddingBottom: 8 + (safeAreaInsets?.bottom ?? 0),
|
|
194
|
+
paddingLeft: 12 + (safeAreaInsets?.left ?? 0),
|
|
195
|
+
paddingRight: 12 + (safeAreaInsets?.right ?? 0)
|
|
196
|
+
} : undefined;
|
|
197
|
+
const playerContent = /*#__PURE__*/_jsxs(View, {
|
|
198
|
+
style: [styles.container, isFullscreen ? {
|
|
199
|
+
...styles.fullscreenContainer,
|
|
200
|
+
width: '100%',
|
|
201
|
+
height: '100%'
|
|
202
|
+
} : style, {
|
|
203
|
+
overflow: isFullscreen ? 'visible' : 'hidden'
|
|
204
|
+
}],
|
|
205
|
+
testID: testID,
|
|
206
|
+
onLayout: e => {
|
|
207
|
+
layoutWidth.value = e.nativeEvent.layout.width;
|
|
208
|
+
},
|
|
209
|
+
children: [/*#__PURE__*/_jsx(VideoPlayer, {
|
|
210
|
+
source: source,
|
|
211
|
+
autoPlay: autoPlay,
|
|
212
|
+
loop: loop,
|
|
213
|
+
poster: poster,
|
|
214
|
+
onProgress: onProgress,
|
|
215
|
+
onEnd: onEnd,
|
|
216
|
+
onError: onError,
|
|
217
|
+
onBuffer: onBuffer
|
|
218
|
+
}), /*#__PURE__*/_jsx(GestureDetector, {
|
|
219
|
+
gesture: composed,
|
|
220
|
+
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
221
|
+
style: [StyleSheet.absoluteFill, {
|
|
222
|
+
// backgroundColor: 'purple',
|
|
223
|
+
}],
|
|
224
|
+
collapsable: false
|
|
225
|
+
})
|
|
226
|
+
}), /*#__PURE__*/_jsx(LoadingPoster, {
|
|
227
|
+
uri: poster
|
|
228
|
+
}), /*#__PURE__*/_jsx(BufferingOverlay, {}), /*#__PURE__*/_jsx(ErrorOverlay, {
|
|
229
|
+
onRetry: handleRetry
|
|
230
|
+
}), /*#__PURE__*/_jsx(DoubleTapSeek, {
|
|
231
|
+
ref: doubleTapRef
|
|
232
|
+
}), /*#__PURE__*/_jsx(Animated.View, {
|
|
233
|
+
style: [StyleSheet.absoluteFill, styles.dimOverlay, controlsStyle],
|
|
234
|
+
pointerEvents: "none"
|
|
235
|
+
}), /*#__PURE__*/_jsx(Animated.View, {
|
|
236
|
+
style: [{
|
|
237
|
+
position: 'absolute',
|
|
238
|
+
bottom: 0,
|
|
239
|
+
left: 0,
|
|
240
|
+
right: 0
|
|
241
|
+
}, controlsStyle],
|
|
242
|
+
pointerEvents: controlsVisible ? 'auto' : 'none',
|
|
243
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
244
|
+
style: [styles.bottomControls, insets],
|
|
245
|
+
children: [resolvedControls?.scrubber && /*#__PURE__*/_jsx(Scrubber, {
|
|
246
|
+
onScrubStart: keepControlsVisible,
|
|
247
|
+
onScrubEnd: showControls
|
|
248
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
249
|
+
style: styles.buttonRow,
|
|
250
|
+
children: [resolvedControls?.playPause && /*#__PURE__*/_jsx(PlayPauseButton, {}), resolvedControls?.time && /*#__PURE__*/_jsx(TimeDisplay, {}), /*#__PURE__*/_jsx(View, {
|
|
251
|
+
style: styles.spacer
|
|
252
|
+
}), resolvedControls?.speed && /*#__PURE__*/_jsx(SpeedButton, {}), resolvedControls?.volume && /*#__PURE__*/_jsx(VolumeButton, {}), resolvedControls?.fullscreen && /*#__PURE__*/_jsx(FullscreenButton, {
|
|
253
|
+
onFullscreenChange: v => {
|
|
254
|
+
StatusBar.setHidden(v, 'fade');
|
|
255
|
+
onFullscreenChange?.(v);
|
|
256
|
+
}
|
|
257
|
+
})]
|
|
258
|
+
})]
|
|
259
|
+
})
|
|
260
|
+
})]
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// In VideoKit.tsx, on mount:
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
VolumeManager.showNativeVolumeUI({
|
|
266
|
+
enabled: false
|
|
267
|
+
});
|
|
268
|
+
return () => {
|
|
269
|
+
VolumeManager.showNativeVolumeUI({
|
|
270
|
+
enabled: true
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
}, []);
|
|
274
|
+
|
|
275
|
+
//on mount and when prop changes
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
setMuted(muted ?? false);
|
|
278
|
+
}, [muted, setMuted]);
|
|
279
|
+
return isFullscreen ? /*#__PURE__*/_jsx(Modal, {
|
|
280
|
+
visible: true,
|
|
281
|
+
presentationStyle: "fullScreen",
|
|
282
|
+
hardwareAccelerated: true,
|
|
283
|
+
navigationBarTranslucent: true,
|
|
284
|
+
statusBarTranslucent: true,
|
|
285
|
+
supportedOrientations: ['landscape', 'landscape-left', 'landscape-right'],
|
|
286
|
+
onDismiss: () => {
|
|
287
|
+
setFullscreen(false);
|
|
288
|
+
onFullscreenChange?.(false);
|
|
289
|
+
},
|
|
290
|
+
onRequestClose: () => {
|
|
291
|
+
setFullscreen(false);
|
|
292
|
+
onFullscreenChange?.(false);
|
|
293
|
+
StatusBar.setHidden(false, 'fade');
|
|
294
|
+
},
|
|
295
|
+
onShow: () => {},
|
|
296
|
+
style: {
|
|
297
|
+
margin: 0
|
|
298
|
+
},
|
|
299
|
+
children: /*#__PURE__*/_jsx(GestureHandlerRootView, {
|
|
300
|
+
style: {
|
|
301
|
+
flex: 1
|
|
302
|
+
},
|
|
303
|
+
children: playerContent
|
|
304
|
+
})
|
|
305
|
+
}) : /*#__PURE__*/_jsx(_Fragment, {
|
|
306
|
+
children: playerContent
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ─── Public export (wraps with providers) ─────────────────────────────────────
|
|
311
|
+
export function VideoKit(props) {
|
|
312
|
+
return /*#__PURE__*/_jsx(VideoPlayerProvider, {
|
|
313
|
+
children: /*#__PURE__*/_jsx(VideoKitInner, {
|
|
314
|
+
...props
|
|
315
|
+
})
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
const styles = StyleSheet.create({
|
|
319
|
+
container: {
|
|
320
|
+
backgroundColor: '#000',
|
|
321
|
+
position: 'relative'
|
|
322
|
+
},
|
|
323
|
+
dimOverlay: {
|
|
324
|
+
backgroundColor: 'rgba(0,0,0,0.45)'
|
|
325
|
+
},
|
|
326
|
+
bottomControls: {
|
|
327
|
+
bottom: 0,
|
|
328
|
+
left: 0,
|
|
329
|
+
right: 0,
|
|
330
|
+
paddingBottom: 8,
|
|
331
|
+
paddingHorizontal: 12
|
|
332
|
+
},
|
|
333
|
+
buttonRow: {
|
|
334
|
+
flexDirection: 'row',
|
|
335
|
+
alignItems: 'center',
|
|
336
|
+
gap: 12,
|
|
337
|
+
marginTop: 4
|
|
338
|
+
},
|
|
339
|
+
fullscreenContainer: {
|
|
340
|
+
flex: 1,
|
|
341
|
+
backgroundColor: '#000'
|
|
342
|
+
},
|
|
343
|
+
spacer: {
|
|
344
|
+
flex: 1
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
//# sourceMappingURL=VideoKit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","useMemo","StyleSheet","View","StatusBar","Modal","useWindowDimensions","GestureDetector","Gesture","Animated","useAnimatedStyle","useSharedValue","withTiming","scheduleOnRN","useVideoStoreApi","VideoPlayerProvider","VideoPlayer","useVideoControls","useVideoOrientation","useVideoPlayerContext","useVideoStore","useVideoBrightness","PlayPauseButton","Scrubber","TimeDisplay","VolumeButton","FullscreenButton","SpeedButton","BufferingOverlay","ErrorOverlay","LoadingPoster","DoubleTapSeek","GestureHandlerRootView","useVideoVolume","VolumeManager","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","VideoKitInner","source","poster","autoPlay","loop","onProgress","onEnd","onError","onBuffer","onFullscreenChange","autoHideDelay","doubleTapSeekSeconds","style","testID","safeAreaInsets","controls","muted","videoRef","doubleTapRef","layoutWidth","isFullscreen","s","height","showControls","keepControlsVisible","toggleControls","adjustBrightness","adjustVolume","controlsVisible","currentTime","duration","setSpeed","setStatus","setError","setMuted","setFullscreen","getState","resolvedControls","undefined","playPause","scrubber","time","volume","fullscreen","speed","seekBy","seconds","next","Math","max","min","current","seek","handleDoubleTap","side","show","handleLongPressStart","handleLongPressEnd","panGesture","Pan","minDistance","e","abs","translationY","translationX","isSignificantSwipe","activeOffsetY","failOffsetX","onUpdate","delta","isLeftSide","x","value","doubleTap","Tap","numberOfTaps","maxDuration","leftZone","rightZone","singleTap","longPress","LongPress","minDuration","onStart","taps","Exclusive","composed","Simultaneous","controlsStyle","opacity","handleRetry","insets","paddingBottom","bottom","paddingLeft","left","paddingRight","right","playerContent","styles","container","fullscreenContainer","width","overflow","onLayout","nativeEvent","layout","children","gesture","absoluteFill","collapsable","uri","onRetry","ref","dimOverlay","pointerEvents","position","bottomControls","onScrubStart","onScrubEnd","buttonRow","spacer","v","setHidden","showNativeVolumeUI","enabled","visible","presentationStyle","hardwareAccelerated","navigationBarTranslucent","statusBarTranslucent","supportedOrientations","onDismiss","onRequestClose","onShow","margin","flex","VideoKit","props","create","backgroundColor","paddingHorizontal","flexDirection","alignItems","gap","marginTop"],"sourceRoot":"../../../src","sources":["components/VideoKit.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { StyleSheet, TouchableOpacity } from 'react-native';
|
|
4
|
+
import { useVideoStore } from "../core/VideoPlayerContext.js";
|
|
5
|
+
import { Icon } from "./Icon.js";
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
export function FullscreenButton({
|
|
8
|
+
onFullscreenChange
|
|
9
|
+
}) {
|
|
10
|
+
const isFullscreen = useVideoStore(s => s.isFullscreen);
|
|
11
|
+
const {
|
|
12
|
+
setFullscreen
|
|
13
|
+
} = useVideoStore(s => s);
|
|
14
|
+
const toggle = () => {
|
|
15
|
+
const next = !isFullscreen;
|
|
16
|
+
setFullscreen(next);
|
|
17
|
+
onFullscreenChange?.(next);
|
|
18
|
+
};
|
|
19
|
+
return /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
20
|
+
onPress: toggle,
|
|
21
|
+
style: styles.btn,
|
|
22
|
+
hitSlop: 12,
|
|
23
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
|
24
|
+
name: isFullscreen ? 'fullscreen-exit' : 'fullscreen',
|
|
25
|
+
size: 22
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const styles = StyleSheet.create({
|
|
30
|
+
btn: {
|
|
31
|
+
padding: 4
|
|
32
|
+
},
|
|
33
|
+
icon: {
|
|
34
|
+
fontSize: 18,
|
|
35
|
+
color: '#fff'
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=FullscreenButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["StyleSheet","TouchableOpacity","useVideoStore","Icon","jsx","_jsx","FullscreenButton","onFullscreenChange","isFullscreen","s","setFullscreen","toggle","next","onPress","style","styles","btn","hitSlop","children","name","size","create","padding","icon","fontSize","color"],"sourceRoot":"../../../../src","sources":["components/controls/FullscreenButton.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,gBAAgB,QAAQ,cAAc;AAC3D,SAASC,aAAa,QAAQ,+BAA4B;AAC1D,SAASC,IAAI,QAAQ,WAAQ;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAM9B,OAAO,SAASC,gBAAgBA,CAAC;EAAEC;AAA0B,CAAC,EAAE;EAC9D,MAAMC,YAAY,GAAGN,aAAa,CAAEO,CAAC,IAAKA,CAAC,CAACD,YAAY,CAAC;EACzD,MAAM;IAAEE;EAAc,CAAC,GAAGR,aAAa,CAAEO,CAAC,IAAKA,CAAC,CAAC;EAEjD,MAAME,MAAM,GAAGA,CAAA,KAAM;IACnB,MAAMC,IAAI,GAAG,CAACJ,YAAY;IAC1BE,aAAa,CAACE,IAAI,CAAC;IACnBL,kBAAkB,GAAGK,IAAI,CAAC;EAC5B,CAAC;EAED,oBACEP,IAAA,CAACJ,gBAAgB;IAACY,OAAO,EAAEF,MAAO;IAACG,KAAK,EAAEC,MAAM,CAACC,GAAI;IAACC,OAAO,EAAE,EAAG;IAAAC,QAAA,eAChEb,IAAA,CAACF,IAAI;MAACgB,IAAI,EAAEX,YAAY,GAAG,iBAAiB,GAAG,YAAa;MAACY,IAAI,EAAE;IAAG,CAAE;EAAC,CACzD,CAAC;AAEvB;AAEA,MAAML,MAAM,GAAGf,UAAU,CAACqB,MAAM,CAAC;EAC/BL,GAAG,EAAE;IAAEM,OAAO,EAAE;EAAE,CAAC;EACnBC,IAAI,EAAE;IAAEC,QAAQ,EAAE,EAAE;IAAEC,KAAK,EAAE;EAAO;AACtC,CAAC,CAAC","ignoreList":[]}
|