@oxyhq/bloom 1.5.0 → 1.7.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/NOTICE +46 -0
- package/docs/media-flight.mdx +162 -3
- package/lib/commonjs/media-flight/MediaFlightHost.js +14 -1
- package/lib/commonjs/media-flight/MediaFlightHost.js.map +1 -1
- package/lib/commonjs/media-flight/MediaFlightHost.web.js +9 -1
- package/lib/commonjs/media-flight/MediaFlightHost.web.js.map +1 -1
- package/lib/commonjs/media-flight/MediaFlightLayer.js +4 -5
- package/lib/commonjs/media-flight/MediaFlightLayer.js.map +1 -1
- package/lib/commonjs/media-flight/media-node.web.js +37 -1
- package/lib/commonjs/media-flight/media-node.web.js.map +1 -1
- package/lib/module/media-flight/MediaFlightHost.js +14 -1
- package/lib/module/media-flight/MediaFlightHost.js.map +1 -1
- package/lib/module/media-flight/MediaFlightHost.web.js +9 -1
- package/lib/module/media-flight/MediaFlightHost.web.js.map +1 -1
- package/lib/module/media-flight/MediaFlightLayer.js +4 -5
- package/lib/module/media-flight/MediaFlightLayer.js.map +1 -1
- package/lib/module/media-flight/media-node.web.js +37 -1
- package/lib/module/media-flight/media-node.web.js.map +1 -1
- package/lib/typescript/commonjs/media-flight/MediaFlightHost.d.ts +2 -1
- package/lib/typescript/commonjs/media-flight/MediaFlightHost.d.ts.map +1 -1
- package/lib/typescript/commonjs/media-flight/MediaFlightHost.web.d.ts +9 -1
- package/lib/typescript/commonjs/media-flight/MediaFlightHost.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts.map +1 -1
- package/lib/typescript/commonjs/media-flight/index.d.ts +1 -1
- package/lib/typescript/commonjs/media-flight/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/media-flight/index.web.d.ts +1 -1
- package/lib/typescript/commonjs/media-flight/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/media-flight/media-node.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/media-flight/types.d.ts +24 -7
- package/lib/typescript/commonjs/media-flight/types.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/MediaFlightHost.d.ts +2 -1
- package/lib/typescript/module/media-flight/MediaFlightHost.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/MediaFlightHost.web.d.ts +9 -1
- package/lib/typescript/module/media-flight/MediaFlightHost.web.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/index.d.ts +1 -1
- package/lib/typescript/module/media-flight/index.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/index.web.d.ts +1 -1
- package/lib/typescript/module/media-flight/index.web.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/media-node.web.d.ts.map +1 -1
- package/lib/typescript/module/media-flight/types.d.ts +24 -7
- package/lib/typescript/module/media-flight/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/media-flight/MediaFlightHost.tsx +21 -4
- package/src/media-flight/MediaFlightHost.web.tsx +20 -4
- package/src/media-flight/MediaFlightLayer.tsx +4 -5
- package/src/media-flight/index.ts +3 -0
- package/src/media-flight/index.web.ts +3 -0
- package/src/media-flight/media-node.web.ts +42 -1
- package/src/media-flight/types.ts +27 -7
|
@@ -225,6 +225,47 @@ function pick(claims: readonly MediaNodeClaim[]): MediaNodeClaim | null {
|
|
|
225
225
|
return best;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/**
|
|
229
|
+
* An element that can be MOVED rather than removed and re-inserted.
|
|
230
|
+
*
|
|
231
|
+
* `moveBefore` is newer than TypeScript's DOM library, so the capability is
|
|
232
|
+
* named here and checked at runtime rather than assumed.
|
|
233
|
+
*/
|
|
234
|
+
interface MovingParent {
|
|
235
|
+
moveBefore(node: Node, child: Node | null): void;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* DERIVED FROM react-native-teleport 1.2.0 — `src/views/Portal/index.tsx`,
|
|
240
|
+
* its `moveElementTo`. MIT, Copyright (c) 2025 Kiryl Ziusko; see `NOTICE`.
|
|
241
|
+
*
|
|
242
|
+
* Changed: typed for TypeScript's DOM library, which does not know `moveBefore`
|
|
243
|
+
* yet, and reduced to the append case Bloom needs (no `before` sibling).
|
|
244
|
+
*
|
|
245
|
+
* Why it is worth taking rather than keeping `appendChild`: `appendChild` of an
|
|
246
|
+
* ATTACHED node is a remove followed by an insert, and the only reason media
|
|
247
|
+
* survives it is that HTML's removal steps await a stable state and abort if
|
|
248
|
+
* the node is back in a document by then. `moveBefore` does not run the removal
|
|
249
|
+
* steps at all — it is the state-preserving primitive, which matters for
|
|
250
|
+
* anything the abort does not cover: focus, `<iframe>`s, CSS animations.
|
|
251
|
+
*
|
|
252
|
+
* Measured for a playing `<video>` in Chrome 151: indistinguishable from
|
|
253
|
+
* `appendChild` (ct 0.60 -> 1.00, never paused, 6 frames, worst frame gap
|
|
254
|
+
* 100 ms — the clip's own cadence — under both), while a real removal pauses
|
|
255
|
+
* and freezes. So this is not a fix for a defect Bloom has; it is the correct
|
|
256
|
+
* primitive for the ones it does not have yet.
|
|
257
|
+
*/
|
|
258
|
+
function moveInto(parent: HTMLElement, child: HTMLElement): void {
|
|
259
|
+
if (supportsMoveBefore && child.parentNode !== null) {
|
|
260
|
+
(parent as unknown as MovingParent).moveBefore(child, null);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
parent.appendChild(child);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const supportsMoveBefore =
|
|
267
|
+
typeof Element !== 'undefined' && 'moveBefore' in Element.prototype;
|
|
268
|
+
|
|
228
269
|
/**
|
|
229
270
|
* Put the wrapper where its top claim says, in ONE synchronous move.
|
|
230
271
|
*
|
|
@@ -237,7 +278,7 @@ function place(record: MediaNodeRecord): void {
|
|
|
237
278
|
const target = topClaim(record)?.el ?? holder(reg);
|
|
238
279
|
if (target === null) return;
|
|
239
280
|
if (record.wrapper.parentElement === target) return;
|
|
240
|
-
target
|
|
281
|
+
moveInto(target, record.wrapper);
|
|
241
282
|
}
|
|
242
283
|
|
|
243
284
|
function sameRender(a: MediaNodeRender, b: MediaNodeRender): boolean {
|
|
@@ -66,6 +66,19 @@ export interface MediaSurfaceVideo {
|
|
|
66
66
|
/** What a media surface paints: a still image, or a consumer-owned video. */
|
|
67
67
|
export type MediaSurfaceContent = MediaSurfaceImage | MediaSurfaceVideo;
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* `MediaSurfaceVideo` carrying the consumer's OWN player type.
|
|
71
|
+
*
|
|
72
|
+
* Bloom transports that object; it never reads it. Narrowing it to
|
|
73
|
+
* `VideoPlayerLike` on the way through would be Bloom asserting something about
|
|
74
|
+
* cargo — and it would land on the consumer, who then has to cast the player
|
|
75
|
+
* back before handing it to expo-video's `VideoView`. A contract that pushes a
|
|
76
|
+
* consumer towards `as` ends up as an `as any` in someone's repo.
|
|
77
|
+
*/
|
|
78
|
+
export interface MediaSurfaceVideoOf<P extends VideoPlayerLike> extends MediaSurfaceVideo {
|
|
79
|
+
player: P;
|
|
80
|
+
}
|
|
81
|
+
|
|
69
82
|
/**
|
|
70
83
|
* A media surface currently owned by the flight layer.
|
|
71
84
|
*
|
|
@@ -233,7 +246,7 @@ export interface MediaFlightController {
|
|
|
233
246
|
* INTRINSIC size (300x150) instead of stretching — so a slot that drops this
|
|
234
247
|
* style paints a 300x150 video inside whatever box it was given. Spread it.
|
|
235
248
|
*/
|
|
236
|
-
export interface MediaVideoSlotProps {
|
|
249
|
+
export interface MediaVideoSlotProps<P extends VideoPlayerLike = VideoPlayerLike> {
|
|
237
250
|
/**
|
|
238
251
|
* The player Bloom was given — never one Bloom created.
|
|
239
252
|
*
|
|
@@ -244,7 +257,7 @@ export interface MediaVideoSlotProps {
|
|
|
244
257
|
* anything else here — keeping the old player, unmounting instead — brings
|
|
245
258
|
* that defect back. See `releaseFlight`.
|
|
246
259
|
*/
|
|
247
|
-
player:
|
|
260
|
+
player: P | null;
|
|
248
261
|
/** Fills the box. Spread it — see above. */
|
|
249
262
|
style: StyleProp<ViewStyle>;
|
|
250
263
|
contentFit: 'contain' | 'cover';
|
|
@@ -267,7 +280,9 @@ export interface MediaVideoSlotProps {
|
|
|
267
280
|
* layer, compared by identity — a new function every render republishes every
|
|
268
281
|
* render. Correct either way, wasteful if you skip it.
|
|
269
282
|
*/
|
|
270
|
-
export type MediaVideoSlot =
|
|
283
|
+
export type MediaVideoSlot<P extends VideoPlayerLike = VideoPlayerLike> = (
|
|
284
|
+
props: MediaVideoSlotProps<P>,
|
|
285
|
+
) => ReactNode;
|
|
271
286
|
|
|
272
287
|
/**
|
|
273
288
|
* A place a media surface may live: the feed row it starts in, the fullscreen
|
|
@@ -279,11 +294,16 @@ export type MediaVideoSlot = (props: MediaVideoSlotProps) => ReactNode;
|
|
|
279
294
|
* ever leaving the document. On native a host renders its media inline, which
|
|
280
295
|
* is what it has always done and what the platform makes correct there.
|
|
281
296
|
*/
|
|
282
|
-
export interface MediaFlightHostProps {
|
|
297
|
+
export interface MediaFlightHostProps<P extends VideoPlayerLike = VideoPlayerLike> {
|
|
283
298
|
/** The id this host shares with the flight and with the other end. */
|
|
284
299
|
id: string;
|
|
285
|
-
/**
|
|
286
|
-
|
|
300
|
+
/**
|
|
301
|
+
* What to paint: a still image, or a consumer-owned expo-video player.
|
|
302
|
+
*
|
|
303
|
+
* The player's own type flows from here into {@link renderVideo}, so a slot
|
|
304
|
+
* gets back exactly what it put in and hands it to `VideoView` with no cast.
|
|
305
|
+
*/
|
|
306
|
+
content: MediaSurfaceImage | MediaSurfaceVideoOf<P>;
|
|
287
307
|
/** Style of the host BOX. Give it the radius and `overflow: 'hidden'` you want. */
|
|
288
308
|
style?: StyleProp<ViewStyle>;
|
|
289
309
|
/** How the media fills the box. Defaults to `'cover'`. */
|
|
@@ -292,7 +312,7 @@ export interface MediaFlightHostProps {
|
|
|
292
312
|
* Paint the video yourself, keeping your own `ref` and expo-video props. See
|
|
293
313
|
* {@link MediaVideoSlot}; memoise it.
|
|
294
314
|
*/
|
|
295
|
-
renderVideo?: MediaVideoSlot
|
|
315
|
+
renderVideo?: MediaVideoSlot<P>;
|
|
296
316
|
/** Whether the video arm shows expo-video's own controls. Defaults to `false`. */
|
|
297
317
|
nativeControls?: boolean;
|
|
298
318
|
accessibilityLabel?: string;
|