@oxyhq/bloom 1.0.6 → 1.2.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/docs/level-picker.mdx +105 -0
- package/docs/media-flight.mdx +272 -0
- package/docs/migrating-the-media-gallery.mdx +103 -0
- package/docs/migrating-to-1.0.mdx +1 -1
- package/docs/slider.mdx +3 -1
- package/docs/zoomable-media-gallery.mdx +116 -0
- package/lib/commonjs/floating/index.js.map +1 -1
- package/lib/commonjs/image-aspect-ratio-cache/aspect-ratio-cache.js +1 -1
- package/lib/commonjs/index.js +8 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +33 -25
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/level-picker/LevelPicker.js +349 -0
- package/lib/commonjs/level-picker/LevelPicker.js.map +1 -0
- package/lib/commonjs/level-picker/LevelPicker.web.js +346 -0
- package/lib/commonjs/level-picker/LevelPicker.web.js.map +1 -0
- package/lib/commonjs/level-picker/constants.js +137 -0
- package/lib/commonjs/level-picker/constants.js.map +1 -0
- package/lib/commonjs/level-picker/index.js +13 -0
- package/lib/commonjs/level-picker/index.js.map +1 -0
- package/lib/commonjs/level-picker/index.web.js +13 -0
- package/lib/commonjs/level-picker/index.web.js.map +1 -0
- package/lib/commonjs/level-picker/types.js +6 -0
- package/lib/commonjs/level-picker/types.js.map +1 -0
- package/lib/commonjs/media-flight/MediaFlightLayer.js +151 -0
- package/lib/commonjs/media-flight/MediaFlightLayer.js.map +1 -0
- package/lib/commonjs/media-flight/MediaSurface.js +188 -0
- package/lib/commonjs/media-flight/MediaSurface.js.map +1 -0
- package/lib/commonjs/media-flight/constants.js +39 -0
- package/lib/commonjs/media-flight/constants.js.map +1 -0
- package/lib/commonjs/media-flight/expo-video-module.js +148 -0
- package/lib/commonjs/media-flight/expo-video-module.js.map +1 -0
- package/lib/commonjs/media-flight/index.js +102 -0
- package/lib/commonjs/media-flight/index.js.map +1 -0
- package/lib/commonjs/media-flight/store.js +457 -0
- package/lib/commonjs/media-flight/store.js.map +1 -0
- package/lib/commonjs/media-flight/types.js +6 -0
- package/lib/commonjs/media-flight/types.js.map +1 -0
- package/lib/commonjs/media-flight/use-media-flight.js +41 -0
- package/lib/commonjs/media-flight/use-media-flight.js.map +1 -0
- package/lib/commonjs/tab-bar/TabBarBase.js +1 -1
- package/lib/commonjs/{zoomable-image-gallery/ZoomableImageGallery.js → zoomable-media-gallery/ZoomableMediaGallery.js} +185 -131
- package/lib/commonjs/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -0
- package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.js.map +1 -1
- package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.js +5 -5
- package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.js.map +1 -1
- package/lib/commonjs/zoomable-media-gallery/types.js +6 -0
- package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/types.js.map +1 -1
- package/lib/module/floating/index.js +5 -0
- package/lib/module/floating/index.js.map +1 -1
- package/lib/module/image-aspect-ratio-cache/aspect-ratio-cache.js +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +3 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/level-picker/LevelPicker.js +343 -0
- package/lib/module/level-picker/LevelPicker.js.map +1 -0
- package/lib/module/level-picker/LevelPicker.web.js +340 -0
- package/lib/module/level-picker/LevelPicker.web.js.map +1 -0
- package/lib/module/level-picker/constants.js +131 -0
- package/lib/module/level-picker/constants.js.map +1 -0
- package/lib/module/level-picker/index.js +4 -0
- package/lib/module/level-picker/index.js.map +1 -0
- package/lib/module/level-picker/index.web.js +4 -0
- package/lib/module/level-picker/index.web.js.map +1 -0
- package/lib/module/level-picker/types.js +4 -0
- package/lib/module/level-picker/types.js.map +1 -0
- package/lib/module/media-flight/MediaFlightLayer.js +146 -0
- package/lib/module/media-flight/MediaFlightLayer.js.map +1 -0
- package/lib/module/media-flight/MediaSurface.js +180 -0
- package/lib/module/media-flight/MediaSurface.js.map +1 -0
- package/lib/module/media-flight/constants.js +35 -0
- package/lib/module/media-flight/constants.js.map +1 -0
- package/lib/module/media-flight/expo-video-module.js +142 -0
- package/lib/module/media-flight/expo-video-module.js.map +1 -0
- package/lib/module/media-flight/index.js +9 -0
- package/lib/module/media-flight/index.js.map +1 -0
- package/lib/module/media-flight/store.js +439 -0
- package/lib/module/media-flight/store.js.map +1 -0
- package/lib/module/media-flight/types.js +4 -0
- package/lib/module/media-flight/types.js.map +1 -0
- package/lib/module/media-flight/use-media-flight.js +36 -0
- package/lib/module/media-flight/use-media-flight.js.map +1 -0
- package/lib/module/tab-bar/TabBarBase.js +1 -1
- package/lib/module/{zoomable-image-gallery/ZoomableImageGallery.js → zoomable-media-gallery/ZoomableMediaGallery.js} +184 -130
- package/lib/module/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -0
- package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.js.map +1 -1
- package/lib/module/zoomable-media-gallery/index.js +5 -0
- package/lib/module/zoomable-media-gallery/index.js.map +1 -0
- package/lib/module/zoomable-media-gallery/types.js +4 -0
- package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/types.js.map +1 -1
- package/lib/typescript/commonjs/floating/index.d.ts +5 -0
- package/lib/typescript/commonjs/floating/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +2 -0
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/level-picker/LevelPicker.d.ts +6 -0
- package/lib/typescript/commonjs/level-picker/LevelPicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/level-picker/LevelPicker.web.d.ts +6 -0
- package/lib/typescript/commonjs/level-picker/LevelPicker.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/level-picker/constants.d.ts +93 -0
- package/lib/typescript/commonjs/level-picker/constants.d.ts.map +1 -0
- package/lib/typescript/commonjs/level-picker/index.d.ts +3 -0
- package/lib/typescript/commonjs/level-picker/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/level-picker/index.web.d.ts +3 -0
- package/lib/typescript/commonjs/level-picker/index.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/level-picker/types.d.ts +63 -0
- package/lib/typescript/commonjs/level-picker/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts +11 -0
- package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/MediaSurface.d.ts +106 -0
- package/lib/typescript/commonjs/media-flight/MediaSurface.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/constants.d.ts +18 -0
- package/lib/typescript/commonjs/media-flight/constants.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/expo-video-module.d.ts +103 -0
- package/lib/typescript/commonjs/media-flight/expo-video-module.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/index.d.ts +9 -0
- package/lib/typescript/commonjs/media-flight/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/store.d.ts +132 -0
- package/lib/typescript/commonjs/media-flight/store.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/types.d.ts +195 -0
- package/lib/typescript/commonjs/media-flight/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/media-flight/use-media-flight.d.ts +4 -0
- package/lib/typescript/commonjs/media-flight/use-media-flight.d.ts.map +1 -0
- package/lib/typescript/commonjs/zoomable-media-gallery/ZoomableMediaGallery.d.ts +5 -0
- package/lib/typescript/commonjs/zoomable-media-gallery/ZoomableMediaGallery.d.ts.map +1 -0
- package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts.map +1 -1
- package/lib/typescript/commonjs/zoomable-media-gallery/index.d.ts +4 -0
- package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/zoomable-media-gallery/types.d.ts +90 -0
- package/lib/typescript/commonjs/zoomable-media-gallery/types.d.ts.map +1 -0
- package/lib/typescript/module/floating/index.d.ts +5 -0
- package/lib/typescript/module/floating/index.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +2 -0
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/level-picker/LevelPicker.d.ts +6 -0
- package/lib/typescript/module/level-picker/LevelPicker.d.ts.map +1 -0
- package/lib/typescript/module/level-picker/LevelPicker.web.d.ts +6 -0
- package/lib/typescript/module/level-picker/LevelPicker.web.d.ts.map +1 -0
- package/lib/typescript/module/level-picker/constants.d.ts +93 -0
- package/lib/typescript/module/level-picker/constants.d.ts.map +1 -0
- package/lib/typescript/module/level-picker/index.d.ts +3 -0
- package/lib/typescript/module/level-picker/index.d.ts.map +1 -0
- package/lib/typescript/module/level-picker/index.web.d.ts +3 -0
- package/lib/typescript/module/level-picker/index.web.d.ts.map +1 -0
- package/lib/typescript/module/level-picker/types.d.ts +63 -0
- package/lib/typescript/module/level-picker/types.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts +11 -0
- package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/MediaSurface.d.ts +106 -0
- package/lib/typescript/module/media-flight/MediaSurface.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/constants.d.ts +18 -0
- package/lib/typescript/module/media-flight/constants.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/expo-video-module.d.ts +103 -0
- package/lib/typescript/module/media-flight/expo-video-module.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/index.d.ts +9 -0
- package/lib/typescript/module/media-flight/index.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/store.d.ts +132 -0
- package/lib/typescript/module/media-flight/store.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/types.d.ts +195 -0
- package/lib/typescript/module/media-flight/types.d.ts.map +1 -0
- package/lib/typescript/module/media-flight/use-media-flight.d.ts +4 -0
- package/lib/typescript/module/media-flight/use-media-flight.d.ts.map +1 -0
- package/lib/typescript/module/zoomable-media-gallery/ZoomableMediaGallery.d.ts +5 -0
- package/lib/typescript/module/zoomable-media-gallery/ZoomableMediaGallery.d.ts.map +1 -0
- package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts.map +1 -1
- package/lib/typescript/module/zoomable-media-gallery/index.d.ts +4 -0
- package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/index.d.ts.map +1 -1
- package/lib/typescript/module/zoomable-media-gallery/types.d.ts +90 -0
- package/lib/typescript/module/zoomable-media-gallery/types.d.ts.map +1 -0
- package/package.json +61 -8
- package/src/floating/index.ts +5 -0
- package/src/image-aspect-ratio-cache/aspect-ratio-cache.ts +1 -1
- package/src/index.ts +4 -1
- package/src/index.web.ts +4 -1
- package/src/level-picker/LevelPicker.tsx +365 -0
- package/src/level-picker/LevelPicker.web.tsx +374 -0
- package/src/level-picker/constants.ts +131 -0
- package/src/level-picker/index.ts +2 -0
- package/src/level-picker/index.web.ts +2 -0
- package/src/level-picker/types.ts +63 -0
- package/src/media-flight/MediaFlightLayer.tsx +144 -0
- package/src/media-flight/MediaSurface.tsx +233 -0
- package/src/media-flight/constants.ts +32 -0
- package/src/media-flight/expo-video-module.ts +181 -0
- package/src/media-flight/index.ts +33 -0
- package/src/media-flight/store.ts +497 -0
- package/src/media-flight/types.ts +210 -0
- package/src/media-flight/use-media-flight.ts +42 -0
- package/src/tab-bar/TabBarBase.tsx +1 -1
- package/src/{zoomable-image-gallery/ZoomableImageGallery.tsx → zoomable-media-gallery/ZoomableMediaGallery.tsx} +192 -117
- package/src/zoomable-media-gallery/index.ts +11 -0
- package/src/zoomable-media-gallery/types.ts +100 -0
- package/docs/zoomable-image-gallery.mdx +0 -66
- package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js.map +0 -1
- package/lib/commonjs/zoomable-image-gallery/types.js +0 -2
- package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js.map +0 -1
- package/lib/module/zoomable-image-gallery/index.js +0 -5
- package/lib/module/zoomable-image-gallery/index.js.map +0 -1
- package/lib/module/zoomable-image-gallery/types.js +0 -2
- package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts +0 -5
- package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +0 -1
- package/lib/typescript/commonjs/zoomable-image-gallery/index.d.ts +0 -4
- package/lib/typescript/commonjs/zoomable-image-gallery/types.d.ts +0 -56
- package/lib/typescript/commonjs/zoomable-image-gallery/types.d.ts.map +0 -1
- package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts +0 -5
- package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +0 -1
- package/lib/typescript/module/zoomable-image-gallery/index.d.ts +0 -4
- package/lib/typescript/module/zoomable-image-gallery/types.d.ts +0 -56
- package/lib/typescript/module/zoomable-image-gallery/types.d.ts.map +0 -1
- package/src/zoomable-image-gallery/index.ts +0 -9
- package/src/zoomable-image-gallery/types.ts +0 -59
- /package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.js +0 -0
- /package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.js +0 -0
- /package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts +0 -0
- /package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts +0 -0
- /package/src/{zoomable-image-gallery → zoomable-media-gallery}/constants.ts +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The layer that survives navigation.
|
|
5
|
+
*
|
|
6
|
+
* ## The problem it exists for
|
|
7
|
+
*
|
|
8
|
+
* A shared-element transition normally assumes the ORIGIN screen is still
|
|
9
|
+
* mounted while the element travels — which is why `react-native-teleport` needs
|
|
10
|
+
* `presentation: 'transparentModal'` and has no web story at all. Under
|
|
11
|
+
* expo-router on web the origin route is UNMOUNTED the moment the URL changes,
|
|
12
|
+
* so anything the origin was rendering (a `VideoView`, a decoded image) is gone
|
|
13
|
+
* before the first frame of the transition.
|
|
14
|
+
*
|
|
15
|
+
* The fix is to move the surface OUT of both screens for the duration of the
|
|
16
|
+
* flight. `<MediaFlightLayer>` is mounted ONCE at the app root and renders
|
|
17
|
+
* through Bloom's `Portal`, whose outlet lives above the router on both
|
|
18
|
+
* platforms — so the surface it paints belongs to neither route and neither
|
|
19
|
+
* route can take it down. Origin and destination only DECLARE where they want
|
|
20
|
+
* it (`registerAnchor` + `flyTo`); the layer is what actually paints it.
|
|
21
|
+
*
|
|
22
|
+
* ## One surface per id
|
|
23
|
+
*
|
|
24
|
+
* That is the contract, and for video it is the whole feature. expo-video keeps
|
|
25
|
+
* the `VideoPlayer` OBJECT separate from the `VideoView` that shows it, and one
|
|
26
|
+
* player may feed several views — so moving a video is a matter of mounting ONE
|
|
27
|
+
* view in the right place, never of creating a second player. A second surface
|
|
28
|
+
* for the same id would mean two views mounted over one another and a visible
|
|
29
|
+
* swap; the store enforces one by RETARGETING an existing flight rather than
|
|
30
|
+
* adding to it.
|
|
31
|
+
*
|
|
32
|
+
* ## It never takes a click
|
|
33
|
+
*
|
|
34
|
+
* Every node here is `pointerEvents="none"` (or `box-none` on the root, via
|
|
35
|
+
* `OverlayRoot`). A flying surface is a picture of something the app is already
|
|
36
|
+
* showing: the controls underneath it stay the ones the user is pressing, and a
|
|
37
|
+
* layer mounted for the whole life of the app that swallowed presses would be
|
|
38
|
+
* indistinguishable from a frozen UI.
|
|
39
|
+
*/
|
|
40
|
+
import { useEffect, useSyncExternalStore } from 'react';
|
|
41
|
+
import { StyleSheet } from 'react-native';
|
|
42
|
+
import { interpolate, useAnimatedStyle } from 'react-native-reanimated';
|
|
43
|
+
import { OverlayRoot } from "../overlay/index.js";
|
|
44
|
+
import { Portal } from '../portal';
|
|
45
|
+
import { MediaSurface } from "./MediaSurface.js";
|
|
46
|
+
import { getFlights, notifySurfaceMounted, subscribeToFlights } from "./store.js";
|
|
47
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
48
|
+
/**
|
|
49
|
+
* Mount ONCE, at the app root, above the router. Renders nothing at all until a
|
|
50
|
+
* flight is live, so it costs a subscription and no view while idle — and takes
|
|
51
|
+
* an overlay rank only while it is actually painting, which is what keeps the
|
|
52
|
+
* overlay stack's counter able to reset (see `overlay/stack.ts`).
|
|
53
|
+
*/
|
|
54
|
+
export function MediaFlightLayer() {
|
|
55
|
+
const flights = useSyncExternalStore(subscribeToFlights, getFlights, getFlights);
|
|
56
|
+
if (flights.length === 0) return null;
|
|
57
|
+
return /*#__PURE__*/_jsx(Portal, {
|
|
58
|
+
children: /*#__PURE__*/_jsx(OverlayRoot, {
|
|
59
|
+
children: flights.map(flight => /*#__PURE__*/_jsx(MediaFlightSurface, {
|
|
60
|
+
flight: flight
|
|
61
|
+
}, flight.id))
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
MediaFlightLayer.displayName = 'MediaFlightLayer';
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* One flying surface.
|
|
69
|
+
*
|
|
70
|
+
* ## Why the size is animated rather than scaled
|
|
71
|
+
*
|
|
72
|
+
* The media gallery flies its images with a uniform `scale`, which is right
|
|
73
|
+
* there: it opens from a thumbnail into a box of the SAME aspect ratio, so one
|
|
74
|
+
* factor describes the whole move. A flight does not have that luxury — it
|
|
75
|
+
* routinely goes from a cropped square tile to a 16:9 player — and a uniform
|
|
76
|
+
* scale would leave the first frame the wrong height, i.e. visibly not the
|
|
77
|
+
* thumbnail it is supposed to be replacing. Interpolating `width`/`height` is
|
|
78
|
+
* exact at both ends; the position still rides a transform, so the only layout
|
|
79
|
+
* work per frame is one absolutely-positioned node resizing.
|
|
80
|
+
*/
|
|
81
|
+
function MediaFlightSurface({
|
|
82
|
+
flight
|
|
83
|
+
}) {
|
|
84
|
+
const {
|
|
85
|
+
id,
|
|
86
|
+
from,
|
|
87
|
+
to,
|
|
88
|
+
progress,
|
|
89
|
+
content,
|
|
90
|
+
cornerRadius,
|
|
91
|
+
contentFit,
|
|
92
|
+
surfaceType
|
|
93
|
+
} = flight;
|
|
94
|
+
|
|
95
|
+
// The COMMIT signal `flyTo`'s promise waits on, and the reason it is an effect
|
|
96
|
+
// rather than anything derived: what the caller needs to know is that React
|
|
97
|
+
// has actually put this surface in the tree, and an effect is the only thing
|
|
98
|
+
// in React that means exactly that. On web it is also the moment the
|
|
99
|
+
// `<video>` element joined expo-video's mounted set — which is what carries
|
|
100
|
+
// `currentTime` across from the origin, and what stops working the instant
|
|
101
|
+
// the caller navigates first.
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
notifySurfaceMounted(id);
|
|
104
|
+
}, [id]);
|
|
105
|
+
|
|
106
|
+
// Deltas rather than absolute rects, so the worklet closes over four numbers.
|
|
107
|
+
const originX = from.x - to.x;
|
|
108
|
+
const originY = from.y - to.y;
|
|
109
|
+
|
|
110
|
+
// CRITICAL — every shared value a mapper READS must be listed in its deps.
|
|
111
|
+
// On web WITHOUT the react-native-worklets babel plugin, reanimated cannot
|
|
112
|
+
// auto-detect the reads and drives the mapper off the deps array instead:
|
|
113
|
+
// with none, it runs ONCE and freezes at the opening frame while `progress`
|
|
114
|
+
// animates underneath it. Same rule as `ZoomableMediaGallery` and
|
|
115
|
+
// `BottomSheetBase`. Do NOT strip these.
|
|
116
|
+
const boxStyle = useAnimatedStyle(() => ({
|
|
117
|
+
transform: [{
|
|
118
|
+
translateX: interpolate(progress.value, [0, 1], [originX, 0])
|
|
119
|
+
}, {
|
|
120
|
+
translateY: interpolate(progress.value, [0, 1], [originY, 0])
|
|
121
|
+
}],
|
|
122
|
+
width: interpolate(progress.value, [0, 1], [from.width, to.width]),
|
|
123
|
+
height: interpolate(progress.value, [0, 1], [from.height, to.height])
|
|
124
|
+
}), [progress, originX, originY, from.width, from.height, to.width, to.height]);
|
|
125
|
+
return /*#__PURE__*/_jsx(MediaSurface, {
|
|
126
|
+
content: content,
|
|
127
|
+
contentFit: contentFit,
|
|
128
|
+
surfaceType: surfaceType
|
|
129
|
+
// A flying surface is a picture, never a control: it must not intercept
|
|
130
|
+
// the press that is already travelling to whatever is underneath it.
|
|
131
|
+
,
|
|
132
|
+
pointerEvents: "none",
|
|
133
|
+
style: [styles.box, {
|
|
134
|
+
left: to.x,
|
|
135
|
+
top: to.y,
|
|
136
|
+
borderRadius: cornerRadius
|
|
137
|
+
}, boxStyle]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const styles = StyleSheet.create({
|
|
141
|
+
box: {
|
|
142
|
+
position: 'absolute',
|
|
143
|
+
overflow: 'hidden'
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=MediaFlightLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useSyncExternalStore","StyleSheet","interpolate","useAnimatedStyle","OverlayRoot","Portal","MediaSurface","getFlights","notifySurfaceMounted","subscribeToFlights","jsx","_jsx","MediaFlightLayer","flights","length","children","map","flight","MediaFlightSurface","id","displayName","from","to","progress","content","cornerRadius","contentFit","surfaceType","originX","x","originY","y","boxStyle","transform","translateX","value","translateY","width","height","pointerEvents","style","styles","box","left","top","borderRadius","create","position","overflow"],"sourceRoot":"../../../src","sources":["media-flight/MediaFlightLayer.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ONE renderer for "an image or a video, painted into a box".
|
|
5
|
+
*
|
|
6
|
+
* Both the flight layer and the media gallery need exactly this, and they need
|
|
7
|
+
* it to be the same code: a flight that lands inside the gallery hands its
|
|
8
|
+
* surface over frame-for-frame, so two renderers that disagree by a pixel of
|
|
9
|
+
* `contentFit` or a corner radius show the swap.
|
|
10
|
+
*
|
|
11
|
+
* BOTH ARMS RENDER THE SAME BOX — an `Animated.View` with the media filling it —
|
|
12
|
+
* rather than the image arm rendering an animated `Image` directly. That is the
|
|
13
|
+
* property that makes an image and a video interchangeable at a call site: the
|
|
14
|
+
* caller's style means the same thing either way, the corner radius clips a
|
|
15
|
+
* platform video surface the way it rounds an image, and the transform lands on
|
|
16
|
+
* a node reanimated is allowed to drive (expo-video's own host is not one).
|
|
17
|
+
*/
|
|
18
|
+
import { memo, useCallback, useState } from 'react';
|
|
19
|
+
import { Platform, StyleSheet, View } from 'react-native';
|
|
20
|
+
import { Image } from 'expo-image';
|
|
21
|
+
import Animated from 'react-native-reanimated';
|
|
22
|
+
import { handOffFlight } from "./store.js";
|
|
23
|
+
import { loadExpoVideo, warnExpoVideoUnavailable } from "./expo-video-module.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Exactly what `Animated.View` accepts, taken from the component rather than
|
|
27
|
+
* restated: a caller hands this component the output of `useAnimatedStyle` and a
|
|
28
|
+
* hand-written `StyleProp<ViewStyle>` would reject it.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The style a STILL accepts. The intersection is what lets one value reach both
|
|
33
|
+
* an `Image` and a `View`: `ViewStyle` and `ImageStyle` disagree on exactly one
|
|
34
|
+
* key (`overflow`, which `ViewStyle` also allows to be `'scroll'`), and the
|
|
35
|
+
* intersection narrows it to the two values both accept.
|
|
36
|
+
*/
|
|
37
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
38
|
+
// Web-only: a media surface is never a drag source. Written as an inline
|
|
39
|
+
// conditional SPREAD rather than a `Platform.select` returning `undefined` —
|
|
40
|
+
// spreading a `T | undefined` into JSX crashes tsc 5.9 outright
|
|
41
|
+
// (`getIntersectionTypeFacts: type.types is not iterable`), and the gallery
|
|
42
|
+
// already wrote it this way for the same reason.
|
|
43
|
+
const webDraggableProps = Platform.OS === 'web' ? {
|
|
44
|
+
draggable: false
|
|
45
|
+
} : {};
|
|
46
|
+
/**
|
|
47
|
+
* A still image, or a video fed by a player the CONSUMER owns.
|
|
48
|
+
*
|
|
49
|
+
* The video arm mounts a `VideoView` around the caller's `player`. Bloom never
|
|
50
|
+
* creates, replaces or releases that player — handing one player to a new view
|
|
51
|
+
* is what moves a playing video between surfaces without restarting it, and it
|
|
52
|
+
* is the reason this component takes a player object rather than a source URL.
|
|
53
|
+
*/
|
|
54
|
+
export const MediaSurface = /*#__PURE__*/memo(function MediaSurface({
|
|
55
|
+
content,
|
|
56
|
+
style,
|
|
57
|
+
contentFit = 'contain',
|
|
58
|
+
surfaceType = 'textureView',
|
|
59
|
+
nativeControls = false,
|
|
60
|
+
accessibilityLabel,
|
|
61
|
+
pointerEvents,
|
|
62
|
+
flightId
|
|
63
|
+
}) {
|
|
64
|
+
// Captured once — see `surfaceType` above. A consumer changing it later gets
|
|
65
|
+
// the value the view was mounted with, which is the only value expo-video
|
|
66
|
+
// supports.
|
|
67
|
+
const [mountedSurfaceType] = useState(surfaceType);
|
|
68
|
+
|
|
69
|
+
// Both arms report the same fact — "there is a picture here now" — because the
|
|
70
|
+
// destination of a flight can be either, and a caller should not have to know
|
|
71
|
+
// which one it wired. expo-video raises `onFirstFrameRender` from `loadeddata`
|
|
72
|
+
// on web; expo-image raises `onLoad` once the source is decoded and displayed.
|
|
73
|
+
const reportLive = useCallback(() => {
|
|
74
|
+
if (flightId !== undefined) handOffFlight(flightId);
|
|
75
|
+
}, [flightId]);
|
|
76
|
+
const still = content.kind === 'video' ? content.poster : content.uri;
|
|
77
|
+
// Loaded for the video arm only, and only when there is one — an image
|
|
78
|
+
// surface must never make an app resolve an optional native peer.
|
|
79
|
+
const expoVideo = content.kind === 'video' ? loadExpoVideo() : null;
|
|
80
|
+
if (content.kind === 'video' && expoVideo === null) {
|
|
81
|
+
// Degrade to the poster rather than to nothing: a black hole where a video
|
|
82
|
+
// should be reads as a broken app, a still frame reads as a video that has
|
|
83
|
+
// not started. The warning is what makes the difference visible to the
|
|
84
|
+
// developer, once, in dev.
|
|
85
|
+
warnExpoVideoUnavailable();
|
|
86
|
+
}
|
|
87
|
+
return /*#__PURE__*/_jsxs(Animated.View, {
|
|
88
|
+
style: [styles.box, style],
|
|
89
|
+
pointerEvents: pointerEvents,
|
|
90
|
+
children: [still === undefined ? null :
|
|
91
|
+
/*#__PURE__*/
|
|
92
|
+
// Behind the video (and the whole picture on the image arm), so the box
|
|
93
|
+
// is never empty while a first frame decodes and a flight that starts
|
|
94
|
+
// before playback still carries a picture. This is also why a flight
|
|
95
|
+
// never has to wait for a decode: an unpainted `<video>` sets no
|
|
96
|
+
// `poster` attribute and an Android TextureView runs with the ExoPlayer
|
|
97
|
+
// shutter off, so neither draws anything opaque over this.
|
|
98
|
+
_jsx(Image, {
|
|
99
|
+
source: {
|
|
100
|
+
uri: still
|
|
101
|
+
},
|
|
102
|
+
contentFit: contentFit,
|
|
103
|
+
style: StyleSheet.absoluteFill,
|
|
104
|
+
transition: 0,
|
|
105
|
+
accessibilityLabel: accessibilityLabel
|
|
106
|
+
// Only the arm that IS the picture reports being live. On the video
|
|
107
|
+
// arm the poster is scenery: handing off on it would release the
|
|
108
|
+
// flying surface while the destination still had no video.
|
|
109
|
+
,
|
|
110
|
+
onLoad: content.kind === 'video' ? undefined : reportLive,
|
|
111
|
+
...webDraggableProps
|
|
112
|
+
}), content.kind === 'video' && expoVideo !== null ? /*#__PURE__*/_jsx(expoVideo.VideoView, {
|
|
113
|
+
player: content.player,
|
|
114
|
+
contentFit: contentFit,
|
|
115
|
+
surfaceType: mountedSurfaceType,
|
|
116
|
+
nativeControls: nativeControls,
|
|
117
|
+
style: StyleSheet.absoluteFill,
|
|
118
|
+
accessibilityLabel: accessibilityLabel,
|
|
119
|
+
onFirstFrameRender: reportLive
|
|
120
|
+
}) : null]
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
MediaSurface.displayName = 'MediaSurface';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The STILL of a media item — a video's poster, or the image itself — and never
|
|
127
|
+
* a video view.
|
|
128
|
+
*
|
|
129
|
+
* This is what every surface that is not the live one renders: an off-screen
|
|
130
|
+
* gallery page, a thumbnail-strip tile, an origin placeholder while its media is
|
|
131
|
+
* in flight. Mounting a `MediaSurface` there instead would put a second
|
|
132
|
+
* `VideoView` on the same player, which is precisely what the "one live surface
|
|
133
|
+
* per id" contract forbids — and on a thumbnail strip it would mean one decoder
|
|
134
|
+
* per tile.
|
|
135
|
+
*/
|
|
136
|
+
export function MediaPoster({
|
|
137
|
+
content,
|
|
138
|
+
style,
|
|
139
|
+
contentFit = 'cover',
|
|
140
|
+
accessibilityLabel
|
|
141
|
+
}) {
|
|
142
|
+
const uri = content.kind === 'video' ? content.poster : content.uri;
|
|
143
|
+
if (uri === undefined) return /*#__PURE__*/_jsx(EmptyMediaSurface, {
|
|
144
|
+
style: style
|
|
145
|
+
});
|
|
146
|
+
return /*#__PURE__*/_jsx(Image, {
|
|
147
|
+
source: {
|
|
148
|
+
uri
|
|
149
|
+
},
|
|
150
|
+
contentFit: contentFit,
|
|
151
|
+
style: style,
|
|
152
|
+
transition: 0,
|
|
153
|
+
accessibilityLabel: accessibilityLabel,
|
|
154
|
+
...webDraggableProps
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* A box with no media at all — what a gallery page renders for a video item
|
|
160
|
+
* whose poster is unknown, so the layout never collapses.
|
|
161
|
+
*/
|
|
162
|
+
export function EmptyMediaSurface({
|
|
163
|
+
style
|
|
164
|
+
}) {
|
|
165
|
+
return /*#__PURE__*/_jsx(View, {
|
|
166
|
+
style: [styles.empty, style],
|
|
167
|
+
pointerEvents: "none"
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const styles = StyleSheet.create({
|
|
171
|
+
box: {
|
|
172
|
+
// What makes the box's corner radius actually clip a video, and the other
|
|
173
|
+
// half of why the Android surface has to be a `textureView`.
|
|
174
|
+
overflow: 'hidden'
|
|
175
|
+
},
|
|
176
|
+
empty: {
|
|
177
|
+
backgroundColor: 'rgba(255,255,255,0.08)'
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=MediaSurface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["memo","useCallback","useState","Platform","StyleSheet","View","Image","Animated","handOffFlight","loadExpoVideo","warnExpoVideoUnavailable","jsx","_jsx","jsxs","_jsxs","webDraggableProps","OS","draggable","MediaSurface","content","style","contentFit","surfaceType","nativeControls","accessibilityLabel","pointerEvents","flightId","mountedSurfaceType","reportLive","undefined","still","kind","poster","uri","expoVideo","styles","box","children","source","absoluteFill","transition","onLoad","VideoView","player","onFirstFrameRender","displayName","MediaPoster","EmptyMediaSurface","empty","create","overflow","backgroundColor"],"sourceRoot":"../../../src","sources":["media-flight/MediaSurface.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* How long `flyTo` will wait for `<MediaFlightLayer>` to commit the surface
|
|
5
|
+
* before letting the caller carry on regardless (ms).
|
|
6
|
+
*
|
|
7
|
+
* The wait is a COMMIT, not a network round-trip: the surface only has to be
|
|
8
|
+
* mounted, because that is what puts it in expo-video's `_mountedVideos` set
|
|
9
|
+
* while the origin is still there — which is the whole mechanism that carries
|
|
10
|
+
* `currentTime` across. One React commit is a frame or two. Painting is a
|
|
11
|
+
* separate, slower thing that the poster covers (see `MediaSurface`), so it is
|
|
12
|
+
* deliberately NOT waited on here: blocking a tap on a decode would trade a
|
|
13
|
+
* problem nobody can see for one everybody can feel.
|
|
14
|
+
*
|
|
15
|
+
* The timeout exists for the case where no layer is mounted at all. Without it
|
|
16
|
+
* the promise never settles and the consumer never navigates — an app that
|
|
17
|
+
* forgot one line at its root would appear to have a dead feed.
|
|
18
|
+
*/
|
|
19
|
+
export const SURFACE_MOUNT_TIMEOUT_MS = 250;
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* There is deliberately NO hand-off timeout.
|
|
23
|
+
*
|
|
24
|
+
* The obvious one — release the flying surface after N seconds if no destination
|
|
25
|
+
* ever claims it — would have to be wrong in one direction or the other, because
|
|
26
|
+
* the layer cannot tell "the destination failed" from "the caller meant the
|
|
27
|
+
* layer to keep painting this". And the failure it would guard against is not
|
|
28
|
+
* actually bad: a destination that never loads leaves the flying surface
|
|
29
|
+
* showing the video, playing, at exactly the rect the destination wanted, over a
|
|
30
|
+
* destination showing its poster. Going back calls `flyBack`, which releases it.
|
|
31
|
+
*
|
|
32
|
+
* `flyBack(id)` and `releaseFlight(id)` are the escape hatches, and they are
|
|
33
|
+
* the caller's to use.
|
|
34
|
+
*/
|
|
35
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["SURFACE_MOUNT_TIMEOUT_MS"],"sourceRoot":"../../../src","sources":["media-flight/constants.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,wBAAwB,GAAG,GAAG;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","ignoreList":[]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The optional-peer boundary for `expo-video`.
|
|
5
|
+
*
|
|
6
|
+
* Bloom ships no native code and never will, so `expo-video` cannot be a hard
|
|
7
|
+
* dependency: an app that renders no video must not be made to install a native
|
|
8
|
+
* module. It is therefore an OPTIONAL peer, and a static `import` contradicts
|
|
9
|
+
* that — Metro resolves every static import in the eager graph, so an omitted
|
|
10
|
+
* "optional" peer does not degrade, it aborts the whole bundle with `Unable to
|
|
11
|
+
* resolve module expo-video`, naming a package the app never mentions.
|
|
12
|
+
*
|
|
13
|
+
* The load has to be dynamic in the ONE shape Metro understands: a `require()`
|
|
14
|
+
* of a STRING LITERAL as a DIRECT STATEMENT of a `try` block, which Metro
|
|
15
|
+
* collects as an optional dependency (resolving the real module when installed,
|
|
16
|
+
* writing `null` into the dependency map when it is not, so the failure lands in
|
|
17
|
+
* the `catch` below at evaluation time instead of at build time). One `if` of
|
|
18
|
+
* nesting loses that — `isOptionalDependency` returns at the FIRST BlockStatement
|
|
19
|
+
* it meets — hence the `typeof require` guard sits OUTSIDE the try.
|
|
20
|
+
*
|
|
21
|
+
* `require` may also not exist at all (this file backs the `import` condition
|
|
22
|
+
* too, i.e. an ESM build under Node), hence that guard.
|
|
23
|
+
*
|
|
24
|
+
* A missing video module is invisible — a poster where a video should be looks
|
|
25
|
+
* exactly like a video that has not started — so {@link warnExpoVideoUnavailable}
|
|
26
|
+
* names the package once, in dev.
|
|
27
|
+
*
|
|
28
|
+
* @see connection-status/netinfo.ts — the same boundary for netinfo.
|
|
29
|
+
* @see hooks/haptics-module.ts — the same boundary for expo-haptics.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Declared locally rather than taken from the ambient `NodeRequire`, which
|
|
34
|
+
* returns `any`: `unknown` forces the module handle to be narrowed below instead
|
|
35
|
+
* of leaking an untyped value into the caller.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The slice of `expo-video`'s `VideoPlayer` Bloom depends on.
|
|
40
|
+
*
|
|
41
|
+
* Hand-written rather than `typeof import('expo-video')` so no expo-video type
|
|
42
|
+
* reaches Bloom's emitted declarations — a consumer that skips the optional peer
|
|
43
|
+
* must not inherit a TS7016 from Bloom's own `.d.ts`. The two are kept in step by
|
|
44
|
+
* the assignability check in `__tests__/MediaFlight.test.tsx`, which is excluded
|
|
45
|
+
* from the build and so may name the real package.
|
|
46
|
+
*
|
|
47
|
+
* Bloom never CALLS any of this. **The consumer creates the player, owns it and
|
|
48
|
+
* destroys it**; Bloom only hands the object back to a `VideoView`, which is the
|
|
49
|
+
* whole mechanism that lets a video move between surfaces without restarting
|
|
50
|
+
* (expo-video's own docs: "when the same player is playing in multiple video
|
|
51
|
+
* views"). The three members below exist so the type is not `object` — a
|
|
52
|
+
* structural minimum the real `VideoPlayer` satisfies, and that an arbitrary
|
|
53
|
+
* object does not.
|
|
54
|
+
*
|
|
55
|
+
* `play`/`pause` are declared in METHOD syntax deliberately: `strictFunctionTypes`
|
|
56
|
+
* exempts method parameters from contravariance, which keeps a real
|
|
57
|
+
* `VideoPlayer` assignable here across `@types/react` copies.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/** How a video is scaled inside its box. Mirrors expo-video's `VideoContentFit`. */
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Android's rendering surface for a video view.
|
|
64
|
+
*
|
|
65
|
+
* `textureView` is what Bloom asks for everywhere, because a `SurfaceView` is
|
|
66
|
+
* composited by the system OUTSIDE the app's view hierarchy: it ignores the
|
|
67
|
+
* parent's clip, corner radius and transform, so a video flying between two
|
|
68
|
+
* rects would paint as an un-rounded rectangle at the wrong place. It also
|
|
69
|
+
* cannot be changed at runtime (expo-video: "This prop should not be changed at
|
|
70
|
+
* runtime"), which is why {@link MediaSurfaceProps.surfaceType} is captured on
|
|
71
|
+
* first render.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/** The slice of `VideoViewProps` Bloom passes. */
|
|
75
|
+
|
|
76
|
+
/** The slice of expo-video's module surface Bloom renders. */
|
|
77
|
+
|
|
78
|
+
/** `undefined` until the first load attempt, then the module or `null`. */
|
|
79
|
+
let videoModule;
|
|
80
|
+
/** Why the load failed, quoted verbatim in the dev warning. */
|
|
81
|
+
let unavailableReason = '';
|
|
82
|
+
let hasWarned = false;
|
|
83
|
+
|
|
84
|
+
/** The expo-video module, or `null` when the optional peer is not installed. */
|
|
85
|
+
export function loadExpoVideo() {
|
|
86
|
+
if (videoModule !== undefined) return videoModule;
|
|
87
|
+
videoModule = null;
|
|
88
|
+
|
|
89
|
+
// The `typeof require` guard sits OUTSIDE the try on purpose — see the header.
|
|
90
|
+
// Nested one `if`/`else` deeper, the require below is no longer a direct
|
|
91
|
+
// statement of the try block, Metro stops marking it optional, and an app
|
|
92
|
+
// without expo-video fails to BUILD instead of losing the video surface.
|
|
93
|
+
if (typeof require === 'undefined') {
|
|
94
|
+
unavailableReason = 'this bundle has no CommonJS `require`';
|
|
95
|
+
return videoModule;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const loaded = require('expo-video');
|
|
99
|
+
// `VideoView` is a class component upstream, so `typeof` is `'function'`
|
|
100
|
+
// either way; a memo/forwardRef build would be an object carrying
|
|
101
|
+
// `$$typeof`. Both are accepted, nothing else is.
|
|
102
|
+
const resolved = isComponentBearing(loaded) ? loaded : loaded?.default;
|
|
103
|
+
if (isComponentBearing(resolved)) {
|
|
104
|
+
videoModule = {
|
|
105
|
+
VideoView: resolved.VideoView
|
|
106
|
+
};
|
|
107
|
+
} else {
|
|
108
|
+
unavailableReason = 'the module resolved without a `VideoView` export';
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
unavailableReason = error instanceof Error ? error.message : String(error);
|
|
112
|
+
}
|
|
113
|
+
return videoModule;
|
|
114
|
+
}
|
|
115
|
+
function isComponentBearing(candidate) {
|
|
116
|
+
const view = candidate?.VideoView;
|
|
117
|
+
if (typeof view === 'function') return true;
|
|
118
|
+
return typeof view === 'object' && view !== null && '$$typeof' in view;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* One warning per module lifetime, and none in production — the same mechanism
|
|
123
|
+
* as `connection-status/netinfo.ts` and `hooks/haptics-module.ts`. Metro and
|
|
124
|
+
* Vite/Rolldown both fold the `NODE_ENV` check statically, so a production
|
|
125
|
+
* bundle keeps neither the branch nor the message.
|
|
126
|
+
*/
|
|
127
|
+
export function warnExpoVideoUnavailable() {
|
|
128
|
+
if (process.env.NODE_ENV === 'production' || hasWarned) return;
|
|
129
|
+
hasWarned = true;
|
|
130
|
+
// Internal Bloom diagnostic: only the consumer's package.json can fix this,
|
|
131
|
+
// so it names the package, the install command and what is lost.
|
|
132
|
+
// eslint-disable-next-line no-console
|
|
133
|
+
console.warn('[Bloom] A video media surface fell back to its poster: the optional peer ' + '`expo-video` could not be loaded, so no video is rendered and the shared ' + 'media transition carries a still frame instead. Install it ' + '(`npx expo install expo-video`) or pass image content only. ' + `Reason: ${unavailableReason}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Test seam — drops the cached module handle so a suite can load it again. */
|
|
137
|
+
export function resetExpoVideoModule() {
|
|
138
|
+
videoModule = undefined;
|
|
139
|
+
unavailableReason = '';
|
|
140
|
+
hasWarned = false;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=expo-video-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["videoModule","unavailableReason","hasWarned","loadExpoVideo","undefined","require","loaded","resolved","isComponentBearing","default","VideoView","error","Error","message","String","candidate","view","warnExpoVideoUnavailable","process","env","NODE_ENV","console","warn","resetExpoVideoModule"],"sourceRoot":"../../../src","sources":["media-flight/expo-video-module.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAOA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;;AAkBA;;AAKA;AACA,IAAIA,WAA6C;AACjD;AACA,IAAIC,iBAAiB,GAAG,EAAE;AAC1B,IAAIC,SAAS,GAAG,KAAK;;AAErB;AACA,OAAO,SAASC,aAAaA,CAAA,EAAyB;EACpD,IAAIH,WAAW,KAAKI,SAAS,EAAE,OAAOJ,WAAW;EACjDA,WAAW,GAAG,IAAI;;EAElB;EACA;EACA;EACA;EACA,IAAI,OAAOK,OAAO,KAAK,WAAW,EAAE;IAClCJ,iBAAiB,GAAG,uCAAuC;IAC3D,OAAOD,WAAW;EACpB;EAEA,IAAI;IACF,MAAMM,MAAM,GAAGD,OAAO,CAAC,YAAY,CAGtB;IACb;IACA;IACA;IACA,MAAME,QAAQ,GAAGC,kBAAkB,CAACF,MAAM,CAAC,GAAGA,MAAM,GAAGA,MAAM,EAAEG,OAAO;IAEtE,IAAID,kBAAkB,CAACD,QAAQ,CAAC,EAAE;MAChCP,WAAW,GAAG;QAAEU,SAAS,EAAEH,QAAQ,CAACG;MAA+C,CAAC;IACtF,CAAC,MAAM;MACLT,iBAAiB,GAAG,kDAAkD;IACxE;EACF,CAAC,CAAC,OAAOU,KAAK,EAAE;IACdV,iBAAiB,GAAGU,KAAK,YAAYC,KAAK,GAAGD,KAAK,CAACE,OAAO,GAAGC,MAAM,CAACH,KAAK,CAAC;EAC5E;EAEA,OAAOX,WAAW;AACpB;AAEA,SAASQ,kBAAkBA,CACzBO,SAA8E,EACU;EACxF,MAAMC,IAAI,GAAGD,SAAS,EAAEL,SAAS;EACjC,IAAI,OAAOM,IAAI,KAAK,UAAU,EAAE,OAAO,IAAI;EAC3C,OAAO,OAAOA,IAAI,KAAK,QAAQ,IAAIA,IAAI,KAAK,IAAI,IAAI,UAAU,IAAIA,IAAI;AACxE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,wBAAwBA,CAAA,EAAS;EAC/C,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,IAAIlB,SAAS,EAAE;EACxDA,SAAS,GAAG,IAAI;EAChB;EACA;EACA;EACAmB,OAAO,CAACC,IAAI,CACV,2EAA2E,GACzE,2EAA2E,GAC3E,6DAA6D,GAC7D,8DAA8D,GAC9D,WAAWrB,iBAAiB,EAChC,CAAC;AACH;;AAEA;AACA,OAAO,SAASsB,oBAAoBA,CAAA,EAAS;EAC3CvB,WAAW,GAAGI,SAAS;EACvBH,iBAAiB,GAAG,EAAE;EACtBC,SAAS,GAAG,KAAK;AACnB","ignoreList":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export { MediaFlightLayer } from "./MediaFlightLayer.js";
|
|
4
|
+
export { MediaSurface, MediaPoster, EmptyMediaSurface } from "./MediaSurface.js";
|
|
5
|
+
export { useMediaFlight } from "./use-media-flight.js";
|
|
6
|
+
export { DEFAULT_FLIGHT_CORNER_RADIUS, flightProgress, handOffFlight, hasFlight, releaseFlight, resetMediaFlight } from "./store.js";
|
|
7
|
+
export { SURFACE_MOUNT_TIMEOUT_MS } from "./constants.js";
|
|
8
|
+
export { loadExpoVideo, warnExpoVideoUnavailable, resetExpoVideoModule } from "./expo-video-module.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["MediaFlightLayer","MediaSurface","MediaPoster","EmptyMediaSurface","useMediaFlight","DEFAULT_FLIGHT_CORNER_RADIUS","flightProgress","handOffFlight","hasFlight","releaseFlight","resetMediaFlight","SURFACE_MOUNT_TIMEOUT_MS","loadExpoVideo","warnExpoVideoUnavailable","resetExpoVideoModule"],"sourceRoot":"../../../src","sources":["media-flight/index.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAQ,uBAAoB;AACrD,SAASC,YAAY,EAAEC,WAAW,EAAEC,iBAAiB,QAAQ,mBAAgB;AAC7E,SAASC,cAAc,QAAQ,uBAAoB;AACnD,SACEC,4BAA4B,EAC5BC,cAAc,EACdC,aAAa,EACbC,SAAS,EACTC,aAAa,EACbC,gBAAgB,QACX,YAAS;AAChB,SAASC,wBAAwB,QAAQ,gBAAa;AACtD,SACEC,aAAa,EACbC,wBAAwB,EACxBC,oBAAoB,QAMf,wBAAqB","ignoreList":[]}
|