basalt-core 0.0.0-rc5

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 (325) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli/basalt.d.ts +3 -0
  3. package/dist/cli/basalt.d.ts.map +1 -0
  4. package/dist/cli/basalt.js +47 -0
  5. package/dist/cli/basalt.js.map +1 -0
  6. package/dist/cli/bundle-cli.d.ts +12 -0
  7. package/dist/cli/bundle-cli.d.ts.map +1 -0
  8. package/dist/cli/bundle-cli.js +124 -0
  9. package/dist/cli/bundle-cli.js.map +1 -0
  10. package/dist/cli/bundleWithAssets.d.ts +79 -0
  11. package/dist/cli/bundleWithAssets.d.ts.map +1 -0
  12. package/dist/cli/bundleWithAssets.js +198 -0
  13. package/dist/cli/bundleWithAssets.js.map +1 -0
  14. package/dist/cli/desktop.d.ts +339 -0
  15. package/dist/cli/desktop.d.ts.map +1 -0
  16. package/dist/cli/desktop.js +1029 -0
  17. package/dist/cli/desktop.js.map +1 -0
  18. package/dist/cli/doctor.d.ts +31 -0
  19. package/dist/cli/doctor.d.ts.map +1 -0
  20. package/dist/cli/doctor.js +283 -0
  21. package/dist/cli/doctor.js.map +1 -0
  22. package/dist/cli/init.d.ts +77 -0
  23. package/dist/cli/init.d.ts.map +1 -0
  24. package/dist/cli/init.js +442 -0
  25. package/dist/cli/init.js.map +1 -0
  26. package/dist/cli/metro.d.ts +49 -0
  27. package/dist/cli/metro.d.ts.map +1 -0
  28. package/dist/cli/metro.js +148 -0
  29. package/dist/cli/metro.js.map +1 -0
  30. package/dist/cli/packageApp.d.ts +102 -0
  31. package/dist/cli/packageApp.d.ts.map +1 -0
  32. package/dist/cli/packageApp.js +319 -0
  33. package/dist/cli/packageApp.js.map +1 -0
  34. package/dist/cli/steps.d.ts +34 -0
  35. package/dist/cli/steps.d.ts.map +1 -0
  36. package/dist/cli/steps.js +53 -0
  37. package/dist/cli/steps.js.map +1 -0
  38. package/dist/metro-config.d.ts +168 -0
  39. package/dist/metro-config.d.ts.map +1 -0
  40. package/dist/metro-config.js +671 -0
  41. package/dist/metro-config.js.map +1 -0
  42. package/dist/react-native.config.d.ts +7 -0
  43. package/dist/react-native.config.d.ts.map +1 -0
  44. package/dist/react-native.config.js +80 -0
  45. package/dist/react-native.config.js.map +1 -0
  46. package/dist/src/DragSource.d.ts +52 -0
  47. package/dist/src/DragSource.d.ts.map +1 -0
  48. package/dist/src/DragSource.js +97 -0
  49. package/dist/src/DragSource.js.map +1 -0
  50. package/dist/src/DropTarget.d.ts +58 -0
  51. package/dist/src/DropTarget.d.ts.map +1 -0
  52. package/dist/src/DropTarget.js +131 -0
  53. package/dist/src/DropTarget.js.map +1 -0
  54. package/dist/src/KeyHandler.d.ts +57 -0
  55. package/dist/src/KeyHandler.d.ts.map +1 -0
  56. package/dist/src/KeyHandler.js +48 -0
  57. package/dist/src/KeyHandler.js.map +1 -0
  58. package/dist/src/Menu.d.ts +72 -0
  59. package/dist/src/Menu.d.ts.map +1 -0
  60. package/dist/src/Menu.js +179 -0
  61. package/dist/src/Menu.js.map +1 -0
  62. package/dist/src/TitleBar.d.ts +75 -0
  63. package/dist/src/TitleBar.d.ts.map +1 -0
  64. package/dist/src/TitleBar.js +236 -0
  65. package/dist/src/TitleBar.js.map +1 -0
  66. package/dist/src/Window.d.ts +87 -0
  67. package/dist/src/Window.d.ts.map +1 -0
  68. package/dist/src/Window.js +248 -0
  69. package/dist/src/Window.js.map +1 -0
  70. package/dist/src/closeRequest.d.ts +55 -0
  71. package/dist/src/closeRequest.d.ts.map +1 -0
  72. package/dist/src/closeRequest.js +134 -0
  73. package/dist/src/closeRequest.js.map +1 -0
  74. package/dist/src/index.d.ts +45 -0
  75. package/dist/src/index.d.ts.map +1 -0
  76. package/dist/src/index.js +92 -0
  77. package/dist/src/index.js.map +1 -0
  78. package/dist/src/overrides/Alert.d.ts +69 -0
  79. package/dist/src/overrides/Alert.d.ts.map +1 -0
  80. package/dist/src/overrides/Alert.js +112 -0
  81. package/dist/src/overrides/Alert.js.map +1 -0
  82. package/dist/src/overrides/BaseViewConfig.d.ts +28 -0
  83. package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -0
  84. package/dist/src/overrides/BaseViewConfig.js +72 -0
  85. package/dist/src/overrides/BaseViewConfig.js.map +1 -0
  86. package/dist/src/overrides/Platform.linux.d.ts +10 -0
  87. package/dist/src/overrides/Platform.linux.d.ts.map +1 -0
  88. package/dist/src/overrides/Platform.linux.js +15 -0
  89. package/dist/src/overrides/Platform.linux.js.map +1 -0
  90. package/dist/src/overrides/Platform.macos.d.ts +10 -0
  91. package/dist/src/overrides/Platform.macos.d.ts.map +1 -0
  92. package/dist/src/overrides/Platform.macos.js +15 -0
  93. package/dist/src/overrides/Platform.macos.js.map +1 -0
  94. package/dist/src/overrides/Platform.windows.d.ts +10 -0
  95. package/dist/src/overrides/Platform.windows.d.ts.map +1 -0
  96. package/dist/src/overrides/Platform.windows.js +15 -0
  97. package/dist/src/overrides/Platform.windows.js.map +1 -0
  98. package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts +24 -0
  99. package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts.map +1 -0
  100. package/dist/src/overrides/ReactDevToolsSettingsManager.js +30 -0
  101. package/dist/src/overrides/ReactDevToolsSettingsManager.js.map +1 -0
  102. package/dist/src/overrides/RefreshControl.d.ts +52 -0
  103. package/dist/src/overrides/RefreshControl.d.ts.map +1 -0
  104. package/dist/src/overrides/RefreshControl.js +92 -0
  105. package/dist/src/overrides/RefreshControl.js.map +1 -0
  106. package/dist/src/overrides/ScrollView.d.ts +39 -0
  107. package/dist/src/overrides/ScrollView.d.ts.map +1 -0
  108. package/dist/src/overrides/ScrollView.js +59 -0
  109. package/dist/src/overrides/ScrollView.js.map +1 -0
  110. package/dist/src/overrides/Share.d.ts +96 -0
  111. package/dist/src/overrides/Share.d.ts.map +1 -0
  112. package/dist/src/overrides/Share.js +97 -0
  113. package/dist/src/overrides/Share.js.map +1 -0
  114. package/dist/src/overrides/TextInput.d.ts +81 -0
  115. package/dist/src/overrides/TextInput.d.ts.map +1 -0
  116. package/dist/src/overrides/TextInput.js +213 -0
  117. package/dist/src/overrides/TextInput.js.map +1 -0
  118. package/dist/src/overrides/View.d.ts +36 -0
  119. package/dist/src/overrides/View.d.ts.map +1 -0
  120. package/dist/src/overrides/View.js +99 -0
  121. package/dist/src/overrides/View.js.map +1 -0
  122. package/dist/src/overrides/createPlatform.d.ts +32 -0
  123. package/dist/src/overrides/createPlatform.d.ts.map +1 -0
  124. package/dist/src/overrides/createPlatform.js +84 -0
  125. package/dist/src/overrides/createPlatform.js.map +1 -0
  126. package/dist/src/overrides/setUpDeveloperTools.d.ts +28 -0
  127. package/dist/src/overrides/setUpDeveloperTools.d.ts.map +1 -0
  128. package/dist/src/overrides/setUpDeveloperTools.js +84 -0
  129. package/dist/src/overrides/setUpDeveloperTools.js.map +1 -0
  130. package/dist/src/overrides/setUpXHR.d.ts +46 -0
  131. package/dist/src/overrides/setUpXHR.d.ts.map +1 -0
  132. package/dist/src/overrides/setUpXHR.js +236 -0
  133. package/dist/src/overrides/setUpXHR.js.map +1 -0
  134. package/dist/src/quitRequest.d.ts +55 -0
  135. package/dist/src/quitRequest.d.ts.map +1 -0
  136. package/dist/src/quitRequest.js +121 -0
  137. package/dist/src/quitRequest.js.map +1 -0
  138. package/dist/src/resourcePath.d.ts +18 -0
  139. package/dist/src/resourcePath.d.ts.map +1 -0
  140. package/dist/src/resourcePath.js +31 -0
  141. package/dist/src/resourcePath.js.map +1 -0
  142. package/dist/src/responseBody.d.ts +76 -0
  143. package/dist/src/responseBody.d.ts.map +1 -0
  144. package/dist/src/responseBody.js +94 -0
  145. package/dist/src/responseBody.js.map +1 -0
  146. package/dist/src/responseHeaders.d.ts +40 -0
  147. package/dist/src/responseHeaders.d.ts.map +1 -0
  148. package/dist/src/responseHeaders.js +75 -0
  149. package/dist/src/responseHeaders.js.map +1 -0
  150. package/dist/src/titleBarState.d.ts +43 -0
  151. package/dist/src/titleBarState.d.ts.map +1 -0
  152. package/dist/src/titleBarState.js +77 -0
  153. package/dist/src/titleBarState.js.map +1 -0
  154. package/dist/src/useContextMenu.d.ts +113 -0
  155. package/dist/src/useContextMenu.d.ts.map +1 -0
  156. package/dist/src/useContextMenu.js +109 -0
  157. package/dist/src/useContextMenu.js.map +1 -0
  158. package/dist/src/useDialog.d.ts +98 -0
  159. package/dist/src/useDialog.d.ts.map +1 -0
  160. package/dist/src/useDialog.js +112 -0
  161. package/dist/src/useDialog.js.map +1 -0
  162. package/dist/src/useDisplays.d.ts +70 -0
  163. package/dist/src/useDisplays.d.ts.map +1 -0
  164. package/dist/src/useDisplays.js +118 -0
  165. package/dist/src/useDisplays.js.map +1 -0
  166. package/dist/src/useHandledKeys.d.ts +38 -0
  167. package/dist/src/useHandledKeys.d.ts.map +1 -0
  168. package/dist/src/useHandledKeys.js +70 -0
  169. package/dist/src/useHandledKeys.js.map +1 -0
  170. package/dist/src/useWindow.d.ts +140 -0
  171. package/dist/src/useWindow.d.ts.map +1 -0
  172. package/dist/src/useWindow.js +233 -0
  173. package/dist/src/useWindow.js.map +1 -0
  174. package/dist/tsconfig.tsbuildinfo +1 -0
  175. package/native/CMakeLists.txt +355 -0
  176. package/native/bootstrap.sh +613 -0
  177. package/native/cmake/CompilerFlags.cmake +49 -0
  178. package/native/cmake/Expo.cmake +125 -0
  179. package/native/cmake/ReactNativeCore.cmake +612 -0
  180. package/native/cmake/Reanimated.cmake +108 -0
  181. package/native/cmake/Skia.cmake +379 -0
  182. package/native/cmake/ThirdParty.cmake +290 -0
  183. package/native/cmake/Worklets.cmake +67 -0
  184. package/native/cmake/codegen/CMakeLists.txt +32 -0
  185. package/native/core/AppIdentity.cpp +85 -0
  186. package/native/core/AppIdentity.h +59 -0
  187. package/native/core/AppPaths.cpp +96 -0
  188. package/native/core/AppPaths.h +53 -0
  189. package/native/core/AppearanceModule.cpp +60 -0
  190. package/native/core/AppearanceModule.h +40 -0
  191. package/native/core/Backface.h +59 -0
  192. package/native/core/BlobModule.cpp +283 -0
  193. package/native/core/BlobModule.h +76 -0
  194. package/native/core/BlobRegistry.cpp +75 -0
  195. package/native/core/BlobRegistry.h +44 -0
  196. package/native/core/ColorScheme.cpp +105 -0
  197. package/native/core/ColorScheme.h +59 -0
  198. package/native/core/ComponentRegistry.h +30 -0
  199. package/native/core/ControlMetrics.h +37 -0
  200. package/native/core/CoreModules.cpp +592 -0
  201. package/native/core/CoreModules.h +308 -0
  202. package/native/core/DebuggingOverlay.cpp +106 -0
  203. package/native/core/DebuggingOverlay.h +65 -0
  204. package/native/core/DesktopControls.cpp +232 -0
  205. package/native/core/DesktopControls.h +170 -0
  206. package/native/core/DevBundle.cpp +108 -0
  207. package/native/core/DevBundle.h +69 -0
  208. package/native/core/DevMenu.cpp +99 -0
  209. package/native/core/DevMenu.h +75 -0
  210. package/native/core/DialogModule.cpp +150 -0
  211. package/native/core/DialogModule.h +51 -0
  212. package/native/core/DragAndDrop.cpp +45 -0
  213. package/native/core/DragAndDrop.h +225 -0
  214. package/native/core/ExpoImageComponent.cpp +79 -0
  215. package/native/core/ExpoImageComponent.h +80 -0
  216. package/native/core/ExpoModules.cpp +415 -0
  217. package/native/core/ExpoModules.h +115 -0
  218. package/native/core/ExpoRuntime.cpp +366 -0
  219. package/native/core/ExpoRuntime.h +42 -0
  220. package/native/core/FocusRing.h +36 -0
  221. package/native/core/FontRegistry.h +51 -0
  222. package/native/core/GestureHandlerModule.cpp +136 -0
  223. package/native/core/GestureHandlerModule.h +71 -0
  224. package/native/core/Gestures.cpp +533 -0
  225. package/native/core/Gestures.h +145 -0
  226. package/native/core/HoverTracker.cpp +69 -0
  227. package/native/core/HoverTracker.h +109 -0
  228. package/native/core/HttpClient.cpp +282 -0
  229. package/native/core/ImageBytes.cpp +205 -0
  230. package/native/core/ImageBytes.h +29 -0
  231. package/native/core/ImageCache.cpp +51 -0
  232. package/native/core/ImageCache.h +89 -0
  233. package/native/core/JsRuntimeAccess.cpp +70 -0
  234. package/native/core/JsRuntimeAccess.h +60 -0
  235. package/native/core/JsiPromise.h +51 -0
  236. package/native/core/KeyEvents.cpp +116 -0
  237. package/native/core/KeyEvents.h +144 -0
  238. package/native/core/LogBoxSurface.cpp +46 -0
  239. package/native/core/LogBoxSurface.h +68 -0
  240. package/native/core/MenuModel.h +117 -0
  241. package/native/core/MenuModule.cpp +209 -0
  242. package/native/core/MenuModule.h +66 -0
  243. package/native/core/MountingWalk.h +524 -0
  244. package/native/core/PackageModules.cpp.in +25 -0
  245. package/native/core/PackageModules.h +50 -0
  246. package/native/core/PlatformConstantsModule.cpp +63 -0
  247. package/native/core/PlatformConstantsModule.h +64 -0
  248. package/native/core/PlatformServices.h +213 -0
  249. package/native/core/PointerButtons.h +63 -0
  250. package/native/core/PullToRefresh.cpp +57 -0
  251. package/native/core/PullToRefresh.h +73 -0
  252. package/native/core/ReanimatedCompat.h +47 -0
  253. package/native/core/ReanimatedModule.cpp +203 -0
  254. package/native/core/ReanimatedModule.h +55 -0
  255. package/native/core/ScrollAnimation.cpp +59 -0
  256. package/native/core/ScrollAnimation.h +70 -0
  257. package/native/core/ScrollBounds.cpp +26 -0
  258. package/native/core/ScrollBounds.h +68 -0
  259. package/native/core/ScrollIndicator.cpp +50 -0
  260. package/native/core/ScrollIndicator.h +69 -0
  261. package/native/core/ScrollMomentum.cpp +71 -0
  262. package/native/core/ScrollMomentum.h +73 -0
  263. package/native/core/ScrollSnap.cpp +123 -0
  264. package/native/core/ScrollSnap.h +80 -0
  265. package/native/core/ShareFallback.cpp +101 -0
  266. package/native/core/ShareFallback.h +45 -0
  267. package/native/core/SkiaPictureViewComponent.cpp +11 -0
  268. package/native/core/SkiaPictureViewComponent.h +47 -0
  269. package/native/core/SourceCodeModule.cpp +55 -0
  270. package/native/core/SourceCodeModule.h +53 -0
  271. package/native/core/StatusBarModule.cpp +23 -0
  272. package/native/core/StatusBarModule.h +42 -0
  273. package/native/core/TestDialog.cpp +148 -0
  274. package/native/core/TestDialog.h +96 -0
  275. package/native/core/TestKeys.cpp +78 -0
  276. package/native/core/TestKeys.h +50 -0
  277. package/native/core/TestQuitFile.cpp +33 -0
  278. package/native/core/TestQuitFile.h +60 -0
  279. package/native/core/TestSettle.h +192 -0
  280. package/native/core/TitleBarRegions.h +31 -0
  281. package/native/core/TurboModuleProxy.cpp +51 -0
  282. package/native/core/TurboModuleProxy.h +46 -0
  283. package/native/core/UIManagerAccess.cpp +43 -0
  284. package/native/core/UIManagerAccess.h +43 -0
  285. package/native/core/WindowBoundsCache.cpp +319 -0
  286. package/native/core/WindowControl.h +235 -0
  287. package/native/core/WindowHost.h +158 -0
  288. package/native/core/WindowMethods.cpp +167 -0
  289. package/native/core/WindowMethods.h +84 -0
  290. package/native/core/WindowsModule.cpp +448 -0
  291. package/native/core/WindowsModule.h +133 -0
  292. package/native/core/WorkletsModule.cpp +199 -0
  293. package/native/core/WorkletsModule.h +57 -0
  294. package/native/core/portability_probe.cpp +210 -0
  295. package/native/tests/EventRecorder.h +124 -0
  296. package/native/tests/TestHarness.cpp +109 -0
  297. package/native/tests/TestHarness.h +89 -0
  298. package/native/tests/TreeDump.h +49 -0
  299. package/native/tests/test_app_identity.cpp +114 -0
  300. package/native/tests/test_app_paths.cpp +48 -0
  301. package/native/tests/test_appearance.cpp +107 -0
  302. package/native/tests/test_backface.cpp +79 -0
  303. package/native/tests/test_blobs.cpp +157 -0
  304. package/native/tests/test_controls.cpp +185 -0
  305. package/native/tests/test_devbundle.cpp +103 -0
  306. package/native/tests/test_drag_and_drop.cpp +143 -0
  307. package/native/tests/test_gestures.cpp +331 -0
  308. package/native/tests/test_hover.cpp +92 -0
  309. package/native/tests/test_image_cache.cpp +109 -0
  310. package/native/tests/test_js_runtime_access.cpp +137 -0
  311. package/native/tests/test_key_events.cpp +235 -0
  312. package/native/tests/test_momentum.cpp +138 -0
  313. package/native/tests/test_quit_file.cpp +104 -0
  314. package/native/tests/test_scroll_animation.cpp +120 -0
  315. package/native/tests/test_scroll_bounds.cpp +66 -0
  316. package/native/tests/test_scroll_indicator.cpp +149 -0
  317. package/native/tests/test_scroll_snap.cpp +112 -0
  318. package/native/tests/test_settle.cpp +115 -0
  319. package/native/tests/test_share.cpp +75 -0
  320. package/native/tests/test_sourcecode.cpp +62 -0
  321. package/native/tests/test_window_close.cpp +119 -0
  322. package/native/tests/test_window_limits.cpp +123 -0
  323. package/package.json +43 -0
  324. package/react-native.config.js +86 -0
  325. package/supported-versions.json +66 -0
@@ -0,0 +1,203 @@
1
+ #include "ReanimatedModule.h"
2
+
3
+ #include "Gestures.h"
4
+ #include "PlatformServices.h"
5
+ #include "UIManagerAccess.h"
6
+
7
+ #include <glog/logging.h>
8
+
9
+ #ifdef BASALT_HAS_REANIMATED
10
+ #include <reanimated/NativeModules/ReanimatedModuleProxy.h>
11
+ #include <reanimated/RuntimeDecorators/RNRuntimeDecorator.h>
12
+ #include <reanimated/Tools/PlatformDepMethodsHolder.h>
13
+ #include <worklets/Compat/StableApi.h>
14
+ #endif
15
+
16
+ namespace basalt {
17
+
18
+ bool hasReanimated() {
19
+ #ifdef BASALT_HAS_REANIMATED
20
+ return true;
21
+ #else
22
+ return false;
23
+ #endif
24
+ }
25
+
26
+ #ifdef BASALT_HAS_REANIMATED
27
+
28
+ namespace {
29
+
30
+ using facebook::jsi::Runtime;
31
+ using facebook::jsi::Value;
32
+ using facebook::react::TurboModule;
33
+
34
+ std::shared_ptr<reanimated::ReanimatedModuleProxy> &heldProxy() {
35
+ static std::shared_ptr<reanimated::ReanimatedModuleProxy> proxy;
36
+ return proxy;
37
+ }
38
+
39
+ // Reanimated's operations are flushed once a frame, forever, from the moment it
40
+ // is installed. The frame is a timer for the same reason worklets' is: the
41
+ // display link on each platform belongs to React Native's own choreographer,
42
+ // which pauses whenever React Native has no animation of its own -- which is
43
+ // exactly when a Reanimated one might be running.
44
+ constexpr double kFrameMilliseconds = 16;
45
+
46
+ void scheduleFlush() {
47
+ postDelayed(kFrameMilliseconds, []() {
48
+ if (auto proxy = heldProxy()) {
49
+ proxy->performOperations();
50
+ scheduleFlush();
51
+ }
52
+ });
53
+ }
54
+
55
+ reanimated::PlatformDepMethodsHolder makePlatformDepMethodsHolder() {
56
+ reanimated::PlatformDepMethodsHolder holder{};
57
+
58
+ holder.requestRender = [](std::function<void(const double)> callback) {
59
+ postDelayed(kFrameMilliseconds, [callback = std::move(callback)]() {
60
+ callback(monotonicMilliseconds());
61
+ });
62
+ };
63
+
64
+ #ifdef __APPLE__
65
+ // iOS takes a snapshot of a view before a shared-element transition. Nothing
66
+ // here does shared-element transitions, and the field exists on Apple builds
67
+ // whether or not it is used.
68
+ holder.forceScreenSnapshotFunction = [](facebook::react::Tag) {};
69
+ #endif
70
+
71
+ // The direct-to-view path, which skips the shadow tree for props that can be
72
+ // applied to a mounted view immediately. Not wired: this platform's mounting
73
+ // managers only accept mutations from a Fabric transaction, which is what
74
+ // makes their thread rule assertable. Reanimated's other path -- committing
75
+ // to the shadow tree -- is the one used here, and it is the one that works on
76
+ // every platform.
77
+ holder.synchronouslyUpdateUIPropsFunction = [](const int, const folly::dynamic &) {};
78
+
79
+ holder.getAnimationTimestamp = []() { return monotonicMilliseconds(); };
80
+
81
+ // useAnimatedSensor. A desktop has no accelerometer, gyroscope or
82
+ // magnetometer; -1 is Reanimated's own "could not register".
83
+ holder.registerSensor = [](int, int, int, std::function<void(double[], int)>) { return -1; };
84
+ holder.unregisterSensor = [](int) {};
85
+
86
+ // A worklet telling a gesture handler what to do, which is how
87
+ // GestureStateManager.activate() and friends work. The registry is
88
+ // core/Gestures.h's, so this is the two halves of phase 37 and phase 38
89
+ // meeting.
90
+ holder.setGestureStateFunction = [](int handlerTag, int newState) {
91
+ postToUiThread([handlerTag, newState]() { gestures().setStateFromWorklet(handlerTag, newState); });
92
+ };
93
+
94
+ // A desktop has no soft keyboard to move out of the way of.
95
+ holder.subscribeForKeyboardEvents = [](std::function<void(int, int)>, bool, bool) { return 0; };
96
+ holder.unsubscribeFromKeyboardEvents = [](int) {};
97
+
98
+ holder.maybeFlushUIUpdatesQueueFunction = []() {};
99
+
100
+ // CSS transitions driven by the platform rather than by Reanimated's own
101
+ // clock -- an optimisation Apple has and this does not. Declining every
102
+ // property means Reanimated animates them itself.
103
+ holder.cssCanRouteProperty = [](const std::string &,
104
+ const reanimated::css::EasingConfig &) { return false; };
105
+ holder.cssRemoveTransition = [](facebook::react::Tag, const std::string &) {};
106
+
107
+ // Hover and press pseudo-selectors, which need the view layer to report
108
+ // pointer state per view. Not wired yet.
109
+ holder.attachPseudoSelector = [](facebook::react::Tag,
110
+ reanimated::PseudoSelector,
111
+ std::function<void(bool)>) {};
112
+ holder.detachPseudoSelector = [](facebook::react::Tag, reanimated::PseudoSelector) {};
113
+
114
+ return holder;
115
+ }
116
+
117
+ } // namespace
118
+
119
+ DesktopReanimatedModule::DesktopReanimatedModule(
120
+ std::shared_ptr<facebook::react::CallInvoker> jsInvoker)
121
+ : TurboModule(kModuleName, std::move(jsInvoker)) {
122
+ methodMap_["installTurboModule"] = MethodMetadata{0, installTurboModule};
123
+ }
124
+
125
+ DesktopReanimatedModule::~DesktopReanimatedModule() {
126
+ heldProxy().reset();
127
+ }
128
+
129
+ Value DesktopReanimatedModule::installTurboModule(Runtime &runtime,
130
+ TurboModule &module,
131
+ const Value * /*args*/,
132
+ size_t /*count*/) {
133
+ auto &self = static_cast<DesktopReanimatedModule &>(module);
134
+
135
+ // Worklets put both of these on the JavaScript global when its own module
136
+ // installed. Reading them back is Reanimated's own arrangement for finding
137
+ // the runtime it shares with worklets rather than making a second one.
138
+ auto global = runtime.global();
139
+ auto uiWorkletRuntime = worklets::getWorkletRuntimeFromHolder(
140
+ runtime, global.getPropertyAsObject(runtime, "__UI_WORKLET_RUNTIME_HOLDER"));
141
+ auto uiScheduler = worklets::getUISchedulerFromHolder(
142
+ runtime, global.getPropertyAsObject(runtime, "__UI_SCHEDULER_HOLDER"));
143
+
144
+ if (uiWorkletRuntime == nullptr || uiScheduler == nullptr) {
145
+ LOG(ERROR) << "reanimated: the worklets runtime is not installed; is "
146
+ "react-native-worklets compiled into this host?";
147
+ return Value(false);
148
+ }
149
+
150
+ const auto platformDepMethodsHolder = makePlatformDepMethodsHolder();
151
+ auto proxy = std::make_shared<reanimated::ReanimatedModuleProxy>(uiWorkletRuntime,
152
+ uiScheduler,
153
+ runtime,
154
+ self.jsInvoker_,
155
+ platformDepMethodsHolder,
156
+ /*isReducedMotion=*/false);
157
+ proxy->init(platformDepMethodsHolder);
158
+
159
+ auto &uiRuntime = worklets::getJSIRuntimeFromWorkletRuntime(uiWorkletRuntime);
160
+ reanimated::RNRuntimeDecorator::decorate(runtime, uiRuntime, proxy);
161
+
162
+ // The shadow-tree half. Without a UIManager Reanimated still runs -- shared
163
+ // values update and callbacks fire -- and nothing it animates reaches the
164
+ // screen, which is the confusing failure, so it is worth a loud line.
165
+ if (auto uiManager = sharedUIManager()) {
166
+ proxy->initializeFabric(uiManager);
167
+ } else {
168
+ LOG(ERROR) << "reanimated: no UIManager, so animated styles will not be applied";
169
+ }
170
+
171
+ // Every event Fabric dispatches, offered to Reanimated before the components
172
+ // see it. That is how a scroll handler or a gesture callback written as a
173
+ // worklet runs at all: without it they are declared, attached and never
174
+ // called.
175
+ //
176
+ // Only events raised on the UI thread, which is what iOS does and for the
177
+ // same reason -- a worklet runtime may only be touched from the thread that
178
+ // owns it, and an event from the JavaScript thread (a layout, a state update)
179
+ // arrives on the wrong one.
180
+ std::weak_ptr<reanimated::ReanimatedModuleProxy> weakProxy = proxy;
181
+ const bool listening = installEventListener(std::make_shared<facebook::react::EventListener>(
182
+ [weakProxy](const facebook::react::RawEvent &rawEvent) {
183
+ if (!isUiThread()) {
184
+ return false;
185
+ }
186
+ if (auto proxy = weakProxy.lock()) {
187
+ return proxy->handleRawEvent(rawEvent, monotonicMilliseconds());
188
+ }
189
+ return false;
190
+ }));
191
+ if (!listening) {
192
+ LOG(WARNING) << "reanimated: no event listener, so scroll and gesture "
193
+ "worklets will not run";
194
+ }
195
+
196
+ heldProxy() = proxy;
197
+ scheduleFlush();
198
+ return Value(true);
199
+ }
200
+
201
+ #endif
202
+
203
+ } // namespace basalt
@@ -0,0 +1,55 @@
1
+ // react-native-reanimated, on top of core/WorkletsModule.h.
2
+ //
3
+ // The same arrangement again, and by now the pattern is the point: the package
4
+ // ships a large body of portable C++ -- the animation clock, the shadow-tree
5
+ // cloning that applies an animated style without a React re-render, the CSS
6
+ // engine, the registries -- and a small per-platform half that wires it to a
7
+ // host. This is that half.
8
+ //
9
+ // It is a thicker seam than worklets' because Reanimated reaches further into
10
+ // the renderer. Three things have to be found for it:
11
+ //
12
+ // - The **UI worklet runtime** and its scheduler, which worklets installed on
13
+ // the JavaScript global and which Reanimated reads back from there. That is
14
+ // Reanimated's own arrangement, not something invented here.
15
+ // - The **UIManager**, because Reanimated commits to the shadow tree itself.
16
+ // ReactCxxPlatform hands one to the mounting manager, which is where this
17
+ // gets it; see core/UIManagerAccess.h.
18
+ // - A **frame**, on which its operations are flushed.
19
+ //
20
+ // What is deliberately not here is `PlatformDepMethodsHolder`'s long tail:
21
+ // sensors, keyboard events, screen snapshots and pseudo-selector observers are
22
+ // no-ops, because a desktop has no accelerometer and no soft keyboard, and the
23
+ // other two are iOS's answers to iOS problems. Each one is a field in a struct
24
+ // rather than a silent omission, which is the useful thing about that struct.
25
+
26
+ #pragma once
27
+
28
+ #include <ReactCommon/TurboModule.h>
29
+
30
+ #include <memory>
31
+
32
+ namespace basalt {
33
+
34
+ // Whether this build has react-native-reanimated compiled into it.
35
+ bool hasReanimated();
36
+
37
+ #ifdef BASALT_HAS_REANIMATED
38
+
39
+ class DesktopReanimatedModule : public facebook::react::TurboModule {
40
+ public:
41
+ static constexpr const char *kModuleName = "ReanimatedModule";
42
+
43
+ explicit DesktopReanimatedModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker);
44
+ ~DesktopReanimatedModule() override;
45
+
46
+ private:
47
+ static facebook::jsi::Value installTurboModule(facebook::jsi::Runtime &runtime,
48
+ facebook::react::TurboModule &module,
49
+ const facebook::jsi::Value *args,
50
+ size_t count);
51
+ };
52
+
53
+ #endif
54
+
55
+ } // namespace basalt
@@ -0,0 +1,59 @@
1
+ #include "ScrollAnimation.h"
2
+
3
+ namespace basalt {
4
+
5
+ namespace {
6
+
7
+ // Cubic ease-in-out on [0, 1]. See the header for why this curve.
8
+ double eased(double t) {
9
+ if (t < 0.5) {
10
+ return 4.0 * t * t * t;
11
+ }
12
+ const double shifted = -2.0 * t + 2.0;
13
+ return 1.0 - (shifted * shifted * shifted) / 2.0;
14
+ }
15
+
16
+ } // namespace
17
+
18
+ bool ScrollAnimation::start(double fromX, double fromY, double toX, double toY) {
19
+ if (fromX == toX && fromY == toY) {
20
+ running_ = false;
21
+ return false;
22
+ }
23
+ running_ = true;
24
+ elapsed_ = 0.0;
25
+ fromX_ = fromX;
26
+ fromY_ = fromY;
27
+ toX_ = toX;
28
+ toY_ = toY;
29
+ return true;
30
+ }
31
+
32
+ bool ScrollAnimation::advance(double seconds, double &x, double &y) {
33
+ if (!running_) {
34
+ x = toX_;
35
+ y = toY_;
36
+ return false;
37
+ }
38
+
39
+ elapsed_ += seconds;
40
+ if (elapsed_ >= kDurationSeconds) {
41
+ // Exactly the target, not the curve evaluated near 1.0. An app that scrolls
42
+ // to a computed offset and then reads it back should get its own number.
43
+ x = toX_;
44
+ y = toY_;
45
+ running_ = false;
46
+ return false;
47
+ }
48
+
49
+ const double progress = eased(elapsed_ / kDurationSeconds);
50
+ x = fromX_ + (toX_ - fromX_) * progress;
51
+ y = fromY_ + (toY_ - fromY_) * progress;
52
+ return true;
53
+ }
54
+
55
+ void ScrollAnimation::stop() {
56
+ running_ = false;
57
+ }
58
+
59
+ } // namespace basalt
@@ -0,0 +1,70 @@
1
+ // A programmatic scroll that moves rather than jumps.
2
+ //
3
+ // `scrollTo({x, y, animated: true})` is one of the most-used things a list does
4
+ // -- scroll to top, scroll to the newest message -- and until now the `animated`
5
+ // flag was parsed and dropped, so every one of them arrived instantly.
6
+ //
7
+ // ## Why this is not ScrollMomentum
8
+ //
9
+ // The file next door is deliberate about it: a fling is velocity with friction
10
+ // and *no target*, because where it lands is a consequence of how hard it was
11
+ // thrown. This is the opposite -- a target is the only thing given, and what has
12
+ // to be invented is the path to it. Exponential friction cannot be used here at
13
+ // all: it approaches its destination asymptotically and never arrives.
14
+ //
15
+ // So: a fixed duration and an easing curve, which is what UIScrollView and
16
+ // Android's smooth scroller both do, and what makes two of these in a row look
17
+ // deliberate rather than elastic.
18
+ //
19
+ // ## The curve
20
+ //
21
+ // Cubic ease-in-out. It starts slow, accelerates, and settles -- and, more
22
+ // usefully, its derivative is zero at both ends, so a scroll that begins where
23
+ // the last one ended has no visible seam. A linear ramp is the obvious
24
+ // alternative and looks mechanical precisely because it starts and stops at full
25
+ // speed.
26
+ //
27
+ // Absolute positions rather than deltas, unlike ScrollMomentum. A fling asks
28
+ // "how far since last frame", because it has no idea where it will end; an
29
+ // animation knows exactly where it must be at time t, and computing that from
30
+ // the start point avoids the drift that accumulating deltas would give over
31
+ // ninety frames.
32
+
33
+ #pragma once
34
+
35
+ namespace basalt {
36
+
37
+ class ScrollAnimation {
38
+ public:
39
+ // Long enough to read as movement, short enough not to feel slow. iOS uses
40
+ // about this for `setContentOffset:animated:`; Android's default smooth
41
+ // scroll is a little longer and feels it.
42
+ static constexpr double kDurationSeconds = 0.3;
43
+
44
+ // Begins a scroll from one offset to another. A target equal to the start is
45
+ // not an animation and returns false, so a caller can apply the offset and be
46
+ // done rather than running a curve that goes nowhere.
47
+ bool start(double fromX, double fromY, double toX, double toY);
48
+
49
+ // Advances by `seconds` and reports where the offset should now be. Returns
50
+ // false on the final step, whose position is exactly the target -- the curve
51
+ // is evaluated at 1.0 rather than approached, so an animated scroll always
52
+ // arrives at the number it was asked for.
53
+ bool advance(double seconds, double &x, double &y);
54
+
55
+ void stop();
56
+
57
+ bool isRunning() const {
58
+ return running_;
59
+ }
60
+
61
+ private:
62
+ bool running_{false};
63
+ double elapsed_{0.0};
64
+ double fromX_{0.0};
65
+ double fromY_{0.0};
66
+ double toX_{0.0};
67
+ double toY_{0.0};
68
+ };
69
+
70
+ } // namespace basalt
@@ -0,0 +1,26 @@
1
+ #include "ScrollBounds.h"
2
+
3
+ #include <algorithm>
4
+
5
+ namespace basalt {
6
+
7
+ ScrollRange scrollRangeFor(double containerLength,
8
+ double contentLength,
9
+ ScrollAxisInsets insets) {
10
+ ScrollRange range;
11
+ // Pulling *before* the content is what a leading inset buys, so the range
12
+ // starts below zero rather than at it.
13
+ range.minimum = -insets.leading;
14
+ range.maximum = std::max(range.minimum, contentLength - containerLength + insets.trailing);
15
+ return range;
16
+ }
17
+
18
+ double clampScrollOffset(double offset,
19
+ double containerLength,
20
+ double contentLength,
21
+ ScrollAxisInsets insets) {
22
+ const ScrollRange range = scrollRangeFor(containerLength, contentLength, insets);
23
+ return std::clamp(offset, range.minimum, range.maximum);
24
+ }
25
+
26
+ } // namespace basalt
@@ -0,0 +1,68 @@
1
+ // How far a scroll view may be scrolled, once `contentInset` has had its say.
2
+ //
3
+ // Three hosts had the same four lines of arithmetic -- clamp between zero and
4
+ // `content - container` -- and none of them read `contentInset`, which was
5
+ // parsed, stored, echoed back in the scroll event, and otherwise ignored. A
6
+ // list that asked to be inset from the top scrolled as though it had not.
7
+ //
8
+ // ## What an inset does
9
+ //
10
+ // It is not padding. Padding makes the content bigger; an inset makes the
11
+ // *scrollable range* bigger while leaving the content the size it is. With a
12
+ // top inset of 50 the list may be pulled 50 points further down than its first
13
+ // row, exposing empty space above it -- which is what a header that overlays
14
+ // the list needs, and the reason iOS has the prop at all.
15
+ //
16
+ // So the range runs from `-leading` to `content - container + trailing`,
17
+ // instead of from zero to `content - container`. With no insets those are the
18
+ // same numbers, which is why nothing changed for anybody who never set one.
19
+ //
20
+ // ## Two insets, not one
21
+ //
22
+ // `contentInset` moves the content and `scrollIndicatorInsets` moves the
23
+ // scrollbar, and an app may set either without the other: a header that covers
24
+ // the top of the list usually wants both, and a window with a rounded corner
25
+ // wants only the second. They are separate parameters here for the same reason
26
+ // React Native keeps them separate props.
27
+
28
+ #pragma once
29
+
30
+ namespace basalt {
31
+
32
+ // One axis of an `EdgeInsets`: the inset before the content and the one after
33
+ // it. Vertically that is top and bottom; horizontally, left and right.
34
+ struct ScrollAxisInsets {
35
+ double leading{0.0};
36
+ double trailing{0.0};
37
+ };
38
+
39
+ // The offsets a scroll view may rest at, on one axis. `minimum` is zero or
40
+ // negative, `maximum` is at least `minimum`.
41
+ struct ScrollRange {
42
+ double minimum{0.0};
43
+ double maximum{0.0};
44
+
45
+ double length() const { return maximum - minimum; }
46
+ };
47
+
48
+ // The range for one axis.
49
+ //
50
+ // `maximum` is never below `minimum`: content shorter than its container with a
51
+ // leading inset can still be pulled, and the two ends must not cross, or a
52
+ // clamp between them would answer with whichever was written last.
53
+ ScrollRange scrollRangeFor(double containerLength,
54
+ double contentLength,
55
+ ScrollAxisInsets insets = {});
56
+
57
+ // An offset brought inside that range.
58
+ //
59
+ // The one place the three hosts agreed already, and now the one place it is
60
+ // written: an offset outside the range is a momentum frame, a `scrollTo` past
61
+ // the end, or content that shrank under a scrolled view, and all three want the
62
+ // nearest reachable position rather than a refusal.
63
+ double clampScrollOffset(double offset,
64
+ double containerLength,
65
+ double contentLength,
66
+ ScrollAxisInsets insets = {});
67
+
68
+ } // namespace basalt
@@ -0,0 +1,50 @@
1
+ #include "ScrollIndicator.h"
2
+
3
+ #include <algorithm>
4
+
5
+ namespace basalt {
6
+
7
+ ScrollIndicator scrollIndicatorFor(double containerLength,
8
+ double contentLength,
9
+ double scrollOffset,
10
+ ScrollAxisInsets content,
11
+ ScrollAxisInsets indicator) {
12
+ ScrollIndicator result;
13
+ if (containerLength <= 0.0) {
14
+ return result;
15
+ }
16
+
17
+ // Nothing to indicate when there is nowhere to go. Asked of the range rather
18
+ // than of the content, because a `contentInset` is somewhere to go: a list
19
+ // that fits exactly but can be pulled down past its top does scroll, and a
20
+ // bar is how you know that.
21
+ const ScrollRange range = scrollRangeFor(containerLength, contentLength, content);
22
+ if (range.length() <= 0.0) {
23
+ return result;
24
+ }
25
+
26
+ // The track: the view, less the standard inset at each end, less whatever
27
+ // `scrollIndicatorInsets` asks for on top of that.
28
+ const double start = kScrollIndicatorInset + indicator.leading;
29
+ const double end = containerLength - kScrollIndicatorInset - indicator.trailing;
30
+ const double track = end - start;
31
+ if (track <= 0.0) {
32
+ return result;
33
+ }
34
+
35
+ // The thumb is as long as the visible fraction of everything there is to
36
+ // scroll through, with a floor. A very long list would otherwise end up with
37
+ // a one-pixel thumb.
38
+ const double scrollable = range.length() + containerLength;
39
+ const double fraction = containerLength / scrollable;
40
+ const double length = std::min(track, std::max(kScrollIndicatorMinimumLength, track * fraction));
41
+
42
+ const double progress = std::clamp((scrollOffset - range.minimum) / range.length(), 0.0, 1.0);
43
+
44
+ result.visible = true;
45
+ result.length = length;
46
+ result.offset = start + progress * (track - length);
47
+ return result;
48
+ }
49
+
50
+ } // namespace basalt
@@ -0,0 +1,69 @@
1
+ // The scrollbar a scroll view draws over itself.
2
+ //
3
+ // None of the three hosts drew one, so a long list gave no sign of how long it
4
+ // was or where you were in it -- which on a desktop reads as a bug rather than
5
+ // a style.
6
+ //
7
+ // ## Drawn rather than borrowed
8
+ //
9
+ // Each toolkit has a scrollbar and none of them is available here. GTK's comes
10
+ // with `GtkScrolledWindow`, AppKit's `NSScroller` comes with `NSScrollView`,
11
+ // and this platform's scroll view is neither -- it is a `<View>` that moves its
12
+ // children, because that is what Fabric hands it. Adopting a toolkit scroll
13
+ // container would mean giving it the scrolling too, and then React Native and
14
+ // the toolkit would both believe they own the offset.
15
+ //
16
+ // So it is drawn, and the geometry is decided here so that all three draw the
17
+ // same thing. That also makes it testable, which is worth more than usual: a
18
+ // scrollbar is pure paint, and paint is what these hosts cannot assert.
19
+ //
20
+ // ## The shape
21
+ //
22
+ // An overlay indicator, like every modern desktop: a rounded bar inset from the
23
+ // trailing edge, sized to the fraction of the content on screen, positioned by
24
+ // how far through it you are. Not a classic scrollbar with arrows and a
25
+ // trough -- nothing here is a drag target yet, which `docs/backlog` records.
26
+
27
+ #pragma once
28
+
29
+ #include "ScrollBounds.h"
30
+
31
+ namespace basalt {
32
+
33
+ // Drawing constants, here rather than in three hosts so they cannot drift.
34
+ // Thin, because it sits over content rather than beside it.
35
+ inline constexpr double kScrollIndicatorThickness = 6.0;
36
+ // From the trailing edge, and from each end of the track.
37
+ inline constexpr double kScrollIndicatorInset = 2.0;
38
+ // Below this a thumb stops reading as a position and starts reading as a dot.
39
+ inline constexpr double kScrollIndicatorMinimumLength = 24.0;
40
+
41
+ struct ScrollIndicator {
42
+ // False when everything fits: a scrollbar for content that cannot scroll is
43
+ // noise, and every list shorter than its container would grow one.
44
+ bool visible{false};
45
+ // Along the track, from its start, in points.
46
+ double offset{0.0};
47
+ double length{0.0};
48
+ };
49
+
50
+ // Where the thumb goes for one axis.
51
+ //
52
+ // `scrollOffset` may be outside the range -- an elastic overscroll goes
53
+ // negative at the top -- and the result is clamped rather than refused, because
54
+ // a thumb that vanished at the limits would flicker at exactly the moment
55
+ // somebody is looking at it.
56
+ //
57
+ // Two sets of insets, and they do different jobs. `content` is the app's
58
+ // `contentInset`: it changes how far the view scrolls, so it changes what
59
+ // fraction of the way through any given offset is. `indicator` is
60
+ // `scrollIndicatorInsets`: it shortens the track the thumb runs in and nothing
61
+ // else, which is what a header overlaying the top of a list wants -- the bar
62
+ // should start below it.
63
+ ScrollIndicator scrollIndicatorFor(double containerLength,
64
+ double contentLength,
65
+ double scrollOffset,
66
+ ScrollAxisInsets content = {},
67
+ ScrollAxisInsets indicator = {});
68
+
69
+ } // namespace basalt
@@ -0,0 +1,71 @@
1
+ #include "ScrollMomentum.h"
2
+
3
+ #include <algorithm>
4
+ #include <cmath>
5
+
6
+ namespace basalt {
7
+
8
+ namespace {
9
+
10
+ // Pixels per second below which a fling is over. Roughly a pixel every two
11
+ // frames, which is slower than a screen can show moving.
12
+ constexpr double kStopSpeed = 30.0;
13
+
14
+ // A fling is not allowed to take longer than this per step. A frame clock that
15
+ // stalls -- a window dragged between monitors, a machine that swapped -- would
16
+ // otherwise hand `advance` a whole second and teleport the list.
17
+ constexpr double kMaxStepSeconds = 0.1;
18
+
19
+ double speed(double x, double y) {
20
+ return std::sqrt(x * x + y * y);
21
+ }
22
+
23
+ } // namespace
24
+
25
+ bool ScrollMomentum::start(double velocityX, double velocityY, double decelerationRate) {
26
+ if (speed(velocityX, velocityY) < kStopSpeed) {
27
+ running_ = false;
28
+ return false;
29
+ }
30
+ velocityX_ = velocityX;
31
+ velocityY_ = velocityY;
32
+ // Clamped rather than trusted: the prop is a float an app can set to
33
+ // anything, and a rate of 1 or more is a fling that never stops.
34
+ decelerationRate_ = std::clamp(decelerationRate, 0.5, 0.9999);
35
+ running_ = true;
36
+ return true;
37
+ }
38
+
39
+ bool ScrollMomentum::advance(double seconds, double &dx, double &dy) {
40
+ dx = 0;
41
+ dy = 0;
42
+ if (!running_) {
43
+ return false;
44
+ }
45
+ const double step = std::clamp(seconds, 0.0, kMaxStepSeconds);
46
+
47
+ // The distance covered during the step, at the velocity it started with. A
48
+ // closed-form integral of the decay would be more exact; at sixty steps a
49
+ // second the difference is under a pixel over a whole fling, and this stays
50
+ // readable.
51
+ dx = velocityX_ * step;
52
+ dy = velocityY_ * step;
53
+
54
+ const double decay = std::pow(decelerationRate_, step * 1000.0);
55
+ velocityX_ *= decay;
56
+ velocityY_ *= decay;
57
+
58
+ if (speed(velocityX_, velocityY_) < kStopSpeed) {
59
+ running_ = false;
60
+ return false;
61
+ }
62
+ return true;
63
+ }
64
+
65
+ void ScrollMomentum::stop() {
66
+ running_ = false;
67
+ velocityX_ = 0;
68
+ velocityY_ = 0;
69
+ }
70
+
71
+ } // namespace basalt