@oxyhq/bloom 1.1.0 → 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.
Files changed (150) hide show
  1. package/docs/media-flight.mdx +272 -0
  2. package/docs/migrating-the-media-gallery.mdx +103 -0
  3. package/docs/migrating-to-1.0.mdx +1 -1
  4. package/docs/zoomable-media-gallery.mdx +116 -0
  5. package/lib/commonjs/image-aspect-ratio-cache/aspect-ratio-cache.js +1 -1
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/index.web.js.map +1 -1
  8. package/lib/commonjs/media-flight/MediaFlightLayer.js +151 -0
  9. package/lib/commonjs/media-flight/MediaFlightLayer.js.map +1 -0
  10. package/lib/commonjs/media-flight/MediaSurface.js +188 -0
  11. package/lib/commonjs/media-flight/MediaSurface.js.map +1 -0
  12. package/lib/commonjs/media-flight/constants.js +39 -0
  13. package/lib/commonjs/media-flight/constants.js.map +1 -0
  14. package/lib/commonjs/media-flight/expo-video-module.js +148 -0
  15. package/lib/commonjs/media-flight/expo-video-module.js.map +1 -0
  16. package/lib/commonjs/media-flight/index.js +102 -0
  17. package/lib/commonjs/media-flight/index.js.map +1 -0
  18. package/lib/commonjs/media-flight/store.js +457 -0
  19. package/lib/commonjs/media-flight/store.js.map +1 -0
  20. package/lib/commonjs/media-flight/types.js +6 -0
  21. package/lib/commonjs/media-flight/types.js.map +1 -0
  22. package/lib/commonjs/media-flight/use-media-flight.js +41 -0
  23. package/lib/commonjs/media-flight/use-media-flight.js.map +1 -0
  24. package/lib/commonjs/tab-bar/TabBarBase.js +1 -1
  25. package/lib/commonjs/{zoomable-image-gallery/ZoomableImageGallery.js → zoomable-media-gallery/ZoomableMediaGallery.js} +185 -131
  26. package/lib/commonjs/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -0
  27. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.js.map +1 -1
  28. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.js +5 -5
  29. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.js.map +1 -1
  30. package/lib/commonjs/zoomable-media-gallery/types.js +6 -0
  31. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/types.js.map +1 -1
  32. package/lib/module/image-aspect-ratio-cache/aspect-ratio-cache.js +1 -1
  33. package/lib/module/index.js +2 -1
  34. package/lib/module/index.js.map +1 -1
  35. package/lib/module/index.web.js +2 -1
  36. package/lib/module/index.web.js.map +1 -1
  37. package/lib/module/media-flight/MediaFlightLayer.js +146 -0
  38. package/lib/module/media-flight/MediaFlightLayer.js.map +1 -0
  39. package/lib/module/media-flight/MediaSurface.js +180 -0
  40. package/lib/module/media-flight/MediaSurface.js.map +1 -0
  41. package/lib/module/media-flight/constants.js +35 -0
  42. package/lib/module/media-flight/constants.js.map +1 -0
  43. package/lib/module/media-flight/expo-video-module.js +142 -0
  44. package/lib/module/media-flight/expo-video-module.js.map +1 -0
  45. package/lib/module/media-flight/index.js +9 -0
  46. package/lib/module/media-flight/index.js.map +1 -0
  47. package/lib/module/media-flight/store.js +439 -0
  48. package/lib/module/media-flight/store.js.map +1 -0
  49. package/lib/module/media-flight/types.js +4 -0
  50. package/lib/module/media-flight/types.js.map +1 -0
  51. package/lib/module/media-flight/use-media-flight.js +36 -0
  52. package/lib/module/media-flight/use-media-flight.js.map +1 -0
  53. package/lib/module/tab-bar/TabBarBase.js +1 -1
  54. package/lib/module/{zoomable-image-gallery/ZoomableImageGallery.js → zoomable-media-gallery/ZoomableMediaGallery.js} +184 -130
  55. package/lib/module/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -0
  56. package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.js.map +1 -1
  57. package/lib/module/zoomable-media-gallery/index.js +5 -0
  58. package/lib/module/zoomable-media-gallery/index.js.map +1 -0
  59. package/lib/module/zoomable-media-gallery/types.js +4 -0
  60. package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/types.js.map +1 -1
  61. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  63. package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts +11 -0
  64. package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/media-flight/MediaSurface.d.ts +106 -0
  66. package/lib/typescript/commonjs/media-flight/MediaSurface.d.ts.map +1 -0
  67. package/lib/typescript/commonjs/media-flight/constants.d.ts +18 -0
  68. package/lib/typescript/commonjs/media-flight/constants.d.ts.map +1 -0
  69. package/lib/typescript/commonjs/media-flight/expo-video-module.d.ts +103 -0
  70. package/lib/typescript/commonjs/media-flight/expo-video-module.d.ts.map +1 -0
  71. package/lib/typescript/commonjs/media-flight/index.d.ts +9 -0
  72. package/lib/typescript/commonjs/media-flight/index.d.ts.map +1 -0
  73. package/lib/typescript/commonjs/media-flight/store.d.ts +132 -0
  74. package/lib/typescript/commonjs/media-flight/store.d.ts.map +1 -0
  75. package/lib/typescript/commonjs/media-flight/types.d.ts +195 -0
  76. package/lib/typescript/commonjs/media-flight/types.d.ts.map +1 -0
  77. package/lib/typescript/commonjs/media-flight/use-media-flight.d.ts +4 -0
  78. package/lib/typescript/commonjs/media-flight/use-media-flight.d.ts.map +1 -0
  79. package/lib/typescript/commonjs/zoomable-media-gallery/ZoomableMediaGallery.d.ts +5 -0
  80. package/lib/typescript/commonjs/zoomable-media-gallery/ZoomableMediaGallery.d.ts.map +1 -0
  81. package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/zoomable-media-gallery/index.d.ts +4 -0
  83. package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/zoomable-media-gallery/types.d.ts +90 -0
  85. package/lib/typescript/commonjs/zoomable-media-gallery/types.d.ts.map +1 -0
  86. package/lib/typescript/module/index.d.ts.map +1 -1
  87. package/lib/typescript/module/index.web.d.ts.map +1 -1
  88. package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts +11 -0
  89. package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts.map +1 -0
  90. package/lib/typescript/module/media-flight/MediaSurface.d.ts +106 -0
  91. package/lib/typescript/module/media-flight/MediaSurface.d.ts.map +1 -0
  92. package/lib/typescript/module/media-flight/constants.d.ts +18 -0
  93. package/lib/typescript/module/media-flight/constants.d.ts.map +1 -0
  94. package/lib/typescript/module/media-flight/expo-video-module.d.ts +103 -0
  95. package/lib/typescript/module/media-flight/expo-video-module.d.ts.map +1 -0
  96. package/lib/typescript/module/media-flight/index.d.ts +9 -0
  97. package/lib/typescript/module/media-flight/index.d.ts.map +1 -0
  98. package/lib/typescript/module/media-flight/store.d.ts +132 -0
  99. package/lib/typescript/module/media-flight/store.d.ts.map +1 -0
  100. package/lib/typescript/module/media-flight/types.d.ts +195 -0
  101. package/lib/typescript/module/media-flight/types.d.ts.map +1 -0
  102. package/lib/typescript/module/media-flight/use-media-flight.d.ts +4 -0
  103. package/lib/typescript/module/media-flight/use-media-flight.d.ts.map +1 -0
  104. package/lib/typescript/module/zoomable-media-gallery/ZoomableMediaGallery.d.ts +5 -0
  105. package/lib/typescript/module/zoomable-media-gallery/ZoomableMediaGallery.d.ts.map +1 -0
  106. package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts.map +1 -1
  107. package/lib/typescript/module/zoomable-media-gallery/index.d.ts +4 -0
  108. package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/index.d.ts.map +1 -1
  109. package/lib/typescript/module/zoomable-media-gallery/types.d.ts +90 -0
  110. package/lib/typescript/module/zoomable-media-gallery/types.d.ts.map +1 -0
  111. package/package.json +42 -8
  112. package/src/image-aspect-ratio-cache/aspect-ratio-cache.ts +1 -1
  113. package/src/index.ts +2 -1
  114. package/src/index.web.ts +2 -1
  115. package/src/media-flight/MediaFlightLayer.tsx +144 -0
  116. package/src/media-flight/MediaSurface.tsx +233 -0
  117. package/src/media-flight/constants.ts +32 -0
  118. package/src/media-flight/expo-video-module.ts +181 -0
  119. package/src/media-flight/index.ts +33 -0
  120. package/src/media-flight/store.ts +497 -0
  121. package/src/media-flight/types.ts +210 -0
  122. package/src/media-flight/use-media-flight.ts +42 -0
  123. package/src/tab-bar/TabBarBase.tsx +1 -1
  124. package/src/{zoomable-image-gallery/ZoomableImageGallery.tsx → zoomable-media-gallery/ZoomableMediaGallery.tsx} +192 -117
  125. package/src/zoomable-media-gallery/index.ts +11 -0
  126. package/src/zoomable-media-gallery/types.ts +100 -0
  127. package/docs/zoomable-image-gallery.mdx +0 -66
  128. package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js.map +0 -1
  129. package/lib/commonjs/zoomable-image-gallery/types.js +0 -2
  130. package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js.map +0 -1
  131. package/lib/module/zoomable-image-gallery/index.js +0 -5
  132. package/lib/module/zoomable-image-gallery/index.js.map +0 -1
  133. package/lib/module/zoomable-image-gallery/types.js +0 -2
  134. package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts +0 -5
  135. package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +0 -1
  136. package/lib/typescript/commonjs/zoomable-image-gallery/index.d.ts +0 -4
  137. package/lib/typescript/commonjs/zoomable-image-gallery/types.d.ts +0 -56
  138. package/lib/typescript/commonjs/zoomable-image-gallery/types.d.ts.map +0 -1
  139. package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts +0 -5
  140. package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +0 -1
  141. package/lib/typescript/module/zoomable-image-gallery/index.d.ts +0 -4
  142. package/lib/typescript/module/zoomable-image-gallery/types.d.ts +0 -56
  143. package/lib/typescript/module/zoomable-image-gallery/types.d.ts.map +0 -1
  144. package/src/zoomable-image-gallery/index.ts +0 -9
  145. package/src/zoomable-image-gallery/types.ts +0 -59
  146. /package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.js +0 -0
  147. /package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.js +0 -0
  148. /package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts +0 -0
  149. /package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts +0 -0
  150. /package/src/{zoomable-image-gallery → zoomable-media-gallery}/constants.ts +0 -0
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "DEFAULT_FLIGHT_CORNER_RADIUS", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _store.DEFAULT_FLIGHT_CORNER_RADIUS;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "EmptyMediaSurface", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _MediaSurface.EmptyMediaSurface;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "MediaFlightLayer", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _MediaFlightLayer.MediaFlightLayer;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "MediaPoster", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _MediaSurface.MediaPoster;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "MediaSurface", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _MediaSurface.MediaSurface;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "SURFACE_MOUNT_TIMEOUT_MS", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _constants.SURFACE_MOUNT_TIMEOUT_MS;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "flightProgress", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _store.flightProgress;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "handOffFlight", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _store.handOffFlight;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "hasFlight", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _store.hasFlight;
58
+ }
59
+ });
60
+ Object.defineProperty(exports, "loadExpoVideo", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _expoVideoModule.loadExpoVideo;
64
+ }
65
+ });
66
+ Object.defineProperty(exports, "releaseFlight", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _store.releaseFlight;
70
+ }
71
+ });
72
+ Object.defineProperty(exports, "resetExpoVideoModule", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _expoVideoModule.resetExpoVideoModule;
76
+ }
77
+ });
78
+ Object.defineProperty(exports, "resetMediaFlight", {
79
+ enumerable: true,
80
+ get: function () {
81
+ return _store.resetMediaFlight;
82
+ }
83
+ });
84
+ Object.defineProperty(exports, "useMediaFlight", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _useMediaFlight.useMediaFlight;
88
+ }
89
+ });
90
+ Object.defineProperty(exports, "warnExpoVideoUnavailable", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _expoVideoModule.warnExpoVideoUnavailable;
94
+ }
95
+ });
96
+ var _MediaFlightLayer = require("./MediaFlightLayer.js");
97
+ var _MediaSurface = require("./MediaSurface.js");
98
+ var _useMediaFlight = require("./use-media-flight.js");
99
+ var _store = require("./store.js");
100
+ var _constants = require("./constants.js");
101
+ var _expoVideoModule = require("./expo-video-module.js");
102
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_MediaFlightLayer","require","_MediaSurface","_useMediaFlight","_store","_constants","_expoVideoModule"],"sourceRoot":"../../../src","sources":["media-flight/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,iBAAA,GAAAC,OAAA;AACA,IAAAC,aAAA,GAAAD,OAAA;AACA,IAAAE,eAAA,GAAAF,OAAA;AACA,IAAAG,MAAA,GAAAH,OAAA;AAQA,IAAAI,UAAA,GAAAJ,OAAA;AACA,IAAAK,gBAAA,GAAAL,OAAA","ignoreList":[]}
@@ -0,0 +1,457 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DEFAULT_FLIGHT_CORNER_RADIUS = void 0;
7
+ exports.flightProgress = flightProgress;
8
+ exports.flyBack = flyBack;
9
+ exports.flyTo = flyTo;
10
+ exports.getFlights = getFlights;
11
+ exports.handOffFlight = handOffFlight;
12
+ exports.hasFlight = hasFlight;
13
+ exports.measureAnchor = measureAnchor;
14
+ exports.notifySurfaceMounted = notifySurfaceMounted;
15
+ exports.notifySurfaceSettled = notifySurfaceSettled;
16
+ exports.registerAnchor = registerAnchor;
17
+ exports.releaseFlight = releaseFlight;
18
+ exports.resetMediaFlight = resetMediaFlight;
19
+ exports.subscribeToFlights = subscribeToFlights;
20
+ var _reactNative = require("react-native");
21
+ var _reactNativeReanimated = require("react-native-reanimated");
22
+ var _index = require("../design-tokens/index.js");
23
+ var _constants = require("./constants.js");
24
+ var _constants2 = require("../zoomable-media-gallery/constants.js");
25
+ /**
26
+ * The media-flight registry: anchors, live surfaces, and the animation that
27
+ * moves them.
28
+ *
29
+ * ## Why the animation lives HERE and not in the layer
30
+ *
31
+ * A flight is started by an imperative call (`flyTo`) from a screen that may be
32
+ * about to unmount. If the layer drove the animation from an effect keyed on the
33
+ * flight record, the first frame would be one commit late — and on web, where
34
+ * the origin route is genuinely gone by the next commit, that frame is the one
35
+ * the user sees. Driving the shared value at the call site makes the leg start
36
+ * exactly when the caller says it does and leaves the layer a pure painter.
37
+ *
38
+ * The shared values are created with `makeMutable` rather than `useSharedValue`
39
+ * for the same reason: they belong to a flight, not to a component, and the
40
+ * component that paints a flight is not the one that starts it.
41
+ *
42
+ * ## Why the registry is anchored on `globalThis`
43
+ *
44
+ * Same reason as the portal group and the overlay stack: `exports` ships a
45
+ * `react-native` → `src` condition beside the `lib/module` and `lib/commonjs`
46
+ * forks, and a bundler can resolve `@oxyhq/bloom/media-flight` through different
47
+ * conditions from different call sites. Two physical copies of this module would
48
+ * each keep their own registry, and the `<MediaFlightLayer>` mounted at the app
49
+ * root would never see the flight a screen started.
50
+ */
51
+
52
+ /**
53
+ * Default corner radius of a flying box — Bloom's `radius-12`, the same value
54
+ * the media gallery fits its media at, so a flight that lands in the gallery
55
+ * lands on an identical shape.
56
+ */
57
+ const DEFAULT_FLIGHT_CORNER_RADIUS = exports.DEFAULT_FLIGHT_CORNER_RADIUS = _index.RADIUS['radius-12'];
58
+
59
+ /**
60
+ * Bookkeeping the layer does not RENDER, kept out of the `MediaFlight` record
61
+ * on purpose.
62
+ *
63
+ * The record is replaced on every visual change so its identity tells React the
64
+ * leg moved; folding these flags into it would churn that identity on events
65
+ * nobody paints, and folding the record into these would put mutable state back
66
+ * in a rendered position. They are separate because they answer to different
67
+ * consumers.
68
+ */
69
+
70
+ function emptyRegistry() {
71
+ return {
72
+ anchors: new Map(),
73
+ flights: new Map(),
74
+ status: new Map(),
75
+ listeners: new Set(),
76
+ snapshot: [],
77
+ progress: (0, _reactNativeReanimated.makeMutable)(0)
78
+ };
79
+ }
80
+ function statusFor(id) {
81
+ const reg = registry();
82
+ let status = reg.status.get(id);
83
+ if (!status) {
84
+ status = {
85
+ mounted: false,
86
+ settled: false,
87
+ handedOff: false,
88
+ mountWaiters: [],
89
+ mountTimer: null
90
+ };
91
+ reg.status.set(id, status);
92
+ }
93
+ return status;
94
+ }
95
+ function clearTimers(status) {
96
+ if (status.mountTimer !== null) clearTimeout(status.mountTimer);
97
+ status.mountTimer = null;
98
+ }
99
+ function resolveMountWaiters(status) {
100
+ const waiters = status.mountWaiters;
101
+ status.mountWaiters = [];
102
+ if (status.mountTimer !== null) {
103
+ clearTimeout(status.mountTimer);
104
+ status.mountTimer = null;
105
+ }
106
+ for (const waiter of waiters) waiter();
107
+ }
108
+ function registry() {
109
+ globalThis.__oxyhq_bloom_media_flight__ ??= emptyRegistry();
110
+ return globalThis.__oxyhq_bloom_media_flight__;
111
+ }
112
+ function publish(reg) {
113
+ reg.snapshot = [...reg.flights.values()];
114
+ for (const listener of reg.listeners) listener();
115
+ }
116
+
117
+ /** Subscribe to the live-surface set. The layer's `useSyncExternalStore` half. */
118
+ function subscribeToFlights(listener) {
119
+ const reg = registry();
120
+ reg.listeners.add(listener);
121
+ return () => {
122
+ reg.listeners.delete(listener);
123
+ };
124
+ }
125
+
126
+ /** The live surfaces, oldest first. Stable identity between changes. */
127
+ function getFlights() {
128
+ return registry().snapshot;
129
+ }
130
+
131
+ /** The shared progress value of the most recent leg. */
132
+ function flightProgress() {
133
+ return registry().progress;
134
+ }
135
+
136
+ /**
137
+ * Register (or clear) the node that anchors `id`.
138
+ *
139
+ * A `Map` re-insertion moves the key to the end, which is what makes "the most
140
+ * recently registered node is the anchor" true even when an origin screen's
141
+ * callback ref fires again after the destination has registered.
142
+ */
143
+ function registerAnchor(id, node) {
144
+ const reg = registry();
145
+ reg.anchors.delete(id);
146
+ if (node !== null) reg.anchors.set(id, node);
147
+ }
148
+ function measureAnchor(id) {
149
+ const node = registry().anchors.get(id);
150
+ if (!node) return Promise.resolve(null);
151
+ return new Promise(resolve => {
152
+ node.measureInWindow((x, y, width, height) => {
153
+ // A zero-area measurement is what a node reports while it is laid out but
154
+ // not yet on screen. Flying to it would collapse the surface to a point,
155
+ // so it reads as "no anchor" and the caller skips the transition.
156
+ resolve(width > 0 && height > 0 ? {
157
+ x,
158
+ y,
159
+ width,
160
+ height
161
+ } : null);
162
+ });
163
+ });
164
+ }
165
+
166
+ /** Whether a surface is currently live for `id`. */
167
+ function hasFlight(id) {
168
+ return registry().flights.has(id);
169
+ }
170
+
171
+ /**
172
+ * Take the surface for `id` live (if it is not already) and move it to `rect`.
173
+ *
174
+ * Retargeting mid-flight keeps the SAME `MediaFlight` record — and therefore the
175
+ * same mounted `VideoView` — which is the whole point. A second record would be
176
+ * a second surface for one id, and swapping between them is exactly the remount
177
+ * that restarts playback.
178
+ *
179
+ * ## Why it returns a promise, and what the promise means
180
+ *
181
+ * It resolves once the layer has COMMITTED a surface for this id — not once
182
+ * that surface has painted.
183
+ *
184
+ * The distinction is the whole ordering contract. expo-video's web player keeps
185
+ * a `Set` of mounted `<video>` elements and, on each mount, copies
186
+ * `currentTime`, play state, volume, muted and rate from `[...set][0]`. If the
187
+ * set is EMPTY when the new element mounts, it returns early and the element
188
+ * starts at zero — a restart. So the layer's surface has to enter that set while
189
+ * the origin's is still in it, which means the caller must not tear the origin
190
+ * down (on web: must not navigate) until this promise resolves.
191
+ *
192
+ * That knowledge lives here rather than in the caller, which is the point: a
193
+ * consumer that has to know the mount order is a consumer that will get it wrong
194
+ * once and produce an intermittent restart nobody can reproduce locally.
195
+ *
196
+ * Painting is deliberately NOT waited on. `MediaSurface` renders the poster
197
+ * BEHIND the video on both platforms, and neither an unpainted `<video>` (no
198
+ * `poster` attribute is set) nor an Android `TextureView` with the ExoPlayer
199
+ * shutter off draws anything opaque — so the still shows through until the first
200
+ * frame lands, and there is no black box to hide. Waiting for a decode would
201
+ * trade an invisible problem for a laggy tap.
202
+ */
203
+ function flyTo(id, rect, content, options) {
204
+ const reg = registry();
205
+ const existing = reg.flights.get(id);
206
+ if (existing) {
207
+ // A retarget REPLACES the record rather than mutating it. Identity is what
208
+ // tells React (and the React Compiler) that the leg changed: a mutated
209
+ // record has the same identity, so a memoized read of `flight.from` would
210
+ // keep returning the previous leg's origin forever — the exact
211
+ // external-mutable-state stale read the compiler is documented to produce.
212
+ // The shared value is carried over untouched, so the surface resumes rather
213
+ // than restarting.
214
+ const next = {
215
+ ...existing,
216
+ // The leg that was running is abandoned where it stands: `from` becomes
217
+ // the rect the surface is CURRENTLY at, so a retarget never snaps.
218
+ from: interpolateRect(existing.from, existing.to, existing.progress.value),
219
+ to: rect,
220
+ content,
221
+ cornerRadius: options?.cornerRadius ?? existing.cornerRadius,
222
+ contentFit: options?.contentFit ?? existing.contentFit,
223
+ // NOT retargetable: `MediaSurface` captures it on first render because
224
+ // expo-video forbids changing it at runtime, so a new value here would be
225
+ // silently ignored by the view it is meant to configure.
226
+ surfaceType: existing.surfaceType,
227
+ landing: false,
228
+ generation: existing.generation + 1
229
+ };
230
+ reg.flights.set(id, next);
231
+ const retargeted = statusFor(id);
232
+ retargeted.settled = false;
233
+ animate(next, false);
234
+ publish(reg);
235
+ return awaitSurfaceMount(id);
236
+ }
237
+
238
+ // Nothing live yet. `from` is the origin rect the caller measured; without one
239
+ // the surface simply appears at `rect` rather than flying in from a corner.
240
+ const flight = {
241
+ id,
242
+ content,
243
+ from: options?.from ?? rect,
244
+ to: rect,
245
+ cornerRadius: options?.cornerRadius ?? DEFAULT_FLIGHT_CORNER_RADIUS,
246
+ contentFit: options?.contentFit ?? 'cover',
247
+ surfaceType: options?.surfaceType ?? 'textureView',
248
+ progress: (0, _reactNativeReanimated.makeMutable)(0),
249
+ landing: false,
250
+ generation: 0
251
+ };
252
+ reg.flights.set(id, flight);
253
+ const status = statusFor(id);
254
+ status.mounted = false;
255
+ status.settled = false;
256
+ status.handedOff = false;
257
+ animate(flight, false);
258
+ publish(reg);
259
+ return awaitSurfaceMount(id);
260
+ }
261
+
262
+ /**
263
+ * Resolve once `<MediaFlightLayer>` reports it has committed the surface, or
264
+ * after {@link SURFACE_MOUNT_TIMEOUT_MS} — which is what happens when no layer
265
+ * is mounted at all. Degrading to "carry on without a transition" is right;
266
+ * never resolving would mean an app that forgot one line at its root has a feed
267
+ * whose videos cannot be opened.
268
+ */
269
+ function awaitSurfaceMount(id) {
270
+ const status = statusFor(id);
271
+ if (status.mounted) return Promise.resolve();
272
+ return new Promise(resolve => {
273
+ status.mountWaiters.push(resolve);
274
+ if (status.mountTimer !== null) return;
275
+ status.mountTimer = setTimeout(() => {
276
+ status.mountTimer = null;
277
+ warnNoLayerMounted();
278
+ resolveMountWaiters(status);
279
+ }, _constants.SURFACE_MOUNT_TIMEOUT_MS);
280
+ });
281
+ }
282
+
283
+ /**
284
+ * The layer calls this from the surface's mount effect. It is the commit signal
285
+ * `flyTo` waits on, and the only thing that makes the ordering contract above
286
+ * true rather than hopeful.
287
+ */
288
+ function notifySurfaceMounted(id) {
289
+ const status = statusFor(id);
290
+ status.mounted = true;
291
+ resolveMountWaiters(status);
292
+ }
293
+
294
+ /** The layer calls this when a leg's animation finishes. */
295
+ function notifySurfaceSettled(id) {
296
+ const status = statusFor(id);
297
+ status.settled = true;
298
+ if (status.handedOff) releaseFlight(id);
299
+ }
300
+
301
+ /**
302
+ * A destination surface reporting that it is LIVE — it has presented a frame of
303
+ * its own, so the flying copy is now redundant and can go.
304
+ *
305
+ * This is the release condition, and it is deliberately not the animation's
306
+ * clock. Measured against production, a fullscreen video route needs ~1 s from
307
+ * tap to first presented frame; releasing when a ~300 ms animation ends would
308
+ * leave ~700 ms with nothing live on screen — the hole the transition exists to
309
+ * cover, made longer.
310
+ *
311
+ * Wire it by giving the destination's `<MediaSurface>` a `flightId`; it calls
312
+ * this itself on its first frame. A destination that renders something other
313
+ * than a Bloom surface can call it directly.
314
+ */
315
+ function handOffFlight(id) {
316
+ const reg = registry();
317
+ if (!reg.flights.has(id)) return;
318
+ const status = statusFor(id);
319
+ status.handedOff = true;
320
+ // Mid-flight the surface is still travelling: releasing now would make it
321
+ // vanish somewhere between the two rects. `notifySurfaceSettled` picks it up.
322
+ if (status.settled) releaseFlight(id);
323
+ }
324
+
325
+ /**
326
+ * Aim the live surface at its anchor and release it once it lands.
327
+ *
328
+ * With no measurable anchor there is nothing to fly to, so the surface is
329
+ * released immediately — whoever owns the media renders its own copy again at
330
+ * that point, and holding a flying copy over it would double the video.
331
+ */
332
+ function flyBack(id) {
333
+ const flight = registry().flights.get(id);
334
+ if (!flight) return;
335
+ void measureAnchor(id).then(rect => {
336
+ // Re-read: the flight may have been released or retargeted while the
337
+ // measurement was outstanding (`measureInWindow` is asynchronous on both
338
+ // platforms), and landing a stale record would fly the wrong surface.
339
+ const reg = registry();
340
+ if (reg.flights.get(id) !== flight) return;
341
+ if (rect === null) {
342
+ releaseFlight(id);
343
+ return;
344
+ }
345
+ const landing = {
346
+ ...flight,
347
+ from: interpolateRect(flight.from, flight.to, flight.progress.value),
348
+ to: rect,
349
+ landing: true,
350
+ generation: flight.generation + 1
351
+ };
352
+ reg.flights.set(id, landing);
353
+ animate(landing, true);
354
+ publish(reg);
355
+ });
356
+ }
357
+
358
+ /** Drop the surface for `id`. Called when a landing leg settles, and on teardown. */
359
+ function releaseFlight(id) {
360
+ const reg = registry();
361
+ const status = reg.status.get(id);
362
+ if (status) {
363
+ // A waiter still parked on `flyTo`'s promise would otherwise hang until its
364
+ // own timeout, holding a caller that has nothing left to wait for.
365
+ clearTimers(status);
366
+ resolveMountWaiters(status);
367
+ reg.status.delete(id);
368
+ }
369
+ if (!reg.flights.delete(id)) return;
370
+ publish(reg);
371
+ }
372
+
373
+ /** Test seam — drops every anchor and surface. */
374
+ function resetMediaFlight() {
375
+ const existing = globalThis.__oxyhq_bloom_media_flight__;
376
+ // Timers outlive a registry swap: an unfired mount timeout from the previous
377
+ // suite would warn — and resolve a waiter nobody is holding — inside the next.
378
+ if (existing) for (const status of existing.status.values()) clearTimers(status);
379
+ globalThis.__oxyhq_bloom_media_flight__ = emptyRegistry();
380
+ hasWarnedNoLayer = false;
381
+ }
382
+ let hasWarnedNoLayer = false;
383
+
384
+ /**
385
+ * One warning per module lifetime, and none in production — the same mechanism
386
+ * as the optional-peer boundaries. A missing `<MediaFlightLayer>` is otherwise
387
+ * completely silent: every `flyTo` resolves on its timeout and the app simply
388
+ * never shows a transition, which looks like the feature not being wired rather
389
+ * than the root not being.
390
+ */
391
+ function warnNoLayerMounted() {
392
+ if (process.env.NODE_ENV === 'production' || hasWarnedNoLayer) return;
393
+ hasWarnedNoLayer = true;
394
+ // eslint-disable-next-line no-console
395
+ console.warn('[Bloom] flyTo() timed out waiting for a media surface to mount. Nothing is ' + 'rendering <MediaFlightLayer>, so no media transition will ever run and a ' + 'video opened from a feed will restart. Mount it ONCE at the app root ' + '(app/_layout.tsx), above the router.');
396
+ }
397
+
398
+ /** Rect at `t` along `from` → `to`, so a retarget resumes rather than snapping. */
399
+ function interpolateRect(from, to, t) {
400
+ const clamped = t < 0 ? 0 : t > 1 ? 1 : t;
401
+ return {
402
+ x: from.x + (to.x - from.x) * clamped,
403
+ y: from.y + (to.y - from.y) * clamped,
404
+ width: from.width + (to.width - from.width) * clamped,
405
+ height: from.height + (to.height - from.height) * clamped
406
+ };
407
+ }
408
+
409
+ /**
410
+ * Run one leg: 0 → 1 on the flight's own value, and on the shared `progress` a
411
+ * consumer reads.
412
+ *
413
+ * Both are driven with the SAME curve rather than one deriving from the other,
414
+ * because deriving would need a `useAnimatedReaction` — a hook, in a module with
415
+ * no component to hang it on. Two animations on two shared values cost a few
416
+ * bytes on the UI thread and keep the driver at the call site.
417
+ *
418
+ * The springs and the web timings are the media gallery's, imported rather than
419
+ * re-tuned: a flight that lands in the gallery and the gallery's own open
420
+ * transition are the same motion, and two copies of a spring config drift.
421
+ */
422
+ function animate(flight, landing) {
423
+ const reg = registry();
424
+ const id = flight.id;
425
+ // EVERY leg reports its settlement, because the release condition is now
426
+ // "settled AND the destination is live" and either can arrive first. A
427
+ // `finished === false` callback means the leg was interrupted by a retarget,
428
+ // which owns the surface from then on.
429
+ //
430
+ // A LANDING leg is the one case that releases on its own: it has flown back to
431
+ // its anchor and there is nothing left to cover.
432
+ const onSettled = finished => {
433
+ 'worklet';
434
+
435
+ if (finished === false) return;
436
+ (0, _reactNativeReanimated.runOnJS)(landing ? releaseFlight : notifySurfaceSettled)(id);
437
+ };
438
+ flight.progress.value = 0;
439
+ reg.progress.value = 0;
440
+ if (_reactNative.Platform.OS === 'web') {
441
+ const duration = landing ? _constants2.CLOSE_DURATION_WEB : _constants2.OPEN_DURATION_WEB;
442
+ const easing = landing ? _reactNativeReanimated.Easing.in(_reactNativeReanimated.Easing.cubic) : _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.cubic);
443
+ flight.progress.value = (0, _reactNativeReanimated.withTiming)(1, {
444
+ duration,
445
+ easing
446
+ }, onSettled);
447
+ reg.progress.value = (0, _reactNativeReanimated.withTiming)(1, {
448
+ duration,
449
+ easing
450
+ });
451
+ return;
452
+ }
453
+ const spring = landing ? _constants2.CLOSE_SPRING : _constants2.OPEN_SPRING;
454
+ flight.progress.value = (0, _reactNativeReanimated.withSpring)(1, spring, onSettled);
455
+ reg.progress.value = (0, _reactNativeReanimated.withSpring)(1, spring);
456
+ }
457
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_reactNativeReanimated","_index","_constants","_constants2","DEFAULT_FLIGHT_CORNER_RADIUS","exports","RADIUS","emptyRegistry","anchors","Map","flights","status","listeners","Set","snapshot","progress","makeMutable","statusFor","id","reg","registry","get","mounted","settled","handedOff","mountWaiters","mountTimer","set","clearTimers","clearTimeout","resolveMountWaiters","waiters","waiter","globalThis","__oxyhq_bloom_media_flight__","publish","values","listener","subscribeToFlights","add","delete","getFlights","flightProgress","registerAnchor","node","measureAnchor","Promise","resolve","measureInWindow","x","y","width","height","hasFlight","has","flyTo","rect","content","options","existing","next","from","interpolateRect","to","value","cornerRadius","contentFit","surfaceType","landing","generation","retargeted","animate","awaitSurfaceMount","flight","push","setTimeout","warnNoLayerMounted","SURFACE_MOUNT_TIMEOUT_MS","notifySurfaceMounted","notifySurfaceSettled","releaseFlight","handOffFlight","flyBack","then","resetMediaFlight","hasWarnedNoLayer","process","env","NODE_ENV","console","warn","t","clamped","onSettled","finished","runOnJS","Platform","OS","duration","CLOSE_DURATION_WEB","OPEN_DURATION_WEB","easing","Easing","in","cubic","out","withTiming","spring","CLOSE_SPRING","OPEN_SPRING","withSpring"],"sourceRoot":"../../../src","sources":["media-flight/store.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["media-flight/types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useMediaFlight = useMediaFlight;
7
+ var _store = require("./store.js");
8
+ /**
9
+ * The consumer-facing handle on the flight layer.
10
+ *
11
+ * Every member is a module-level function over a `globalThis`-anchored registry,
12
+ * so the object is a frozen constant rather than something rebuilt per render:
13
+ * a caller may hold it in a dependency array, a callback ref or a gesture
14
+ * closure without any of them going stale, and there is no provider to mount.
15
+ */
16
+
17
+ /**
18
+ * `flyTo` / `flyBack` / `registerAnchor` / `measureAnchor`, plus the shared
19
+ * `progress` value of the most recent leg.
20
+ *
21
+ * `progress` is resolved through a getter rather than captured at module load,
22
+ * because `resetMediaFlight()` (the test seam) replaces the registry — a
23
+ * captured value would keep pointing at the discarded one and every assertion
24
+ * about progress would read a box nothing writes.
25
+ */
26
+ const controller = Object.freeze({
27
+ registerAnchor: _store.registerAnchor,
28
+ measureAnchor: _store.measureAnchor,
29
+ flyTo: _store.flyTo,
30
+ flyBack: _store.flyBack,
31
+ handOff: _store.handOffFlight,
32
+ get progress() {
33
+ return (0, _store.flightProgress)();
34
+ }
35
+ });
36
+
37
+ /** The media-flight controller. Stable for the life of the bundle. */
38
+ function useMediaFlight() {
39
+ return controller;
40
+ }
41
+ //# sourceMappingURL=use-media-flight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_store","require","controller","Object","freeze","registerAnchor","measureAnchor","flyTo","flyBack","handOff","handOffFlight","progress","flightProgress","useMediaFlight"],"sourceRoot":"../../../src","sources":["media-flight/use-media-flight.ts"],"mappings":";;;;;;AAQA,IAAAA,MAAA,GAAAC,OAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,UAAiC,GAAGC,MAAM,CAACC,MAAM,CAAC;EACtDC,cAAc,EAAdA,qBAAc;EACdC,aAAa,EAAbA,oBAAa;EACbC,KAAK,EAALA,YAAK;EACLC,OAAO,EAAPA,cAAO;EACPC,OAAO,EAAEC,oBAAa;EACtB,IAAIC,QAAQA,CAAA,EAAG;IACb,OAAO,IAAAC,qBAAc,EAAC,CAAC;EACzB;AACF,CAAC,CAAC;;AAEF;AACO,SAASC,cAAcA,CAAA,EAA0B;EACtD,OAAOX,UAAU;AACnB","ignoreList":[]}
@@ -245,7 +245,7 @@ function TabBarBody({
245
245
  // never minimize and the highlight would never move, with no error anywhere.
246
246
  // Native (plugin present) auto-tracks and ignores the extra deps, so listing
247
247
  // them is correct on both platforms. Same rule as `BottomSheetBase` and
248
- // `ZoomableImageGallery`. Do NOT strip these.
248
+ // `ZoomableMediaGallery`. Do NOT strip these.
249
249
  const barStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
250
250
  const height = (0, _reactNativeReanimated.interpolate)(progress.value, [0, 1], [_shared.EXPANDED_HEIGHT, _shared.MINIMIZED_HEIGHT], _reactNativeReanimated.Extrapolation.CLAMP);
251
251
  // Revolut-style: the pill shrinks in both dimensions.