@octane-xplat/video 0.7.3 → 0.10.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/README.md +55 -0
- package/dist/native/Video.tsrx.js +9 -8
- package/dist/native/octane-client-build.json +1 -1
- package/dist/native/video-chrome.tsrx.js +4 -4
- package/dist/web/Video.web.tsrx.js +12 -13
- package/dist/web/octane-client-build.json +1 -1
- package/dist/web/video-chrome.web.tsrx.js +4 -4
- package/package.json +18 -14
- package/src/Video.macos.tsrx +1 -1
- package/src/Video.tsrx +4 -3
- package/src/Video.web.tsrx +4 -3
- package/src/layout-child.web.ts +1 -1
- package/src/props.ts +5 -3
- package/src/video-chrome.tsrx +4 -4
- package/src/video-chrome.web.tsrx +4 -4
- package/types/index.d.ts +2 -2
- package/types/index.macos.d.ts +2 -2
- package/types/props.d.ts +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# `@octane-xplat/video`
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
pnpm add @octane-xplat/video
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Embedded video player for Octane xplat apps: `<video>` on web and
|
|
8
|
+
`@nstudio/nativescript-exoplayer` on native (ExoPlayer on Android,
|
|
9
|
+
`AVPlayerViewController` on iOS), with a macOS entry. The OS engine owns
|
|
10
|
+
the pixels while all chrome is self-drawn, so `controls` looks identical
|
|
11
|
+
on every target.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Video } from '@octane-xplat/video'
|
|
15
|
+
|
|
16
|
+
export function Preview() {
|
|
17
|
+
return (
|
|
18
|
+
<Video
|
|
19
|
+
src="https://example.com/clip.mp4"
|
|
20
|
+
controls
|
|
21
|
+
fit="contain"
|
|
22
|
+
onReady={(event) => console.log(event.duration)}
|
|
23
|
+
onEnded={() => console.log('Done')}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
All times are milliseconds on every platform. `onError` is web-only — the
|
|
30
|
+
plugin players surface no error event on native. `handle.native` is the
|
|
31
|
+
platform surface for anything the shared props don't cover, and the
|
|
32
|
+
`ios`/`android`/`web` escape props apply after the shared props.
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// Player.web.tsx — this failure callback and escape bag are browser-specific.
|
|
36
|
+
import { Video } from '@octane-xplat/video'
|
|
37
|
+
|
|
38
|
+
export function Player() {
|
|
39
|
+
return (
|
|
40
|
+
<Video
|
|
41
|
+
src="https://example.com/clip.mp4"
|
|
42
|
+
web={{ preload: 'metadata' }}
|
|
43
|
+
onError={(event) => console.log(event.message)}
|
|
44
|
+
ref={(handle) => {
|
|
45
|
+
console.log(handle.duration(), handle.native)
|
|
46
|
+
handle.seekTo(1000)
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Per-target limits are recorded in
|
|
54
|
+
[known limits](../../docs/verify/known-limits.md). Exercised by
|
|
55
|
+
[`VideoDemo`](../demos/src/VideoDemo.tsrx).
|
|
@@ -2,10 +2,10 @@ import { cx } from "./cx.mobile.js";
|
|
|
2
2
|
import { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState } from "./escape-props.js";
|
|
3
3
|
import { layoutChildProps } from "./layout-child.js";
|
|
4
4
|
import { VideoChrome } from "./video-chrome.tsrx.js";
|
|
5
|
-
import { defineUniversalComponent, hookSlots, registerElement, universalComponent, universalIf, universalPlan, universalProps, universalValue, useCallback, useEffect, useRef, useState } from "@nativescript-community/octane";
|
|
5
|
+
import { defineUniversalComponent, hookSlots, registerElement, universalComponent, universalIf, universalPlan, universalProps, universalValue, useCallback, useEffect, useImperativeHandle, useRef, useState } from "@nativescript-community/octane";
|
|
6
6
|
import { Video, VideoFill } from "@nstudio/nativescript-exoplayer";
|
|
7
7
|
//#region src/Video.tsrx
|
|
8
|
-
var _hs$ = /* @__PURE__ */ hookSlots(
|
|
8
|
+
var _hs$ = /* @__PURE__ */ hookSlots(12);
|
|
9
9
|
var _h$0 = /* @__PURE__ */ Symbol(_hs$);
|
|
10
10
|
var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
|
|
11
11
|
var _h$2 = /* @__PURE__ */ Symbol(_hs$ + 2);
|
|
@@ -17,6 +17,7 @@ var _h$7 = /* @__PURE__ */ Symbol(_hs$ + 7);
|
|
|
17
17
|
var _h$8 = /* @__PURE__ */ Symbol(_hs$ + 8);
|
|
18
18
|
var _h$9 = /* @__PURE__ */ Symbol(_hs$ + 9);
|
|
19
19
|
var _h$10 = /* @__PURE__ */ Symbol(_hs$ + 10);
|
|
20
|
+
var _h$11 = /* @__PURE__ */ Symbol(_hs$ + 11);
|
|
20
21
|
var __octaneUniversalPlan0 = universalPlan("nativescript", {
|
|
21
22
|
"kind": "slot",
|
|
22
23
|
"slot": 0
|
|
@@ -61,9 +62,10 @@ var Video$1 = defineUniversalComponent("nativescript", function Video(props) {
|
|
|
61
62
|
const [internalMuted, setInternalMuted] = useState(false, _h$5);
|
|
62
63
|
const muted = props.muted ?? internalMuted;
|
|
63
64
|
const appliedSrc = useRef(void 0, _h$6);
|
|
65
|
+
useImperativeHandle(props.ref, () => handle(host.current), [], _h$7);
|
|
64
66
|
const bindHost = useCallback((v) => {
|
|
65
67
|
host.current = v;
|
|
66
|
-
}, [], _h$
|
|
68
|
+
}, [], _h$8);
|
|
67
69
|
const drive = (v, next) => {
|
|
68
70
|
if (!v) return;
|
|
69
71
|
if (next) v.play();
|
|
@@ -73,19 +75,18 @@ var Video$1 = defineUniversalComponent("nativescript", function Video(props) {
|
|
|
73
75
|
const v = host.current;
|
|
74
76
|
if (!v) return;
|
|
75
77
|
applyEscapeProps(v, props);
|
|
76
|
-
|
|
77
|
-
}, [], _h$8);
|
|
78
|
+
}, [], _h$9);
|
|
78
79
|
useEffect(() => {
|
|
79
80
|
const v = host.current;
|
|
80
81
|
if (!v || props.src === appliedSrc.current) return;
|
|
81
82
|
appliedSrc.current = props.src;
|
|
82
83
|
v.src = props.src;
|
|
83
|
-
}, [props.src], _h$
|
|
84
|
+
}, [props.src], _h$10);
|
|
84
85
|
useEffect(() => {
|
|
85
86
|
if (props.playing === void 0) return;
|
|
86
87
|
setPlaying(props.playing);
|
|
87
88
|
drive(host.current, props.playing);
|
|
88
|
-
}, [props.playing], _h$
|
|
89
|
+
}, [props.playing], _h$11);
|
|
89
90
|
const togglePlay = () => {
|
|
90
91
|
const next = !playing;
|
|
91
92
|
setPlaying(next);
|
|
@@ -120,7 +121,7 @@ var Video$1 = defineUniversalComponent("nativescript", function Video(props) {
|
|
|
120
121
|
[
|
|
121
122
|
"set",
|
|
122
123
|
"className",
|
|
123
|
-
cx("vx-
|
|
124
|
+
cx("vx-layers", "vx-video", props.className)
|
|
124
125
|
],
|
|
125
126
|
[
|
|
126
127
|
"set",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineUniversalComponent, hookSlots, universalChildren, universalComponent, universalIf, universalPlan, universalProps, universalValue, useEffect, useState } from "@nativescript-community/octane";
|
|
2
|
-
import { Icon, Image, Pressable,
|
|
2
|
+
import { HStack, Icon, Image, Pressable, Slider, Text, View } from "@octane-xplat/ui";
|
|
3
3
|
//#region src/video-chrome.tsrx
|
|
4
4
|
var _hs$ = /* @__PURE__ */ hookSlots(2);
|
|
5
5
|
var _h$0 = /* @__PURE__ */ Symbol(_hs$);
|
|
@@ -209,7 +209,7 @@ var VideoChrome = defineUniversalComponent("nativescript", function VideoChrome(
|
|
|
209
209
|
"justifyContent",
|
|
210
210
|
"end"
|
|
211
211
|
]], universalChildren("nativescript", () => {
|
|
212
|
-
return universalValue(__octaneUniversalPlan7, [universalComponent("nativescript",
|
|
212
|
+
return universalValue(__octaneUniversalPlan7, [universalComponent("nativescript", HStack, universalProps([
|
|
213
213
|
[
|
|
214
214
|
"set",
|
|
215
215
|
"className",
|
|
@@ -217,13 +217,13 @@ var VideoChrome = defineUniversalComponent("nativescript", function VideoChrome(
|
|
|
217
217
|
],
|
|
218
218
|
[
|
|
219
219
|
"set",
|
|
220
|
-
"
|
|
220
|
+
"vAlign",
|
|
221
221
|
"center"
|
|
222
222
|
],
|
|
223
223
|
[
|
|
224
224
|
"set",
|
|
225
225
|
"gap",
|
|
226
|
-
|
|
226
|
+
2
|
|
227
227
|
]
|
|
228
228
|
], universalChildren("nativescript", () => {
|
|
229
229
|
return universalValue(__octaneUniversalPlan6, [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { applyEscapeProps } from "./escape-props.web.js";
|
|
2
2
|
import { layoutChildProps } from "./layout-child.web.js";
|
|
3
3
|
import { VideoChrome } from "./video-chrome.web.tsrx.js";
|
|
4
|
-
import { __s, bagOf, child, clone, componentSlotVoid, delegateEvents, evt1, evt1e, evt1u, evt2e, evt2u, hookSlots, ifBlock, markDangerouslySetInnerHTMLChildren, queueRefAttach, queueRefDetach, setAttribute, setBooleanAttribute, setEventHandler, setStyleProperty, sibling, snapshotSpread, template, useEffect, useRef, useState } from "octane";
|
|
4
|
+
import { __s, bagOf, child, clone, componentSlotVoid, delegateEvents, evt1, evt1e, evt1u, evt2e, evt2u, hookSlots, ifBlock, markDangerouslySetInnerHTMLChildren, queueRefAttach, queueRefDetach, setAttribute, setBooleanAttribute, setEventHandler, setStyleProperty, sibling, snapshotSpread, template, useEffect, useImperativeHandle, useRef, useState } from "octane";
|
|
5
5
|
import { bindSignalAttribute, bindSignalHostPropSources, compilerMemoRegion, enableSignalBindings, hookMemoCreate, hookMemoPublishInvariant, replaceRef, setPlainAttribute, setURLAttribute } from "octane/internal/client";
|
|
6
6
|
//#region src/Video.web.tsrx
|
|
7
7
|
enableSignalBindings(1, true);
|
|
@@ -15,7 +15,7 @@ delegateEvents([
|
|
|
15
15
|
"timeupdate"
|
|
16
16
|
]);
|
|
17
17
|
var _t$0 = /* @__PURE__ */ template("<div><video class=\"vx-video-surface\" playsinline=\"\" preload=\"metadata\"></video><!></div>");
|
|
18
|
-
var _hs$ = /* @__PURE__ */ hookSlots(
|
|
18
|
+
var _hs$ = /* @__PURE__ */ hookSlots(9);
|
|
19
19
|
var __event = (e, setDuration, props) => {
|
|
20
20
|
const ms = e.currentTarget.duration * 1e3;
|
|
21
21
|
setDuration(Number.isFinite(ms) ? ms : 0);
|
|
@@ -62,7 +62,7 @@ function __then$0(__props, __s, __extra) {
|
|
|
62
62
|
setPosition(ms);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
}, __block.endMarker, void 0, 2, void 0, void 0, "c:
|
|
65
|
+
}, __block.endMarker, void 0, 2, void 0, void 0, "c:c3e56410");
|
|
66
66
|
}
|
|
67
67
|
var _rm$3 = [
|
|
68
68
|
"s",
|
|
@@ -121,6 +121,7 @@ var Video = /* @__PURE__ */ __s(function Video(props, __s, __extra) {
|
|
|
121
121
|
duration: () => Number.isFinite(v.duration) ? v.duration * 1e3 : 0,
|
|
122
122
|
native: v
|
|
123
123
|
}));
|
|
124
|
+
useImperativeHandle(props.ref, () => handle(el.current), [], _hs$ + 8);
|
|
124
125
|
if (__s.block.pending && !__s.block.crossRenderUpdate) return;
|
|
125
126
|
let _b = __s.slots[0];
|
|
126
127
|
if (_b === void 0) {
|
|
@@ -128,7 +129,7 @@ var Video = /* @__PURE__ */ __s(function Video(props, __s, __extra) {
|
|
|
128
129
|
const _root = clone(_t$0);
|
|
129
130
|
_m0 = props.id;
|
|
130
131
|
_m1 = [
|
|
131
|
-
"vx-
|
|
132
|
+
"vx-layers",
|
|
132
133
|
"vx-video",
|
|
133
134
|
props.className
|
|
134
135
|
];
|
|
@@ -200,14 +201,13 @@ var Video = /* @__PURE__ */ __s(function Video(props, __s, __extra) {
|
|
|
200
201
|
"aria-live",
|
|
201
202
|
_m11
|
|
202
203
|
]
|
|
203
|
-
], "b:
|
|
204
|
+
], "b:f375fbc0", true);
|
|
204
205
|
const _el0 = child(_root);
|
|
205
206
|
queueRefAttach(__s, _m15 = (v) => {
|
|
206
207
|
el.current = v;
|
|
207
208
|
if (!v) return;
|
|
208
209
|
v.muted = muted;
|
|
209
210
|
applyEscapeProps(v, props);
|
|
210
|
-
props.bind?.(handle(v));
|
|
211
211
|
}, _m14 = _el0);
|
|
212
212
|
(__s.cleanups ??= []).push(() => _b && queueRefDetach(_b.p, _b.o));
|
|
213
213
|
evt1(_el0, "$$play", setPlaying, true);
|
|
@@ -254,7 +254,7 @@ var Video = /* @__PURE__ */ __s(function Video(props, __s, __extra) {
|
|
|
254
254
|
}
|
|
255
255
|
{
|
|
256
256
|
const _v = [
|
|
257
|
-
"vx-
|
|
257
|
+
"vx-layers",
|
|
258
258
|
"vx-video",
|
|
259
259
|
props.className
|
|
260
260
|
];
|
|
@@ -354,14 +354,13 @@ var Video = /* @__PURE__ */ __s(function Video(props, __s, __extra) {
|
|
|
354
354
|
"aria-live",
|
|
355
355
|
_b.l
|
|
356
356
|
]
|
|
357
|
-
], "b:
|
|
357
|
+
], "b:f375fbc0", true);
|
|
358
358
|
{
|
|
359
359
|
const _r = (v) => {
|
|
360
360
|
el.current = v;
|
|
361
361
|
if (!v) return;
|
|
362
362
|
v.muted = muted;
|
|
363
363
|
applyEscapeProps(v, props);
|
|
364
|
-
props.bind?.(handle(v));
|
|
365
364
|
};
|
|
366
365
|
if (_r !== _b.p) _b.p = replaceRef(__s, _b.p, _r, _b.o);
|
|
367
366
|
}
|
|
@@ -369,10 +368,10 @@ var Video = /* @__PURE__ */ __s(function Video(props, __s, __extra) {
|
|
|
369
368
|
evt2u(_b.w, __event$, props, setPlaying);
|
|
370
369
|
evt1u(_b.x, __event$2, props);
|
|
371
370
|
}
|
|
372
|
-
_b.q = bindSignalAttribute(__s, _b.q, _b.o, "src", props.src, "b:
|
|
373
|
-
_b.r = bindSignalAttribute(__s, _b.r, _b.o, "poster", props.poster, "b:
|
|
374
|
-
_b.s = bindSignalAttribute(__s, _b.s, _b.o, "muted", muted, "b:
|
|
375
|
-
_b.t = bindSignalAttribute(__s, _b.t, _b.o, "loop", props.loop, "b:
|
|
371
|
+
_b.q = bindSignalAttribute(__s, _b.q, _b.o, "src", props.src, "b:7dbcd207", setURLAttribute);
|
|
372
|
+
_b.r = bindSignalAttribute(__s, _b.r, _b.o, "poster", props.poster, "b:1b786c6f", setPlainAttribute);
|
|
373
|
+
_b.s = bindSignalAttribute(__s, _b.s, _b.o, "muted", muted, "b:39d924bf", setAttribute);
|
|
374
|
+
_b.t = bindSignalAttribute(__s, _b.t, _b.o, "loop", props.loop, "b:1aecad9d", setBooleanAttribute);
|
|
376
375
|
{
|
|
377
376
|
const _v = props.fit ?? "contain";
|
|
378
377
|
if (_b.u !== _v) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { bag4, child, clone, componentSlot, drainFrag, hookSlots, ifBlock, markChildrenBlock, markWarm, registerWarmPlan, template, useEffect, useState, warmChild } from "octane";
|
|
2
2
|
import { textHoleUpdate } from "octane/internal/client";
|
|
3
|
-
import { Icon, Image, Pressable,
|
|
3
|
+
import { HStack, Icon, Image, Pressable, Slider, Text, View } from "@octane-xplat/ui";
|
|
4
4
|
//#region src/video-chrome.web.tsrx
|
|
5
5
|
var _t$0 = /* @__PURE__ */ template("<!>", 0, 1);
|
|
6
6
|
var _hs$ = /* @__PURE__ */ hookSlots(12);
|
|
@@ -138,10 +138,10 @@ function __then$4(__props, __s, __extra) {
|
|
|
138
138
|
"children": markChildrenBlock(__children$27, __childrenBody$5)
|
|
139
139
|
}, __block.endMarker, void 0, void 0, void 0, void 0, "c:9bf9319c");
|
|
140
140
|
}
|
|
141
|
-
componentSlot(__s, 0, __block.parentNode,
|
|
141
|
+
componentSlot(__s, 0, __block.parentNode, HStack, {
|
|
142
142
|
"className": "vx-video-bar",
|
|
143
|
-
"
|
|
144
|
-
"gap":
|
|
143
|
+
"vAlign": "center",
|
|
144
|
+
"gap": 2,
|
|
145
145
|
"children": markChildrenBlock(__children$15, __childrenBody$6)
|
|
146
146
|
}, __block.endMarker, void 0, void 0, void 0, void 0, "c:455e7102");
|
|
147
147
|
}
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/video",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Embedded video player for Octane xplat — web <video> + @nstudio/nativescript-exoplayer (ExoPlayer / AVPlayerViewController) with self-drawn chrome",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
6
|
+
"android",
|
|
7
|
+
"avplayer",
|
|
8
8
|
"cross-platform",
|
|
9
|
-
"video",
|
|
10
|
-
"video-player",
|
|
11
9
|
"exoplayer",
|
|
12
|
-
"
|
|
10
|
+
"ios",
|
|
13
11
|
"media",
|
|
14
12
|
"nativescript",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
13
|
+
"octane",
|
|
14
|
+
"video",
|
|
15
|
+
"video-player",
|
|
16
|
+
"web",
|
|
17
|
+
"xplat"
|
|
18
18
|
],
|
|
19
|
-
"license": "MIT",
|
|
20
19
|
"homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/video",
|
|
20
|
+
"license": "MIT",
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "
|
|
23
|
+
"url": "https://github.com/octane-xplat/octane-xplat",
|
|
24
24
|
"directory": "packages/video"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
@@ -48,11 +48,12 @@
|
|
|
48
48
|
"@nstudio/nativescript-exoplayer": "6.2.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@nativescript-community/octane": "0.2.
|
|
51
|
+
"@nativescript-community/octane": "0.2.4",
|
|
52
52
|
"@nativescript/core": "9.1.2",
|
|
53
|
-
"@octane-xplat/ui": "0.
|
|
53
|
+
"@octane-xplat/ui": "0.10.0",
|
|
54
54
|
"@octanejs/vite-plugin": "0.1.61",
|
|
55
55
|
"octane": "0.6.3",
|
|
56
|
+
"tsrx-typegen": "0.2.2",
|
|
56
57
|
"typescript": "5.9.3",
|
|
57
58
|
"vite": "8.3.0"
|
|
58
59
|
},
|
|
@@ -71,6 +72,9 @@
|
|
|
71
72
|
}
|
|
72
73
|
},
|
|
73
74
|
"scripts": {
|
|
74
|
-
"build": "vite build && vite build --mode native &&
|
|
75
|
+
"build": "vite build && vite build --mode native && pnpm typegen && node ../../scripts/check-native-dist.mjs",
|
|
76
|
+
"typegen": "tsc -p tsconfig.types.json",
|
|
77
|
+
"test:packed": "node tests/packed-consumer.mjs",
|
|
78
|
+
"pack:check": "tsrx-typegen --pack-check"
|
|
75
79
|
}
|
|
76
80
|
}
|
package/src/Video.macos.tsrx
CHANGED
package/src/Video.tsrx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
|
-
import { useCallback, useEffect, useRef, useState } from 'octane';
|
|
2
|
+
import { useImperativeHandle, useCallback, useEffect, useRef, useState } from 'octane';
|
|
3
3
|
import { registerElement } from '@nativescript-community/octane';
|
|
4
4
|
import type { Attributes } from '@nativescript-community/octane/intrinsics';
|
|
5
5
|
import { Video as NSVideo, VideoFill } from '@nstudio/nativescript-exoplayer';
|
|
@@ -47,6 +47,8 @@ export function Video(props: VideoProps) @{
|
|
|
47
47
|
|
|
48
48
|
// Stable identity — an inline closure re-fires ref(null)/ref(v) per
|
|
49
49
|
// render, which would bounce host.current around the effects below.
|
|
50
|
+
useImperativeHandle(props.ref, () => handle(host.current!), []);
|
|
51
|
+
|
|
50
52
|
const bindHost = useCallback((v: any) => {
|
|
51
53
|
host.current = v;
|
|
52
54
|
}, []);
|
|
@@ -64,7 +66,6 @@ export function Video(props: VideoProps) @{
|
|
|
64
66
|
const v = host.current;
|
|
65
67
|
if (!v) return;
|
|
66
68
|
applyEscapeProps(v, props);
|
|
67
|
-
props.bind?.(handle(v));
|
|
68
69
|
}, []);
|
|
69
70
|
|
|
70
71
|
useEffect(() => {
|
|
@@ -101,7 +102,7 @@ export function Video(props: VideoProps) @{
|
|
|
101
102
|
id={props.id}
|
|
102
103
|
rows="*"
|
|
103
104
|
columns="*"
|
|
104
|
-
className={cx('vx-
|
|
105
|
+
className={cx('vx-layers', 'vx-video', props.className)}
|
|
105
106
|
style={props.style}
|
|
106
107
|
{...layoutChildProps(props)}
|
|
107
108
|
accessible={props.accessible}
|
package/src/Video.web.tsrx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'octane';
|
|
1
|
+
import { useImperativeHandle, useEffect, useRef, useState } from 'octane';
|
|
2
2
|
import type { VideoHandle, VideoProps } from './props';
|
|
3
3
|
import { applyEscapeProps } from './escape-props';
|
|
4
4
|
import { layoutChildProps } from './layout-child.web';
|
|
@@ -71,9 +71,11 @@ export function Video(props: VideoProps) @{
|
|
|
71
71
|
native: v,
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
+
useImperativeHandle(props.ref, () => handle(el.current), []);
|
|
75
|
+
|
|
74
76
|
<div
|
|
75
77
|
id={props.id}
|
|
76
|
-
className={['vx-
|
|
78
|
+
className={['vx-layers', 'vx-video', props.className]}
|
|
77
79
|
{...layoutChildProps(props, props.style)}
|
|
78
80
|
role={props.accessibilityRole}
|
|
79
81
|
aria-label={props.accessibilityLabel}
|
|
@@ -91,7 +93,6 @@ export function Video(props: VideoProps) @{
|
|
|
91
93
|
if (!v) return;
|
|
92
94
|
v.muted = muted;
|
|
93
95
|
applyEscapeProps(v, props);
|
|
94
|
-
props.bind?.(handle(v));
|
|
95
96
|
}}
|
|
96
97
|
className="vx-video-surface"
|
|
97
98
|
src={props.src}
|
package/src/layout-child.web.ts
CHANGED
|
@@ -68,7 +68,7 @@ export function layoutChildProps(
|
|
|
68
68
|
style.order = props.order
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// Flex-container props (View/
|
|
71
|
+
// Flex-container props (View/HStack/Pressable hosts) — RN vocabulary on the
|
|
72
72
|
// element style. Numbers become px via octane's style normalization.
|
|
73
73
|
if (props.justifyContent !== undefined) {
|
|
74
74
|
style.justifyContent = FLEX_JUSTIFY[props.justifyContent] ?? props.justifyContent
|
package/src/props.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Octane } from 'octane/jsx-runtime'
|
|
2
|
+
|
|
1
3
|
export interface LayoutChildProps {
|
|
2
4
|
row?: number
|
|
3
5
|
col?: number
|
|
@@ -12,7 +14,7 @@ export interface LayoutChildProps {
|
|
|
12
14
|
order?: number
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
/** Flex-container props shared by View/
|
|
17
|
+
/** Flex-container props shared by View/HStack/Pressable — RN vocabulary, applied
|
|
16
18
|
* to the host flexboxlayout natively and the element's style on web.
|
|
17
19
|
* `gap` is a dip number (px on web); NS supports it on FlexboxLayout only
|
|
18
20
|
* (GridLayout has no gap). */
|
|
@@ -93,7 +95,7 @@ export interface VideoProps extends LayoutChildProps, AccessibilityProps {
|
|
|
93
95
|
/** Frame shown until playback starts. */
|
|
94
96
|
poster?: string
|
|
95
97
|
/** Controlled playback — pair with `onPlayingChange`. Leave unset for
|
|
96
|
-
* uncontrolled playback (the transport and `
|
|
98
|
+
* uncontrolled playback (the transport and `ref` handle still work). */
|
|
97
99
|
playing?: boolean
|
|
98
100
|
/** Uncontrolled start-playing shorthand. Browsers block unmuted
|
|
99
101
|
* autoplay — pair with `muted` when `autoPlay` matters on web. */
|
|
@@ -117,7 +119,7 @@ export interface VideoProps extends LayoutChildProps, AccessibilityProps {
|
|
|
117
119
|
onError?: (e: VideoEvent) => void
|
|
118
120
|
/** Imperative handle — play/pause/seek/time plus `native` for anything
|
|
119
121
|
* the shared props don't cover. */
|
|
120
|
-
|
|
122
|
+
ref?: Octane.Ref<VideoHandle>
|
|
121
123
|
/** Platform escape hatches, applied after the shared props. */
|
|
122
124
|
ios?: Record<string, any>
|
|
123
125
|
android?: Record<string, any>
|
package/src/video-chrome.tsrx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
2
|
import { useEffect, useState } from 'octane';
|
|
3
|
-
import { Icon, Image, Pressable,
|
|
3
|
+
import { Icon, Image, Pressable, HStack, Slider, Text, View } from '@octane-xplat/ui';
|
|
4
4
|
|
|
5
5
|
/** Self-drawn video transport — the chrome half of the surface-hosted
|
|
6
6
|
* `Video` component. Identical structure to the native twin (only the
|
|
7
7
|
* pragma differs): every layer composes xplat primitives,
|
|
8
8
|
* so the transport draws the same pixels on every target — the leaf only
|
|
9
|
-
* supplies the surface. The layers stack inside the leaf's `vx-
|
|
9
|
+
* supplies the surface. The layers stack inside the leaf's `vx-layers`
|
|
10
10
|
* grid (later = on top), so this fragment's children are each a
|
|
11
11
|
* full-frame layer. Times are milliseconds (matches both plugin players;
|
|
12
12
|
* the web leaf converts from `HTMLMediaElement`'s seconds). */
|
|
@@ -78,7 +78,7 @@ export function VideoChrome(props: VideoChromeProps) @{
|
|
|
78
78
|
// them pointer-events:none so taps reach the surface/tap layer; NS
|
|
79
79
|
// layout views never capture touches without handlers.
|
|
80
80
|
<View className="vx-video-barwrap" justifyContent="end">
|
|
81
|
-
<
|
|
81
|
+
<HStack className="vx-video-bar" vAlign="center" gap={2}>
|
|
82
82
|
<Pressable
|
|
83
83
|
className="vx-video-btn"
|
|
84
84
|
accessibilityRole="button"
|
|
@@ -109,7 +109,7 @@ export function VideoChrome(props: VideoChromeProps) @{
|
|
|
109
109
|
color="#fff"
|
|
110
110
|
/>
|
|
111
111
|
</Pressable>
|
|
112
|
-
</
|
|
112
|
+
</HStack>
|
|
113
113
|
</View>
|
|
114
114
|
</>
|
|
115
115
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useEffect, useState } from 'octane';
|
|
2
|
-
import { Icon, Image, Pressable,
|
|
2
|
+
import { Icon, Image, Pressable, HStack, Slider, Text, View } from '@octane-xplat/ui';
|
|
3
3
|
|
|
4
4
|
/** Self-drawn video transport — the chrome half of the surface-hosted
|
|
5
5
|
* `Video` component. Identical structure to the native twin (only the
|
|
6
6
|
* pragma differs): every layer composes xplat primitives,
|
|
7
7
|
* so the transport draws the same pixels on every target — the leaf only
|
|
8
|
-
* supplies the surface. The layers stack inside the leaf's `vx-
|
|
8
|
+
* supplies the surface. The layers stack inside the leaf's `vx-layers`
|
|
9
9
|
* grid (later = on top), so this fragment's children are each a
|
|
10
10
|
* full-frame layer. Times are milliseconds (matches both plugin players;
|
|
11
11
|
* the web leaf converts from `HTMLMediaElement`'s seconds). */
|
|
@@ -77,7 +77,7 @@ export function VideoChrome(props: VideoChromeProps) @{
|
|
|
77
77
|
// them pointer-events:none so taps reach the surface/tap layer; NS
|
|
78
78
|
// layout views never capture touches without handlers.
|
|
79
79
|
<View className="vx-video-barwrap" justifyContent="end">
|
|
80
|
-
<
|
|
80
|
+
<HStack className="vx-video-bar" vAlign="center" gap={2}>
|
|
81
81
|
<Pressable
|
|
82
82
|
className="vx-video-btn"
|
|
83
83
|
accessibilityRole="button"
|
|
@@ -108,7 +108,7 @@ export function VideoChrome(props: VideoChromeProps) @{
|
|
|
108
108
|
color="#fff"
|
|
109
109
|
/>
|
|
110
110
|
</Pressable>
|
|
111
|
-
</
|
|
111
|
+
</HStack>
|
|
112
112
|
</View>
|
|
113
113
|
</>
|
|
114
114
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UniversalComponent } from 'octane/universal'
|
|
2
|
-
import type { VideoProps } from './props'
|
|
2
|
+
import type { VideoProps } from './props.js'
|
|
3
3
|
|
|
4
4
|
export declare const Video: UniversalComponent<VideoProps>
|
|
5
|
-
export type { VideoEvent, VideoFit, VideoHandle, VideoProps } from './props'
|
|
5
|
+
export type { VideoEvent, VideoFit, VideoHandle, VideoProps } from './props.js'
|
package/types/index.macos.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { VideoProps } from './props'
|
|
1
|
+
import type { VideoProps } from './props.js'
|
|
2
2
|
|
|
3
|
-
export type { VideoEvent, VideoFit, VideoHandle, VideoProps } from './props'
|
|
3
|
+
export type { VideoEvent, VideoFit, VideoHandle, VideoProps } from './props.js'
|
|
4
4
|
export declare function Video(props: VideoProps): unknown
|
package/types/props.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Octane } from 'octane/jsx-runtime';
|
|
1
2
|
export interface LayoutChildProps {
|
|
2
3
|
row?: number;
|
|
3
4
|
col?: number;
|
|
@@ -11,7 +12,7 @@ export interface LayoutChildProps {
|
|
|
11
12
|
alignSelf?: string;
|
|
12
13
|
order?: number;
|
|
13
14
|
}
|
|
14
|
-
/** Flex-container props shared by View/
|
|
15
|
+
/** Flex-container props shared by View/HStack/Pressable — RN vocabulary, applied
|
|
15
16
|
* to the host flexboxlayout natively and the element's style on web.
|
|
16
17
|
* `gap` is a dip number (px on web); NS supports it on FlexboxLayout only
|
|
17
18
|
* (GridLayout has no gap). */
|
|
@@ -71,7 +72,7 @@ export interface VideoProps extends LayoutChildProps, AccessibilityProps {
|
|
|
71
72
|
/** Frame shown until playback starts. */
|
|
72
73
|
poster?: string;
|
|
73
74
|
/** Controlled playback — pair with `onPlayingChange`. Leave unset for
|
|
74
|
-
* uncontrolled playback (the transport and `
|
|
75
|
+
* uncontrolled playback (the transport and `ref` handle still work). */
|
|
75
76
|
playing?: boolean;
|
|
76
77
|
/** Uncontrolled start-playing shorthand. Browsers block unmuted
|
|
77
78
|
* autoplay — pair with `muted` when `autoPlay` matters on web. */
|
|
@@ -95,7 +96,7 @@ export interface VideoProps extends LayoutChildProps, AccessibilityProps {
|
|
|
95
96
|
onError?: (e: VideoEvent) => void;
|
|
96
97
|
/** Imperative handle — play/pause/seek/time plus `native` for anything
|
|
97
98
|
* the shared props don't cover. */
|
|
98
|
-
|
|
99
|
+
ref?: Octane.Ref<VideoHandle>;
|
|
99
100
|
/** Platform escape hatches, applied after the shared props. */
|
|
100
101
|
ios?: Record<string, any>;
|
|
101
102
|
android?: Record<string, any>;
|