@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.
Files changed (220) hide show
  1. package/docs/level-picker.mdx +105 -0
  2. package/docs/media-flight.mdx +272 -0
  3. package/docs/migrating-the-media-gallery.mdx +103 -0
  4. package/docs/migrating-to-1.0.mdx +1 -1
  5. package/docs/slider.mdx +3 -1
  6. package/docs/zoomable-media-gallery.mdx +116 -0
  7. package/lib/commonjs/floating/index.js.map +1 -1
  8. package/lib/commonjs/image-aspect-ratio-cache/aspect-ratio-cache.js +1 -1
  9. package/lib/commonjs/index.js +8 -0
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/index.web.js +33 -25
  12. package/lib/commonjs/index.web.js.map +1 -1
  13. package/lib/commonjs/level-picker/LevelPicker.js +349 -0
  14. package/lib/commonjs/level-picker/LevelPicker.js.map +1 -0
  15. package/lib/commonjs/level-picker/LevelPicker.web.js +346 -0
  16. package/lib/commonjs/level-picker/LevelPicker.web.js.map +1 -0
  17. package/lib/commonjs/level-picker/constants.js +137 -0
  18. package/lib/commonjs/level-picker/constants.js.map +1 -0
  19. package/lib/commonjs/level-picker/index.js +13 -0
  20. package/lib/commonjs/level-picker/index.js.map +1 -0
  21. package/lib/commonjs/level-picker/index.web.js +13 -0
  22. package/lib/commonjs/level-picker/index.web.js.map +1 -0
  23. package/lib/commonjs/level-picker/types.js +6 -0
  24. package/lib/commonjs/level-picker/types.js.map +1 -0
  25. package/lib/commonjs/media-flight/MediaFlightLayer.js +151 -0
  26. package/lib/commonjs/media-flight/MediaFlightLayer.js.map +1 -0
  27. package/lib/commonjs/media-flight/MediaSurface.js +188 -0
  28. package/lib/commonjs/media-flight/MediaSurface.js.map +1 -0
  29. package/lib/commonjs/media-flight/constants.js +39 -0
  30. package/lib/commonjs/media-flight/constants.js.map +1 -0
  31. package/lib/commonjs/media-flight/expo-video-module.js +148 -0
  32. package/lib/commonjs/media-flight/expo-video-module.js.map +1 -0
  33. package/lib/commonjs/media-flight/index.js +102 -0
  34. package/lib/commonjs/media-flight/index.js.map +1 -0
  35. package/lib/commonjs/media-flight/store.js +457 -0
  36. package/lib/commonjs/media-flight/store.js.map +1 -0
  37. package/lib/commonjs/media-flight/types.js +6 -0
  38. package/lib/commonjs/media-flight/types.js.map +1 -0
  39. package/lib/commonjs/media-flight/use-media-flight.js +41 -0
  40. package/lib/commonjs/media-flight/use-media-flight.js.map +1 -0
  41. package/lib/commonjs/tab-bar/TabBarBase.js +1 -1
  42. package/lib/commonjs/{zoomable-image-gallery/ZoomableImageGallery.js → zoomable-media-gallery/ZoomableMediaGallery.js} +185 -131
  43. package/lib/commonjs/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -0
  44. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.js.map +1 -1
  45. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.js +5 -5
  46. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.js.map +1 -1
  47. package/lib/commonjs/zoomable-media-gallery/types.js +6 -0
  48. package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/types.js.map +1 -1
  49. package/lib/module/floating/index.js +5 -0
  50. package/lib/module/floating/index.js.map +1 -1
  51. package/lib/module/image-aspect-ratio-cache/aspect-ratio-cache.js +1 -1
  52. package/lib/module/index.js +3 -1
  53. package/lib/module/index.js.map +1 -1
  54. package/lib/module/index.web.js +3 -1
  55. package/lib/module/index.web.js.map +1 -1
  56. package/lib/module/level-picker/LevelPicker.js +343 -0
  57. package/lib/module/level-picker/LevelPicker.js.map +1 -0
  58. package/lib/module/level-picker/LevelPicker.web.js +340 -0
  59. package/lib/module/level-picker/LevelPicker.web.js.map +1 -0
  60. package/lib/module/level-picker/constants.js +131 -0
  61. package/lib/module/level-picker/constants.js.map +1 -0
  62. package/lib/module/level-picker/index.js +4 -0
  63. package/lib/module/level-picker/index.js.map +1 -0
  64. package/lib/module/level-picker/index.web.js +4 -0
  65. package/lib/module/level-picker/index.web.js.map +1 -0
  66. package/lib/module/level-picker/types.js +4 -0
  67. package/lib/module/level-picker/types.js.map +1 -0
  68. package/lib/module/media-flight/MediaFlightLayer.js +146 -0
  69. package/lib/module/media-flight/MediaFlightLayer.js.map +1 -0
  70. package/lib/module/media-flight/MediaSurface.js +180 -0
  71. package/lib/module/media-flight/MediaSurface.js.map +1 -0
  72. package/lib/module/media-flight/constants.js +35 -0
  73. package/lib/module/media-flight/constants.js.map +1 -0
  74. package/lib/module/media-flight/expo-video-module.js +142 -0
  75. package/lib/module/media-flight/expo-video-module.js.map +1 -0
  76. package/lib/module/media-flight/index.js +9 -0
  77. package/lib/module/media-flight/index.js.map +1 -0
  78. package/lib/module/media-flight/store.js +439 -0
  79. package/lib/module/media-flight/store.js.map +1 -0
  80. package/lib/module/media-flight/types.js +4 -0
  81. package/lib/module/media-flight/types.js.map +1 -0
  82. package/lib/module/media-flight/use-media-flight.js +36 -0
  83. package/lib/module/media-flight/use-media-flight.js.map +1 -0
  84. package/lib/module/tab-bar/TabBarBase.js +1 -1
  85. package/lib/module/{zoomable-image-gallery/ZoomableImageGallery.js → zoomable-media-gallery/ZoomableMediaGallery.js} +184 -130
  86. package/lib/module/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -0
  87. package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.js.map +1 -1
  88. package/lib/module/zoomable-media-gallery/index.js +5 -0
  89. package/lib/module/zoomable-media-gallery/index.js.map +1 -0
  90. package/lib/module/zoomable-media-gallery/types.js +4 -0
  91. package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/types.js.map +1 -1
  92. package/lib/typescript/commonjs/floating/index.d.ts +5 -0
  93. package/lib/typescript/commonjs/floating/index.d.ts.map +1 -1
  94. package/lib/typescript/commonjs/index.d.ts +2 -0
  95. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  96. package/lib/typescript/commonjs/index.web.d.ts +2 -0
  97. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/level-picker/LevelPicker.d.ts +6 -0
  99. package/lib/typescript/commonjs/level-picker/LevelPicker.d.ts.map +1 -0
  100. package/lib/typescript/commonjs/level-picker/LevelPicker.web.d.ts +6 -0
  101. package/lib/typescript/commonjs/level-picker/LevelPicker.web.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/level-picker/constants.d.ts +93 -0
  103. package/lib/typescript/commonjs/level-picker/constants.d.ts.map +1 -0
  104. package/lib/typescript/commonjs/level-picker/index.d.ts +3 -0
  105. package/lib/typescript/commonjs/level-picker/index.d.ts.map +1 -0
  106. package/lib/typescript/commonjs/level-picker/index.web.d.ts +3 -0
  107. package/lib/typescript/commonjs/level-picker/index.web.d.ts.map +1 -0
  108. package/lib/typescript/commonjs/level-picker/types.d.ts +63 -0
  109. package/lib/typescript/commonjs/level-picker/types.d.ts.map +1 -0
  110. package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts +11 -0
  111. package/lib/typescript/commonjs/media-flight/MediaFlightLayer.d.ts.map +1 -0
  112. package/lib/typescript/commonjs/media-flight/MediaSurface.d.ts +106 -0
  113. package/lib/typescript/commonjs/media-flight/MediaSurface.d.ts.map +1 -0
  114. package/lib/typescript/commonjs/media-flight/constants.d.ts +18 -0
  115. package/lib/typescript/commonjs/media-flight/constants.d.ts.map +1 -0
  116. package/lib/typescript/commonjs/media-flight/expo-video-module.d.ts +103 -0
  117. package/lib/typescript/commonjs/media-flight/expo-video-module.d.ts.map +1 -0
  118. package/lib/typescript/commonjs/media-flight/index.d.ts +9 -0
  119. package/lib/typescript/commonjs/media-flight/index.d.ts.map +1 -0
  120. package/lib/typescript/commonjs/media-flight/store.d.ts +132 -0
  121. package/lib/typescript/commonjs/media-flight/store.d.ts.map +1 -0
  122. package/lib/typescript/commonjs/media-flight/types.d.ts +195 -0
  123. package/lib/typescript/commonjs/media-flight/types.d.ts.map +1 -0
  124. package/lib/typescript/commonjs/media-flight/use-media-flight.d.ts +4 -0
  125. package/lib/typescript/commonjs/media-flight/use-media-flight.d.ts.map +1 -0
  126. package/lib/typescript/commonjs/zoomable-media-gallery/ZoomableMediaGallery.d.ts +5 -0
  127. package/lib/typescript/commonjs/zoomable-media-gallery/ZoomableMediaGallery.d.ts.map +1 -0
  128. package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/zoomable-media-gallery/index.d.ts +4 -0
  130. package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/index.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/zoomable-media-gallery/types.d.ts +90 -0
  132. package/lib/typescript/commonjs/zoomable-media-gallery/types.d.ts.map +1 -0
  133. package/lib/typescript/module/floating/index.d.ts +5 -0
  134. package/lib/typescript/module/floating/index.d.ts.map +1 -1
  135. package/lib/typescript/module/index.d.ts +2 -0
  136. package/lib/typescript/module/index.d.ts.map +1 -1
  137. package/lib/typescript/module/index.web.d.ts +2 -0
  138. package/lib/typescript/module/index.web.d.ts.map +1 -1
  139. package/lib/typescript/module/level-picker/LevelPicker.d.ts +6 -0
  140. package/lib/typescript/module/level-picker/LevelPicker.d.ts.map +1 -0
  141. package/lib/typescript/module/level-picker/LevelPicker.web.d.ts +6 -0
  142. package/lib/typescript/module/level-picker/LevelPicker.web.d.ts.map +1 -0
  143. package/lib/typescript/module/level-picker/constants.d.ts +93 -0
  144. package/lib/typescript/module/level-picker/constants.d.ts.map +1 -0
  145. package/lib/typescript/module/level-picker/index.d.ts +3 -0
  146. package/lib/typescript/module/level-picker/index.d.ts.map +1 -0
  147. package/lib/typescript/module/level-picker/index.web.d.ts +3 -0
  148. package/lib/typescript/module/level-picker/index.web.d.ts.map +1 -0
  149. package/lib/typescript/module/level-picker/types.d.ts +63 -0
  150. package/lib/typescript/module/level-picker/types.d.ts.map +1 -0
  151. package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts +11 -0
  152. package/lib/typescript/module/media-flight/MediaFlightLayer.d.ts.map +1 -0
  153. package/lib/typescript/module/media-flight/MediaSurface.d.ts +106 -0
  154. package/lib/typescript/module/media-flight/MediaSurface.d.ts.map +1 -0
  155. package/lib/typescript/module/media-flight/constants.d.ts +18 -0
  156. package/lib/typescript/module/media-flight/constants.d.ts.map +1 -0
  157. package/lib/typescript/module/media-flight/expo-video-module.d.ts +103 -0
  158. package/lib/typescript/module/media-flight/expo-video-module.d.ts.map +1 -0
  159. package/lib/typescript/module/media-flight/index.d.ts +9 -0
  160. package/lib/typescript/module/media-flight/index.d.ts.map +1 -0
  161. package/lib/typescript/module/media-flight/store.d.ts +132 -0
  162. package/lib/typescript/module/media-flight/store.d.ts.map +1 -0
  163. package/lib/typescript/module/media-flight/types.d.ts +195 -0
  164. package/lib/typescript/module/media-flight/types.d.ts.map +1 -0
  165. package/lib/typescript/module/media-flight/use-media-flight.d.ts +4 -0
  166. package/lib/typescript/module/media-flight/use-media-flight.d.ts.map +1 -0
  167. package/lib/typescript/module/zoomable-media-gallery/ZoomableMediaGallery.d.ts +5 -0
  168. package/lib/typescript/module/zoomable-media-gallery/ZoomableMediaGallery.d.ts.map +1 -0
  169. package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts.map +1 -1
  170. package/lib/typescript/module/zoomable-media-gallery/index.d.ts +4 -0
  171. package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/index.d.ts.map +1 -1
  172. package/lib/typescript/module/zoomable-media-gallery/types.d.ts +90 -0
  173. package/lib/typescript/module/zoomable-media-gallery/types.d.ts.map +1 -0
  174. package/package.json +61 -8
  175. package/src/floating/index.ts +5 -0
  176. package/src/image-aspect-ratio-cache/aspect-ratio-cache.ts +1 -1
  177. package/src/index.ts +4 -1
  178. package/src/index.web.ts +4 -1
  179. package/src/level-picker/LevelPicker.tsx +365 -0
  180. package/src/level-picker/LevelPicker.web.tsx +374 -0
  181. package/src/level-picker/constants.ts +131 -0
  182. package/src/level-picker/index.ts +2 -0
  183. package/src/level-picker/index.web.ts +2 -0
  184. package/src/level-picker/types.ts +63 -0
  185. package/src/media-flight/MediaFlightLayer.tsx +144 -0
  186. package/src/media-flight/MediaSurface.tsx +233 -0
  187. package/src/media-flight/constants.ts +32 -0
  188. package/src/media-flight/expo-video-module.ts +181 -0
  189. package/src/media-flight/index.ts +33 -0
  190. package/src/media-flight/store.ts +497 -0
  191. package/src/media-flight/types.ts +210 -0
  192. package/src/media-flight/use-media-flight.ts +42 -0
  193. package/src/tab-bar/TabBarBase.tsx +1 -1
  194. package/src/{zoomable-image-gallery/ZoomableImageGallery.tsx → zoomable-media-gallery/ZoomableMediaGallery.tsx} +192 -117
  195. package/src/zoomable-media-gallery/index.ts +11 -0
  196. package/src/zoomable-media-gallery/types.ts +100 -0
  197. package/docs/zoomable-image-gallery.mdx +0 -66
  198. package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js.map +0 -1
  199. package/lib/commonjs/zoomable-image-gallery/types.js +0 -2
  200. package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js.map +0 -1
  201. package/lib/module/zoomable-image-gallery/index.js +0 -5
  202. package/lib/module/zoomable-image-gallery/index.js.map +0 -1
  203. package/lib/module/zoomable-image-gallery/types.js +0 -2
  204. package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts +0 -5
  205. package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +0 -1
  206. package/lib/typescript/commonjs/zoomable-image-gallery/index.d.ts +0 -4
  207. package/lib/typescript/commonjs/zoomable-image-gallery/types.d.ts +0 -56
  208. package/lib/typescript/commonjs/zoomable-image-gallery/types.d.ts.map +0 -1
  209. package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts +0 -5
  210. package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +0 -1
  211. package/lib/typescript/module/zoomable-image-gallery/index.d.ts +0 -4
  212. package/lib/typescript/module/zoomable-image-gallery/types.d.ts +0 -56
  213. package/lib/typescript/module/zoomable-image-gallery/types.d.ts.map +0 -1
  214. package/src/zoomable-image-gallery/index.ts +0 -9
  215. package/src/zoomable-image-gallery/types.ts +0 -59
  216. /package/lib/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.js +0 -0
  217. /package/lib/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.js +0 -0
  218. /package/lib/typescript/commonjs/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts +0 -0
  219. /package/lib/typescript/module/{zoomable-image-gallery → zoomable-media-gallery}/constants.d.ts +0 -0
  220. /package/src/{zoomable-image-gallery → zoomable-media-gallery}/constants.ts +0 -0
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: LevelPicker
3
+ description: A stepped level over a disclosure — the surface, not what the levels mean.
4
+ order: 35
5
+ ---
6
+
7
+ # LevelPicker
8
+
9
+ A short, ordered scale picked on a rail, with a disclosure underneath that
10
+ reveals the detail rows for whatever the scale is a summary of. It is the body
11
+ of a menu panel: put it inside a `DropdownMenuContent` and give it rows.
12
+
13
+ ```tsx
14
+ import { LevelPicker } from '@oxyhq/bloom/level-picker';
15
+ import {
16
+ DropdownMenu,
17
+ DropdownMenuContent,
18
+ DropdownMenuSub,
19
+ DropdownMenuSubContent,
20
+ DropdownMenuSubTrigger,
21
+ DropdownMenuTrigger,
22
+ } from '@oxyhq/bloom/dropdown-menu';
23
+
24
+ <DropdownMenu>
25
+ <DropdownMenuTrigger asChild label="Quality">
26
+ <Button variant="ghost">{QUALITY[level]}</Button>
27
+ </DropdownMenuTrigger>
28
+ <DropdownMenuContent align="end" className="w-[224px]">
29
+ <LevelPicker
30
+ accessibilityLabel="Quality"
31
+ levels={QUALITY}
32
+ value={level}
33
+ onValueChange={setLevel}
34
+ minLabel="Faster"
35
+ maxLabel="Sharper"
36
+ detailsLabel="Advanced">
37
+ <DropdownMenuSub>
38
+ <DropdownMenuSubTrigger>Format</DropdownMenuSubTrigger>
39
+ <DropdownMenuSubContent side="right" align="start">
40
+
41
+ </DropdownMenuSubContent>
42
+ </DropdownMenuSub>
43
+ </LevelPicker>
44
+ </DropdownMenuContent>
45
+ </DropdownMenu>
46
+ ```
47
+
48
+ ## Which prop decides what
49
+
50
+ | prop | decides |
51
+ | ------------------------------------------------ | -------------------------------------------------------------- |
52
+ | `levels` | how many stops there are, and what each is called |
53
+ | `value` / `onValueChange` | the selected stop, as an index — fully controlled |
54
+ | `accessibilityLabel` | what the level applies to. **Required** |
55
+ | `minLabel` / `maxLabel` | the ends of the scale, shown while the rail is being worked |
56
+ | `detailsLabel` | the disclosure row's text. Defaults to `Details` |
57
+ | `expanded` / `defaultExpanded` / `onExpandedChange` | whether the details are showing |
58
+ | `children` | the rows the disclosure reveals |
59
+
60
+ ## `levels` is the whole scale
61
+
62
+ The array's LENGTH is the number of stops — two, five, nine — and each entry is
63
+ that stop's own name, announced as the slider's value. So a level is never a
64
+ bare number to a screen reader:
65
+
66
+ ```tsx
67
+ levels={['Draft', 'Standard', 'Fine', 'Very fine', 'Maximum']}
68
+ value={1} // "Standard"
69
+ ```
70
+
71
+ There is no `min`, `max` or `step`: a level picker is for a scale short enough
72
+ to name every position on. If yours is not, you want a
73
+ [`Slider`](/docs/bloom/main/slider).
74
+
75
+ ## It owns the surface, not the meaning
76
+
77
+ The picker knows the number of stops, their names, and that a disclosure reveals
78
+ some rows. It knows nothing about what a stop selects or what the rows do —
79
+ those are `children`, and they are ordinary menu rows. Keeping that line is what
80
+ lets one component serve a quality scale, a privacy scale and a compression
81
+ scale without learning about any of them.
82
+
83
+ ## Label it, and do not rely on the captions
84
+
85
+ `minLabel` and `maxLabel` are captions on the SCALE ("Faster" → "Sharper"), and
86
+ they are visible only while the rail is hovered, focused or being dragged.
87
+ Neither is a name for the control: ARIA computes no name from a `slider`'s
88
+ contents, and a caption beside one is a sibling. `accessibilityLabel` is
89
+ required in the type for that reason.
90
+
91
+ ## Keyboard and pointer
92
+
93
+ On web the rail is a focusable `role="slider"`: <kbd>←</kbd>/<kbd>→</kbd> (and
94
+ <kbd>↑</kbd>/<kbd>↓</kbd>) step one level, <kbd>Home</kbd> and <kbd>End</kbd> go
95
+ to the ends, and a drag holds pointer capture so it keeps steering past the end
96
+ of the track. On native the same control is an `adjustable` with `increment` and
97
+ `decrement` actions, driven by a `PanResponder`.
98
+
99
+ ## Both platforms, two layouts
100
+
101
+ The picker is web-forked, and the reason is the details region: a sub-menu is a
102
+ flyout on web and an INLINE disclosure on native, so the native fork measures
103
+ the region on every layout instead of animating to a height it computed. Both
104
+ forks read one set of stops, insets and colour roles, so the control is the same
105
+ control — see `src/level-picker/constants.ts`.
@@ -0,0 +1,272 @@
1
+ ---
2
+ title: MediaFlight
3
+ description: A shared-element media transition that survives the route change — on web and on native.
4
+ order: 75
5
+ ---
6
+
7
+ # MediaFlight
8
+
9
+ A picture — or a **playing video** — moves from where it is to where it is
10
+ going, across a navigation, without restarting and without being re-downloaded.
11
+
12
+ ```tsx
13
+ // app/_layout.tsx — mounted ONCE, at the root, above the router.
14
+ import { MediaFlightLayer } from '@oxyhq/bloom/media-flight';
15
+
16
+ <MediaFlightLayer />
17
+ ```
18
+
19
+ ```tsx
20
+ // the origin: a feed thumbnail
21
+ import { useMediaFlight } from '@oxyhq/bloom/media-flight';
22
+
23
+ const flight = useMediaFlight();
24
+
25
+ <Pressable
26
+ ref={(node) => flight.registerAnchor(mediaId, node)}
27
+ onPress={async () => {
28
+ const from = await flight.measureAnchor(mediaId);
29
+ // AWAIT, then navigate. Never the other way round — see below.
30
+ await flight.flyTo(mediaId, targetRect, { kind: 'video', player, poster }, { from: from ?? undefined });
31
+ router.push(`/videos?id=${mediaId}`);
32
+ }}
33
+ >
34
+ {/* while it is in flight, render a HOLE here — never a second copy */}
35
+ </Pressable>
36
+ ```
37
+
38
+ ```tsx
39
+ // the destination: it says where it wants the surface, and takes it over by
40
+ // reporting its own first frame. `flightId` is the entire wiring.
41
+ <MediaSurface content={{ kind: 'video', player, poster }} flightId={mediaId} />
42
+ ```
43
+
44
+ ## The one rule: await `flyTo` before tearing the origin down
45
+
46
+ expo-video's **web** player keeps a `Set` of mounted `<video>` elements and, on
47
+ each new mount, copies `currentTime`, play state, volume, muted and rate from
48
+ `[...set][0]`. If that set is EMPTY when the new element mounts it returns early
49
+ and the element starts **at zero**.
50
+
51
+ So the layer's surface has to enter the set while the origin's is still in it.
52
+ On web, navigating unmounts the origin route — so navigating before the layer
53
+ has committed is exactly the restart, and it is intermittent, because whether
54
+ you win the race depends on a commit you do not control.
55
+
56
+ `flyTo` returns a promise that resolves on that commit. Awaiting it is the whole
57
+ contract, and it is the only ordering fact a consumer has to know — everything
58
+ else is the layer's problem. It resolves on a short timeout when no
59
+ `<MediaFlightLayer>` is mounted, so a missing root component degrades to "no
60
+ transition" and warns once in dev, rather than leaving a feed whose videos
61
+ cannot be opened.
62
+
63
+ It does **not** wait for a decode. `MediaSurface` renders the poster BEHIND the
64
+ video on both platforms, and neither an unpainted `<video>` (expo-video sets no
65
+ `poster` attribute) nor an Android `TextureView` with the ExoPlayer shutter off
66
+ draws anything opaque — so the still shows through until the first frame lands.
67
+ Waiting for paint would trade an invisible problem for a laggy tap.
68
+
69
+ ## The poster must already be in the image cache
70
+
71
+ `flyTo` resolves on the layer's COMMIT, not on its first painted pixel. That
72
+ trade is only sound if committing is *effectively* painting — and whether it is
73
+ depends entirely on one thing. Measured in Chrome, milliseconds from `flyTo`
74
+ resolving to the flying surface having visible pixels:
75
+
76
+ | the poster URI | ms |
77
+ | --- | --- |
78
+ | already rendered by the page (in the image cache) | **1–5** |
79
+ | never requested before (same file, cache-busted) | **510–900** |
80
+
81
+ So a **warm** poster makes the commit a frame, and a **cold** one opens a
82
+ half-second hole exactly where the origin has just disappeared. Measured in a
83
+ consuming app the hole was ~350 ms, framed by "the feed row stopped painting"
84
+ and "the flight had not started".
85
+
86
+ **The fix is not to make `flyTo` wait.** Waiting would move that half second in
87
+ front of the user's tap, which is worse in the place people actually feel it.
88
+ The fix is to make sure the origin has already painted the exact URI the flight
89
+ will carry.
90
+
91
+ <Callout variant="warning" title="expo-video does not fetch your poster">
92
+ On web, expo-video's `VideoView` renders `<video src=…>` with **no `poster`
93
+ attribute**. So a feed that shows video and passes a poster to the video view
94
+ never actually requests that URL — and the flight is then the first thing that
95
+ asks for it, at the worst possible moment. Render the still yourself under the
96
+ video (`MediaPoster` is exported for exactly this), or prefetch it.
97
+ </Callout>
98
+
99
+ One-minute check: in the Network panel, does the poster request appear **when
100
+ you tap**? If so, this is what you are looking at.
101
+
102
+ `scripts/verify-media-flight.mjs` gates Bloom's half — that a warm surface
103
+ presents within a frame or two, with no re-fetch and no fade. Its control flies
104
+ a cold poster over a latency-throttled link, so "warm is fast" cannot be
105
+ reported by a harness that always says zero.
106
+
107
+ ## The layer leaves when the DESTINATION is live, not when the animation ends
108
+
109
+ Measured against production: opening a full-screen video route takes **~996 ms**
110
+ (median, n=10) from tap to first presented frame — ~545 ms to mount the route,
111
+ ~380 ms to `loadedmetadata`, ~40 ms to the frame. A flight animation lasts about
112
+ 300 ms. Releasing the surface when the animation ends would therefore uncover a
113
+ ~700 ms hole *exactly* where the transition was supposed to hide one.
114
+
115
+ So the release condition is an observable fact, not a clock: the destination's
116
+ own first frame. Give the destination's `<MediaSurface>` a `flightId` and it
117
+ reports that itself (expo-video's `onFirstFrameRender`, expo-image's `onLoad`).
118
+ `flight.handOff(id)` is there for a destination that renders something else.
119
+
120
+ Called mid-flight, a hand-off is remembered rather than obeyed — the surface
121
+ finishes travelling first, or it would vanish between the two rects.
122
+
123
+ **The success criterion is continuity, not speed.** With a shared player the
124
+ frame is already on screen before the tap; the flight does not make the video
125
+ appear sooner, it makes it never disappear. Measure "was there ever no frame?"
126
+ and "did `currentTime` advance monotonically?", not time-to-first-frame.
127
+
128
+ ## Why this exists rather than `react-native-teleport`
129
+
130
+ A shared-element transition normally assumes the origin screen is still mounted
131
+ while the element travels. That is why `react-native-teleport` requires
132
+ `presentation: 'transparentModal'`, and why it has no web story at all.
133
+
134
+ Under expo-router on web the origin route is **unmounted** the moment the URL
135
+ changes. Anything the origin was rendering — a `VideoView`, a decoded image —
136
+ is gone before the first frame of the transition.
137
+
138
+ So the surface is moved OUT of both screens for the duration of the flight.
139
+ `MediaFlightLayer` is mounted once at the app root and renders through Bloom's
140
+ `Portal`, whose outlet lives above the router on both platforms. The surface it
141
+ paints belongs to neither route, so neither route can take it down. Origin and
142
+ destination only **declare** where they want it; the layer is what paints it.
143
+
144
+ ## Why the layer does not own the surface at rest
145
+
146
+ A tempting design is for the feed cell to render only an anchor and let the
147
+ layer paint every video, so there is never a swap at all. It does not work, and
148
+ the reason is not performance.
149
+
150
+ The layer paints through the `Portal`, which is outside every `overflow: hidden`
151
+ and every z-index in the app. A feed video painted there would render **over** a
152
+ sticky header, over a sidebar, over any open sheet, and it would not be clipped
153
+ by the feed column's own rounded corners. That is not a risk to be measured away
154
+ — the layer would have to know the app's clip regions, which is exactly what it
155
+ cannot know. It holds on web and on native alike.
156
+
157
+ Covering the whole screen is correct for the ~300 ms of a transition and wrong
158
+ for the rest of the time. So: the cell owns its surface at rest, the layer owns
159
+ it during the flight, and the handshake above is what makes the two swaps
160
+ invisible.
161
+
162
+ ## One live surface per id
163
+
164
+ That is the contract, and for video it is the whole feature. expo-video keeps
165
+ the `VideoPlayer` **object** separate from the `VideoView` that shows it, and
166
+ one player may feed several views — so moving a video is a matter of mounting
167
+ ONE view in the right place, never of creating a second player.
168
+
169
+ Concretely:
170
+
171
+ - `flyTo` on an id that is already flying **retargets** the same surface. It
172
+ never adds a second one, and the surface resumes from where it currently is
173
+ rather than snapping back to the original origin.
174
+ - The origin and the destination must render a **hole** (or the poster still —
175
+ `MediaPoster` is exported for exactly that) while the surface is in the layer.
176
+ Two copies is what this exists to prevent.
177
+ - `flyBack` measures the current anchor, lands there, and releases. With no
178
+ measurable anchor it releases immediately, because a flying copy held over a
179
+ destination that has already drawn its own media is the duplicate again.
180
+
181
+ ## The API
182
+
183
+ | member | does |
184
+ | ------------------------------- | ------------------------------------------------------------- |
185
+ | `registerAnchor(id, node)` | declares the host view that anchors `id`; `null` clears it |
186
+ | `measureAnchor(id)` | that node's window rect, or `null` when it has none |
187
+ | `flyTo(id, rect, content, opts)`| takes the surface live and moves it to `rect` |
188
+ | `flyBack(id)` | flies it to its anchor and releases it on landing |
189
+ | `progress` | `SharedValue<number>`, 0 → 1 for the most recent leg |
190
+
191
+ The most recently registered node for an id **is** the anchor, which is what
192
+ makes a destination mounting over an origin take over as the fly-back target
193
+ without either of them coordinating.
194
+
195
+ ## It never takes a click
196
+
197
+ Every node the layer renders is `pointerEvents="none"`, inside an `OverlayRoot`
198
+ that is `box-none`. A flying surface is a picture of something the app is
199
+ already showing; the controls underneath it stay the ones the user is pressing.
200
+
201
+ The layer also renders **nothing at all** while no flight is live — which is
202
+ what keeps it out of the overlay stack's live set, so the rank counter can
203
+ still reset (see `overlay/stack.ts`). It takes a rank only while it is
204
+ actually painting, and therefore stacks by open order like every other Bloom
205
+ surface.
206
+
207
+ ## Why the size is animated rather than scaled
208
+
209
+ `ZoomableMediaGallery` flies its media with a uniform `scale`, which is right
210
+ there: it opens from a thumbnail into a box of the same aspect ratio. A flight
211
+ does not have that luxury — it routinely goes from a cropped square tile to a
212
+ 16:9 player — and a uniform scale would leave the first frame the wrong height,
213
+ i.e. visibly not the thumbnail it is replacing. `width`/`height` are
214
+ interpolated instead; the position still rides a transform, so the only layout
215
+ work per frame is one absolutely-positioned node resizing.
216
+
217
+ ## Android: a flight crosses a surface-type boundary
218
+
219
+ expo-video renders Android video into a `SurfaceView` by default. A flight
220
+ cannot: a `SurfaceView` is composited by the system OUTSIDE the view hierarchy,
221
+ so it ignores its parent's clip, corner radius and transform — every property a
222
+ flying box depends on. The layer therefore flies as a `textureView`.
223
+
224
+ **So unless one side changes, the hand-off swaps surface types.** Whether that
225
+ is visible is a device question and nothing here answers it. Measured on a real
226
+ device it may not flicker at all, in which case the right action is none.
227
+
228
+ The knob exists so both arrangements can be measured:
229
+
230
+ ```tsx
231
+ // fly as a surfaceView, matching a destination that has not changed
232
+ flight.flyTo(id, rect, content, { surfaceType: 'surfaceView' });
233
+ ```
234
+
235
+ ```tsx
236
+ // …or leave the flight alone and give the DESTINATION a textureView
237
+ <MediaSurface content={content} flightId={id} surfaceType="textureView" />
238
+ ```
239
+
240
+ Flying as a `surfaceView` will not transform correctly on Android — that is the
241
+ trade the first option makes. `surfaceType` is captured on first render on both
242
+ sides (expo-video forbids changing it at runtime), so a retarget deliberately
243
+ does not accept a new one.
244
+
245
+ ## Peers
246
+
247
+ `expo-image` is required (hence the subpath — the family is deliberately not on
248
+ the root barrel, because Metro does not tree-shake). `expo-video` is
249
+ **optional**: an app that flies only images never installs it, and one that
250
+ flies video without it gets the poster plus a single dev warning naming the
251
+ package.
252
+
253
+ ## What a jest run can and cannot see
254
+
255
+ The registry: that a flight is created, that a second `flyTo` retargets rather
256
+ than duplicating, that `flyBack` releases, that the layer renders nothing while
257
+ idle and a surface when one is live, and that `flyTo` really waits for the
258
+ layer's commit.
259
+
260
+ What it can never see is the MOTION. Every reanimated animation resolves
261
+ synchronously under the test mock, so a mapper that runs once and freezes at the
262
+ opening frame — the documented web failure mode of this package — produces the
263
+ same tree as one that animates. Two browser gates cover it, both headful against
264
+ real Chrome:
265
+
266
+ - `node scripts/verify-media-flight.mjs` samples the flying surface's
267
+ `getBoundingClientRect` during and after the flight, and distinguishes frozen
268
+ (never leaves the origin) from snapped (already at the destination) from
269
+ animating, then asserts it lands on the destination rect and is released.
270
+ - `node scripts/verify-overlay-stacking.mjs` parks a surface over a button and
271
+ clicks the button with trusted input, which is the only way to tell a layer
272
+ that is `pointer-events: none` from one that merely looks like it.
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: Migrating the media gallery
3
+ description: ZoomableImageGallery became ZoomableMediaGallery when the family learned to page video. Two symbols, seven files, two repos — and the subpath you already import still resolves.
4
+ order: 3
5
+ ---
6
+
7
+ # Migrating the media gallery
8
+
9
+ The full-screen viewer now pages **video as well as images**, so the family is
10
+ `zoomable-media-gallery` and the component is `ZoomableMediaGallery`. Bloom
11
+ follows the clean-cut rule: there is no `@deprecated` alias and no old-name
12
+ shim. This page is the whole bridge.
13
+
14
+ ## What actually changed
15
+
16
+ Two exported names, and nothing else:
17
+
18
+ | Old | New |
19
+ | --- | --- |
20
+ | `ZoomableImageGallery` | `ZoomableMediaGallery` |
21
+ | `ZoomableImageGalleryHandle` | `ZoomableMediaGalleryHandle` |
22
+ | `ZoomableImageGalleryProps` | `ZoomableMediaGalleryProps` |
23
+
24
+ Everything else you import from this family keeps its name: `GalleryImage`,
25
+ `MeasureThumb`, `MeasuredRect`, and every constant.
26
+
27
+ <Callout variant="info" title="The subpath still resolves">
28
+ `@oxyhq/bloom/zoomable-image-gallery` and
29
+ `@oxyhq/bloom/zoomable-media-gallery` are two specifiers for the SAME module.
30
+ The old one is not a shim being tolerated — an image gallery is exactly what
31
+ this serves when every item is an image, so it stays a first-class entry point.
32
+ You only have to change the *names you import*, not the path you import them
33
+ from. Changing the path too is tidier, and optional.
34
+ </Callout>
35
+
36
+ ## An image item is unchanged
37
+
38
+ `kind` is optional on the image arm precisely so this stays true:
39
+
40
+ ```tsx
41
+ const images: GalleryImage[] = [
42
+ { uri: 'https://…/a.jpg', alt: 'A photo', aspectRatio: 1.5 },
43
+ ];
44
+ ```
45
+
46
+ If your call site only ever passes images, the rename is the entire migration.
47
+
48
+ ## Every affected file in the ecosystem
49
+
50
+ Measured across `~/Oxy` (agent worktrees excluded). **Two repos, seven files,
51
+ and in every one of them the fix is the two symbol renames above.**
52
+
53
+ | Repo | File |
54
+ | --- | --- |
55
+ | Homiio | `packages/frontend/hooks/usePropertyPhotoGallery.ts` |
56
+ | Homiio | `packages/frontend/components/property/PhotoGallery.tsx` |
57
+ | Homiio | `packages/frontend/components/property/PhotoGrid.tsx` |
58
+ | Homiio | `packages/frontend/utils/propertyUtils.ts` |
59
+ | Mention | `packages/frontend/components/ZoomableAvatar.tsx` |
60
+ | Mention | `packages/frontend/components/Post/PostAttachmentsRow.tsx` |
61
+ | Mention | `packages/frontend/components/Post/Attachments/PostAttachmentMedia.tsx` |
62
+
63
+ `propertyUtils.ts` and `PostAttachmentMedia.tsx` import only `GalleryImage` /
64
+ `MeasuredRect`, which did not change — they appear here because they name the
65
+ subpath, and they need no edit at all.
66
+
67
+ <Callout variant="info" title="Noted is not affected">
68
+ `Noted/packages/frontend/components/notes/attachments/ZoomableImageGallery.tsx`
69
+ is an app-local component (a port of Mention's original), reached through
70
+ `@/components/...`. It imports nothing from Bloom, so this rename does not touch
71
+ it. It is listed here because a `grep` for the old name finds it and it looks
72
+ like a call site.
73
+ </Callout>
74
+
75
+ ## Why the failure is safe
76
+
77
+ A symbol that no longer exists fails at RESOLUTION — a TypeScript error and a
78
+ bundler error, at build time, naming the identifier. There is no version of this
79
+ that renders wrong or misbehaves at runtime, and nothing sees it until the app
80
+ deliberately bumps Bloom.
81
+
82
+ ## While you are here: video
83
+
84
+ Adding a video page needs a `VideoPlayer` **you** create and own — Bloom never
85
+ creates or destroys one:
86
+
87
+ ```tsx
88
+ import { useVideoPlayer } from 'expo-video';
89
+ import type { GalleryMedia } from '@oxyhq/bloom/zoomable-media-gallery';
90
+
91
+ const player = useVideoPlayer(videoUrl);
92
+
93
+ const items: GalleryMedia[] = [
94
+ { uri: 'https://…/a.jpg', alt: 'A photo', aspectRatio: 1.5 },
95
+ { kind: 'video', id: 'clip-1', player, poster: 'https://…/still.jpg', aspectRatio: 1.777 },
96
+ ];
97
+ ```
98
+
99
+ `expo-video` is an optional peer. An app that pages only images never installs
100
+ it; one that pages video without it gets posters and a single dev warning.
101
+
102
+ See [MediaFlight](./media-flight) for moving that same player between a feed
103
+ thumbnail and a full-screen route without restarting playback.
@@ -185,7 +185,7 @@ failure, not a type error.
185
185
  | `@oxyhq/bloom/menu` | `@oxyhq/bloom/dropdown-menu` | The family was ported to shadcn/react-native-reusables' public API. Every `Menu*` export is `DropdownMenu*`. |
186
186
  | `@oxyhq/bloom/collapsible` | `@oxyhq/bloom/accordion` | `Collapsible` called `UIManager.setLayoutAnimationEnabledExperimental(true)` at module scope and reached the root barrel through `export *`, so that side effect ran for every barrel consumer on Android old-arch whether or not the component was used. |
187
187
  | `@oxyhq/bloom/grouped-buttons` | `@oxyhq/bloom/settings-list` + `@oxyhq/bloom/item` | The only one of the three row renderers with no `accessibilityRole`, no `accessibilityLabel` and no `aria-disabled`, built on `TouchableOpacity`/`activeOpacity` instead of `useInteractionState`. |
188
- | `@oxyhq/bloom/pressable-with-hover` | none — inline it | One internal user. It now lives inside `zoomable-image-gallery` as `NavArrow`, the package's only hover-styled control. |
188
+ | `@oxyhq/bloom/pressable-with-hover` | none — inline it | One internal user. It now lives inside `zoomable-media-gallery` as `NavArrow`, the package's only hover-styled control. |
189
189
 
190
190
  ### Subpaths added
191
191
 
package/docs/slider.mdx CHANGED
@@ -68,6 +68,8 @@ throwing; an empty or whitespace-only string counts as missing, because
68
68
  into and is hard to land on a specific value.
69
69
  - **There are fewer than about five positions.** Use a
70
70
  [`SegmentedControl`](/docs/bloom/main/segmented-control) or a
71
- [`Radio`](/docs/bloom/main/radio) group — they name the options.
71
+ [`Radio`](/docs/bloom/main/radio) group — they name the options. A
72
+ [`LevelPicker`](/docs/bloom/main/level-picker) is the third answer: a rail
73
+ with named stops, for a short scale that still reads as a continuum.
72
74
  - **The range is huge and non-linear.** A slider over 1–1,000,000 gives most of
73
75
  its travel to values nobody wants.
@@ -0,0 +1,116 @@
1
+ ---
2
+ title: ZoomableMediaGallery
3
+ description: The full-screen media viewer — images and video, mounted once, opened imperatively.
4
+ order: 71
5
+ ---
6
+
7
+ # ZoomableMediaGallery
8
+
9
+ Full-screen images **and video** with pinch-zoom, swipe between, and
10
+ drag-to-dismiss. Mount it once near the app root and open it from anywhere.
11
+
12
+ ```tsx
13
+ import { ZoomableMediaGallery, type ZoomableMediaGalleryHandle } from '@oxyhq/bloom/zoomable-media-gallery';
14
+
15
+ const gallery = useRef<ZoomableMediaGalleryHandle>(null);
16
+
17
+ <ZoomableMediaGallery ref={gallery} measureThumb={measureThumb} />
18
+
19
+ // from a thumbnail
20
+ gallery.current?.open(items, index);
21
+ ```
22
+
23
+ ## Two specifiers, one module
24
+
25
+ `@oxyhq/bloom/zoomable-image-gallery` resolves the same module and keeps
26
+ working: an image gallery is exactly what this serves when every item is an
27
+ image. The COMPONENT was renamed, so update the identifier —
28
+ `ZoomableImageGallery` no longer exists, and there is no alias.
29
+
30
+ ## A page is an image or a video
31
+
32
+ ```tsx
33
+ import { useVideoPlayer } from 'expo-video';
34
+ import type { GalleryMedia } from '@oxyhq/bloom/zoomable-media-gallery';
35
+
36
+ // YOU create the player and YOU own it. Bloom never creates or releases one.
37
+ const player = useVideoPlayer(videoUrl);
38
+
39
+ const items: GalleryMedia[] = [
40
+ { uri: 'https://…/photo.jpg', alt: 'A photo', aspectRatio: 1.5 },
41
+ { kind: 'video', id: 'clip-1', player, poster: 'https://…/still.jpg', aspectRatio: 1.777 },
42
+ ];
43
+ ```
44
+
45
+ An image item is unchanged — `{ uri }` — because `kind` is optional on that
46
+ arm. A video item carries the `VideoPlayer` object itself, and that is the
47
+ whole mechanism behind "the video does not restart when it opens": expo-video
48
+ keeps the player separate from the `VideoView` that shows it, and one player
49
+ can feed several views. Handing the same player to this gallery moves a playing
50
+ video into full screen without re-opening the stream.
51
+
52
+ Give a video an `aspectRatio`. Unlike an image there is nothing to probe, so
53
+ without one the page opens at the default ratio and resizes when the first
54
+ frame arrives.
55
+
56
+ ## Exactly one video view is mounted
57
+
58
+ The ACTIVE page. Every other page, and every thumbnail-strip tile, renders the
59
+ poster still. A second `VideoView` on the same player would be a duplicate
60
+ surface — the thing this family and `media-flight` are both built to avoid —
61
+ and on a strip it would be one decoder per tile.
62
+
63
+ One surface swap happens per opening: the pre-pager open surface hands over to
64
+ the pager's active page once the open animation settles.
65
+
66
+ ## Which prop decides what
67
+
68
+ | prop | decides |
69
+ | ------------------ | --------------------------------------------------------- |
70
+ | `measureThumb` | the rect the opening animation grows FROM |
71
+ | `cornerRadius` | the thumbnail's corner, so the transition matches it |
72
+ | `indicatorVariant` | `dots` or `thumbnails` for the page indicator |
73
+ | `videoControls` | whether video pages show expo-video's transport controls |
74
+
75
+ `open(items, index, rect?)` takes the whole set and which one to show.
76
+
77
+ ## Why it is imperative
78
+
79
+ One gallery serves every thumbnail on a screen. Making it declarative would
80
+ mean a piece of state per grid, or one shared "which item is open" flag
81
+ threaded through everything that can show media. The ref is what lets a
82
+ thumbnail deep in a list open it without the list knowing the gallery exists.
83
+
84
+ ## `measureThumb` is what makes the transition read
85
+
86
+ Without it the gallery fades in from nowhere. With it, the image grows out of
87
+ the thumbnail the user pressed, which tells them *which* image they opened —
88
+ useful precisely in the case where a grid has several similar photos.
89
+
90
+ It returns a promise because measuring is asynchronous on native. Returning
91
+ `null` is fine and degrades to the fade.
92
+
93
+ ## `alt` is the caption and the accessible text
94
+
95
+ Set `alt` on each item. It is shown as the caption for the active page, and it
96
+ is the only description a screen reader has — a media viewer with no alt text
97
+ is a screen with nothing on it.
98
+
99
+ ## Peers
100
+
101
+ It requires `expo-image`, which is why the family is **not** on the root
102
+ barrel: Metro does not tree-shake, so importing the barrel would drag that peer
103
+ into every consumer's build whether or not they use a gallery. Import it from
104
+ its subpath.
105
+
106
+ `expo-video` is an **optional** peer, loaded through
107
+ `media-flight/expo-video-module` with the one dynamic-require shape Metro marks
108
+ optional. An app that ships no video never has to install it; one that does and
109
+ forgets gets its video pages degraded to their posters, with a single dev
110
+ warning naming the package.
111
+
112
+ ## What a jest run can and cannot see
113
+
114
+ That it renders nothing until `open()` is called, and that it opens at the
115
+ index it was given. The gestures — pinch, pan-to-dismiss, the shared-element
116
+ transition — belong to a device build.
@@ -1 +1 @@
1
- {"version":3,"names":["_constants","require","_context","_FloatingPanel","_menuRows","_menuSubInline","_TriggerSlot","_useAnchorRect","_useSheetOpenBridge"],"sourceRoot":"../../../src","sources":["floating/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,IAAAA,UAAA,GAAAC,OAAA;AAMA,IAAAC,QAAA,GAAAD,OAAA;AAaA,IAAAE,cAAA,GAAAF,OAAA;AACA,IAAAG,SAAA,GAAAH,OAAA;AAKA,IAAAI,cAAA,GAAAJ,OAAA;AACA,IAAAK,YAAA,GAAAL,OAAA;AAEA,IAAAM,cAAA,GAAAN,OAAA;AACA,IAAAO,mBAAA,GAAAP,OAAA","ignoreList":[]}
1
+ {"version":3,"names":["_constants","require","_context","_FloatingPanel","_menuRows","_menuSubInline","_TriggerSlot","_useAnchorRect","_useSheetOpenBridge"],"sourceRoot":"../../../src","sources":["floating/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,IAAAA,UAAA,GAAAC,OAAA;AAMA,IAAAC,QAAA,GAAAD,OAAA;AAaA,IAAAE,cAAA,GAAAF,OAAA;AACA,IAAAG,SAAA,GAAAH,OAAA;AAKA,IAAAI,cAAA,GAAAJ,OAAA;AACA,IAAAK,YAAA,GAAAL,OAAA;AAEA,IAAAM,cAAA,GAAAN,OAAA;AACA,IAAAO,mBAAA,GAAAP,OAAA","ignoreList":[]}
@@ -10,7 +10,7 @@ var _reactNative = require("react-native");
10
10
  * the image source URI.
11
11
  *
12
12
  * Intended for a thumbnail renderer and a fullscreen viewer (e.g.
13
- * `@oxyhq/bloom/zoomable-image-gallery`) sharing the SAME image URI to read
13
+ * `@oxyhq/bloom/zoomable-media-gallery`) sharing the SAME image URI to read
14
14
  * from and write to this one map, so an image already resolved as a thumbnail
15
15
  * has its ratio on hand when it opens "big" — no second cache, no duplicate
16
16
  * `Image.getSize` round-trip on the hot path. If the two surfaces render
@@ -93,6 +93,7 @@ var _exportNames = {
93
93
  InputGroup: true,
94
94
  InputGroupAddon: true,
95
95
  Slider: true,
96
+ LevelPicker: true,
96
97
  Combobox: true,
97
98
  BottomSheet: true,
98
99
  LinkPreviewCard: true,
@@ -329,6 +330,12 @@ Object.defineProperty(exports, "Label", {
329
330
  return _index26.Label;
330
331
  }
331
332
  });
333
+ Object.defineProperty(exports, "LevelPicker", {
334
+ enumerable: true,
335
+ get: function () {
336
+ return _levelPicker.LevelPicker;
337
+ }
338
+ });
332
339
  Object.defineProperty(exports, "LinkPreviewCard", {
333
340
  enumerable: true,
334
341
  get: function () {
@@ -881,6 +888,7 @@ var _index26 = require("./label/index.js");
881
888
  var _index27 = require("./field/index.js");
882
889
  var _index28 = require("./input-group/index.js");
883
890
  var _index29 = require("./slider/index.js");
891
+ var _levelPicker = require("./level-picker");
884
892
  var _combobox = require("./combobox");
885
893
  var _bottomSheet = require("./bottom-sheet");
886
894
  var _index30 = require("./card/index.js");