react-native-gtkx 0.2.0-alpha.2 → 0.3.0-alpha.1

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 (340) hide show
  1. package/README.md +5 -2
  2. package/dist/aliases/index.d.ts +84 -0
  3. package/dist/aliases/index.js +208 -0
  4. package/dist/aliases/index.js.map +1 -0
  5. package/dist/animated/index.d.ts +2 -0
  6. package/dist/animated/index.js +5 -0
  7. package/dist/animated/index.js.map +1 -1
  8. package/dist/animated/types.d.ts +1 -0
  9. package/dist/animated/types.js.map +1 -1
  10. package/dist/animated/value-animation.js +17 -4
  11. package/dist/animated/value-animation.js.map +1 -1
  12. package/dist/apis/host.gtkx.js +9 -12
  13. package/dist/apis/host.gtkx.js.map +1 -1
  14. package/dist/apis/index.d.ts +4 -2
  15. package/dist/apis/index.js +2 -0
  16. package/dist/apis/index.js.map +1 -1
  17. package/dist/apis/keyboard.d.ts +60 -0
  18. package/dist/apis/keyboard.js +63 -0
  19. package/dist/apis/keyboard.js.map +1 -0
  20. package/dist/apis/log-box.d.ts +15 -0
  21. package/dist/apis/log-box.js +46 -0
  22. package/dist/apis/log-box.js.map +1 -0
  23. package/dist/apis/platform.d.ts +18 -1
  24. package/dist/apis/platform.js.map +1 -1
  25. package/dist/common/index.d.ts +0 -1
  26. package/dist/common/index.js +24 -1
  27. package/dist/common/index.js.map +1 -1
  28. package/dist/components/animated.d.ts +70 -6
  29. package/dist/components/animated.js +559 -46
  30. package/dist/components/animated.js.map +1 -1
  31. package/dist/components/driven-size.d.ts +27 -0
  32. package/dist/components/driven-size.js +85 -0
  33. package/dist/components/driven-size.js.map +1 -0
  34. package/dist/components/find-node-handle.d.ts +11 -0
  35. package/dist/components/find-node-handle.js +53 -0
  36. package/dist/components/find-node-handle.js.map +1 -0
  37. package/dist/components/flat-list.d.ts +3 -2
  38. package/dist/components/flat-list.js.map +1 -1
  39. package/dist/components/frame-scheduler.d.ts +16 -0
  40. package/dist/components/frame-scheduler.js +37 -0
  41. package/dist/components/frame-scheduler.js.map +1 -0
  42. package/dist/components/image.d.ts +6 -1
  43. package/dist/components/image.js +15 -4
  44. package/dist/components/image.js.map +1 -1
  45. package/dist/components/index.d.ts +7 -5
  46. package/dist/components/index.js +5 -3
  47. package/dist/components/index.js.map +1 -1
  48. package/dist/components/measure.d.ts +51 -1
  49. package/dist/components/measure.js +101 -2
  50. package/dist/components/measure.js.map +1 -1
  51. package/dist/components/pressable.d.ts +61 -1
  52. package/dist/components/pressable.js +151 -4
  53. package/dist/components/pressable.js.map +1 -1
  54. package/dist/components/rect-store.d.ts +58 -0
  55. package/dist/components/rect-store.js +124 -3
  56. package/dist/components/rect-store.js.map +1 -1
  57. package/dist/components/root.js +6 -1
  58. package/dist/components/root.js.map +1 -1
  59. package/dist/components/scroll-phase.d.ts +35 -0
  60. package/dist/components/scroll-phase.js +26 -0
  61. package/dist/components/scroll-phase.js.map +1 -0
  62. package/dist/components/scroll-view.d.ts +39 -3
  63. package/dist/components/scroll-view.js +378 -43
  64. package/dist/components/scroll-view.js.map +1 -1
  65. package/dist/components/text-input.js +9 -25
  66. package/dist/components/text-input.js.map +1 -1
  67. package/dist/components/text.d.ts +6 -2
  68. package/dist/components/text.js +43 -8
  69. package/dist/components/text.js.map +1 -1
  70. package/dist/components/use-focus.d.ts +27 -0
  71. package/dist/components/use-focus.js +116 -0
  72. package/dist/components/use-focus.js.map +1 -0
  73. package/dist/components/use-layout-child.d.ts +13 -1
  74. package/dist/components/use-layout-child.js +188 -5
  75. package/dist/components/use-layout-child.js.map +1 -1
  76. package/dist/components/view.d.ts +5 -2
  77. package/dist/components/view.js +18 -13
  78. package/dist/components/view.js.map +1 -1
  79. package/dist/components/virtualized-list.d.ts +45 -5
  80. package/dist/components/virtualized-list.js +90 -24
  81. package/dist/components/virtualized-list.js.map +1 -1
  82. package/dist/components/wheel-scroll-session.d.ts +7 -0
  83. package/dist/components/wheel-scroll-session.js +53 -0
  84. package/dist/components/wheel-scroll-session.js.map +1 -0
  85. package/dist/components/widget-retention.d.ts +35 -0
  86. package/dist/components/widget-retention.js +169 -0
  87. package/dist/components/widget-retention.js.map +1 -0
  88. package/dist/contracts.d.ts +4 -0
  89. package/dist/contracts.js.map +1 -1
  90. package/dist/dnd/context.d.ts +69 -0
  91. package/dist/dnd/context.js +149 -0
  92. package/dist/dnd/context.js.map +1 -0
  93. package/dist/dnd/draggable.d.ts +59 -0
  94. package/dist/dnd/draggable.js +149 -0
  95. package/dist/dnd/draggable.js.map +1 -0
  96. package/dist/dnd/droppable.d.ts +24 -0
  97. package/dist/dnd/droppable.js +74 -0
  98. package/dist/dnd/droppable.js.map +1 -0
  99. package/dist/dnd/gtk-controllers.d.ts +39 -0
  100. package/dist/dnd/gtk-controllers.js +110 -0
  101. package/dist/dnd/gtk-controllers.js.map +1 -0
  102. package/dist/dnd/index.d.ts +6 -0
  103. package/dist/dnd/index.js +31 -0
  104. package/dist/dnd/index.js.map +1 -0
  105. package/dist/dnd/order.d.ts +7 -0
  106. package/dist/dnd/order.js +20 -0
  107. package/dist/dnd/order.js.map +1 -0
  108. package/dist/dnd/payload.d.ts +14 -0
  109. package/dist/dnd/payload.js +41 -0
  110. package/dist/dnd/payload.js.map +1 -0
  111. package/dist/dnd/sortable.d.ts +49 -0
  112. package/dist/dnd/sortable.js +307 -0
  113. package/dist/dnd/sortable.js.map +1 -0
  114. package/dist/dnd/types.d.ts +290 -0
  115. package/dist/dnd/types.js +25 -0
  116. package/dist/dnd/types.js.map +1 -0
  117. package/dist/gesture-handler-compat/builder.d.ts +251 -0
  118. package/dist/gesture-handler-compat/builder.js +513 -0
  119. package/dist/gesture-handler-compat/builder.js.map +1 -0
  120. package/dist/gesture-handler-compat/composition.d.ts +23 -0
  121. package/dist/gesture-handler-compat/composition.js +111 -0
  122. package/dist/gesture-handler-compat/composition.js.map +1 -0
  123. package/dist/gesture-handler-compat/deciders.d.ts +3 -0
  124. package/dist/gesture-handler-compat/deciders.js +47 -0
  125. package/dist/gesture-handler-compat/deciders.js.map +1 -0
  126. package/dist/gesture-handler-compat/detector-runtime.d.ts +44 -0
  127. package/dist/gesture-handler-compat/detector-runtime.js +374 -0
  128. package/dist/gesture-handler-compat/detector-runtime.js.map +1 -0
  129. package/dist/gesture-handler-compat/detector.d.ts +22 -0
  130. package/dist/gesture-handler-compat/detector.js +104 -0
  131. package/dist/gesture-handler-compat/detector.js.map +1 -0
  132. package/dist/gesture-handler-compat/fling.d.ts +24 -0
  133. package/dist/gesture-handler-compat/fling.js +123 -0
  134. package/dist/gesture-handler-compat/fling.js.map +1 -0
  135. package/dist/gesture-handler-compat/force-touch.d.ts +13 -0
  136. package/dist/gesture-handler-compat/force-touch.js +40 -0
  137. package/dist/gesture-handler-compat/force-touch.js.map +1 -0
  138. package/dist/gesture-handler-compat/hooks.d.ts +157 -0
  139. package/dist/gesture-handler-compat/hooks.js +268 -0
  140. package/dist/gesture-handler-compat/hooks.js.map +1 -0
  141. package/dist/gesture-handler-compat/hover.d.ts +2 -0
  142. package/dist/gesture-handler-compat/hover.js +22 -0
  143. package/dist/gesture-handler-compat/hover.js.map +1 -0
  144. package/dist/gesture-handler-compat/index.d.ts +98 -0
  145. package/dist/gesture-handler-compat/index.js +255 -0
  146. package/dist/gesture-handler-compat/index.js.map +1 -0
  147. package/dist/gesture-handler-compat/long-press.d.ts +6 -0
  148. package/dist/gesture-handler-compat/long-press.js +21 -0
  149. package/dist/gesture-handler-compat/long-press.js.map +1 -0
  150. package/dist/gesture-handler-compat/manual.d.ts +2 -0
  151. package/dist/gesture-handler-compat/manual.js +18 -0
  152. package/dist/gesture-handler-compat/manual.js.map +1 -0
  153. package/dist/gesture-handler-compat/native.d.ts +7 -0
  154. package/dist/gesture-handler-compat/native.js +34 -0
  155. package/dist/gesture-handler-compat/native.js.map +1 -0
  156. package/dist/gesture-handler-compat/orchestrator.d.ts +77 -0
  157. package/dist/gesture-handler-compat/orchestrator.js +284 -0
  158. package/dist/gesture-handler-compat/orchestrator.js.map +1 -0
  159. package/dist/gesture-handler-compat/pan.d.ts +23 -0
  160. package/dist/gesture-handler-compat/pan.js +116 -0
  161. package/dist/gesture-handler-compat/pan.js.map +1 -0
  162. package/dist/gesture-handler-compat/recognizer.d.ts +268 -0
  163. package/dist/gesture-handler-compat/recognizer.js +1056 -0
  164. package/dist/gesture-handler-compat/recognizer.js.map +1 -0
  165. package/dist/gesture-handler-compat/relations.d.ts +43 -0
  166. package/dist/gesture-handler-compat/relations.js +128 -0
  167. package/dist/gesture-handler-compat/relations.js.map +1 -0
  168. package/dist/gesture-handler-compat/tap.d.ts +6 -0
  169. package/dist/gesture-handler-compat/tap.js +29 -0
  170. package/dist/gesture-handler-compat/tap.js.map +1 -0
  171. package/dist/gesture-handler-compat/touchpad.d.ts +41 -0
  172. package/dist/gesture-handler-compat/touchpad.js +64 -0
  173. package/dist/gesture-handler-compat/touchpad.js.map +1 -0
  174. package/dist/gesture-handler-compat/types.d.ts +441 -0
  175. package/dist/gesture-handler-compat/types.js +167 -0
  176. package/dist/gesture-handler-compat/types.js.map +1 -0
  177. package/dist/gtk/controllers.d.ts +39 -0
  178. package/dist/gtk/controllers.js +92 -0
  179. package/dist/gtk/controllers.js.map +1 -0
  180. package/dist/gtk/index.d.ts +2 -1
  181. package/dist/gtk/index.js +7 -1
  182. package/dist/gtk/index.js.map +1 -1
  183. package/dist/gtkx/bridge/geometry.js +6 -4
  184. package/dist/gtkx/bridge/geometry.js.map +1 -1
  185. package/dist/gtkx/bridge/index.d.ts +5 -3
  186. package/dist/gtkx/bridge/index.js +6 -3
  187. package/dist/gtkx/bridge/index.js.map +1 -1
  188. package/dist/gtkx/bridge/slot-portal.js.map +1 -1
  189. package/dist/gtkx/bridge/use-signal.js +1 -1
  190. package/dist/gtkx/bridge/use-signal.js.map +1 -1
  191. package/dist/gtkx/bridge/view-box.d.ts +56 -0
  192. package/dist/gtkx/bridge/view-box.js +394 -9
  193. package/dist/gtkx/bridge/view-box.js.map +1 -1
  194. package/dist/gtkx/bridge/widget-css.d.ts +17 -0
  195. package/dist/gtkx/bridge/widget-css.js +72 -0
  196. package/dist/gtkx/bridge/widget-css.js.map +1 -0
  197. package/dist/index.d.ts +3 -3
  198. package/dist/index.js +2 -2
  199. package/dist/index.js.map +1 -1
  200. package/dist/layout/driven-size.d.ts +12 -0
  201. package/dist/layout/driven-size.js +70 -0
  202. package/dist/layout/driven-size.js.map +1 -0
  203. package/dist/layout/engine.d.ts +17 -1
  204. package/dist/layout/engine.js +3 -20
  205. package/dist/layout/engine.js.map +1 -1
  206. package/dist/layout/node.d.ts +13 -0
  207. package/dist/layout/node.js +14 -0
  208. package/dist/layout/node.js.map +1 -1
  209. package/dist/layout/yoga.d.ts +3 -2
  210. package/dist/layout/yoga.js +5 -2
  211. package/dist/layout/yoga.js.map +1 -1
  212. package/dist/mcp/data/generated.d.ts +257 -60
  213. package/dist/mcp/data/generated.js +306 -62
  214. package/dist/mcp/data/generated.js.map +1 -1
  215. package/dist/metro/index.d.ts +10 -0
  216. package/dist/metro/index.js +21 -12
  217. package/dist/metro/index.js.map +1 -1
  218. package/dist/navigation/sidebar.d.ts +16 -0
  219. package/dist/navigation/sidebar.js +65 -1
  220. package/dist/navigation/sidebar.js.map +1 -1
  221. package/dist/reanimated-compat/animated-ref.d.ts +32 -0
  222. package/dist/reanimated-compat/animated-ref.js +57 -0
  223. package/dist/reanimated-compat/animated-ref.js.map +1 -0
  224. package/dist/reanimated-compat/animation.d.ts +177 -0
  225. package/dist/reanimated-compat/animation.js +540 -0
  226. package/dist/reanimated-compat/animation.js.map +1 -0
  227. package/dist/reanimated-compat/color.d.ts +28 -0
  228. package/dist/reanimated-compat/color.js +249 -0
  229. package/dist/reanimated-compat/color.js.map +1 -0
  230. package/dist/reanimated-compat/decay.d.ts +39 -0
  231. package/dist/reanimated-compat/decay.js +96 -0
  232. package/dist/reanimated-compat/decay.js.map +1 -0
  233. package/dist/reanimated-compat/easing.d.ts +30 -0
  234. package/dist/reanimated-compat/easing.js +76 -0
  235. package/dist/reanimated-compat/easing.js.map +1 -0
  236. package/dist/reanimated-compat/hooks.d.ts +14 -0
  237. package/dist/reanimated-compat/hooks.js +217 -0
  238. package/dist/reanimated-compat/hooks.js.map +1 -0
  239. package/dist/reanimated-compat/index.d.ts +258 -0
  240. package/dist/reanimated-compat/index.js +464 -0
  241. package/dist/reanimated-compat/index.js.map +1 -0
  242. package/dist/reanimated-compat/interpolation.d.ts +18 -0
  243. package/dist/reanimated-compat/interpolation.js +122 -0
  244. package/dist/reanimated-compat/interpolation.js.map +1 -0
  245. package/dist/reanimated-compat/layout-animation-config.d.ts +43 -0
  246. package/dist/reanimated-compat/layout-animation-config.js +78 -0
  247. package/dist/reanimated-compat/layout-animation-config.js.map +1 -0
  248. package/dist/reanimated-compat/layout-animation-presets.d.ts +117 -0
  249. package/dist/reanimated-compat/layout-animation-presets.js +498 -0
  250. package/dist/reanimated-compat/layout-animation-presets.js.map +1 -0
  251. package/dist/reanimated-compat/layout-animation-runtime.d.ts +21 -0
  252. package/dist/reanimated-compat/layout-animation-runtime.js +311 -0
  253. package/dist/reanimated-compat/layout-animation-runtime.js.map +1 -0
  254. package/dist/reanimated-compat/layout-animation-view.d.ts +27 -0
  255. package/dist/reanimated-compat/layout-animation-view.js +266 -0
  256. package/dist/reanimated-compat/layout-animation-view.js.map +1 -0
  257. package/dist/reanimated-compat/layout-animation.d.ts +171 -0
  258. package/dist/reanimated-compat/layout-animation.js +469 -0
  259. package/dist/reanimated-compat/layout-animation.js.map +1 -0
  260. package/dist/reanimated-compat/layout-transitions.d.ts +83 -0
  261. package/dist/reanimated-compat/layout-transitions.js +350 -0
  262. package/dist/reanimated-compat/layout-transitions.js.map +1 -0
  263. package/dist/reanimated-compat/mutable.d.ts +29 -0
  264. package/dist/reanimated-compat/mutable.js +139 -0
  265. package/dist/reanimated-compat/mutable.js.map +1 -0
  266. package/dist/reanimated-compat/props.d.ts +18 -0
  267. package/dist/reanimated-compat/props.js +111 -0
  268. package/dist/reanimated-compat/props.js.map +1 -0
  269. package/dist/reanimated-compat/scroll-handler.d.ts +119 -0
  270. package/dist/reanimated-compat/scroll-handler.js +274 -0
  271. package/dist/reanimated-compat/scroll-handler.js.map +1 -0
  272. package/dist/reanimated-compat/scroll-offset.d.ts +12 -0
  273. package/dist/reanimated-compat/scroll-offset.js +104 -0
  274. package/dist/reanimated-compat/scroll-offset.js.map +1 -0
  275. package/dist/reanimated-compat/style.d.ts +90 -0
  276. package/dist/reanimated-compat/style.js +452 -0
  277. package/dist/reanimated-compat/style.js.map +1 -0
  278. package/dist/reanimated-compat/test-timers.d.ts +28 -0
  279. package/dist/reanimated-compat/test-timers.js +136 -0
  280. package/dist/reanimated-compat/test-timers.js.map +1 -0
  281. package/dist/reanimated-compat/threads.d.ts +13 -0
  282. package/dist/reanimated-compat/threads.js +41 -0
  283. package/dist/reanimated-compat/threads.js.map +1 -0
  284. package/dist/reanimated-compat/tracking.d.ts +41 -0
  285. package/dist/reanimated-compat/tracking.js +106 -0
  286. package/dist/reanimated-compat/tracking.js.map +1 -0
  287. package/dist/reanimated-compat/updater-animations.d.ts +36 -0
  288. package/dist/reanimated-compat/updater-animations.js +273 -0
  289. package/dist/reanimated-compat/updater-animations.js.map +1 -0
  290. package/dist/responder/system.d.ts +80 -7
  291. package/dist/responder/system.js +143 -23
  292. package/dist/responder/system.js.map +1 -1
  293. package/dist/responder/use-responder.d.ts +11 -0
  294. package/dist/responder/use-responder.js +225 -6
  295. package/dist/responder/use-responder.js.map +1 -1
  296. package/dist/runner/host-dev.js +1 -1
  297. package/dist/runner/host-dev.js.map +1 -1
  298. package/dist/runner/host.js +1 -1
  299. package/dist/runner/host.js.map +1 -1
  300. package/dist/runner/index.js +3 -3
  301. package/dist/runner/index.js.map +1 -1
  302. package/dist/sea/gtkx-config-module.js +1 -1
  303. package/dist/sea/gtkx-config-module.js.map +1 -1
  304. package/dist/style/absolute-insets.d.ts +26 -0
  305. package/dist/style/absolute-insets.js +113 -0
  306. package/dist/style/absolute-insets.js.map +1 -0
  307. package/dist/style/animated-size.d.ts +25 -0
  308. package/dist/style/animated-size.js +225 -0
  309. package/dist/style/animated-size.js.map +1 -0
  310. package/dist/style/colors.d.ts +17 -0
  311. package/dist/style/colors.js +25 -6
  312. package/dist/style/colors.js.map +1 -1
  313. package/dist/style/imperative-css.d.ts +21 -0
  314. package/dist/style/imperative-css.js +63 -0
  315. package/dist/style/imperative-css.js.map +1 -0
  316. package/dist/style/index.d.ts +2 -1
  317. package/dist/style/index.js +2 -1
  318. package/dist/style/index.js.map +1 -1
  319. package/dist/style/split-style.js +5 -0
  320. package/dist/style/split-style.js.map +1 -1
  321. package/dist/testing/index.js.map +1 -1
  322. package/dist/unsupported-export.d.ts +8 -0
  323. package/dist/unsupported-export.js +66 -0
  324. package/dist/unsupported-export.js.map +1 -0
  325. package/dist/vite/index.d.ts +21 -8
  326. package/dist/vite/index.js +127 -82
  327. package/dist/vite/index.js.map +1 -1
  328. package/dist/vitest/index.d.ts +2 -2
  329. package/dist/vitest/index.js.map +1 -1
  330. package/dist/worklets-compat/index.d.ts +4 -0
  331. package/dist/worklets-compat/index.js +28 -0
  332. package/dist/worklets-compat/index.js.map +1 -0
  333. package/dist/worklets-compat/surface.d.ts +110 -0
  334. package/dist/worklets-compat/surface.js +153 -0
  335. package/dist/worklets-compat/surface.js.map +1 -0
  336. package/package.json +25 -9
  337. package/types.d.ts +9 -0
  338. package/dist/common/list.d.ts +0 -82
  339. package/dist/common/list.js +0 -166
  340. package/dist/common/list.js.map +0 -1
@@ -0,0 +1,104 @@
1
+ // `useScrollOffset` (and `useScrollViewOffset`, its own deprecated alias
2
+ // upstream) — a shared value that always holds a scrollable's current offset.
3
+ //
4
+ // Upstream builds it out of `useEvent`, which subscribes a native view tag to
5
+ // the scroll event names and lets the UI runtime write the value. Here it is
6
+ // shorter and reads the same: an `AnimatedRef` on a scrollable resolves to the
7
+ // `GtkScrolledWindow` behind it, and its adjustments already emit
8
+ // `value-changed` on the loop this JS is on — the same signal
9
+ // `ScrollView.emitScroll` runs from. So the value moves with the scroll, with
10
+ // no React render and no event machinery, which is what the hook promises.
11
+ //
12
+ // **It costs nothing to be untracked.** Nothing is connected until a hook
13
+ // actually points at a scrollable, and it is disconnected when the component
14
+ // unmounts or the ref moves to a different one. A scrollable nobody tracks is
15
+ // the widget it always was.
16
+ import { useEffect, useRef, useState } from "react";
17
+ import { widgetForHandle } from "../components/measure";
18
+ import { warnOnce } from "../style/dev-warning";
19
+ import { Gtk } from "../gtkx/bridge/index";
20
+ const instanceOf = (animatedRef) => {
21
+ if (!animatedRef) {
22
+ return null;
23
+ }
24
+ return typeof animatedRef === "function" ? animatedRef() : animatedRef.current;
25
+ };
26
+ /**
27
+ * The scrolled window a ref stands for. A `ScrollView`'s handle IS the
28
+ * scrolled window; a windowed list's handle resolves through to the
29
+ * `ScrollView` it renders (`registerHandleAlias`), which is the same rule
30
+ * `findNodeHandle` and `measureLayout` already follow — so this works on a
31
+ * `FlatList` ref without knowing anything about lists.
32
+ */
33
+ const scrolledWindowOf = (animatedRef) => {
34
+ const widget = widgetForHandle(instanceOf(animatedRef));
35
+ return widget instanceof Gtk.ScrolledWindow ? widget : null;
36
+ };
37
+ export const createScrollOffsetHooks = (makeMutable) => {
38
+ const useScrollOffset = (animatedRef,
39
+ // Upstream's second argument: write into the caller's shared value
40
+ // instead of minting one, so two hooks can share an offset.
41
+ providedOffset) => {
42
+ // useState rather than a lazily-filled ref for the reason `useSharedValue`
43
+ // reaches for it: this value IS the return value, so a ref would be a
44
+ // render-time read.
45
+ const [internal] = useState(() => makeMutable(0));
46
+ const offset = providedOffset ?? internal;
47
+ // The widget currently subscribed to, so a re-render that resolved to the
48
+ // same one reconnects nothing.
49
+ const attached = useRef(null);
50
+ const detach = useRef(null);
51
+ // No dependency array on purpose. A ref is attached by React AFTER the
52
+ // render that created it, so the first run of this effect commonly
53
+ // resolves to nothing and the second one — a commit later, with the list
54
+ // mounted — is the one that finds the scroller. Upstream solves the same
55
+ // problem with `animatedRef.observe`; re-resolving per commit is the same
56
+ // answer without a second observer protocol, and it is one WeakMap lookup
57
+ // when the answer has not changed.
58
+ useEffect(() => {
59
+ const widget = scrolledWindowOf(animatedRef);
60
+ if (widget === attached.current) {
61
+ return;
62
+ }
63
+ detach.current?.();
64
+ detach.current = null;
65
+ attached.current = widget;
66
+ if (!widget) {
67
+ if (instanceOf(animatedRef) !== null) {
68
+ warnOnce("useScrollOffset", "useScrollOffset was given a ref that is not on a scrollable, so the " +
69
+ "offset will stay at 0. Pass the ref to a ScrollView, FlatList or " +
70
+ "Animated.ScrollView.");
71
+ }
72
+ return;
73
+ }
74
+ const hadjustment = widget.getHadjustment();
75
+ const vadjustment = widget.getVadjustment();
76
+ const update = () => {
77
+ // Upstream's own rule, mirrored exactly: the horizontal offset when
78
+ // there is one, the vertical otherwise. One shared value cannot carry
79
+ // two axes, and this is the choice every consumer is written against.
80
+ const x = hadjustment.getValue();
81
+ offset.value = x === 0 ? vadjustment.getValue() : x;
82
+ };
83
+ update();
84
+ hadjustment.on("value-changed", update);
85
+ vadjustment.on("value-changed", update);
86
+ detach.current = () => {
87
+ hadjustment.off("value-changed", update);
88
+ vadjustment.off("value-changed", update);
89
+ };
90
+ });
91
+ useEffect(() => () => {
92
+ detach.current?.();
93
+ detach.current = null;
94
+ attached.current = null;
95
+ }, []);
96
+ return offset;
97
+ };
98
+ return {
99
+ useScrollOffset,
100
+ /** Upstream's own deprecated alias, kept so library call sites are unchanged. */
101
+ useScrollViewOffset: useScrollOffset,
102
+ };
103
+ };
104
+ //# sourceMappingURL=scroll-offset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-offset.js","sourceRoot":"","sources":["../../src/reanimated-compat/scroll-offset.ts"],"names":[],"mappings":"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","sourcesContent":["// `useScrollOffset` (and `useScrollViewOffset`, its own deprecated alias\n// upstream) — a shared value that always holds a scrollable's current offset.\n//\n// Upstream builds it out of `useEvent`, which subscribes a native view tag to\n// the scroll event names and lets the UI runtime write the value. Here it is\n// shorter and reads the same: an `AnimatedRef` on a scrollable resolves to the\n// `GtkScrolledWindow` behind it, and its adjustments already emit\n// `value-changed` on the loop this JS is on — the same signal\n// `ScrollView.emitScroll` runs from. So the value moves with the scroll, with\n// no React render and no event machinery, which is what the hook promises.\n//\n// **It costs nothing to be untracked.** Nothing is connected until a hook\n// actually points at a scrollable, and it is disconnected when the component\n// unmounts or the ref moves to a different one. A scrollable nobody tracks is\n// the widget it always was.\nimport { useEffect, useRef, useState } from \"react\"\nimport { widgetForHandle } from \"../components/measure\"\nimport { warnOnce } from \"../style/dev-warning\"\nimport { Gtk } from \"../gtkx/bridge/index\"\nimport type { SharedValue } from \"./mutable\"\n\ntype MakeMutable = <T>(initial: T) => SharedValue<T>\n\n/** Either spelling of a ref, as everything else on this surface accepts. */\ntype ScrollableRef = (() => unknown) | { current: unknown } | null | undefined\n\nconst instanceOf = (animatedRef: ScrollableRef): unknown => {\n if (!animatedRef) {\n return null\n }\n return typeof animatedRef === \"function\" ? animatedRef() : animatedRef.current\n}\n\n/**\n * The scrolled window a ref stands for. A `ScrollView`'s handle IS the\n * scrolled window; a windowed list's handle resolves through to the\n * `ScrollView` it renders (`registerHandleAlias`), which is the same rule\n * `findNodeHandle` and `measureLayout` already follow — so this works on a\n * `FlatList` ref without knowing anything about lists.\n */\nconst scrolledWindowOf = (\n animatedRef: ScrollableRef,\n): Gtk.ScrolledWindow | null => {\n const widget = widgetForHandle(instanceOf(animatedRef))\n return widget instanceof Gtk.ScrolledWindow ? widget : null\n}\n\nexport const createScrollOffsetHooks = (makeMutable: MakeMutable) => {\n const useScrollOffset = (\n animatedRef: ScrollableRef,\n // Upstream's second argument: write into the caller's shared value\n // instead of minting one, so two hooks can share an offset.\n providedOffset?: SharedValue<number>,\n ): SharedValue<number> => {\n // useState rather than a lazily-filled ref for the reason `useSharedValue`\n // reaches for it: this value IS the return value, so a ref would be a\n // render-time read.\n const [internal] = useState(() => makeMutable(0))\n const offset = providedOffset ?? internal\n\n // The widget currently subscribed to, so a re-render that resolved to the\n // same one reconnects nothing.\n const attached = useRef<Gtk.ScrolledWindow | null>(null)\n const detach = useRef<(() => void) | null>(null)\n\n // No dependency array on purpose. A ref is attached by React AFTER the\n // render that created it, so the first run of this effect commonly\n // resolves to nothing and the second one — a commit later, with the list\n // mounted — is the one that finds the scroller. Upstream solves the same\n // problem with `animatedRef.observe`; re-resolving per commit is the same\n // answer without a second observer protocol, and it is one WeakMap lookup\n // when the answer has not changed.\n useEffect(() => {\n const widget = scrolledWindowOf(animatedRef)\n if (widget === attached.current) {\n return\n }\n detach.current?.()\n detach.current = null\n attached.current = widget\n if (!widget) {\n if (instanceOf(animatedRef) !== null) {\n warnOnce(\n \"useScrollOffset\",\n \"useScrollOffset was given a ref that is not on a scrollable, so the \" +\n \"offset will stay at 0. Pass the ref to a ScrollView, FlatList or \" +\n \"Animated.ScrollView.\",\n )\n }\n return\n }\n\n const hadjustment = widget.getHadjustment()\n const vadjustment = widget.getVadjustment()\n const update = (): void => {\n // Upstream's own rule, mirrored exactly: the horizontal offset when\n // there is one, the vertical otherwise. One shared value cannot carry\n // two axes, and this is the choice every consumer is written against.\n const x = hadjustment.getValue()\n offset.value = x === 0 ? vadjustment.getValue() : x\n }\n update()\n hadjustment.on(\"value-changed\", update)\n vadjustment.on(\"value-changed\", update)\n detach.current = () => {\n hadjustment.off(\"value-changed\", update)\n vadjustment.off(\"value-changed\", update)\n }\n })\n\n useEffect(\n () => () => {\n detach.current?.()\n detach.current = null\n attached.current = null\n },\n [],\n )\n\n return offset\n }\n\n return {\n useScrollOffset,\n /** Upstream's own deprecated alias, kept so library call sites are unchanged. */\n useScrollViewOffset: useScrollOffset,\n }\n}\n"]}
@@ -0,0 +1,90 @@
1
+ export type StyleValue = number | string;
2
+ export type StyleObject = Record<string, unknown>;
3
+ /** The animated node a style leaf is replaced with. */
4
+ export type StyleNode = {
5
+ addListener(callback: (state: {
6
+ value: StyleValue;
7
+ }) => void): string;
8
+ removeListener(id: string): void;
9
+ __getValue(): StyleValue;
10
+ /** @internal Publishes a new value to the view layer. */
11
+ __push(value: StyleValue): void;
12
+ };
13
+ /**
14
+ * @internal Shared with `props.ts`: `useAnimatedProps` publishes through the
15
+ * exact same node the style path does, because the receivers duck-type it the
16
+ * same way (`addListener` + `__getValue`).
17
+ */
18
+ export declare const createStyleNode: (initial: StyleValue) => StyleNode;
19
+ /** @internal Test seam: the warning is once per session by design. */
20
+ export declare const resetUndriveableWarnings: () => void;
21
+ /**
22
+ * Whether a property that finishes an animation has to be published through a
23
+ * React render to land at all.
24
+ *
25
+ * Every warning on the layout path ends with "the new value is applied on the
26
+ * next React render", and until now that was true only by luck: a value that
27
+ * moves solely inside a `useAnimatedStyle` produces no render, so the last
28
+ * frame of the animation was the last place it existed. `@gorhom/bottom-sheet`
29
+ * is exactly that case — it bounds its scrollable with an animated `height`
30
+ * and nothing else re-renders — and `spike/core-exports` is what found it.
31
+ *
32
+ * Layout properties only. `opacity`, `transform` and colours are written to
33
+ * the widget on the frame they change, so a render at the end would be a
34
+ * render for nothing; a `width`/`height` the driven-size rule ACCEPTS is on
35
+ * screen at the right size already, and the render is what puts the same value
36
+ * into Yoga so the committed layout and the override agree.
37
+ *
38
+ * At the end of the animation AND on a cadence while it runs, which is the
39
+ * correction §10 made to §9: the settle alone kept the promise only when the
40
+ * animation was short and never when its target moved every frame, and
41
+ * gorhom's sheet was blank for 1.38 s because of it. Ten renders a second at
42
+ * the very most, against sixty frames — still the whole difference between
43
+ * this and the naive layout write the refusal is about
44
+ * (docs/research/animated-size.md §3, and LANDING_INTERVAL_MS in
45
+ * ./updater-animations.ts for the numbers).
46
+ */
47
+ export declare const settlesThroughReact: (property: string) => boolean;
48
+ export type AnimatedStyle = {
49
+ /**
50
+ * The object handed to `Animated.View`. Stable while an animation runs — a
51
+ * driven frame is a write into a node, not a new style — and replaced by a
52
+ * shallow copy exactly once per `renew()`, which is how a value that cannot
53
+ * be driven reaches the view layer at all.
54
+ */
55
+ readonly style: StyleObject;
56
+ /** The nodes behind it, reusable when the style has to be rebuilt. */
57
+ readonly nodes: ReadonlyMap<string, StyleNode>;
58
+ /**
59
+ * Publishes a fresh updater result. Returns false when the SHAPE changed
60
+ * (a transform entry appeared, vanished or swapped kind) and the caller
61
+ * must rebuild — the node set no longer matches, and the bindings in the
62
+ * view layer were made against the old one.
63
+ */
64
+ apply(next: StyleObject): boolean;
65
+ /**
66
+ * Gives the style a new identity, so a render that follows actually reaches
67
+ * the view.
68
+ *
69
+ * A stable object was the right default and it is still what a running
70
+ * animation gets, but it is not enough on its own: `@gorhom/bottom-sheet`
71
+ * wraps the view this style lands on in `memo`, and a re-render of the
72
+ * component that OWNS the `useAnimatedStyle` stops at that boundary with
73
+ * every prop identical. The value then exists in the style and never reaches
74
+ * Yoga — measured, `spike/core-exports`: the sheet's content mask stayed at
75
+ * the height of the animation's first frame while the animation itself ran
76
+ * to 543 px.
77
+ *
78
+ * Called for a property the platform will not drive at frame rate when its
79
+ * animation settles, and at most ten times a second while it runs — never
80
+ * per frame. See LANDING_INTERVAL_MS in ./updater-animations.ts for why the
81
+ * settle on its own was not enough.
82
+ */
83
+ renew(): void;
84
+ };
85
+ /**
86
+ * Builds the node-backed style. `reuse` carries nodes over from a previous
87
+ * build so a shape change keeps the identity of the leaves that survived it,
88
+ * which is what stops the view layer re-binding the parts that did not move.
89
+ */
90
+ export declare const createAnimatedStyle: (source: StyleObject, reuse?: ReadonlyMap<string, StyleNode>) => AnimatedStyle;
@@ -0,0 +1,452 @@
1
+ // Turning a `useAnimatedStyle` updater's plain object into a style the view
2
+ // layer can drive without React.
3
+ //
4
+ // The mapper returns ordinary values every frame. On the first run each
5
+ // animatable leaf is replaced by a small animated NODE and the mapping is
6
+ // remembered; later runs only push new values into those nodes, so a running
7
+ // animation costs zero React renders. `src/components/animated.tsx`
8
+ // recognises those nodes structurally and writes them straight to GTK —
9
+ // `widget.setOpacity` for opacity, the rect store plus `queueAllocate` for
10
+ // transforms, and a CSS provider private to the widget for colours.
11
+ //
12
+ // WHERE THE BOUNDARY IS NOW. Opacity, transforms and colours are driven
13
+ // unconditionally. `flex`, every `margin*`/`padding*`, `gap`, `flexBasis` and
14
+ // the `min*`/`max*` family are refused, and that is a refusal on measured
15
+ // grounds rather than a gap waiting to be filled: a layout write has to go
16
+ // through Yoga, and a pass plus its commit walk costs what the CONTAINER
17
+ // costs, not what the animated value costs — 52 µs for a five-child
18
+ // container, 133 µs at sixty, 496 µs at three hundred, per frame. The same
19
+ // frame's transform write is 1.5 µs and does not grow at all.
20
+ //
21
+ // It is a cost argument and ONLY a cost argument, which is narrower than this
22
+ // comment used to claim. docs/research/animated-size.md re-measured the two
23
+ // other things that were said here: GTK re-measuring the ancestors after the
24
+ // resize adds nothing at any tree size, and a size write cannot move the
25
+ // window — the RN root reports a zero size request, so the toplevel never
26
+ // re-negotiates. (An `IntrinsicRoot` mounted directly in GTK chrome is the one
27
+ // exception, and it does change the window's request.)
28
+ //
29
+ // TWO CARVE-OUTS, and neither is a softening of that.
30
+ //
31
+ // - `top`/`left`/`right`/`bottom` on a node whose OWN `position` is
32
+ // `"absolute"`, because an out-of-flow node's inset has an exact transform
33
+ // equivalent: moving it changes nothing but where it is drawn, which is
34
+ // what the transform path already does, so no Yoga pass is needed at all —
35
+ // src/style/absolute-insets.ts, docs/research/absolute-insets.md.
36
+ // - `width`/`height` where the change is CONFINED to the node that owns it.
37
+ // There is no transform that reproduces a size change (a scale grows about
38
+ // the centre and stretches the content instead of re-laying it out —
39
+ // measured), so this one really does run Yoga; it just runs it rooted at
40
+ // the animated node rather than at the tree's root, which is 6.6 µs for a
41
+ // leaf and 23 µs with wrapped text, IDENTICAL at 5, 60 and 300 siblings —
42
+ // src/style/animated-size.ts, docs/research/animated-size.md.
43
+ //
44
+ // Both rules are measured, neither is universal, and the configurations where
45
+ // they fail are refused as loudly as `flex` is.
46
+ //
47
+ // The rule for everything undriveable stays what it was: it must be VISIBLE.
48
+ // A property that changes between mapper runs but cannot be driven says so
49
+ // once, by name — and layout properties say it in their own words, because
50
+ // "use translateX instead of left" is advice and "cannot be written" is not.
51
+ import { INSET_PROPERTIES, insetRefusalReason, insetTranslation, } from "../style/absolute-insets";
52
+ import { SIZE_PROPERTIES } from "../style/animated-size";
53
+ import { DRIVEABLE_COLOR_PROPERTIES } from "../style/imperative-css";
54
+ /**
55
+ * @internal Shared with `props.ts`: `useAnimatedProps` publishes through the
56
+ * exact same node the style path does, because the receivers duck-type it the
57
+ * same way (`addListener` + `__getValue`).
58
+ */
59
+ export const createStyleNode = (initial) => {
60
+ let current = initial;
61
+ const listeners = new Map();
62
+ let nextListenerId = 1;
63
+ return {
64
+ addListener(callback) {
65
+ const id = String(nextListenerId++);
66
+ listeners.set(id, callback);
67
+ return id;
68
+ },
69
+ removeListener(id) {
70
+ listeners.delete(id);
71
+ },
72
+ __getValue() {
73
+ return current;
74
+ },
75
+ __push(value) {
76
+ if (Object.is(value, current)) {
77
+ return;
78
+ }
79
+ current = value;
80
+ for (const listener of [...listeners.values()]) {
81
+ listener({ value: current });
82
+ }
83
+ },
84
+ };
85
+ };
86
+ const isStyleValue = (value) => typeof value === "number" || typeof value === "string";
87
+ const OPACITY = "opacity";
88
+ const Z_INDEX = "zIndex";
89
+ const transformLeafKey = (index, part) => `transform.${index}.${part}`;
90
+ const isInsetProperty = (property) => INSET_PROPERTIES.includes(property);
91
+ const isSizeProperty = (property) => SIZE_PROPERTIES.includes(property);
92
+ /**
93
+ * Whether this style's `property` is one of the insets that becomes a
94
+ * transform. A number is required rather than merely a `DimensionValue`: a
95
+ * percentage has no fixed offset from a point base, and switching to one
96
+ * mid-animation changes the leaf signature, which rebuilds the style and puts
97
+ * the property back on the refusal path where it belongs.
98
+ *
99
+ * The updater's object is not the whole style. `style={[styles.row, animated]}`
100
+ * is how most people write this, so `position` and the opposite edge are very
101
+ * often in a SIBLING entry that this module never sees. When the updater says
102
+ * nothing about `position`, the question is simply not answerable here and the
103
+ * leaf is made optimistically — the view layer re-asks it against the
104
+ * FLATTENED style, which is the only place the true answer exists, and warns
105
+ * there if the answer is no (components/animated.tsx). Nothing becomes silent
106
+ * either way; only which channel says it moves.
107
+ */
108
+ const isDriveableInset = (source, property) => {
109
+ if (!isInsetProperty(property) || typeof source[property] !== "number") {
110
+ return false;
111
+ }
112
+ return source.position === undefined
113
+ ? true
114
+ : insetTranslation(source, property) !== null;
115
+ };
116
+ // RN's layout properties, as `STYLE_PROPERTIES_CONFIG` enumerates them.
117
+ // Enumerated by hand rather than derived by subtracting the driveable set,
118
+ // because the point of the list is to produce a DIFFERENT message: these are
119
+ // refused for a measured reason and have a real alternative, which
120
+ // `borderStyle` does not.
121
+ const LAYOUT_PROPERTIES = new Set([
122
+ "aspectRatio",
123
+ "borderBottomWidth",
124
+ "borderEndWidth",
125
+ "borderLeftWidth",
126
+ "borderRightWidth",
127
+ "borderStartWidth",
128
+ "borderTopWidth",
129
+ "borderWidth",
130
+ "bottom",
131
+ "columnGap",
132
+ "end",
133
+ "flex",
134
+ "flexBasis",
135
+ "flexGrow",
136
+ "flexShrink",
137
+ "gap",
138
+ "height",
139
+ "left",
140
+ "margin",
141
+ "marginBottom",
142
+ "marginEnd",
143
+ "marginHorizontal",
144
+ "marginLeft",
145
+ "marginRight",
146
+ "marginStart",
147
+ "marginTop",
148
+ "marginVertical",
149
+ "maxHeight",
150
+ "maxWidth",
151
+ "minHeight",
152
+ "minWidth",
153
+ "padding",
154
+ "paddingBottom",
155
+ "paddingEnd",
156
+ "paddingHorizontal",
157
+ "paddingLeft",
158
+ "paddingRight",
159
+ "paddingStart",
160
+ "paddingTop",
161
+ "paddingVertical",
162
+ "right",
163
+ "rowGap",
164
+ "start",
165
+ "top",
166
+ "width",
167
+ ]);
168
+ // Which transform to reach for instead, in the two kinds it comes in. The
169
+ // distinction is not pedantry — `scaleX` was named as the replacement for
170
+ // `width` here and it is not one, which docs/research/animated-size.md §6
171
+ // measured on a 100×60 box widened to 260:
172
+ //
173
+ // - a scale grows about the view's CENTRE, so the box MOVES: x went 500 →
174
+ // 420, where the width change kept it at 500;
175
+ // - a scale scales the CONTENT with the box instead of re-laying it out: the
176
+ // label inside kept its three-line, 45 px-tall layout and was drawn 2.6×
177
+ // wide — stretched glyphs — where the width change re-wrapped it to one
178
+ // line, 15 px tall.
179
+ //
180
+ // So an inset really does have a transform that reproduces it, and a size does
181
+ // not. Offering `scaleX` as if it did sends people to a different behaviour
182
+ // with the same name on it — which is also why a numeric `width`/`height` is
183
+ // driven for real now and only reaches this table as a PERCENTAGE, where
184
+ // there is no point base to lay out at.
185
+ const EXACT_ALTERNATIVE = {
186
+ bottom: "translateY",
187
+ end: "translateX",
188
+ left: "translateX",
189
+ right: "translateX",
190
+ start: "translateX",
191
+ top: "translateY",
192
+ };
193
+ const APPROXIMATE_ALTERNATIVE = {
194
+ height: "scaleY",
195
+ width: "scaleX",
196
+ };
197
+ // One warning per property name per session, matching the platform's
198
+ // warnNativeDriverIgnored policy: a 60 Hz mapper must not produce 60 lines a
199
+ // second, and the name is the actionable part.
200
+ const warned = new Set();
201
+ const warnUndriveable = (property, source) => {
202
+ if (warned.has(property)) {
203
+ return;
204
+ }
205
+ warned.add(property);
206
+ const isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
207
+ if (isProduction) {
208
+ return;
209
+ }
210
+ const insetReason = isInsetProperty(property)
211
+ ? insetRefusalReason(source, property)
212
+ : null;
213
+ if (insetReason) {
214
+ console.warn(`react-native-reanimated: useAnimatedStyle changed \`${property}\`. This node IS absolutely ` +
215
+ `positioned — which is normally driven at frame rate here — but ${insetReason}, so no ` +
216
+ "translation reproduces it and it would need a Yoga pass. Give the axis a single edge (or a " +
217
+ `definite size) and \`${property}\` animates; otherwise animate ` +
218
+ `\`transform: [{ ${EXACT_ALTERNATIVE[property]}: … }]\`. The new value is applied on the next ` +
219
+ "React render. See docs/api.md.");
220
+ return;
221
+ }
222
+ if (LAYOUT_PROPERTIES.has(property)) {
223
+ const exact = EXACT_ALTERNATIVE[property];
224
+ const approximate = APPROXIMATE_ALTERNATIVE[property];
225
+ console.warn(`react-native-reanimated: useAnimatedStyle changed \`${property}\`, a LAYOUT property. ` +
226
+ "react-native-gtkx does not drive layout at frame rate on purpose: a layout write costs a Yoga " +
227
+ "pass over the container plus the commit walk that follows it, and that cost grows with the " +
228
+ "CONTAINER rather than with the number of animated values — measured at 52 µs for a five-child " +
229
+ "container and 496 µs at three hundred, against a transform's 1.5 µs. " +
230
+ (exact
231
+ ? `Animate \`transform: [{ ${exact}: … }]\` instead — it reproduces the move exactly, it is ` +
232
+ "paint-only, it costs the same at any tree size, and it is what RN's own native driver " +
233
+ "restricts you to. "
234
+ : approximate
235
+ ? `The closest transform is \`transform: [{ ${approximate}: … }]\`, but it is NOT the same ` +
236
+ "thing and it is worth knowing how: a scale grows about the view's CENTRE, so the box " +
237
+ "moves as it grows, and it scales the CONTENT with the box instead of re-laying it out — " +
238
+ "text stretches rather than re-wrapping. Reach for it when the content can take being " +
239
+ "stretched (a plain box, an image), not as a replacement. "
240
+ : "Transforms are paint-only and cost the same at any tree size. ") +
241
+ (isInsetProperty(property)
242
+ ? `(\`${property}\` IS driven at frame rate on a node whose own \`position\` is "absolute", ` +
243
+ "where moving it is exactly a translation and touches no sibling.) "
244
+ : isSizeProperty(property)
245
+ ? `(A NUMERIC \`${property}\` IS driven at frame rate where the change is confined to the node ` +
246
+ "that owns it. This one is a percentage, which has no point base to re-lay the subtree out " +
247
+ "at.) "
248
+ : "") +
249
+ "The new value is applied on the next React render. See docs/api.md.");
250
+ return;
251
+ }
252
+ console.warn(`react-native-reanimated: useAnimatedStyle changed \`${property}\`, which react-native-gtkx cannot ` +
253
+ "write to a mounted widget without a React render. `opacity`, `transform` and colours animate at " +
254
+ "frame rate here; the new value is applied on the next render instead. See docs/api.md.");
255
+ };
256
+ /** @internal Test seam: the warning is once per session by design. */
257
+ export const resetUndriveableWarnings = () => {
258
+ warned.clear();
259
+ };
260
+ /**
261
+ * Whether a property that finishes an animation has to be published through a
262
+ * React render to land at all.
263
+ *
264
+ * Every warning on the layout path ends with "the new value is applied on the
265
+ * next React render", and until now that was true only by luck: a value that
266
+ * moves solely inside a `useAnimatedStyle` produces no render, so the last
267
+ * frame of the animation was the last place it existed. `@gorhom/bottom-sheet`
268
+ * is exactly that case — it bounds its scrollable with an animated `height`
269
+ * and nothing else re-renders — and `spike/core-exports` is what found it.
270
+ *
271
+ * Layout properties only. `opacity`, `transform` and colours are written to
272
+ * the widget on the frame they change, so a render at the end would be a
273
+ * render for nothing; a `width`/`height` the driven-size rule ACCEPTS is on
274
+ * screen at the right size already, and the render is what puts the same value
275
+ * into Yoga so the committed layout and the override agree.
276
+ *
277
+ * At the end of the animation AND on a cadence while it runs, which is the
278
+ * correction §10 made to §9: the settle alone kept the promise only when the
279
+ * animation was short and never when its target moved every frame, and
280
+ * gorhom's sheet was blank for 1.38 s because of it. Ten renders a second at
281
+ * the very most, against sixty frames — still the whole difference between
282
+ * this and the naive layout write the refusal is about
283
+ * (docs/research/animated-size.md §3, and LANDING_INTERVAL_MS in
284
+ * ./updater-animations.ts for the numbers).
285
+ */
286
+ export const settlesThroughReact = (property) => LAYOUT_PROPERTIES.has(property);
287
+ /**
288
+ * Collects the animatable leaves of a style, in the order the view layer
289
+ * composes them (the transform array's order IS the composition order in RN).
290
+ */
291
+ const leavesOf = (source) => {
292
+ const leaves = [];
293
+ if (typeof source[OPACITY] === "number") {
294
+ leaves.push({ key: OPACITY, value: source[OPACITY] });
295
+ }
296
+ // Driven for real, and by the same kind of write opacity uses: the paint
297
+ // and pick order of the container (gtkx/bridge/view-box.ts). It has to be
298
+ // driveable rather than merely accepted — `useSortable` puts it in the
299
+ // style object on every frame, so a refusal here is a refusal of the whole
300
+ // sortable-list shape.
301
+ if (typeof source[Z_INDEX] === "number") {
302
+ leaves.push({ key: Z_INDEX, value: source[Z_INDEX] });
303
+ }
304
+ for (const property of DRIVEABLE_COLOR_PROPERTIES) {
305
+ const value = source[property];
306
+ // Strings only. A colour is a string on this platform (RN's packed
307
+ // integers never reach a GTK stylesheet), so a number here is not a
308
+ // colour we can drive and belongs on the warn path with everything else.
309
+ if (typeof value === "string") {
310
+ leaves.push({ key: property, value });
311
+ }
312
+ }
313
+ for (const property of INSET_PROPERTIES) {
314
+ if (isDriveableInset(source, property)) {
315
+ leaves.push({ key: property, value: source[property] });
316
+ }
317
+ }
318
+ // Sizes: a number is the whole of what can be decided HERE. Whether the
319
+ // change is confined to the node depends on the container's
320
+ // `flexDirection`, its `alignItems` and where its own size comes from —
321
+ // none of which is in the updater's object, and none of which is even in
322
+ // the animated component's props. So the leaf is made optimistically and
323
+ // the view layer, which has the layout tree, answers and warns
324
+ // (src/style/animated-size.ts, components/animated.tsx). A percentage stays
325
+ // on the refusal path: it has no point base to lay out at, and switching to
326
+ // one mid-animation changes the leaf signature, which rebuilds the style.
327
+ for (const property of SIZE_PROPERTIES) {
328
+ if (typeof source[property] === "number") {
329
+ leaves.push({ key: property, value: source[property] });
330
+ }
331
+ }
332
+ if (Array.isArray(source.transform)) {
333
+ source.transform.forEach((entry, index) => {
334
+ if (typeof entry !== "object" || entry === null) {
335
+ return;
336
+ }
337
+ const part = Object.keys(entry)[0];
338
+ if (part === undefined) {
339
+ return;
340
+ }
341
+ const value = entry[part];
342
+ if (isStyleValue(value)) {
343
+ leaves.push({ key: transformLeafKey(index, part), value });
344
+ }
345
+ });
346
+ }
347
+ return leaves;
348
+ };
349
+ const signatureOf = (leaves) => leaves.map((leaf) => leaf.key).join("|");
350
+ /**
351
+ * Builds the node-backed style. `reuse` carries nodes over from a previous
352
+ * build so a shape change keeps the identity of the leaves that survived it,
353
+ * which is what stops the view layer re-binding the parts that did not move.
354
+ */
355
+ export const createAnimatedStyle = (source, reuse) => {
356
+ const leaves = leavesOf(source);
357
+ const signature = signatureOf(leaves);
358
+ const nodes = new Map();
359
+ for (const leaf of leaves) {
360
+ const existing = reuse?.get(leaf.key);
361
+ if (existing) {
362
+ existing.__push(leaf.value);
363
+ nodes.set(leaf.key, existing);
364
+ }
365
+ else {
366
+ nodes.set(leaf.key, createStyleNode(leaf.value));
367
+ }
368
+ }
369
+ // Reassigned by `renew()` only. Every other write below — the node
370
+ // substitutions here, and `apply`'s update of a value it cannot drive — goes
371
+ // INTO the object currently published, so a renewed copy carries the latest
372
+ // of everything rather than a snapshot taken when it was made.
373
+ let style = { ...source };
374
+ const opacityNode = nodes.get(OPACITY);
375
+ if (opacityNode) {
376
+ style[OPACITY] = opacityNode;
377
+ }
378
+ const zIndexNode = nodes.get(Z_INDEX);
379
+ if (zIndexNode) {
380
+ style[Z_INDEX] = zIndexNode;
381
+ }
382
+ for (const property of DRIVEABLE_COLOR_PROPERTIES) {
383
+ const colorNode = nodes.get(property);
384
+ if (colorNode) {
385
+ style[property] = colorNode;
386
+ }
387
+ }
388
+ // The view layer duck-types these exactly as it does opacity and colours,
389
+ // and turns each into a translate measured from the position Yoga committed
390
+ // (components/animated.tsx, splitAnimated).
391
+ for (const property of INSET_PROPERTIES) {
392
+ const insetNode = nodes.get(property);
393
+ if (insetNode) {
394
+ style[property] = insetNode;
395
+ }
396
+ }
397
+ for (const property of SIZE_PROPERTIES) {
398
+ const sizeNode = nodes.get(property);
399
+ if (sizeNode) {
400
+ style[property] = sizeNode;
401
+ }
402
+ }
403
+ if (Array.isArray(source.transform)) {
404
+ style.transform = source.transform.map((entry, index) => {
405
+ if (typeof entry !== "object" || entry === null) {
406
+ return entry;
407
+ }
408
+ const part = Object.keys(entry)[0];
409
+ if (part === undefined) {
410
+ return entry;
411
+ }
412
+ const node = nodes.get(transformLeafKey(index, part));
413
+ return node ? { [part]: node } : entry;
414
+ });
415
+ }
416
+ // The last values seen for everything that is NOT node-backed, so a change
417
+ // can be reported rather than silently dropped.
418
+ let staticSnapshot = source;
419
+ return {
420
+ get style() {
421
+ return style;
422
+ },
423
+ nodes,
424
+ renew() {
425
+ style = { ...style };
426
+ },
427
+ apply(next) {
428
+ const nextLeaves = leavesOf(next);
429
+ if (signatureOf(nextLeaves) !== signature) {
430
+ return false;
431
+ }
432
+ for (const leaf of nextLeaves) {
433
+ nodes.get(leaf.key)?.__push(leaf.value);
434
+ }
435
+ for (const key of Object.keys(next)) {
436
+ if (key === OPACITY || key === "transform" || nodes.has(key)) {
437
+ continue;
438
+ }
439
+ if (!Object.is(next[key], staticSnapshot[key])) {
440
+ warnUndriveable(key, next);
441
+ // Kept up to date anyway: the next React render — whenever it
442
+ // happens, for whatever reason — then applies the current value
443
+ // rather than the one from mount.
444
+ style[key] = next[key];
445
+ }
446
+ }
447
+ staticSnapshot = next;
448
+ return true;
449
+ },
450
+ };
451
+ };
452
+ //# sourceMappingURL=style.js.map