@rafaelaugusto/jolt 0.1.0-beta.9 → 0.1.0-rc.2

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 (576) hide show
  1. package/README.md +167 -21
  2. package/dist/animate.d.ts +25 -4
  3. package/dist/animate.d.ts.map +1 -1
  4. package/dist/animate.js +67 -26
  5. package/dist/animate.js.map +1 -1
  6. package/dist/blur/index.d.ts +6 -0
  7. package/dist/blur/index.d.ts.map +1 -0
  8. package/dist/blur/index.js +196 -0
  9. package/dist/blur/index.js.map +1 -0
  10. package/dist/blur/native.d.ts +17 -0
  11. package/dist/blur/native.d.ts.map +1 -0
  12. package/dist/blur/native.js +44 -0
  13. package/dist/blur/native.js.map +1 -0
  14. package/dist/blur/types.d.ts +32 -0
  15. package/dist/blur/types.d.ts.map +1 -0
  16. package/dist/blur/types.js +2 -0
  17. package/dist/blur/types.js.map +1 -0
  18. package/dist/bottom-sheet/geometry.d.ts +18 -0
  19. package/dist/bottom-sheet/geometry.d.ts.map +1 -0
  20. package/dist/bottom-sheet/geometry.js +51 -0
  21. package/dist/bottom-sheet/geometry.js.map +1 -0
  22. package/dist/bottom-sheet/index.d.ts +56 -0
  23. package/dist/bottom-sheet/index.d.ts.map +1 -0
  24. package/dist/bottom-sheet/index.js +462 -0
  25. package/dist/bottom-sheet/index.js.map +1 -0
  26. package/dist/bottom-sheet/native.d.ts +11 -0
  27. package/dist/bottom-sheet/native.d.ts.map +1 -0
  28. package/dist/bottom-sheet/native.js +173 -0
  29. package/dist/bottom-sheet/native.js.map +1 -0
  30. package/dist/config.d.ts +9 -0
  31. package/dist/config.d.ts.map +1 -1
  32. package/dist/config.js +40 -1
  33. package/dist/config.js.map +1 -1
  34. package/dist/decay.d.ts +1 -0
  35. package/dist/decay.d.ts.map +1 -1
  36. package/dist/decay.js +7 -0
  37. package/dist/decay.js.map +1 -1
  38. package/dist/drag-physics.d.ts +6 -1
  39. package/dist/drag-physics.d.ts.map +1 -1
  40. package/dist/drag.d.ts +17 -3
  41. package/dist/drag.d.ts.map +1 -1
  42. package/dist/drag.js +34 -11
  43. package/dist/drag.js.map +1 -1
  44. package/dist/driver/android-gradient.d.ts +5 -0
  45. package/dist/driver/android-gradient.d.ts.map +1 -0
  46. package/dist/driver/android-gradient.js +99 -0
  47. package/dist/driver/android-gradient.js.map +1 -0
  48. package/dist/driver/android-particles.d.ts +6 -0
  49. package/dist/driver/android-particles.d.ts.map +1 -0
  50. package/dist/driver/android-particles.js +93 -0
  51. package/dist/driver/android-particles.js.map +1 -0
  52. package/dist/driver/android.d.ts.map +1 -1
  53. package/dist/driver/android.js +27 -1
  54. package/dist/driver/android.js.map +1 -1
  55. package/dist/driver/frame.d.ts +3 -0
  56. package/dist/driver/frame.d.ts.map +1 -0
  57. package/dist/driver/frame.js +7 -0
  58. package/dist/driver/frame.js.map +1 -0
  59. package/dist/driver/index.d.ts +4 -0
  60. package/dist/driver/index.d.ts.map +1 -1
  61. package/dist/driver/index.js.map +1 -1
  62. package/dist/driver/ios-gradient.d.ts +5 -0
  63. package/dist/driver/ios-gradient.d.ts.map +1 -0
  64. package/dist/driver/ios-gradient.js +131 -0
  65. package/dist/driver/ios-gradient.js.map +1 -0
  66. package/dist/driver/ios-scroll-delegate.d.ts +4 -0
  67. package/dist/driver/ios-scroll-delegate.d.ts.map +1 -0
  68. package/dist/driver/ios-scroll-delegate.js +26 -0
  69. package/dist/driver/ios-scroll-delegate.js.map +1 -0
  70. package/dist/driver/ios.d.ts.map +1 -1
  71. package/dist/driver/ios.js +9 -0
  72. package/dist/driver/ios.js.map +1 -1
  73. package/dist/easing.d.ts +3 -1
  74. package/dist/easing.d.ts.map +1 -1
  75. package/dist/easing.js +18 -1
  76. package/dist/easing.js.map +1 -1
  77. package/dist/engine.d.ts +31 -2
  78. package/dist/engine.d.ts.map +1 -1
  79. package/dist/engine.js +194 -42
  80. package/dist/engine.js.map +1 -1
  81. package/dist/gesture-native.d.ts +28 -0
  82. package/dist/gesture-native.d.ts.map +1 -0
  83. package/dist/gesture-native.js +61 -0
  84. package/dist/gesture-native.js.map +1 -0
  85. package/dist/gestures/index.d.ts +69 -0
  86. package/dist/gestures/index.d.ts.map +1 -0
  87. package/dist/gestures/index.js +262 -0
  88. package/dist/gestures/index.js.map +1 -0
  89. package/dist/glass/index.d.ts +55 -0
  90. package/dist/glass/index.d.ts.map +1 -0
  91. package/dist/glass/index.js +205 -0
  92. package/dist/glass/index.js.map +1 -0
  93. package/dist/gradient-binding.d.ts +38 -0
  94. package/dist/gradient-binding.d.ts.map +1 -0
  95. package/dist/gradient-binding.js +128 -0
  96. package/dist/gradient-binding.js.map +1 -0
  97. package/dist/gradient.d.ts +105 -0
  98. package/dist/gradient.d.ts.map +1 -0
  99. package/dist/gradient.js +514 -0
  100. package/dist/gradient.js.map +1 -0
  101. package/dist/gravity.d.ts +13 -0
  102. package/dist/gravity.d.ts.map +1 -0
  103. package/dist/gravity.js +84 -0
  104. package/dist/gravity.js.map +1 -0
  105. package/dist/haptics.d.ts.map +1 -1
  106. package/dist/haptics.js +101 -28
  107. package/dist/haptics.js.map +1 -1
  108. package/dist/image-effect.d.ts +1 -0
  109. package/dist/image-effect.d.ts.map +1 -1
  110. package/dist/image-effect.js +10 -2
  111. package/dist/image-effect.js.map +1 -1
  112. package/dist/index.d.ts +19 -7
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +10 -4
  115. package/dist/index.js.map +1 -1
  116. package/dist/inspector/index.d.ts +86 -0
  117. package/dist/inspector/index.d.ts.map +1 -0
  118. package/dist/inspector/index.js +419 -0
  119. package/dist/inspector/index.js.map +1 -0
  120. package/dist/inspector/plot.d.ts +4 -0
  121. package/dist/inspector/plot.d.ts.map +1 -0
  122. package/dist/inspector/plot.js +23 -0
  123. package/dist/inspector/plot.js.map +1 -0
  124. package/dist/inspector/probe.d.ts +19 -0
  125. package/dist/inspector/probe.d.ts.map +1 -0
  126. package/dist/inspector/probe.js +37 -0
  127. package/dist/inspector/probe.js.map +1 -0
  128. package/dist/inspector/tuning.d.ts +19 -0
  129. package/dist/inspector/tuning.d.ts.map +1 -0
  130. package/dist/inspector/tuning.js +37 -0
  131. package/dist/inspector/tuning.js.map +1 -0
  132. package/dist/interactive-navigation/index.d.ts +44 -0
  133. package/dist/interactive-navigation/index.d.ts.map +1 -0
  134. package/dist/interactive-navigation/index.js +350 -0
  135. package/dist/interactive-navigation/index.js.map +1 -0
  136. package/dist/keyboard.d.ts +24 -0
  137. package/dist/keyboard.d.ts.map +1 -1
  138. package/dist/keyboard.js +199 -6
  139. package/dist/keyboard.js.map +1 -1
  140. package/dist/live-spring-driver.d.ts +52 -0
  141. package/dist/live-spring-driver.d.ts.map +1 -0
  142. package/dist/live-spring-driver.js +104 -0
  143. package/dist/live-spring-driver.js.map +1 -0
  144. package/dist/mixer.d.ts +55 -0
  145. package/dist/mixer.d.ts.map +1 -0
  146. package/dist/mixer.js +286 -0
  147. package/dist/mixer.js.map +1 -0
  148. package/dist/motion-scope.d.ts +8 -2
  149. package/dist/motion-scope.d.ts.map +1 -1
  150. package/dist/motion-scope.js +24 -3
  151. package/dist/motion-scope.js.map +1 -1
  152. package/dist/motion-states.d.ts +19 -7
  153. package/dist/motion-states.d.ts.map +1 -1
  154. package/dist/motion-states.js +116 -26
  155. package/dist/motion-states.js.map +1 -1
  156. package/dist/motion-value.d.ts +227 -0
  157. package/dist/motion-value.d.ts.map +1 -0
  158. package/dist/motion-value.js +1074 -0
  159. package/dist/motion-value.js.map +1 -0
  160. package/dist/native/index.d.ts +10 -0
  161. package/dist/native/index.d.ts.map +1 -0
  162. package/dist/native/index.js +6 -0
  163. package/dist/native/index.js.map +1 -0
  164. package/dist/native-properties.d.ts +28 -0
  165. package/dist/native-properties.d.ts.map +1 -0
  166. package/dist/native-properties.js +154 -0
  167. package/dist/native-properties.js.map +1 -0
  168. package/dist/native-property-driver.d.ts +19 -0
  169. package/dist/native-property-driver.d.ts.map +1 -0
  170. package/dist/native-property-driver.js +69 -0
  171. package/dist/native-property-driver.js.map +1 -0
  172. package/dist/native-property.d.ts +37 -0
  173. package/dist/native-property.d.ts.map +1 -0
  174. package/dist/native-property.js +285 -0
  175. package/dist/native-property.js.map +1 -0
  176. package/dist/particles.d.ts +5 -2
  177. package/dist/particles.d.ts.map +1 -1
  178. package/dist/particles.js +16 -10
  179. package/dist/particles.js.map +1 -1
  180. package/dist/path.d.ts.map +1 -1
  181. package/dist/path.js +2 -2
  182. package/dist/path.js.map +1 -1
  183. package/dist/physics/index.d.ts +139 -0
  184. package/dist/physics/index.d.ts.map +1 -0
  185. package/dist/physics/index.js +316 -0
  186. package/dist/physics/index.js.map +1 -0
  187. package/dist/physics/native.d.ts +54 -0
  188. package/dist/physics/native.d.ts.map +1 -0
  189. package/dist/physics/native.js +64 -0
  190. package/dist/physics/native.js.map +1 -0
  191. package/dist/playback-group.d.ts.map +1 -1
  192. package/dist/playback-group.js +17 -1
  193. package/dist/playback-group.js.map +1 -1
  194. package/dist/playback.d.ts +15 -0
  195. package/dist/playback.d.ts.map +1 -1
  196. package/dist/playback.js +23 -0
  197. package/dist/playback.js.map +1 -1
  198. package/dist/predictive-back/index.d.ts +45 -0
  199. package/dist/predictive-back/index.d.ts.map +1 -0
  200. package/dist/predictive-back/index.js +220 -0
  201. package/dist/predictive-back/index.js.map +1 -0
  202. package/dist/predictive-back/presentation.d.ts +4 -0
  203. package/dist/predictive-back/presentation.d.ts.map +1 -0
  204. package/dist/predictive-back/presentation.js +3 -0
  205. package/dist/predictive-back/presentation.js.map +1 -0
  206. package/dist/press.d.ts.map +1 -1
  207. package/dist/press.js +11 -2
  208. package/dist/press.js.map +1 -1
  209. package/dist/reorder/handle.d.ts +6 -0
  210. package/dist/reorder/handle.d.ts.map +1 -0
  211. package/dist/reorder/handle.js +10 -0
  212. package/dist/reorder/handle.js.map +1 -0
  213. package/dist/reorder/index.d.ts +10 -0
  214. package/dist/reorder/index.d.ts.map +1 -0
  215. package/dist/reorder/index.js +233 -0
  216. package/dist/reorder/index.js.map +1 -0
  217. package/dist/reorder/list-view.d.ts +5 -0
  218. package/dist/reorder/list-view.d.ts.map +1 -0
  219. package/dist/reorder/list-view.js +238 -0
  220. package/dist/reorder/list-view.js.map +1 -0
  221. package/dist/reorder/model.d.ts +6 -0
  222. package/dist/reorder/model.d.ts.map +1 -0
  223. package/dist/reorder/model.js +30 -0
  224. package/dist/reorder/model.js.map +1 -0
  225. package/dist/reorder/surface.d.ts +6 -0
  226. package/dist/reorder/surface.d.ts.map +1 -0
  227. package/dist/reorder/surface.js +10 -0
  228. package/dist/reorder/surface.js.map +1 -0
  229. package/dist/reorder/types.d.ts +92 -0
  230. package/dist/reorder/types.d.ts.map +1 -0
  231. package/dist/reorder/types.js +2 -0
  232. package/dist/reorder/types.js.map +1 -0
  233. package/dist/sampling.d.ts +35 -0
  234. package/dist/sampling.d.ts.map +1 -0
  235. package/dist/sampling.js +123 -0
  236. package/dist/sampling.js.map +1 -0
  237. package/dist/scene-appearance.d.ts +14 -0
  238. package/dist/scene-appearance.d.ts.map +1 -0
  239. package/dist/scene-appearance.js +68 -0
  240. package/dist/scene-appearance.js.map +1 -0
  241. package/dist/scene-camera.d.ts +5 -0
  242. package/dist/scene-camera.d.ts.map +1 -0
  243. package/dist/scene-camera.js +23 -0
  244. package/dist/scene-camera.js.map +1 -0
  245. package/dist/scene-shader.d.ts +18 -0
  246. package/dist/scene-shader.d.ts.map +1 -0
  247. package/dist/scene-shader.js +76 -0
  248. package/dist/scene-shader.js.map +1 -0
  249. package/dist/scroll-header/geometry.d.ts +18 -0
  250. package/dist/scroll-header/geometry.d.ts.map +1 -0
  251. package/dist/scroll-header/geometry.js +46 -0
  252. package/dist/scroll-header/geometry.js.map +1 -0
  253. package/dist/scroll-header/index.d.ts +48 -0
  254. package/dist/scroll-header/index.d.ts.map +1 -0
  255. package/dist/scroll-header/index.js +399 -0
  256. package/dist/scroll-header/index.js.map +1 -0
  257. package/dist/scroll-header/native.d.ts +28 -0
  258. package/dist/scroll-header/native.d.ts.map +1 -0
  259. package/dist/scroll-header/native.js +43 -0
  260. package/dist/scroll-header/native.js.map +1 -0
  261. package/dist/sensors/index.d.ts +69 -0
  262. package/dist/sensors/index.d.ts.map +1 -0
  263. package/dist/sensors/index.js +149 -0
  264. package/dist/sensors/index.js.map +1 -0
  265. package/dist/sensors/native.d.ts +20 -0
  266. package/dist/sensors/native.d.ts.map +1 -0
  267. package/dist/sensors/native.js +48 -0
  268. package/dist/sensors/native.js.map +1 -0
  269. package/dist/sequence.d.ts +24 -0
  270. package/dist/sequence.d.ts.map +1 -1
  271. package/dist/sequence.js +181 -19
  272. package/dist/sequence.js.map +1 -1
  273. package/dist/shapes/android.d.ts +3 -0
  274. package/dist/shapes/android.d.ts.map +1 -0
  275. package/dist/shapes/android.js +51 -0
  276. package/dist/shapes/android.js.map +1 -0
  277. package/dist/shapes/index.d.ts +6 -0
  278. package/dist/shapes/index.d.ts.map +1 -0
  279. package/dist/shapes/index.js +238 -0
  280. package/dist/shapes/index.js.map +1 -0
  281. package/dist/shapes/ios.d.ts +3 -0
  282. package/dist/shapes/ios.d.ts.map +1 -0
  283. package/dist/shapes/ios.js +164 -0
  284. package/dist/shapes/ios.js.map +1 -0
  285. package/dist/shapes/native.d.ts +18 -0
  286. package/dist/shapes/native.d.ts.map +1 -0
  287. package/dist/shapes/native.js +10 -0
  288. package/dist/shapes/native.js.map +1 -0
  289. package/dist/shapes/path.d.ts +10 -0
  290. package/dist/shapes/path.d.ts.map +1 -0
  291. package/dist/shapes/path.js +106 -0
  292. package/dist/shapes/path.js.map +1 -0
  293. package/dist/shapes/types.d.ts +55 -0
  294. package/dist/shapes/types.d.ts.map +1 -0
  295. package/dist/shapes/types.js +11 -0
  296. package/dist/shapes/types.js.map +1 -0
  297. package/dist/shared-layout/index.d.ts +40 -0
  298. package/dist/shared-layout/index.d.ts.map +1 -0
  299. package/dist/shared-layout/index.js +267 -0
  300. package/dist/shared-layout/index.js.map +1 -0
  301. package/dist/shared-layout/native.d.ts +15 -0
  302. package/dist/shared-layout/native.d.ts.map +1 -0
  303. package/dist/shared-layout/native.js +79 -0
  304. package/dist/shared-layout/native.js.map +1 -0
  305. package/dist/shared-layout/timing.d.ts +9 -0
  306. package/dist/shared-layout/timing.d.ts.map +1 -0
  307. package/dist/shared-layout/timing.js +68 -0
  308. package/dist/shared-layout/timing.js.map +1 -0
  309. package/dist/shared-navigation/entry.d.ts +51 -0
  310. package/dist/shared-navigation/entry.d.ts.map +1 -0
  311. package/dist/shared-navigation/entry.js +619 -0
  312. package/dist/shared-navigation/entry.js.map +1 -0
  313. package/dist/shared-navigation/index.d.ts +58 -0
  314. package/dist/shared-navigation/index.d.ts.map +1 -0
  315. package/dist/shared-navigation/index.js +318 -0
  316. package/dist/shared-navigation/index.js.map +1 -0
  317. package/dist/shared-navigation/return-signal.d.ts +16 -0
  318. package/dist/shared-navigation/return-signal.d.ts.map +1 -0
  319. package/dist/shared-navigation/return-signal.js +35 -0
  320. package/dist/shared-navigation/return-signal.js.map +1 -0
  321. package/dist/shared-navigation/return-target.d.ts +32 -0
  322. package/dist/shared-navigation/return-target.d.ts.map +1 -0
  323. package/dist/shared-navigation/return-target.js +168 -0
  324. package/dist/shared-navigation/return-target.js.map +1 -0
  325. package/dist/shared-navigation/scope.d.ts +4 -0
  326. package/dist/shared-navigation/scope.d.ts.map +1 -0
  327. package/dist/shared-navigation/scope.js +2 -0
  328. package/dist/shared-navigation/scope.js.map +1 -0
  329. package/dist/shared-navigation/targets.d.ts +6 -0
  330. package/dist/shared-navigation/targets.d.ts.map +1 -0
  331. package/dist/shared-navigation/targets.js +36 -0
  332. package/dist/shared-navigation/targets.js.map +1 -0
  333. package/dist/size-layout.d.ts +19 -0
  334. package/dist/size-layout.d.ts.map +1 -0
  335. package/dist/size-layout.js +216 -0
  336. package/dist/size-layout.js.map +1 -0
  337. package/dist/size.d.ts +19 -0
  338. package/dist/size.d.ts.map +1 -0
  339. package/dist/size.js +251 -0
  340. package/dist/size.js.map +1 -0
  341. package/dist/spring.d.ts +2 -0
  342. package/dist/spring.d.ts.map +1 -1
  343. package/dist/spring.js +11 -0
  344. package/dist/spring.js.map +1 -1
  345. package/dist/svg-path.d.ts +18 -0
  346. package/dist/svg-path.d.ts.map +1 -1
  347. package/dist/svg-path.js +3 -2
  348. package/dist/svg-path.js.map +1 -1
  349. package/dist/testing/clock.d.ts +40 -0
  350. package/dist/testing/clock.d.ts.map +1 -0
  351. package/dist/testing/clock.js +116 -0
  352. package/dist/testing/clock.js.map +1 -0
  353. package/dist/testing/handoff-recorder.d.ts +8 -0
  354. package/dist/testing/handoff-recorder.d.ts.map +1 -0
  355. package/dist/testing/handoff-recorder.js +77 -0
  356. package/dist/testing/handoff-recorder.js.map +1 -0
  357. package/dist/testing/index.d.ts +5 -0
  358. package/dist/testing/index.d.ts.map +1 -0
  359. package/dist/testing/index.js +5 -0
  360. package/dist/testing/index.js.map +1 -0
  361. package/dist/testing/native.d.ts +46 -0
  362. package/dist/testing/native.d.ts.map +1 -0
  363. package/dist/testing/native.js +313 -0
  364. package/dist/testing/native.js.map +1 -0
  365. package/dist/testing/presentation.d.ts +11 -0
  366. package/dist/testing/presentation.d.ts.map +1 -0
  367. package/dist/testing/presentation.js +45 -0
  368. package/dist/testing/presentation.js.map +1 -0
  369. package/dist/testing/replay.d.ts +39 -0
  370. package/dist/testing/replay.d.ts.map +1 -0
  371. package/dist/testing/replay.js +99 -0
  372. package/dist/testing/replay.js.map +1 -0
  373. package/dist/testing/scroll-handoff-native.d.ts +10 -0
  374. package/dist/testing/scroll-handoff-native.d.ts.map +1 -0
  375. package/dist/testing/scroll-handoff-native.js +151 -0
  376. package/dist/testing/scroll-handoff-native.js.map +1 -0
  377. package/dist/testing/scroll-handoff.d.ts +25 -0
  378. package/dist/testing/scroll-handoff.d.ts.map +1 -0
  379. package/dist/testing/scroll-handoff.js +127 -0
  380. package/dist/testing/scroll-handoff.js.map +1 -0
  381. package/dist/testing/sensors.d.ts +13 -0
  382. package/dist/testing/sensors.d.ts.map +1 -0
  383. package/dist/testing/sensors.js +26 -0
  384. package/dist/testing/sensors.js.map +1 -0
  385. package/dist/testing/trace.d.ts +101 -0
  386. package/dist/testing/trace.d.ts.map +1 -0
  387. package/dist/testing/trace.js +263 -0
  388. package/dist/testing/trace.js.map +1 -0
  389. package/dist/timed-animation.d.ts +38 -0
  390. package/dist/timed-animation.d.ts.map +1 -0
  391. package/dist/timed-animation.js +177 -0
  392. package/dist/timed-animation.js.map +1 -0
  393. package/dist/track.d.ts +3 -0
  394. package/dist/track.d.ts.map +1 -1
  395. package/dist/track.js +281 -40
  396. package/dist/track.js.map +1 -1
  397. package/dist/transition.d.ts +54 -2
  398. package/dist/transition.d.ts.map +1 -1
  399. package/dist/transition.js +128 -8
  400. package/dist/transition.js.map +1 -1
  401. package/dist/types.d.ts +10 -1
  402. package/dist/types.d.ts.map +1 -1
  403. package/dist/value-observers.d.ts +22 -0
  404. package/dist/value-observers.d.ts.map +1 -0
  405. package/dist/value-observers.js +122 -0
  406. package/dist/value-observers.js.map +1 -0
  407. package/dist/value-track.d.ts +13 -0
  408. package/dist/value-track.d.ts.map +1 -0
  409. package/dist/value-track.js +59 -0
  410. package/dist/value-track.js.map +1 -0
  411. package/dist/vue/index.d.ts +33 -3
  412. package/dist/vue/index.d.ts.map +1 -1
  413. package/dist/vue/index.js +118 -3
  414. package/dist/vue/index.js.map +1 -1
  415. package/dist/zoomable.d.ts +1 -1
  416. package/dist/zoomable.d.ts.map +1 -1
  417. package/package.json +68 -3
  418. package/platforms/android/include.gradle +10 -0
  419. package/platforms/android/java/org/rafaelaugusto/jolt/BlurEffect.java +89 -0
  420. package/platforms/android/java/org/rafaelaugusto/jolt/CircleMath.java +158 -0
  421. package/platforms/android/java/org/rafaelaugusto/jolt/CircleWorld.java +221 -0
  422. package/platforms/android/java/org/rafaelaugusto/jolt/GestureSession.java +227 -0
  423. package/platforms/android/java/org/rafaelaugusto/jolt/GestureSurface.java +54 -0
  424. package/platforms/android/java/org/rafaelaugusto/jolt/GradientLayer.java +224 -0
  425. package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardFrame.java +53 -0
  426. package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardFrameFollower.java +57 -0
  427. package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardObserver.java +97 -0
  428. package/platforms/android/java/org/rafaelaugusto/jolt/LiveSpring.java +277 -0
  429. package/platforms/android/java/org/rafaelaugusto/jolt/MotionProbe.java +70 -0
  430. package/platforms/android/java/org/rafaelaugusto/jolt/ParticleEmitter.java +192 -0
  431. package/platforms/android/java/org/rafaelaugusto/jolt/ParticleSimulation.java +114 -0
  432. package/platforms/android/java/org/rafaelaugusto/jolt/PredictiveBackSession.java +212 -0
  433. package/platforms/android/java/org/rafaelaugusto/jolt/ReorderHandle.java +25 -0
  434. package/platforms/android/java/org/rafaelaugusto/jolt/ReorderSession.java +213 -0
  435. package/platforms/android/java/org/rafaelaugusto/jolt/ReorderSurface.java +27 -0
  436. package/platforms/android/java/org/rafaelaugusto/jolt/ScrollHeader.java +84 -0
  437. package/platforms/android/java/org/rafaelaugusto/jolt/SensorMath.java +28 -0
  438. package/platforms/android/java/org/rafaelaugusto/jolt/SensorSource.java +217 -0
  439. package/platforms/android/java/org/rafaelaugusto/jolt/ShapeLayer.java +120 -0
  440. package/platforms/android/java/org/rafaelaugusto/jolt/SharedLayoutFlight.java +287 -0
  441. package/platforms/android/java/org/rafaelaugusto/jolt/SharedNavigationScene.java +115 -0
  442. package/platforms/android/java/org/rafaelaugusto/jolt/SpringState.java +39 -0
  443. package/platforms/android/proguard-rules.pro +20 -0
  444. package/platforms/ios/build.xcconfig +1 -1
  445. package/platforms/ios/src/JoltBlur.h +14 -0
  446. package/platforms/ios/src/JoltBlur.m +86 -0
  447. package/platforms/ios/src/JoltCircleMath.h +191 -0
  448. package/platforms/ios/src/JoltCircleWorld.h +18 -0
  449. package/platforms/ios/src/JoltCircleWorld.m +218 -0
  450. package/platforms/ios/src/JoltGestureSession.h +23 -0
  451. package/platforms/ios/src/JoltGestureSession.m +251 -0
  452. package/platforms/ios/src/JoltInteractiveNavigation.h +23 -0
  453. package/platforms/ios/src/JoltInteractiveNavigation.m +255 -0
  454. package/platforms/ios/src/JoltLiveSpring.h +29 -0
  455. package/platforms/ios/src/JoltLiveSpring.m +243 -0
  456. package/platforms/ios/src/JoltMotionProbe.h +9 -0
  457. package/platforms/ios/src/JoltMotionProbe.m +72 -0
  458. package/platforms/ios/src/JoltReorderSession.h +15 -0
  459. package/platforms/ios/src/JoltReorderSession.m +205 -0
  460. package/platforms/ios/src/JoltScrollHeader.h +13 -0
  461. package/platforms/ios/src/JoltScrollHeader.m +101 -0
  462. package/platforms/ios/src/JoltSensorMath.h +39 -0
  463. package/platforms/ios/src/JoltSensorSource.h +13 -0
  464. package/platforms/ios/src/JoltSensorSource.m +201 -0
  465. package/platforms/ios/src/JoltSharedLayoutFlight.h +19 -0
  466. package/platforms/ios/src/JoltSharedLayoutFlight.m +250 -0
  467. package/platforms/ios/src/JoltSpringState.h +35 -0
  468. package/platforms/ios/src/module.modulemap +10 -0
  469. package/src/android-plugin.d.ts +464 -0
  470. package/src/animate.ts +129 -15
  471. package/src/blur/index.ts +195 -0
  472. package/src/blur/native.ts +70 -0
  473. package/src/blur/types.ts +32 -0
  474. package/src/bottom-sheet/geometry.ts +84 -0
  475. package/src/bottom-sheet/index.ts +536 -0
  476. package/src/bottom-sheet/native.ts +214 -0
  477. package/src/config.ts +39 -1
  478. package/src/decay.ts +9 -0
  479. package/src/drag.ts +67 -21
  480. package/src/driver/android-gradient.ts +116 -0
  481. package/src/driver/android-particles.ts +118 -0
  482. package/src/driver/android.ts +31 -1
  483. package/src/driver/frame.ts +10 -0
  484. package/src/driver/index.ts +4 -0
  485. package/src/driver/ios-gradient.ts +136 -0
  486. package/src/driver/ios-scroll-delegate.ts +23 -0
  487. package/src/driver/ios.ts +10 -0
  488. package/src/easing.ts +21 -1
  489. package/src/engine.ts +209 -60
  490. package/src/gesture-native.ts +139 -0
  491. package/src/gestures/index.ts +365 -0
  492. package/src/glass/index.ts +218 -0
  493. package/src/gradient-binding.ts +158 -0
  494. package/src/gradient.ts +663 -0
  495. package/src/gravity.ts +107 -0
  496. package/src/haptics.ts +106 -28
  497. package/src/image-effect.ts +10 -2
  498. package/src/index.ts +56 -7
  499. package/src/inspector/index.ts +523 -0
  500. package/src/inspector/plot.ts +27 -0
  501. package/src/inspector/probe.ts +50 -0
  502. package/src/inspector/tuning.ts +51 -0
  503. package/src/interactive-navigation/index.ts +427 -0
  504. package/src/ios-plugin.d.ts +280 -0
  505. package/src/keyboard.ts +231 -7
  506. package/src/live-spring-driver.ts +181 -0
  507. package/src/mixer.ts +312 -0
  508. package/src/motion-scope.ts +39 -6
  509. package/src/motion-states.ts +149 -42
  510. package/src/motion-value.ts +1289 -0
  511. package/src/native/index.ts +30 -0
  512. package/src/native-properties.ts +188 -0
  513. package/src/native-property-driver.ts +123 -0
  514. package/src/native-property.ts +366 -0
  515. package/src/particles.ts +18 -17
  516. package/src/path.ts +2 -1
  517. package/src/physics/index.ts +476 -0
  518. package/src/physics/native.ts +121 -0
  519. package/src/playback-group.ts +17 -1
  520. package/src/playback.ts +41 -0
  521. package/src/predictive-back/index.ts +280 -0
  522. package/src/predictive-back/presentation.ts +6 -0
  523. package/src/press.ts +10 -2
  524. package/src/reorder/handle.ts +9 -0
  525. package/src/reorder/index.ts +243 -0
  526. package/src/reorder/list-view.ts +262 -0
  527. package/src/reorder/model.ts +47 -0
  528. package/src/reorder/surface.ts +10 -0
  529. package/src/reorder/types.ts +87 -0
  530. package/src/sampling.ts +173 -0
  531. package/src/scene-appearance.ts +92 -0
  532. package/src/scene-camera.ts +30 -0
  533. package/src/scene-shader.ts +139 -0
  534. package/src/scroll-header/geometry.ts +88 -0
  535. package/src/scroll-header/index.ts +530 -0
  536. package/src/scroll-header/native.ts +89 -0
  537. package/src/sensors/index.ts +246 -0
  538. package/src/sensors/native.ts +72 -0
  539. package/src/sequence.ts +209 -20
  540. package/src/shapes/android.ts +63 -0
  541. package/src/shapes/index.ts +267 -0
  542. package/src/shapes/ios.ts +194 -0
  543. package/src/shapes/native.ts +27 -0
  544. package/src/shapes/path.ts +127 -0
  545. package/src/shapes/types.ts +63 -0
  546. package/src/shared-layout/index.ts +343 -0
  547. package/src/shared-layout/native.ts +138 -0
  548. package/src/shared-layout/timing.ts +87 -0
  549. package/src/shared-navigation/entry.ts +695 -0
  550. package/src/shared-navigation/index.ts +414 -0
  551. package/src/shared-navigation/return-signal.ts +41 -0
  552. package/src/shared-navigation/return-target.ts +197 -0
  553. package/src/shared-navigation/scope.ts +3 -0
  554. package/src/shared-navigation/targets.ts +38 -0
  555. package/src/size-layout.ts +237 -0
  556. package/src/size.ts +302 -0
  557. package/src/spring.ts +18 -0
  558. package/src/svg-path.ts +8 -3
  559. package/src/testing/clock.ts +128 -0
  560. package/src/testing/handoff-recorder.ts +98 -0
  561. package/src/testing/index.ts +4 -0
  562. package/src/testing/native.ts +386 -0
  563. package/src/testing/presentation.ts +46 -0
  564. package/src/testing/replay.ts +149 -0
  565. package/src/testing/scroll-handoff-native.ts +201 -0
  566. package/src/testing/scroll-handoff.ts +140 -0
  567. package/src/testing/sensors.ts +41 -0
  568. package/src/testing/trace.ts +340 -0
  569. package/src/timed-animation.ts +192 -0
  570. package/src/track.ts +334 -38
  571. package/src/transition.ts +197 -9
  572. package/src/types.ts +11 -1
  573. package/src/value-observers.ts +147 -0
  574. package/src/value-track.ts +71 -0
  575. package/src/vue/index.ts +147 -1
  576. package/src/zoomable.ts +1 -1
package/src/particles.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { Application, Color, isIOS, type View } from '@nativescript/core'
1
+ import { Application, Color, isAndroid, isIOS, type View } from '@nativescript/core'
2
2
  import { toView } from './animate.js'
3
3
  import type { Target } from './types.js'
4
- import { reducedMotion } from './config.js'
4
+ import { onReducedMotion, reducedMotion } from './config.js'
5
+ import { androidParticles } from './driver/android-particles.js'
5
6
 
6
7
  export interface ConfettiOptions {
7
8
  /** Approximate number of particles in the burst. Defaults to 80. */
@@ -38,7 +39,10 @@ export interface ParticleOptions {
38
39
  duration?: number
39
40
  }
40
41
 
41
- type Settings = Required<Omit<ParticleOptions, 'duration'>> & { duration?: number }
42
+ export type ParticleSettings = Required<Omit<ParticleOptions, 'duration'>> & {
43
+ duration?: number
44
+ }
45
+ type Settings = ParticleSettings
42
46
  const bursts = new WeakMap<View, () => void>()
43
47
  const emitters = new WeakMap<View, () => void>()
44
48
  const palette = ['#facc15', '#ef4444', '#3b82f6', '#22c55e', '#a855f7']
@@ -46,7 +50,7 @@ const textures = new Map<Settings['shape'], UIImage>()
46
50
  const radians = (degrees: number) => (degrees * Math.PI) / 180
47
51
  const BURST_DURATION = 200
48
52
 
49
- /** Bursts from the target's center into its window. iOS only; returns immediate cleanup. */
53
+ /** Bursts from the target's center into its window. Returns immediate cleanup. */
50
54
  export function confetti(target: Target, options: ConfettiOptions = {}): () => void {
51
55
  const count = number('count', options.count ?? 80, 0, 10000)
52
56
  if (!Number.isInteger(count)) throw new RangeError('Particle count must be an integer.')
@@ -70,7 +74,7 @@ export function confetti(target: Target, options: ConfettiOptions = {}): () => v
70
74
  return start(target, settings, true)
71
75
  }
72
76
 
73
- /** Adds a native particle emitter to the target. iOS only; returns immediate cleanup. */
77
+ /** Adds a native particle emitter to the target. Returns immediate cleanup. */
74
78
  export function particles(target: Target, options: ParticleOptions = {}): () => void {
75
79
  return start(target, resolve(options), false)
76
80
  }
@@ -79,7 +83,9 @@ function start(target: Target, settings: Settings, overlay: boolean): () => void
79
83
  const view = toView(target)
80
84
  const running = overlay ? bursts : emitters
81
85
  running.get(view)?.()
82
- if (!isIOS || settings.rate === 0 || reducedMotion()) return () => {}
86
+ if (settings.rate === 0 || reducedMotion()) return () => {}
87
+ if (isAndroid) return androidParticles(view, settings, overlay, running)
88
+ if (!isIOS) return () => {}
83
89
  return new Emitter(view, settings, overlay, running).stop
84
90
  }
85
91
 
@@ -141,7 +147,7 @@ class Emitter {
141
147
  private native: UIView | undefined
142
148
  private window: UIWindow | undefined
143
149
  private timer: ReturnType<typeof setTimeout> | undefined
144
- private observer: ReturnType<typeof Application.ios.addNotificationObserver> | undefined
150
+ private unwatch: (() => void) | undefined
145
151
 
146
152
  constructor(
147
153
  private readonly view: View,
@@ -153,6 +159,8 @@ class Emitter {
153
159
  view.on('loaded', this.schedule)
154
160
  view.on('layoutChanged', this.schedule)
155
161
  view.on('unloaded', this.stop)
162
+ Application.on(Application.suspendEvent, this.stop)
163
+ this.unwatch = onReducedMotion(this.motionChanged)
156
164
  this.schedule()
157
165
  }
158
166
 
@@ -162,17 +170,14 @@ class Emitter {
162
170
  this.view.off('loaded', this.schedule)
163
171
  this.view.off('layoutChanged', this.schedule)
164
172
  this.view.off('unloaded', this.stop)
173
+ Application.off(Application.suspendEvent, this.stop)
165
174
  if (this.running.get(this.view) === this.stop) this.running.delete(this.view)
166
175
  if (this.timer !== undefined) clearTimeout(this.timer)
167
- if (this.observer)
168
- Application.ios.removeNotificationObserver(
169
- this.observer,
170
- UIAccessibilityReduceMotionStatusDidChangeNotification,
171
- )
176
+ this.unwatch?.()
172
177
  this.layer?.removeAllAnimations()
173
178
  this.layer?.removeFromSuperlayer()
174
179
  this.layer = this.native = this.window = undefined
175
- this.timer = this.observer = undefined
180
+ this.timer = this.unwatch = undefined
176
181
  }
177
182
 
178
183
  private schedule = () => {
@@ -232,10 +237,6 @@ class Emitter {
232
237
  ),
233
238
  window,
234
239
  )
235
- this.observer = Application.ios.addNotificationObserver(
236
- UIAccessibilityReduceMotionStatusDidChangeNotification,
237
- this.motionChanged,
238
- )
239
240
  if (this.settings.duration !== undefined) {
240
241
  // The render server stops emission even if JS is blocked. The timer
241
242
  // only removes the empty layer after the last particles have expired.
package/src/path.ts CHANGED
@@ -2,6 +2,7 @@ import { parsePath, type MotionPath } from './svg-path.js'
2
2
  import { reducedMotion, timeScale } from './config.js'
3
3
  import { createTrack, instantTrack, type Track } from './track.js'
4
4
  import {
5
+ fitTransition,
5
6
  mergeTransitions,
6
7
  resolveTransition,
7
8
  type Transition,
@@ -37,7 +38,7 @@ export function preparePath(
37
38
  const geometry = parsePath(keyframes.path)
38
39
  const orient = keyframes.orient === true
39
40
  const transition = resolveTransition(
40
- overrides.path ? mergeTransitions(base, overrides.path) : base,
41
+ fitTransition(overrides.path ? mergeTransitions(base, overrides.path) : base, 2),
41
42
  'opacity',
42
43
  2,
43
44
  )
@@ -0,0 +1,476 @@
1
+ import { Application, type View } from '@nativescript/core'
2
+ import { toView } from '../animate.js'
3
+ import { onReducedMotion, reducedMotion } from '../config.js'
4
+ import type { MotionScope } from '../motion-scope.js'
5
+ import type { Target } from '../types.js'
6
+ import { createCircleDriver, type CircleDriver } from './native.js'
7
+
8
+ export interface PhysicsVector {
9
+ x: number
10
+ y: number
11
+ }
12
+ export interface PhysicsAttachment {
13
+ /** Anchor in container-local DIPs. Scales proportionally when the board resizes. */
14
+ anchor: PhysicsVector
15
+ /** Rest length in DIPs; remains fixed on resize. Default 0. */
16
+ length?: number
17
+ /** Spring force per DIP, 1–1000; default 180. */
18
+ stiffness?: number
19
+ /** Viscous damping, 0–120; default 24. */
20
+ damping?: number
21
+ /** Optional native line, drawn from the anchor to the circle edge. */
22
+ line?: { color: string; width?: number }
23
+ }
24
+ export interface PhysicsSnap {
25
+ /** 1–8 distinct circle centers. Selected natively on release; no initial selection. */
26
+ points: readonly PhysicsVector[]
27
+ stiffness?: number
28
+ damping?: number
29
+ /** Seconds of release-velocity projection for choosing a point, 0–.3; default .12. */
30
+ projection?: number
31
+ }
32
+ export interface PhysicsSpringDrag {
33
+ type: 'spring'
34
+ /** Temporary pointer spring rest length in DIPs, 0–10000; default 0. */
35
+ length?: number
36
+ /** Spring force per DIP, 1–1000; default 180. */
37
+ stiffness?: number
38
+ /** Viscous damping, 0–120; default 24. */
39
+ damping?: number
40
+ /** Optional native tether, visible only during the gesture. */
41
+ line?: { color: string; width?: number }
42
+ }
43
+ export interface CircleBody {
44
+ id: string
45
+ /** A dedicated, square direct child of the container, sized to radius * 2. */
46
+ view: Target
47
+ radius: number
48
+ /** Initial center in container-local DIPs, x right, y down. */
49
+ x: number
50
+ y: number
51
+ mass?: number
52
+ /** DIPs per second; maximum speed 1200. */
53
+ velocity?: PhysicsVector
54
+ attachment?: PhysicsAttachment
55
+ snap?: PhysicsSnap
56
+ /** Direct dragging by default. A spring drag keeps the body dynamic during contact. */
57
+ drag?: 'direct' | PhysicsSpringDrag
58
+ }
59
+ export interface PhysicsOptions {
60
+ /** DIPs/s². Defaults to { x: 0, y: 750 }. */
61
+ gravity?: PhysicsVector
62
+ /** 0–1. Contacts slower than 40 DIPs/s settle without bouncing. Default .65. */
63
+ restitution?: number
64
+ /** Exponential velocity damping per second, 0–20. Default .5. */
65
+ damping?: number
66
+ reducedMotion?: 'pause' | 'continue'
67
+ scope?: MotionScope
68
+ }
69
+ export interface PhysicsSnapshot {
70
+ status: 'running' | 'sleeping' | 'paused' | 'detached' | 'invalid-bounds' | 'disposed'
71
+ bodies: {
72
+ id: string
73
+ x: number
74
+ y: number
75
+ vx: number
76
+ vy: number
77
+ radius: number
78
+ held: boolean
79
+ /** Temporary center target: pointer plus the initial center-to-contact offset, in local DIPs. */
80
+ pointer: {
81
+ anchor: PhysicsVector
82
+ length: number
83
+ stiffness: number
84
+ damping: number
85
+ } | null
86
+ /** Last native release, before snap selection or subsequent integration. */
87
+ release: { x: number; y: number; vx: number; vy: number } | null
88
+ attachment: {
89
+ anchor: PhysicsVector
90
+ length: number
91
+ stiffness: number
92
+ damping: number
93
+ } | null
94
+ snap: { index: number; point: PhysicsVector; settled: boolean } | null
95
+ }[]
96
+ frames: number
97
+ steps: number
98
+ contacts: number
99
+ dragStarts: number
100
+ dragMoves: number
101
+ dragEnds: number
102
+ dragCancels: number
103
+ processingMs: number
104
+ /** Time discarded after UI stalls; the world never catches up without a bound. */
105
+ droppedMs: number
106
+ clock: boolean
107
+ /** Native tether drawing resources retained by this world. */
108
+ guides: number
109
+ }
110
+ export interface PhysicsWorld {
111
+ readonly disposed: boolean
112
+ readonly paused: boolean
113
+ pause(): void
114
+ play(): void
115
+ /** Restore the initial arrangement, scaled to the current container bounds. */
116
+ reset(): void
117
+ /** Mass × DIPs/s. Ignored while paused, detached, reduced or being dragged. */
118
+ impulse(id: string, impulse: PhysicsVector): void
119
+ /** Replace/remove the anchor spring without resetting velocity. Clears the selected snap. */
120
+ attach(id: string, attachment: PhysicsAttachment | null): void
121
+ /** Choose a configured snap point, including while paused. Ignored during an active drag. */
122
+ snapTo(id: string, index: number): void
123
+ /** On-demand diagnostics; never installs a JS frame observer. */
124
+ snapshot(): PhysicsSnapshot
125
+ dispose(): void
126
+ }
127
+ const owners = new WeakSet<View>()
128
+ function number(value: number, name: string, min: number, max: number) {
129
+ if (!Number.isFinite(value) || value < min || value > max)
130
+ throw new RangeError(`${name} must be finite and within ${min}–${max}.`)
131
+ return value
132
+ }
133
+ function vector(value: PhysicsVector, name: string, limit: number): PhysicsVector {
134
+ if (!value || typeof value !== 'object') throw new TypeError(`Expected ${name} vector.`)
135
+ return {
136
+ x: number(value.x, `${name}.x`, -limit, limit),
137
+ y: number(value.y, `${name}.y`, -limit, limit),
138
+ }
139
+ }
140
+ function point(
141
+ value: PhysicsVector,
142
+ name: string,
143
+ width: number,
144
+ height: number,
145
+ inset = 0,
146
+ ) {
147
+ if (!value || typeof value !== 'object') throw new TypeError(`Expected ${name} point.`)
148
+ return {
149
+ x: number(value.x, `${name}.x`, inset, width - inset),
150
+ y: number(value.y, `${name}.y`, inset, height - inset),
151
+ }
152
+ }
153
+ function prepareAttachment(
154
+ value: PhysicsAttachment | null,
155
+ width: number,
156
+ height: number,
157
+ ) {
158
+ if (value === null) return null
159
+ if (!value || typeof value !== 'object')
160
+ throw new TypeError('Expected attachment options or null.')
161
+ const anchor = point(value.anchor, 'anchor', width, height)
162
+ const stiffness = number(value.stiffness ?? 180, 'attachment.stiffness', 1, 1000)
163
+ const damping = number(value.damping ?? 24, 'attachment.damping', 0, 120)
164
+ const length = number(value.length ?? 0, 'attachment.length', 0, 10000)
165
+ let line: { color: number; width: number } | null = null
166
+ if (value.line !== undefined) {
167
+ if (
168
+ !value.line ||
169
+ typeof value.line.color !== 'string' ||
170
+ !/^#[0-9a-f]{6}$/i.test(value.line.color)
171
+ )
172
+ throw new TypeError('Attachment line color must be #RRGGBB.')
173
+ line = {
174
+ color: parseInt(value.line.color.slice(1), 16),
175
+ width: number(value.line.width ?? 1.5, 'attachment.line.width', 0.5, 6),
176
+ }
177
+ }
178
+ return { x: anchor.x, y: anchor.y, length, stiffness, damping, line }
179
+ }
180
+ function prepareSnap(
181
+ value: PhysicsSnap | undefined,
182
+ width: number,
183
+ height: number,
184
+ radius: number,
185
+ ) {
186
+ if (value === undefined) return null
187
+ if (
188
+ !value ||
189
+ !Array.isArray(value.points) ||
190
+ value.points.length < 1 ||
191
+ value.points.length > 8
192
+ )
193
+ throw new RangeError('Snap needs 1–8 distinct points.')
194
+ const points = Array.from(value.points, (p) =>
195
+ point(p, 'snap point', width, height, radius),
196
+ )
197
+ if (new Set(points.map((p) => `${p.x},${p.y}`)).size !== points.length)
198
+ throw new RangeError('Snap points must be distinct.')
199
+ return {
200
+ points,
201
+ stiffness: number(value.stiffness ?? 180, 'snap.stiffness', 1, 1000),
202
+ damping: number(value.damping ?? 24, 'snap.damping', 0, 120),
203
+ projection: number(value.projection ?? 0.12, 'snap.projection', 0, 0.3),
204
+ }
205
+ }
206
+ function prepareDrag(value: CircleBody['drag'], width: number, height: number) {
207
+ if (value === undefined || value === 'direct') return null
208
+ if (!value || typeof value !== 'object' || value.type !== 'spring')
209
+ throw new TypeError('Expected direct dragging or a spring drag configuration.')
210
+ // Share the validated spring ranges and line style; the pointer supplies the anchor natively.
211
+ const {
212
+ x: _x,
213
+ y: _y,
214
+ ...spring
215
+ } = prepareAttachment({ ...value, anchor: { x: 0, y: 0 } }, width, height)!
216
+ return spring
217
+ }
218
+ function untransformed(view: View) {
219
+ return (
220
+ (view.translateX ?? 0) === 0 &&
221
+ (view.translateY ?? 0) === 0 &&
222
+ (view.rotate ?? 0) === 0 &&
223
+ (view.rotateX ?? 0) === 0 &&
224
+ (view.rotateY ?? 0) === 0 &&
225
+ (view.scaleX ?? 1) === 1 &&
226
+ (view.scaleY ?? 1) === 1
227
+ )
228
+ }
229
+ /** Native, circle-only physics for 1–16 dedicated views. Create after layout. */
230
+ export function physicsWorld(
231
+ target: Target,
232
+ bodies: readonly CircleBody[],
233
+ options: PhysicsOptions = {},
234
+ ): PhysicsWorld {
235
+ let host: View | undefined = toView(target)
236
+ if (!Array.isArray(bodies) || bodies.length < 1 || bodies.length > 16)
237
+ throw new RangeError('Physics needs 1–16 circles.')
238
+ if (!options || typeof options !== 'object')
239
+ throw new TypeError('Expected physics options.')
240
+ if (options.scope?.disposed || options.scope?.suspended)
241
+ throw new Error('Physics scope must be active.')
242
+ const policy = options.reducedMotion ?? 'pause'
243
+ if (policy !== 'pause' && policy !== 'continue')
244
+ throw new TypeError('Invalid physics reduced-motion policy.')
245
+ const gravity = vector(options.gravity ?? { x: 0, y: 750 }, 'gravity', 2000)
246
+ const restitution = number(options.restitution ?? 0.65, 'restitution', 0, 1)
247
+ const damping = number(options.damping ?? 0.5, 'damping', 0, 20)
248
+ const { width, height } = host.getActualSize()
249
+ number(width, 'Container width', 1, 10000)
250
+ number(height, 'Container height', 1, 10000)
251
+ for (
252
+ let parent: View | undefined = host;
253
+ parent;
254
+ parent = parent.parent as View | undefined
255
+ )
256
+ if (!untransformed(parent))
257
+ throw new Error('Physics requires an untransformed container and ancestors.')
258
+ const ids: string[] = [],
259
+ unique = new Set<View>()
260
+ let views: View[] = []
261
+ const config = Array.from(bodies, (body) => {
262
+ if (!body || typeof body.id !== 'string' || !body.id.trim() || ids.includes(body.id))
263
+ throw new TypeError('Each circle needs a unique, nonempty id.')
264
+ ids.push(body.id)
265
+ const view = toView(body.view)
266
+ if (view.parent !== host || unique.has(view) || !untransformed(view))
267
+ throw new Error('Use distinct, untransformed direct children for physics circles.')
268
+ if (owners.has(view) || owners.has(host!))
269
+ throw new Error('Physics view already has an owner.')
270
+ if (!view.isLoaded || !view.nativeViewProtected)
271
+ throw new Error('Create physics after native layout.')
272
+ if (!view.isEnabled || view.isUserInteractionEnabled === false)
273
+ throw new Error('Physics circles must accept touch input.')
274
+ // Physics owns native input. A tap/drag/etc listener would compete with the native recognizer.
275
+ for (const gesture of [1, 2, 4, 8, 16, 32, 64, 128])
276
+ if (view.getGestureObservers?.(gesture)?.length)
277
+ throw new Error('Physics circles require exclusive native touch input.')
278
+ const radius = number(body.radius, 'radius', 12, 256),
279
+ mass = number(body.mass ?? 1, 'mass', 0.1, 100)
280
+ const size = view.getActualSize()
281
+ if (Math.abs(size.width - radius * 2) > 1 || Math.abs(size.height - radius * 2) > 1)
282
+ throw new Error('Circle views must be square and sized to twice their radius.')
283
+ const x = number(body.x, 'x', radius, width - radius),
284
+ y = number(body.y, 'y', radius, height - radius)
285
+ const velocity = vector(body.velocity ?? { x: 0, y: 0 }, 'velocity', 1200)
286
+ if (Math.hypot(velocity.x, velocity.y) > 1200)
287
+ throw new RangeError('Circle speed cannot exceed 1200 DIPs/s.')
288
+ views.push(view)
289
+ unique.add(view)
290
+ return {
291
+ x,
292
+ y,
293
+ radius,
294
+ mass,
295
+ vx: velocity.x,
296
+ vy: velocity.y,
297
+ attachment: prepareAttachment(body.attachment ?? null, width, height),
298
+ snap: prepareSnap(body.snap, width, height, radius),
299
+ drag: prepareDrag(body.drag, width, height),
300
+ }
301
+ })
302
+ if (!host.isLoaded || !host.nativeViewProtected)
303
+ throw new Error('Create physics after native layout.')
304
+ if (
305
+ config.reduce((area, b) => area + Math.PI * b.radius ** 2, 0) >
306
+ width * height * 0.4
307
+ )
308
+ throw new RangeError('Circles may occupy at most 40% of the container area.')
309
+ config.forEach((a, i) =>
310
+ config.slice(i + 1).forEach((b) => {
311
+ if (Math.hypot(a.x - b.x, a.y - b.y) < a.radius + b.radius)
312
+ throw new RangeError('Initial circles must not overlap.')
313
+ }),
314
+ )
315
+ let native: CircleDriver | undefined,
316
+ ended = false,
317
+ held = false,
318
+ background = false
319
+ let worldRef: PhysicsWorld | undefined
320
+ const originalNative = new Map([host, ...views].map((v) => [v, v.nativeViewProtected]))
321
+ const releases: (() => void)[] = [],
322
+ unloaded = new Set<View>()
323
+ const update = () => {
324
+ if (ended || !host || !native) return
325
+ if (
326
+ [host, ...views].some(
327
+ (v) => v.nativeViewProtected && v.nativeViewProtected !== originalNative.get(v),
328
+ )
329
+ ) {
330
+ // A rebuilt native hierarchy needs fresh recognizers and original-state captures.
331
+ worldRef?.dispose()
332
+ return
333
+ }
334
+ native.resize(host.getActualSize().width, host.getActualSize().height)
335
+ native.enabled(
336
+ !held &&
337
+ !background &&
338
+ !unloaded.size &&
339
+ (policy === 'continue' || !reducedMotion()) &&
340
+ views.every((v) => v.parent === host && v.isLoaded && !!v.nativeViewProtected),
341
+ )
342
+ }
343
+ const suspend = () => {
344
+ background = true
345
+ update()
346
+ },
347
+ resume = () => {
348
+ background = false
349
+ update()
350
+ }
351
+ const cleanup = () => {
352
+ releases.splice(0).forEach((fn) => fn())
353
+ views.forEach((v) => owners.delete(v))
354
+ if (host) owners.delete(host)
355
+ views = []
356
+ host = undefined
357
+ unloaded.clear()
358
+ originalNative.clear()
359
+ }
360
+ try {
361
+ native = createCircleDriver(host, views, {
362
+ width,
363
+ height,
364
+ gravity,
365
+ restitution,
366
+ damping,
367
+ bodies: config,
368
+ })
369
+ ;[host, ...views].forEach((v) => {
370
+ owners.add(v)
371
+ const loaded = () => {
372
+ unloaded.delete(v)
373
+ update()
374
+ },
375
+ unload = () => {
376
+ unloaded.add(v)
377
+ update()
378
+ }
379
+ v.on('loaded', loaded)
380
+ v.on('unloaded', unload)
381
+ v.on('layoutChanged', update)
382
+ releases.push(() => {
383
+ v.off('loaded', loaded)
384
+ v.off('unloaded', unload)
385
+ v.off('layoutChanged', update)
386
+ })
387
+ })
388
+ Application.on(Application.suspendEvent, suspend)
389
+ Application.on(Application.resumeEvent, resume)
390
+ releases.push(() => {
391
+ Application.off(Application.suspendEvent, suspend)
392
+ Application.off(Application.resumeEvent, resume)
393
+ }, onReducedMotion(update))
394
+ const world: PhysicsWorld = {
395
+ get disposed() {
396
+ return ended
397
+ },
398
+ get paused() {
399
+ return held
400
+ },
401
+ pause() {
402
+ if (!ended) {
403
+ held = true
404
+ update()
405
+ }
406
+ },
407
+ play() {
408
+ if (!ended) {
409
+ held = false
410
+ update()
411
+ }
412
+ },
413
+ reset() {
414
+ if (!ended) native!.reset()
415
+ },
416
+ impulse(id, impulse) {
417
+ const index = ids.indexOf(id)
418
+ if (index < 0) throw new RangeError(`Unknown circle: ${id}`)
419
+ const v = vector(impulse, 'impulse', 120000)
420
+ if (!ended) native!.impulse(index, v.x, v.y)
421
+ },
422
+ attach(id, attachment) {
423
+ const index = ids.indexOf(id)
424
+ if (index < 0) throw new RangeError(`Unknown circle: ${id}`)
425
+ if (ended) return
426
+ const size = host!.getActualSize()
427
+ number(size.width, 'Container width', 1, 10000)
428
+ number(size.height, 'Container height', 1, 10000)
429
+ if (
430
+ config.some((b) => 2 * b.radius > Math.min(size.width, size.height)) ||
431
+ config.reduce((a, b) => a + Math.PI * b.radius ** 2, 0) >
432
+ size.width * size.height * 0.4
433
+ )
434
+ throw new RangeError(
435
+ 'Resize the container to fit its circles before updating an attachment.',
436
+ )
437
+ const prepared = prepareAttachment(attachment, size.width, size.height)
438
+ update()
439
+ if (!ended) native!.attach(index, prepared)
440
+ },
441
+ snapTo(id, index) {
442
+ const body = ids.indexOf(id)
443
+ if (body < 0) throw new RangeError(`Unknown circle: ${id}`)
444
+ const count = config[body]!.snap?.points.length ?? 0
445
+ if (!Number.isInteger(index) || index < 0 || index >= count)
446
+ throw new RangeError('Unknown snap point.')
447
+ if (!ended) native!.snapTo(body, index)
448
+ },
449
+ snapshot() {
450
+ const result = native!.snapshot()
451
+ return { ...result, bodies: result.bodies.map((b, i) => ({ ...b, id: ids[i]! })) }
452
+ },
453
+ dispose() {
454
+ if (ended) return
455
+ ended = true
456
+ try {
457
+ native!.dispose()
458
+ } finally {
459
+ cleanup()
460
+ }
461
+ },
462
+ }
463
+ worldRef = world
464
+ options.scope?.add(world)
465
+ update()
466
+ return world
467
+ } catch (error) {
468
+ ended = true
469
+ try {
470
+ native?.dispose()
471
+ } finally {
472
+ cleanup()
473
+ }
474
+ throw error
475
+ }
476
+ }