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