@octane-xplat/video 0.9.0 → 0.11.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 CHANGED
@@ -1,36 +1,55 @@
1
1
  # `@octane-xplat/video`
2
2
 
3
+ ```sh
4
+ pnpm add @octane-xplat/video
5
+ ```
6
+
3
7
  Embedded video player for Octane xplat apps: `<video>` on web and
4
8
  `@nstudio/nativescript-exoplayer` on native (ExoPlayer on Android,
5
9
  `AVPlayerViewController` on iOS), with a macOS entry. The OS engine owns
6
10
  the pixels while all chrome is self-drawn, so `controls` looks identical
7
11
  on every target.
8
12
 
9
- ```sh
10
- pnpm add @octane-xplat/video
11
- ```
12
-
13
13
  ```tsx
14
14
  import { Video } from '@octane-xplat/video'
15
15
 
16
- ;<Video
17
- src="https://example.com/clip.mp4" // native also accepts ~/ bundle paths and files
18
- poster="https://example.com/poster.jpg"
19
- controls // self-drawn transport, default true
20
- fit="contain" // 'contain' | 'cover' | 'fill'
21
- muted // pair with autoPlay — browsers block unmuted autoplay
22
- playing={isPlaying} // controlled — pair with onPlayingChange, or omit
23
- onReady={(e) => console.log(e.duration)}
24
- onEnded={() => console.log('done')}
25
- bind={(h) => (handle = h)} // play/pause/seekTo(ms)/currentTime/duration + .native
26
- />
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
27
  ```
28
28
 
29
29
  All times are milliseconds on every platform. `onError` is web-only — the
30
- plugin players surface no error event on native. `bind.native` is the
30
+ plugin players surface no error event on native. `handle.native` is the
31
31
  platform surface for anything the shared props don't cover, and the
32
32
  `ios`/`android`/`web` escape props apply after the shared props.
33
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
+
34
53
  Per-target limits are recorded in
35
- [known limits](../../docs/known-limits.md). Exercised by
54
+ [known limits](../../docs/verify/known-limits.md). Exercised by
36
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(11);
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$7);
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
- props.bind?.(handle(v));
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$9);
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$10);
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-stack", "vx-video", props.className)
124
+ cx("vx-layers", "vx-video", props.className)
124
125
  ],
125
126
  [
126
127
  "set",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "c505a9fe-2597-4498-bf16-9fcab5c5e3f2",
3
+ "buildId": "e67f0c43-faee-450b-935f-e50118c1b64c",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
@@ -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, Row, Slider, Text, View } from "@octane-xplat/ui";
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", Row, universalProps([
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
- "alignItems",
220
+ "vAlign",
221
221
  "center"
222
222
  ],
223
223
  [
224
224
  "set",
225
225
  "gap",
226
- 8
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(8);
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:6f1a737f");
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-stack",
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:8e28227a", true);
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-stack",
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:8e28227a", true);
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:8cc4fe21", setURLAttribute);
373
- _b.r = bindSignalAttribute(__s, _b.r, _b.o, "poster", props.poster, "b:96cc8ad6", setPlainAttribute);
374
- _b.s = bindSignalAttribute(__s, _b.s, _b.o, "muted", muted, "b:48ef6972", setAttribute);
375
- _b.t = bindSignalAttribute(__s, _b.t, _b.o, "loop", props.loop, "b:0e1cb1f0", setBooleanAttribute);
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
  {
2
2
  "version": 1,
3
- "buildId": "ca9bd9ae-1120-41bf-94e7-8e741dca5d85",
3
+ "buildId": "23a3635d-d25b-42e9-9dd1-df99240bad2f",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
@@ -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, Row, Slider, Text, View } from "@octane-xplat/ui";
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, Row, {
141
+ componentSlot(__s, 0, __block.parentNode, HStack, {
142
142
  "className": "vx-video-bar",
143
- "alignItems": "center",
144
- "gap": 8,
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@octane-xplat/video",
3
- "version": "0.9.0",
3
+ "version": "0.11.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
6
  "android",
@@ -50,10 +50,10 @@
50
50
  "devDependencies": {
51
51
  "@nativescript-community/octane": "0.2.4",
52
52
  "@nativescript/core": "9.1.2",
53
- "@octane-xplat/ui": "0.9.0",
53
+ "@octane-xplat/ui": "0.11.0",
54
54
  "@octanejs/vite-plugin": "0.1.61",
55
55
  "octane": "0.6.3",
56
- "tsrx-typegen": "0.2.1",
56
+ "tsrx-typegen": "0.2.2",
57
57
  "typescript": "5.9.3",
58
58
  "vite": "8.3.0"
59
59
  },
@@ -1,4 +1,4 @@
1
- /** @jsxImportSource @xplat/macos/renderer */
1
+ /** @jsxImportSource @octane-xplat/macos-renderer */
2
2
  import type { VideoProps } from './props'
3
3
 
4
4
  /** Explicit placeholder until the AppKit host has a video surface. */
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-stack', 'vx-video', props.className)}
105
+ className={cx('vx-layers', 'vx-video', props.className)}
105
106
  style={props.style}
106
107
  {...layoutChildProps(props)}
107
108
  accessible={props.accessible}
@@ -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-stack', 'vx-video', props.className]}
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}
@@ -68,7 +68,7 @@ export function layoutChildProps(
68
68
  style.order = props.order
69
69
  }
70
70
 
71
- // Flex-container props (View/Row/Pressable hosts) — RN vocabulary on the
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/Row/Pressable — RN vocabulary, applied
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 `bind` handle still work). */
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
- bind?: (h: VideoHandle) => void
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>
@@ -1,12 +1,12 @@
1
1
  /** @jsxImportSource @nativescript-community/octane */
2
2
  import { useEffect, useState } from 'octane';
3
- import { Icon, Image, Pressable, Row, Slider, Text, View } from '@octane-xplat/ui';
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-stack`
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
- <Row className="vx-video-bar" alignItems="center" gap={8}>
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
- </Row>
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, Row, Slider, Text, View } from '@octane-xplat/ui';
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-stack`
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
- <Row className="vx-video-bar" alignItems="center" gap={8}>
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
- </Row>
111
+ </HStack>
112
112
  </View>
113
113
  </>
114
114
  }
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/Row/Pressable — RN vocabulary, applied
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 `bind` handle still work). */
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
- bind?: (h: VideoHandle) => void;
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>;