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,311 @@
1
+ // Driving a built layout-animation config against a real GTK widget.
2
+ //
3
+ // The builders in layout-animation.ts produce upstream's own
4
+ // `{ initialValues, animations, callback }`, keyed by style property. This
5
+ // file is the half that knows where each of those properties can actually go
6
+ // on this platform, and it is the same three doors every other animated write
7
+ // here uses — `gtk_widget_set_opacity`, the rect store's transform, and (new)
8
+ // the rect store's layout offset. No React render, no Yoga pass, no second
9
+ // clock: every animation is built with the platform's own engine on the
10
+ // platform's own frame scheduler, exactly as `withTiming` on a shared value
11
+ // is.
12
+ //
13
+ // WHAT IS HONOURED, and the one thing that is not:
14
+ //
15
+ // `opacity` → the widget, per frame.
16
+ // `transform` → the rect store's transform slot, per frame.
17
+ // `originX` / `originY` → the rect store's LAYOUT offset, per frame, as the
18
+ // distance still to travel from where the child was
19
+ // to where the engine put it. This is what makes
20
+ // `LinearTransition` a paint-only animation.
21
+ // `width` / `height` → applied by the layout engine immediately, not
22
+ // animated. `LinearTransition` always emits them,
23
+ // and animating a size means a Yoga pass per frame
24
+ // whose cost is the tree's rather than the value's
25
+ // (63.9 µs at five children, 496.3 µs at three
26
+ // hundred — docs/research/animated-colors.md). This
27
+ // is the same refusal `useAnimatedStyle` already
28
+ // makes for layout properties, and it is the reason
29
+ // the position is animated with a translation.
30
+ //
31
+ // Anything else is named once, per property, per session — the platform's
32
+ // standing rule that an undriveable property must be visible rather than
33
+ // dropped.
34
+ import { clearStoredLayoutOffset, deferDuringAllocate, setStoredLayoutOffset, setStoredTransform, } from "../components/rect-store";
35
+ import { parseAngle } from "../style/transform";
36
+ import { queueAllocate } from "../gtkx/bridge/index";
37
+ import { buildAnimation, isAnimationSpec, } from "./animation";
38
+ // Emitted by LinearTransition on every run and honoured by the layout engine
39
+ // on the next commit rather than per frame — see the header.
40
+ const SIZE_PROPERTIES = new Set(["width", "height"]);
41
+ const warned = new Set();
42
+ const warnUndriveable = (property) => {
43
+ if (warned.has(property)) {
44
+ return;
45
+ }
46
+ warned.add(property);
47
+ const isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
48
+ if (isProduction) {
49
+ return;
50
+ }
51
+ console.warn(`react-native-reanimated: a layout animation asked for \`${property}\`, which react-native-gtkx cannot ` +
52
+ "write to a mounted widget without a React render. Layout animations drive `opacity`, `transform` and " +
53
+ "position here. See docs/api.md.");
54
+ };
55
+ /** @internal Test seam: the warning is once per property per session. */
56
+ export const resetLayoutAnimationWarnings = () => {
57
+ warned.clear();
58
+ };
59
+ const numberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
60
+ const clamp01 = (value) => Math.min(1, Math.max(0, value));
61
+ /**
62
+ * Runs one built config against one widget.
63
+ *
64
+ * `values` is what the builder was handed, and the runtime needs it back:
65
+ * `originX`/`originY` animate towards `target*`, so the offset to write is
66
+ * the driven value minus that target.
67
+ */
68
+ export const runLayoutAnimation = (engine, target, config, values, onEnd) => {
69
+ const { widget, parentWidget } = target;
70
+ // --- the three doors ---------------------------------------------------
71
+ // A `layout` transition's first write happens INSIDE a GTK allocation pass
72
+ // — the engine flushes there, the commit hands the new rect to the rect
73
+ // store, and the observer that starts this animation runs on that write —
74
+ // and queueing an allocation from inside one is what `deferDuringAllocate`
75
+ // exists to stop. Keyed on a token private to this animation so it can
76
+ // never displace the commit's own deferred job for the same widget.
77
+ const allocateToken = {};
78
+ // The container to re-allocate, and it is NOT always the one the caller
79
+ // named. An `entering` animation starts from a layout effect, and React
80
+ // attaches refs from the leaves up — so a view mounting in the same commit
81
+ // as its container sees `parentWidget` null, because the container's own
82
+ // ref has not been assigned yet. The widget is already PARENTED by then
83
+ // (the reconciler's mutation phase runs before any layout effect), so GTK
84
+ // itself has the answer. Without this, every transform- or position-driven
85
+ // entering animation wrote its frames into the rect store and never asked
86
+ // anyone to draw them: the first allocation picked up the initial value and
87
+ // the view froze there — a `ZoomIn` that mounts at scale 0 and stays.
88
+ let container = parentWidget;
89
+ const requestAllocate = () => {
90
+ container ??= widget.getParent();
91
+ const containerWidget = container;
92
+ if (!containerWidget) {
93
+ return;
94
+ }
95
+ const queue = () => queueAllocate(containerWidget);
96
+ if (!deferDuringAllocate(allocateToken, queue)) {
97
+ queue();
98
+ }
99
+ };
100
+ // The live transform array, mutated in place and re-published whole, the
101
+ // same shape src/components/animated.tsx keeps for a driven style.
102
+ let transformParts = [];
103
+ const flushTransform = () => {
104
+ setStoredTransform(widget, transformParts);
105
+ requestAllocate();
106
+ };
107
+ let offsetX = 0;
108
+ let offsetY = 0;
109
+ let hasOffset = false;
110
+ const flushOffset = () => {
111
+ hasOffset = true;
112
+ setStoredLayoutOffset(widget, offsetX, offsetY);
113
+ requestAllocate();
114
+ };
115
+ const opacityChannel = {
116
+ apply(value) {
117
+ const numeric = numberOrNull(value);
118
+ if (numeric !== null) {
119
+ widget.setOpacity(clamp01(numeric));
120
+ }
121
+ },
122
+ start(value) {
123
+ return numberOrNull(value);
124
+ },
125
+ push(value) {
126
+ widget.setOpacity(clamp01(value));
127
+ },
128
+ };
129
+ const originChannel = (axis) => {
130
+ const targetValue = axis === "x" ? values.targetOriginX : values.targetOriginY;
131
+ const write = (offset) => {
132
+ if (axis === "x") {
133
+ offsetX = offset;
134
+ }
135
+ else {
136
+ offsetY = offset;
137
+ }
138
+ flushOffset();
139
+ };
140
+ return {
141
+ apply(value) {
142
+ const numeric = numberOrNull(value);
143
+ if (numeric !== null) {
144
+ write(numeric - targetValue);
145
+ }
146
+ },
147
+ start(value) {
148
+ return numberOrNull(value);
149
+ },
150
+ push(value) {
151
+ write(value - targetValue);
152
+ },
153
+ };
154
+ };
155
+ // An angle slot takes upstream's own spelling as well as a number: the
156
+ // catalogue emits degrees (a numeric animation cannot carry a unit), but
157
+ // `.withInitialValues({ transform: [{ rotate: "45deg" }] })` is written by
158
+ // hand and would otherwise be dropped as "not a number". `parseAngle` is
159
+ // the same reader src/style/transform.ts uses to build the matrix, so both
160
+ // spellings land on the same rotation.
161
+ const ANGLE_KEYS = new Set(["rotate", "rotateZ"]);
162
+ const transformChannel = (index, key) => {
163
+ const read = ANGLE_KEYS.has(key)
164
+ ? (value) => parseAngle(value)
165
+ : numberOrNull;
166
+ return {
167
+ apply(value) {
168
+ const numeric = read(value);
169
+ if (numeric !== null) {
170
+ transformParts[index] = { [key]: numeric };
171
+ flushTransform();
172
+ }
173
+ },
174
+ start(value) {
175
+ return read(value);
176
+ },
177
+ push(value) {
178
+ transformParts[index] = { [key]: value };
179
+ flushTransform();
180
+ },
181
+ };
182
+ };
183
+ // --- initial values ----------------------------------------------------
184
+ const channelFor = (property) => {
185
+ if (property === "opacity") {
186
+ return opacityChannel;
187
+ }
188
+ if (property === "originX") {
189
+ return originChannel("x");
190
+ }
191
+ if (property === "originY") {
192
+ return originChannel("y");
193
+ }
194
+ if (SIZE_PROPERTIES.has(property)) {
195
+ return null;
196
+ }
197
+ warnUndriveable(property);
198
+ return null;
199
+ };
200
+ const eachTransformEntry = (source, visit) => {
201
+ if (!Array.isArray(source)) {
202
+ return;
203
+ }
204
+ source.forEach((entry, index) => {
205
+ if (typeof entry !== "object" || entry === null) {
206
+ return;
207
+ }
208
+ for (const [key, value] of Object.entries(entry)) {
209
+ visit(index, key, value);
210
+ }
211
+ });
212
+ };
213
+ // The transform array is seeded whole from the initial values so a static
214
+ // entry beside an animated one keeps its place in the composition order.
215
+ const initialTransform = config.initialValues.transform;
216
+ if (Array.isArray(initialTransform)) {
217
+ transformParts = initialTransform.map((entry) => typeof entry === "object" && entry !== null
218
+ ? { ...entry }
219
+ : {});
220
+ flushTransform();
221
+ }
222
+ for (const [property, value] of Object.entries(config.initialValues)) {
223
+ if (property === "transform") {
224
+ continue;
225
+ }
226
+ channelFor(property)?.apply(value);
227
+ }
228
+ const jobs = [];
229
+ const collect = (property, value, channel, initial) => {
230
+ if (channel === null) {
231
+ return;
232
+ }
233
+ if (!isAnimationSpec(value)) {
234
+ channel.apply(value);
235
+ return;
236
+ }
237
+ const from = channel.start(initial);
238
+ if (from === null) {
239
+ warnUndriveable(property);
240
+ return;
241
+ }
242
+ jobs.push({ channel, spec: value, from });
243
+ };
244
+ for (const [property, value] of Object.entries(config.animations)) {
245
+ if (property === "transform") {
246
+ eachTransformEntry(value, (index, key, entry) => {
247
+ const initial = transformParts[index]?.[key];
248
+ collect(`transform.${key}`, entry, transformChannel(index, key), initial);
249
+ });
250
+ continue;
251
+ }
252
+ collect(property, value, channelFor(property), config.initialValues[property]);
253
+ }
254
+ const running = [];
255
+ let settled = false;
256
+ let pending = jobs.length;
257
+ let allFinished = true;
258
+ const finish = () => {
259
+ if (settled) {
260
+ return;
261
+ }
262
+ settled = true;
263
+ if (hasOffset) {
264
+ clearStoredLayoutOffset(widget);
265
+ requestAllocate();
266
+ }
267
+ config.callback?.(allFinished);
268
+ onEnd?.(allFinished);
269
+ };
270
+ for (const job of jobs) {
271
+ const driver = new engine.api.Value(job.from);
272
+ const listener = driver.addListener(({ value }) => {
273
+ job.channel.push(value);
274
+ });
275
+ const animation = buildAnimation(engine, driver, job.spec);
276
+ running.push({
277
+ stop: () => {
278
+ animation.stop();
279
+ driver.removeListener(listener);
280
+ },
281
+ });
282
+ animation.start((result) => {
283
+ driver.removeListener(listener);
284
+ if (!result.finished) {
285
+ allFinished = false;
286
+ }
287
+ pending -= 1;
288
+ if (pending === 0) {
289
+ finish();
290
+ }
291
+ });
292
+ }
293
+ if (jobs.length === 0) {
294
+ // Nothing to drive is still a completed animation: whoever is holding a
295
+ // widget for this must be released, or it is held until the timer.
296
+ finish();
297
+ }
298
+ return {
299
+ stop() {
300
+ if (settled) {
301
+ return;
302
+ }
303
+ allFinished = false;
304
+ for (const animation of running) {
305
+ animation.stop();
306
+ }
307
+ finish();
308
+ },
309
+ };
310
+ };
311
+ //# sourceMappingURL=layout-animation-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-animation-runtime.js","sourceRoot":"","sources":["../../src/reanimated-compat/layout-animation-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// Driving a built layout-animation config against a real GTK widget.\n//\n// The builders in layout-animation.ts produce upstream's own\n// `{ initialValues, animations, callback }`, keyed by style property. This\n// file is the half that knows where each of those properties can actually go\n// on this platform, and it is the same three doors every other animated write\n// here uses — `gtk_widget_set_opacity`, the rect store's transform, and (new)\n// the rect store's layout offset. No React render, no Yoga pass, no second\n// clock: every animation is built with the platform's own engine on the\n// platform's own frame scheduler, exactly as `withTiming` on a shared value\n// is.\n//\n// WHAT IS HONOURED, and the one thing that is not:\n//\n// `opacity` → the widget, per frame.\n// `transform` → the rect store's transform slot, per frame.\n// `originX` / `originY` → the rect store's LAYOUT offset, per frame, as the\n// distance still to travel from where the child was\n// to where the engine put it. This is what makes\n// `LinearTransition` a paint-only animation.\n// `width` / `height` → applied by the layout engine immediately, not\n// animated. `LinearTransition` always emits them,\n// and animating a size means a Yoga pass per frame\n// whose cost is the tree's rather than the value's\n// (63.9 µs at five children, 496.3 µs at three\n// hundred — docs/research/animated-colors.md). This\n// is the same refusal `useAnimatedStyle` already\n// makes for layout properties, and it is the reason\n// the position is animated with a translation.\n//\n// Anything else is named once, per property, per session — the platform's\n// standing rule that an undriveable property must be visible rather than\n// dropped.\nimport {\n clearStoredLayoutOffset,\n deferDuringAllocate,\n setStoredLayoutOffset,\n setStoredTransform,\n} from \"../components/rect-store\"\nimport { parseAngle } from \"../style/transform\"\nimport type { TransformPart } from \"../contracts\"\nimport type { Gtk } from \"../gtkx/bridge/index\"\nimport { queueAllocate } from \"../gtkx/bridge/index\"\nimport {\n buildAnimation,\n isAnimationSpec,\n type AnimationEngine,\n type AnimationSpec,\n} from \"./animation\"\nimport type {\n BuiltLayoutAnimation,\n LayoutAnimationValues,\n} from \"./layout-animation\"\n\nexport type LayoutAnimationTarget = {\n widget: Gtk.Widget\n parentWidget: Gtk.Widget | null\n}\n\nexport type RunningLayoutAnimation = {\n /** Cuts the animation short. The callback still fires, with `false`. */\n stop(): void\n}\n\n// Emitted by LinearTransition on every run and honoured by the layout engine\n// on the next commit rather than per frame — see the header.\nconst SIZE_PROPERTIES = new Set([\"width\", \"height\"])\n\nconst warned = new Set<string>()\n\nconst warnUndriveable = (property: string): void => {\n if (warned.has(property)) {\n return\n }\n warned.add(property)\n const isProduction =\n typeof process !== \"undefined\" && process.env.NODE_ENV === \"production\"\n if (isProduction) {\n return\n }\n console.warn(\n `react-native-reanimated: a layout animation asked for \\`${property}\\`, which react-native-gtkx cannot ` +\n \"write to a mounted widget without a React render. Layout animations drive `opacity`, `transform` and \" +\n \"position here. See docs/api.md.\",\n )\n}\n\n/** @internal Test seam: the warning is once per property per session. */\nexport const resetLayoutAnimationWarnings = (): void => {\n warned.clear()\n}\n\nconst numberOrNull = (value: unknown): number | null =>\n typeof value === \"number\" && Number.isFinite(value) ? value : null\n\ntype Channel = {\n /** Applies an immediate value from `initialValues`. */\n apply(value: unknown): void\n /** The value an animation on this property should start from. */\n start(value: unknown): number | null\n /** Pushes a driven value. */\n push(value: number): void\n}\n\nconst clamp01 = (value: number): number => Math.min(1, Math.max(0, value))\n\n/**\n * Runs one built config against one widget.\n *\n * `values` is what the builder was handed, and the runtime needs it back:\n * `originX`/`originY` animate towards `target*`, so the offset to write is\n * the driven value minus that target.\n */\nexport const runLayoutAnimation = (\n engine: AnimationEngine,\n target: LayoutAnimationTarget,\n config: BuiltLayoutAnimation,\n values: LayoutAnimationValues,\n onEnd?: (finished: boolean) => void,\n): RunningLayoutAnimation => {\n const { widget, parentWidget } = target\n\n // --- the three doors ---------------------------------------------------\n\n // A `layout` transition's first write happens INSIDE a GTK allocation pass\n // — the engine flushes there, the commit hands the new rect to the rect\n // store, and the observer that starts this animation runs on that write —\n // and queueing an allocation from inside one is what `deferDuringAllocate`\n // exists to stop. Keyed on a token private to this animation so it can\n // never displace the commit's own deferred job for the same widget.\n const allocateToken = {}\n\n // The container to re-allocate, and it is NOT always the one the caller\n // named. An `entering` animation starts from a layout effect, and React\n // attaches refs from the leaves up — so a view mounting in the same commit\n // as its container sees `parentWidget` null, because the container's own\n // ref has not been assigned yet. The widget is already PARENTED by then\n // (the reconciler's mutation phase runs before any layout effect), so GTK\n // itself has the answer. Without this, every transform- or position-driven\n // entering animation wrote its frames into the rect store and never asked\n // anyone to draw them: the first allocation picked up the initial value and\n // the view froze there — a `ZoomIn` that mounts at scale 0 and stays.\n let container: Gtk.Widget | null = parentWidget\n const requestAllocate = (): void => {\n container ??= widget.getParent() as Gtk.Widget | null\n const containerWidget = container\n if (!containerWidget) {\n return\n }\n const queue = (): void => queueAllocate(containerWidget)\n if (!deferDuringAllocate(allocateToken, queue)) {\n queue()\n }\n }\n\n // The live transform array, mutated in place and re-published whole, the\n // same shape src/components/animated.tsx keeps for a driven style.\n let transformParts: Record<string, number | string>[] = []\n const flushTransform = (): void => {\n setStoredTransform(widget, transformParts as unknown as TransformPart[])\n requestAllocate()\n }\n\n let offsetX = 0\n let offsetY = 0\n let hasOffset = false\n const flushOffset = (): void => {\n hasOffset = true\n setStoredLayoutOffset(widget, offsetX, offsetY)\n requestAllocate()\n }\n\n const opacityChannel: Channel = {\n apply(value) {\n const numeric = numberOrNull(value)\n if (numeric !== null) {\n widget.setOpacity(clamp01(numeric))\n }\n },\n start(value) {\n return numberOrNull(value)\n },\n push(value) {\n widget.setOpacity(clamp01(value))\n },\n }\n\n const originChannel = (axis: \"x\" | \"y\"): Channel => {\n const targetValue =\n axis === \"x\" ? values.targetOriginX : values.targetOriginY\n const write = (offset: number): void => {\n if (axis === \"x\") {\n offsetX = offset\n } else {\n offsetY = offset\n }\n flushOffset()\n }\n return {\n apply(value) {\n const numeric = numberOrNull(value)\n if (numeric !== null) {\n write(numeric - targetValue)\n }\n },\n start(value) {\n return numberOrNull(value)\n },\n push(value) {\n write(value - targetValue)\n },\n }\n }\n\n // An angle slot takes upstream's own spelling as well as a number: the\n // catalogue emits degrees (a numeric animation cannot carry a unit), but\n // `.withInitialValues({ transform: [{ rotate: \"45deg\" }] })` is written by\n // hand and would otherwise be dropped as \"not a number\". `parseAngle` is\n // the same reader src/style/transform.ts uses to build the matrix, so both\n // spellings land on the same rotation.\n const ANGLE_KEYS = new Set([\"rotate\", \"rotateZ\"])\n\n const transformChannel = (index: number, key: string): Channel => {\n const read = ANGLE_KEYS.has(key)\n ? (value: unknown): number | null => parseAngle(value)\n : numberOrNull\n return {\n apply(value) {\n const numeric = read(value)\n if (numeric !== null) {\n transformParts[index] = { [key]: numeric }\n flushTransform()\n }\n },\n start(value) {\n return read(value)\n },\n push(value) {\n transformParts[index] = { [key]: value }\n flushTransform()\n },\n }\n }\n\n // --- initial values ----------------------------------------------------\n\n const channelFor = (property: string): Channel | null => {\n if (property === \"opacity\") {\n return opacityChannel\n }\n if (property === \"originX\") {\n return originChannel(\"x\")\n }\n if (property === \"originY\") {\n return originChannel(\"y\")\n }\n if (SIZE_PROPERTIES.has(property)) {\n return null\n }\n warnUndriveable(property)\n return null\n }\n\n const eachTransformEntry = (\n source: unknown,\n visit: (index: number, key: string, value: unknown) => void,\n ): void => {\n if (!Array.isArray(source)) {\n return\n }\n source.forEach((entry, index) => {\n if (typeof entry !== \"object\" || entry === null) {\n return\n }\n for (const [key, value] of Object.entries(entry)) {\n visit(index, key, value)\n }\n })\n }\n\n // The transform array is seeded whole from the initial values so a static\n // entry beside an animated one keeps its place in the composition order.\n const initialTransform = config.initialValues.transform\n if (Array.isArray(initialTransform)) {\n transformParts = initialTransform.map((entry) =>\n typeof entry === \"object\" && entry !== null\n ? ({ ...entry } as Record<string, number | string>)\n : {},\n )\n flushTransform()\n }\n\n for (const [property, value] of Object.entries(config.initialValues)) {\n if (property === \"transform\") {\n continue\n }\n channelFor(property)?.apply(value)\n }\n\n // --- the animations ----------------------------------------------------\n\n type Job = { channel: Channel; spec: AnimationSpec; from: number }\n const jobs: Job[] = []\n\n const collect = (\n property: string,\n value: unknown,\n channel: Channel | null,\n initial: unknown,\n ): void => {\n if (channel === null) {\n return\n }\n if (!isAnimationSpec(value)) {\n channel.apply(value)\n return\n }\n const from = channel.start(initial)\n if (from === null) {\n warnUndriveable(property)\n return\n }\n jobs.push({ channel, spec: value, from })\n }\n\n for (const [property, value] of Object.entries(config.animations)) {\n if (property === \"transform\") {\n eachTransformEntry(value, (index, key, entry) => {\n const initial = transformParts[index]?.[key]\n collect(\n `transform.${key}`,\n entry,\n transformChannel(index, key),\n initial,\n )\n })\n continue\n }\n collect(\n property,\n value,\n channelFor(property),\n config.initialValues[property],\n )\n }\n\n const running: { stop(): void }[] = []\n let settled = false\n let pending = jobs.length\n let allFinished = true\n\n const finish = (): void => {\n if (settled) {\n return\n }\n settled = true\n if (hasOffset) {\n clearStoredLayoutOffset(widget)\n requestAllocate()\n }\n config.callback?.(allFinished)\n onEnd?.(allFinished)\n }\n\n for (const job of jobs) {\n const driver = new engine.api.Value(job.from)\n const listener = driver.addListener(({ value }) => {\n job.channel.push(value)\n })\n const animation = buildAnimation(engine, driver, job.spec)\n running.push({\n stop: () => {\n animation.stop()\n driver.removeListener(listener)\n },\n })\n animation.start((result) => {\n driver.removeListener(listener)\n if (!result.finished) {\n allFinished = false\n }\n pending -= 1\n if (pending === 0) {\n finish()\n }\n })\n }\n\n if (jobs.length === 0) {\n // Nothing to drive is still a completed animation: whoever is holding a\n // widget for this must be released, or it is held until the timer.\n finish()\n }\n\n return {\n stop() {\n if (settled) {\n return\n }\n allFinished = false\n for (const animation of running) {\n animation.stop()\n }\n finish()\n },\n }\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { type ComponentProps, type ElementType, type ReactNode } from "react";
2
+ import type { LayoutAnimationBuilderLike } from "./layout-animation";
3
+ /** What `entering`, `exiting` and `layout` accept: a builder, or its class. */
4
+ export type LayoutAnimationProps = {
5
+ /** Runs once, when the component mounts. */
6
+ entering?: LayoutAnimationBuilderLike | false | null;
7
+ /**
8
+ * Runs when the component unmounts, on a widget the platform keeps on
9
+ * screen for the duration. Ignored when the component's own container is
10
+ * unmounting in the same commit — there would be nothing left to animate
11
+ * inside.
12
+ */
13
+ exiting?: LayoutAnimationBuilderLike | false | null;
14
+ /** Runs whenever the layout engine commits a new position for this child. */
15
+ layout?: LayoutAnimationBuilderLike | false | null;
16
+ };
17
+ /** @internal Test seam: the warning is once per component per session. */
18
+ export declare const resetLayoutAnimationComponentWarnings: () => void;
19
+ /** The props a layout-animated wrapper adds on top of the component's own. */
20
+ export type LayoutAnimatedComponent<C extends ElementType> = (props: ComponentProps<C> & LayoutAnimationProps) => ReactNode;
21
+ /**
22
+ * Adds `entering`, `exiting` and `layout` to an animated component.
23
+ *
24
+ * The rendered output is byte-for-byte what the wrapped component produces —
25
+ * the wrapper is a function component with no host element of its own.
26
+ */
27
+ export declare const withLayoutAnimations: <C extends ElementType>(component: C) => LayoutAnimatedComponent<C>;
@@ -0,0 +1,266 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // `entering`, `exiting` and `layout` on an animated component.
3
+ //
4
+ // The three props are added by WRAPPING, not by changing the platform's
5
+ // `Animated.View`: the wrapper renders the component it was given, adds no
6
+ // widget to the tree, and reaches the real one through the handle that
7
+ // component already exposes — the same seam `createAnimatedComponent` uses.
8
+ // That is what lets `Animated.Text` and anything through
9
+ // `createAnimatedComponent` take a layout animation on exactly the same
10
+ // terms as `Animated.View`.
11
+ //
12
+ // WHY THE WRAPPER IS WHERE `exiting` LIVES, and this is the whole reason it
13
+ // exists as a component rather than a hook inside the platform: React runs a
14
+ // deleted subtree's layout-effect cleanups from the OUTSIDE IN, and unparents
15
+ // its topmost widget last. A cleanup registered here — one component above
16
+ // the one that owns the widget — therefore runs at the only moment when the
17
+ // widget is still parented, its Yoga node still alive and its layout manager
18
+ // still attached. It hands all three to the platform's retention primitive
19
+ // (src/components/widget-retention.ts), which puts the widget back after the
20
+ // reconciler takes it out and holds everything else until the fade ends or
21
+ // the fallback timer fires.
22
+ //
23
+ // The other two need nothing new. `entering` is "write the initial values on
24
+ // mount and animate to the real ones"; `layout` is "the engine committed a
25
+ // different rect for this child, so walk it there from where it was" — both
26
+ // are snapshot-measure-animate, which is exactly what upstream's own web
27
+ // implementation does on its single thread.
28
+ import { useInsertionEffect, useLayoutEffect, useRef, useState, } from "react";
29
+ import { Dimensions } from "../apis/index";
30
+ import { Animated as PlatformAnimated } from "../components/animated";
31
+ import { glibScheduler } from "../components/frame-scheduler";
32
+ import { useHostNode } from "../components/host-node";
33
+ import { widgetForHandle } from "../components/measure";
34
+ import { getStoredLayoutOffset, getStoredRect, observeStoredRect, } from "../components/rect-store";
35
+ import { retainWidget, } from "../components/widget-retention";
36
+ import { computePointInWindow } from "../gtkx/bridge/index";
37
+ import { useLayoutAnimationSkip } from "./layout-animation-config";
38
+ import { runLayoutAnimation, } from "./layout-animation-runtime";
39
+ /**
40
+ * How much longer than the animation itself a widget may be retained before
41
+ * the fallback drops it. The timer exists for the case where the animation
42
+ * never reports an end at all, so the margin only has to cover the ordinary
43
+ * jitter of a frame source — not a whole animation.
44
+ */
45
+ const RETENTION_MARGIN_MS = 500;
46
+ const ZERO_RECT = { x: 0, y: 0, width: 0, height: 0 };
47
+ // The platform's own Animated api and the frame scheduler behind it: the same
48
+ // pair every other animation in this surface runs on, so a layout animation
49
+ // adds no second clock.
50
+ const ENGINE = {
51
+ api: PlatformAnimated,
52
+ scheduler: glibScheduler,
53
+ };
54
+ const retainForExit = (widget, parentWidget, builder, stop) => retainWidget(widget, parentWidget, {
55
+ // The fallback covers a frame source that never delivers an end, so it
56
+ // only has to outlast the animation the builder describes.
57
+ fallbackMs: builder.getMaxDuration() + RETENTION_MARGIN_MS,
58
+ onRelease: stop,
59
+ });
60
+ const warnedWithoutWidget = new Set();
61
+ const warnNoWidget = (name) => {
62
+ if (warnedWithoutWidget.has(name)) {
63
+ return;
64
+ }
65
+ warnedWithoutWidget.add(name);
66
+ const isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
67
+ if (!isProduction) {
68
+ console.warn(`react-native-reanimated: ${name} was given an \`entering\`, \`exiting\` or \`layout\` animation, but ` +
69
+ "the component exposed no ref carrying a widget, so there is nothing to animate. Put the animation on " +
70
+ "an `Animated.View`, or give the component a `ref` built with the platform's own measure handle. " +
71
+ "See docs/api.md.");
72
+ }
73
+ };
74
+ /** @internal Test seam: the warning is once per component per session. */
75
+ export const resetLayoutAnimationComponentWarnings = () => {
76
+ warnedWithoutWidget.clear();
77
+ };
78
+ const valuesFor = (widget, current, target) => {
79
+ const window = Dimensions.get("window");
80
+ // One FFI call per animation START (never per frame), so a builder reading
81
+ // the global origin gets a real answer rather than a parent-relative one
82
+ // wearing its name.
83
+ const page = computePointInWindow(widget, 0, 0);
84
+ const dx = page ? page.x - target.x : 0;
85
+ const dy = page ? page.y - target.y : 0;
86
+ return {
87
+ targetOriginX: target.x,
88
+ targetOriginY: target.y,
89
+ targetWidth: target.width,
90
+ targetHeight: target.height,
91
+ targetGlobalOriginX: target.x + dx,
92
+ targetGlobalOriginY: target.y + dy,
93
+ currentOriginX: current.x,
94
+ currentOriginY: current.y,
95
+ currentWidth: current.width,
96
+ currentHeight: current.height,
97
+ currentGlobalOriginX: current.x + dx,
98
+ currentGlobalOriginY: current.y + dy,
99
+ windowWidth: window.width,
100
+ windowHeight: window.height,
101
+ };
102
+ };
103
+ const displayNameOf = (component) => {
104
+ if (typeof component === "string") {
105
+ return component;
106
+ }
107
+ const named = component;
108
+ return named?.displayName ?? named?.name ?? "Component";
109
+ };
110
+ /**
111
+ * Adds `entering`, `exiting` and `layout` to an animated component.
112
+ *
113
+ * The rendered output is byte-for-byte what the wrapped component produces —
114
+ * the wrapper is a function component with no host element of its own.
115
+ */
116
+ export const withLayoutAnimations = (component) => {
117
+ const name = displayNameOf(component);
118
+ const LayoutAnimated = ({ entering, exiting, layout, ref, ...rest }) => {
119
+ const host = useHostNode();
120
+ const handleRef = useRef(null);
121
+ // Null unless a `<LayoutAnimationConfig>` is above. Captured once and read
122
+ // from inside the effects below: the object identity is stable for the
123
+ // life of that wrapper, and both of its flags are only meaningful at the
124
+ // moment the effect (or its cleanup) actually runs.
125
+ const skip = useLayoutAnimationSkip();
126
+ // Read by an unmount cleanup and by a rect observer, both of which
127
+ // outlive the render that produced them. Refreshed in an insertion effect
128
+ // — the project's standard escape from writing a ref during render, and
129
+ // early enough that a layout effect in the same commit sees it.
130
+ const exitingRef = useRef(exiting ?? null);
131
+ const layoutRef = useRef(layout ?? null);
132
+ const forwardedRef = useRef(ref);
133
+ useInsertionEffect(() => {
134
+ exitingRef.current = exiting ?? null;
135
+ layoutRef.current = layout ?? null;
136
+ forwardedRef.current = ref;
137
+ });
138
+ // Stable identity: a fresh callback ref every render would detach and
139
+ // reattach the wrapped component's handle on every render.
140
+ const [assignHandle] = useState(() => (instance) => {
141
+ handleRef.current = instance;
142
+ const target = forwardedRef.current;
143
+ if (typeof target === "function") {
144
+ target(instance);
145
+ }
146
+ else if (target) {
147
+ ;
148
+ target.current = instance;
149
+ }
150
+ // No return value: React 19 reads one as a callback-ref cleanup.
151
+ });
152
+ const parentWidgetRef = host.widgetRef;
153
+ // --- entering --------------------------------------------------------
154
+ // Never refreshed, unlike the two above: an entering animation runs once,
155
+ // on mount, so the builder that counts is the one this component was
156
+ // mounted with.
157
+ const enteringRef = useRef(entering ?? null);
158
+ useLayoutEffect(() => {
159
+ const builder = enteringRef.current;
160
+ if (!builder || skip?.entering.current) {
161
+ return;
162
+ }
163
+ const widget = widgetForHandle(handleRef.current);
164
+ if (!widget) {
165
+ warnNoWidget(name);
166
+ return;
167
+ }
168
+ const rect = getStoredRect(widget) ?? ZERO_RECT;
169
+ const values = valuesFor(widget, rect, rect);
170
+ const running = runLayoutAnimation(ENGINE, { widget, parentWidget: parentWidgetRef.current }, builder.build()(values), values);
171
+ return () => running.stop();
172
+ // eslint-disable-next-line react-hooks/exhaustive-deps
173
+ }, []);
174
+ // --- layout ----------------------------------------------------------
175
+ // Keyed on whether there IS a layout animation, not on which one: a rect
176
+ // observer is what turns on the rect store's notify path, and a view that
177
+ // never asked for a layout transition must not pay for it.
178
+ const hasLayout = Boolean(layout);
179
+ useLayoutEffect(() => {
180
+ if (!hasLayout) {
181
+ return;
182
+ }
183
+ const widget = widgetForHandle(handleRef.current);
184
+ if (!widget) {
185
+ warnNoWidget(name);
186
+ return;
187
+ }
188
+ let running = null;
189
+ const unobserve = observeStoredRect(widget, (next, previous) => {
190
+ const builder = layoutRef.current;
191
+ // Nothing to walk from on the first commit, and a pure resize has no
192
+ // position to animate — the size lands immediately either way.
193
+ if (!builder || previous === undefined) {
194
+ return;
195
+ }
196
+ if (previous.x === next.x && previous.y === next.y) {
197
+ return;
198
+ }
199
+ // Where the child is being DRAWN right now, which is the rect it had
200
+ // plus whatever a transition still in flight has added to it.
201
+ const offset = getStoredLayoutOffset(widget);
202
+ const drawn = {
203
+ x: previous.x + offset.dx,
204
+ y: previous.y + offset.dy,
205
+ width: previous.width,
206
+ height: previous.height,
207
+ };
208
+ running?.stop();
209
+ const values = valuesFor(widget, drawn, next);
210
+ running = runLayoutAnimation(ENGINE, { widget, parentWidget: parentWidgetRef.current }, builder.build()(values), values, () => {
211
+ running = null;
212
+ });
213
+ });
214
+ return () => {
215
+ unobserve();
216
+ running?.stop();
217
+ };
218
+ // eslint-disable-next-line react-hooks/exhaustive-deps
219
+ }, [hasLayout]);
220
+ // --- exiting ---------------------------------------------------------
221
+ // Declared last so its cleanup runs after the other two have stopped
222
+ // whatever they were driving: React tears a component's layout effects
223
+ // down in the order they were created.
224
+ useLayoutEffect(() => {
225
+ return () => {
226
+ const builder = exitingRef.current;
227
+ // `skip.exiting` is set by a `<LayoutAnimationConfig skipExiting>`
228
+ // above us, whose own cleanup React already ran — deletions tear down
229
+ // outside in, which is the same ordering `exiting` itself relies on.
230
+ if (!builder || skip?.exiting.current) {
231
+ return;
232
+ }
233
+ const widget = widgetForHandle(handleRef.current);
234
+ // Read HERE and not captured when the effect ran, which is the whole
235
+ // point: null means this component's own container is unmounting in
236
+ // the same commit (React detaches the container's ref before
237
+ // descending into it), and there is then no container left to hold
238
+ // the widget — an exit animation inside a disappearing parent is not
239
+ // one anybody sees.
240
+ // eslint-disable-next-line react-hooks/exhaustive-deps
241
+ const parentWidget = parentWidgetRef.current;
242
+ if (!widget || !parentWidget) {
243
+ return;
244
+ }
245
+ const rect = getStoredRect(widget) ?? ZERO_RECT;
246
+ const values = valuesFor(widget, rect, rect);
247
+ let running = null;
248
+ const retention = retainForExit(widget, parentWidget, builder, () => running?.stop());
249
+ if (retention === null) {
250
+ return;
251
+ }
252
+ running = runLayoutAnimation(ENGINE, { widget, parentWidget }, builder.build()(values), values, () => retention.release());
253
+ };
254
+ // eslint-disable-next-line react-hooks/exhaustive-deps
255
+ }, []);
256
+ const targetProps = { ...rest };
257
+ if (entering || exiting || layout || ref) {
258
+ targetProps.ref = assignHandle;
259
+ }
260
+ const Target = component;
261
+ return _jsx(Target, { ...targetProps });
262
+ };
263
+ LayoutAnimated.displayName = `LayoutAnimated(${name})`;
264
+ return LayoutAnimated;
265
+ };
266
+ //# sourceMappingURL=layout-animation-view.js.map