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,145 @@
1
+ // react-native-gesture-handler's recognisers, on the desktop.
2
+ //
3
+ // RNGH is not an Expo module and has no portable C++ to compile: it ships
4
+ // Objective-C for Apple, Kotlin for Android, and a TypeScript engine for the
5
+ // web. What is portable is its *contract*, which is small and well defined --
6
+ // eight module methods, a six-value state machine, and two device events -- and
7
+ // that contract is what this file implements.
8
+ //
9
+ // The division is the same one the rest of this project uses. Everything here
10
+ // is platform-independent: a handler is a state machine fed with a pointer
11
+ // position and a list of the views under it, and what it produces is a payload
12
+ // to hand to JavaScript. The toolkits contribute two things and no more --
13
+ // where the pointer is, and which views are under it -- which is exactly what
14
+ // each one's touch dispatcher already works out for React Native's own touches.
15
+ //
16
+ // ## What a handler is
17
+ //
18
+ // `createGestureHandler('PanGestureHandler', 7, config)` makes one.
19
+ // `attachGestureHandler(7, viewTag)` says which view it watches. From then on
20
+ // every pointer event that lands on that view, or anything inside it, is
21
+ // offered to the handler, and the handler decides whether this is the gesture
22
+ // it is looking for.
23
+ //
24
+ // The states are RNGH's, and the order matters to its JavaScript:
25
+ // UNDETERMINED -> BEGAN when a pointer lands, BEGAN -> ACTIVE when the
26
+ // recogniser is satisfied, ACTIVE -> END when the pointer lifts. FAILED and
27
+ // CANCELLED are the two ways out.
28
+ //
29
+ // ## What is recognised, and what is not
30
+ //
31
+ // Tap, long press, pan, fling, native and manual. Pinch, rotation and force
32
+ // touch are created and never activate, because they need a second finger or a
33
+ // pressure reading that a mouse does not have; saying so here is better than a
34
+ // handler that looks attached and quietly never fires.
35
+ //
36
+ // One pointer. A desktop has one cursor, so `numberOfPointers` is always 1 and
37
+ // a gesture configured to need two never activates.
38
+ //
39
+ // ## Conflicts
40
+ //
41
+ // When a handler activates it cancels every other handler tracking the same
42
+ // pointer, unless the two were declared simultaneous. `waitFor` holds a handler
43
+ // at BEGAN until the handler it waits for has failed. That is the useful half
44
+ // of RNGH's conflict resolution; what is missing is listed in
45
+ // docs/backlog/expo.md, which is the file that changes when it stops being
46
+
47
+ #pragma once
48
+
49
+ #include <folly/dynamic.h>
50
+
51
+ #include <functional>
52
+ #include <string>
53
+ #include <vector>
54
+
55
+ namespace basalt {
56
+
57
+ // RNGH's State enum, from its State.ts. The numbers are part of the contract:
58
+ // they cross into JavaScript as-is.
59
+ enum class GestureState {
60
+ Undetermined = 0,
61
+ Failed = 1,
62
+ Began = 2,
63
+ Cancelled = 3,
64
+ Active = 4,
65
+ End = 5,
66
+ };
67
+
68
+ // One view under the pointer, with its origin in the surface root's
69
+ // coordinates. The origin is what turns a root-relative pointer position into
70
+ // the view-relative `x`/`y` a gesture payload carries, without this file
71
+ // knowing anything about either toolkit's geometry.
72
+ struct HitView {
73
+ int tag{0};
74
+ double originX{0};
75
+ double originY{0};
76
+ };
77
+
78
+ class GestureRegistry {
79
+ public:
80
+ // How a payload reaches JavaScript. RNGH listens on DeviceEventEmitter for
81
+ // `onGestureHandlerEvent` and `onGestureHandlerStateChange`, so this is set
82
+ // by the TurboModule, which is the thing that can emit one.
83
+ using Emitter = std::function<void(const std::string &eventName, folly::dynamic payload)>;
84
+ void setEmitter(Emitter emitter);
85
+
86
+ // The module's methods.
87
+ void create(const std::string &handlerName, int handlerTag, folly::dynamic config);
88
+ void update(int handlerTag, folly::dynamic config);
89
+ void attach(int handlerTag, int viewTag);
90
+ void drop(int handlerTag);
91
+
92
+ // Input, from a platform's touch dispatcher. `chain` is the views under the
93
+ // point, innermost first, which is the order handlers are offered the gesture
94
+ // in. Positions are in the surface root's coordinates.
95
+ void pointerDown(const std::vector<HitView> &chain, double x, double y, double timestampMs);
96
+ void pointerMove(double x, double y, double timestampMs);
97
+ void pointerUp(double x, double y, double timestampMs);
98
+ void pointerCancel();
99
+
100
+ // Forces a handler into a state, which is what RNGH's `GestureStateManager`
101
+ // does from a worklet: `manager.activate()` inside `onTouchesMove` is a
102
+ // gesture claiming itself rather than waiting for a recogniser to decide.
103
+ // Reanimated is the only caller -- the manager needs a worklet runtime to run
104
+ // in -- so this does nothing useful until phase 38.
105
+ void setStateFromWorklet(int handlerTag, int state);
106
+
107
+ // True once a handler has activated during the current gesture. A touch
108
+ // dispatcher reads this to cancel React Native's own touch, which is what
109
+ // `setJSResponder` does on the platforms RNGH was written for: without it a
110
+ // pan over a <Pressable> both pans and presses.
111
+ bool hasActiveHandler() const;
112
+
113
+ // Whether anything is attached at all. Checked before the work of building a
114
+ // hit chain, because an app that does not use RNGH must not pay for it.
115
+ bool empty() const;
116
+
117
+ private:
118
+ struct Handler;
119
+
120
+ void beginTracking(Handler &handler, const HitView &view, double x, double y, double timestampMs);
121
+ void setState(Handler &handler, GestureState next, double x, double y, double timestampMs);
122
+ bool tryActivate(Handler &handler, double x, double y, double timestampMs);
123
+ void cancelOthers(const Handler &activated, double x, double y, double timestampMs);
124
+ void emitUpdate(const Handler &handler, double x, double y, double timestampMs);
125
+ folly::dynamic payloadFor(const Handler &handler, double x, double y) const;
126
+ Handler *find(int handlerTag);
127
+
128
+ std::vector<Handler> handlers_;
129
+ Emitter emit_;
130
+
131
+ // The gesture in progress. Empty between gestures.
132
+ std::vector<int> tracking_;
133
+ bool pointerIsDown_{false};
134
+ int generation_{0};
135
+ };
136
+
137
+ GestureRegistry &gestures();
138
+
139
+ // A monotonic clock in milliseconds, shared so that both platforms' input
140
+ // timestamps mean the same thing -- durations and velocities are compared
141
+ // against constants from RNGH's own recognisers, which are wall-clock
142
+ // milliseconds.
143
+ double monotonicMilliseconds();
144
+
145
+ } // namespace basalt
@@ -0,0 +1,69 @@
1
+ #include "HoverTracker.h"
2
+
3
+ namespace basalt {
4
+
5
+ using facebook::react::ViewEvents;
6
+
7
+ std::uint16_t hoverListenersFrom(const ViewEvents &events) {
8
+ using Offset = ViewEvents::Offset;
9
+ std::uint16_t mask = HoverListenerNone;
10
+ if (events[Offset::PointerEnter]) {
11
+ mask |= HoverListenerEnter;
12
+ }
13
+ if (events[Offset::PointerLeave]) {
14
+ mask |= HoverListenerLeave;
15
+ }
16
+ if (events[Offset::PointerMove]) {
17
+ mask |= HoverListenerMove;
18
+ }
19
+ if (events[Offset::PointerOver]) {
20
+ mask |= HoverListenerOver;
21
+ }
22
+ if (events[Offset::PointerOut]) {
23
+ mask |= HoverListenerOut;
24
+ }
25
+ if (events[Offset::PointerEnterCapture]) {
26
+ mask |= HoverListenerEnterCapture;
27
+ }
28
+ if (events[Offset::PointerLeaveCapture]) {
29
+ mask |= HoverListenerLeaveCapture;
30
+ }
31
+ if (events[Offset::PointerMoveCapture]) {
32
+ mask |= HoverListenerMoveCapture;
33
+ }
34
+ if (events[Offset::PointerOverCapture]) {
35
+ mask |= HoverListenerOverCapture;
36
+ }
37
+ if (events[Offset::PointerOutCapture]) {
38
+ mask |= HoverListenerOutCapture;
39
+ }
40
+ return mask;
41
+ }
42
+
43
+ bool HoverTracker::admitMove(int tag, std::uint16_t listenersOnPath) {
44
+ if (listenersOnPath != HoverListenerNone) {
45
+ emittedAt_ = tag;
46
+ return true;
47
+ }
48
+ // Nothing here listens. If something did a moment ago, one more move has to
49
+ // go through: it is what tells the processor the cursor left, and it is
50
+ // dispatched at the view the cursor is on now, which is what makes the path
51
+ // diverge from the one it is holding.
52
+ if (emittedAt_ != 0) {
53
+ emittedAt_ = 0;
54
+ return true;
55
+ }
56
+ return false;
57
+ }
58
+
59
+ int HoverTracker::admitLeave() {
60
+ const int tag = emittedAt_;
61
+ emittedAt_ = 0;
62
+ return tag;
63
+ }
64
+
65
+ void HoverTracker::forget() {
66
+ emittedAt_ = 0;
67
+ }
68
+
69
+ } // namespace basalt
@@ -0,0 +1,109 @@
1
+ // Hover, which is the one piece of input a desktop has and a phone does not.
2
+ //
3
+ // React Native's touch events -- what Pressability and every `onPress` run on
4
+ // -- have no concept of a pointer that is present but not pressed. W3C pointer
5
+ // events do, and React Native carries them alongside touches: `onPointerEnter`,
6
+ // `onPointerLeave`, `onPointerOver`, `onPointerOut` and `onPointerMove` are
7
+ // real props, registered in the view config and parsed into `ViewProps::events`
8
+ // by ReactCommon. Nothing on this platform was emitting them.
9
+ //
10
+ // ## What a platform owes, and what it must not do
11
+ //
12
+ // Much less than it looks. `PointerEventsProcessor` in ReactCommon already
13
+ // implements the whole hover model: it remembers the path the cursor was on,
14
+ // diffs it against the new one, and emits `out`, `leave`, `over` and `enter` in
15
+ // the right order with the right listener filtering, all from a single
16
+ // `pointerMove`. It also filters the move itself by whether anything on the
17
+ // path is listening. So a host emits *moves* and nothing else, and every other
18
+ // pointer event an app sees is React Native's own work.
19
+ //
20
+ // This is worth stating because emitting enter and leave as well looks right
21
+ // and is wrong twice over: the processor runs its hover tracking on every
22
+ // pointer event that reaches it, so each extra one produces a second complete
23
+ // round of enter/leave, and the platform's own is then forwarded on top. One
24
+ // `over` from here came out in JavaScript as `over`, `enter` on the ancestor
25
+ // and `enter` on the target -- correct events, three times too many.
26
+ //
27
+ // The one exception is the cursor leaving the surface, which no move can
28
+ // express: a `pointerLeave` from a platform is read by the processor as "the
29
+ // pointer is gone", and it unwinds the whole path itself rather than forwarding
30
+ // what it was sent.
31
+ //
32
+ // ## So what is left here
33
+ //
34
+ // A gate. A cursor crossing a window produces motion at the refresh rate, and
35
+ // turning each one into an event that crosses into JavaScript, for an app that
36
+ // listens to none of them, is a cost every app would pay. React Native on
37
+ // Android has the same problem and answers it the same way -- ask whether
38
+ // anyone is listening before dispatching -- and the answer is in
39
+ // `ViewProps::events`, which the mounting walk already sees on every Create and
40
+ // Update.
41
+ //
42
+ // The gate has one subtlety, and it is the reason this is a small state machine
43
+ // rather than an `if`. A move must also be dispatched on the *first* motion
44
+ // after the cursor leaves everything that was listening: without it the
45
+ // processor never learns the pointer left, and the last hovered view keeps its
46
+ // hover state for good.
47
+
48
+ #pragma once
49
+
50
+ #include <react/renderer/components/view/primitives.h>
51
+
52
+ #include <cstdint>
53
+
54
+ namespace basalt {
55
+
56
+ // Which hover events a view listens for. A subset of React Native's
57
+ // `ViewEvents`, narrowed to the bits this file acts on so that a host can hold
58
+ // one small integer per view instead of a 64-bit set it would have to
59
+ // understand.
60
+ enum HoverListener : std::uint16_t {
61
+ HoverListenerEnter = 1U << 0U,
62
+ HoverListenerLeave = 1U << 1U,
63
+ HoverListenerMove = 1U << 2U,
64
+ HoverListenerOver = 1U << 3U,
65
+ HoverListenerOut = 1U << 4U,
66
+ // The capture phase of each. A listener in the capture phase is on an
67
+ // *ancestor* of the view the event is dispatched to, so it counts towards
68
+ // whether anything on the path is listening.
69
+ HoverListenerEnterCapture = 1U << 5U,
70
+ HoverListenerLeaveCapture = 1U << 6U,
71
+ HoverListenerMoveCapture = 1U << 7U,
72
+ HoverListenerOverCapture = 1U << 8U,
73
+ HoverListenerOutCapture = 1U << 9U,
74
+
75
+ // Nothing here is listened for, which is the common case and the one worth
76
+ // being able to test for in a single comparison.
77
+ HoverListenerNone = 0U,
78
+ };
79
+
80
+ // The mask for a view, from the props ReactCommon parsed. `ViewEvents` is a
81
+ // 64-bit set with a documented bit per prop; this keeps the translation in one
82
+ // place so no host has to know the offsets.
83
+ std::uint16_t hoverListenersFrom(const facebook::react::ViewEvents &events);
84
+
85
+ class HoverTracker {
86
+ public:
87
+ // The cursor is over `tag`, and `listenersOnPath` is the masks of every view
88
+ // from it to the surface root, ORed together. Returns whether a
89
+ // `pointerMove` should be dispatched at `tag`.
90
+ bool admitMove(int tag, std::uint16_t listenersOnPath);
91
+
92
+ // The cursor left the surface. Returns the tag to dispatch a `pointerLeave`
93
+ // at, or 0 for nothing -- which is the case when no move was ever dispatched,
94
+ // because the processor has no path to unwind.
95
+ int admitLeave();
96
+
97
+ // Forget where the cursor was without emitting anything, for a surface
98
+ // teardown: the views in the remembered path are about to stop existing.
99
+ void forget();
100
+
101
+ private:
102
+ // The view the last dispatched move was reported against, or 0 if the last
103
+ // motion was not dispatched. Not simply "the last view under the cursor":
104
+ // what matters is what React Native was told, because that is what it is
105
+ // holding a hover path for.
106
+ int emittedAt_{0};
107
+ };
108
+
109
+ } // namespace basalt
@@ -0,0 +1,282 @@
1
+ // The http seam for the Linux platform, backed by libcurl.
2
+ //
3
+ // `getHttpClientFactory()` is declared by ReactCxxPlatform and defined nowhere
4
+ // in it, exactly like `getDefaultComponentRegistryFactory()`: every host writes
5
+ // its own. `ReactHost` refuses to construct without one, so this file is not
6
+ // optional even for a host that never makes a request.
7
+ //
8
+ // Its counterpart, `getWebSocketClientFactory()`, is *not* here. React Native
9
+ // already ships a working boost::beast client at
10
+ // ReactCxxPlatform/react/http/platform/cxx/WebSocketClient.cpp that its own
11
+ // CMakeLists never compiles; this project builds it as `rn_websocket` rather
12
+ // than writing a second one. See cmake/ReactNativeCore.cmake.
13
+ //
14
+ // Two callers matter:
15
+ //
16
+ // - `DevServerHelper::downloadBundleResourceSync` fetches the Metro bundle
17
+ // and blocks on a std::future that only `onBody` completes. A client that
18
+ // drops its callbacks does not fail there, it hangs, so every exit path
19
+ // below has to end in `onResponseComplete`.
20
+ // - `NetworkingModule` backs fetch/XHR in JS.
21
+ //
22
+ // Threading: one thread per request. Callbacks run on that thread, never on the
23
+ // GTK main thread or the JS thread. Both callers above expect that -- the dev
24
+ // server hands the result to a promise, and NetworkingModule bounces through
25
+ // its CallInvoker.
26
+
27
+ #include "BlobRegistry.h"
28
+ #include "DevBundle.h"
29
+
30
+ #include <react/http/IHttpClient.h>
31
+
32
+ #include <curl/curl.h>
33
+ #include <folly/io/IOBuf.h>
34
+ #include <glog/logging.h>
35
+
36
+ #include <algorithm>
37
+ #include <atomic>
38
+ // For the fixed-width types in IHttpClient's signatures. Reached through
39
+ // DevBundle.h today, which is not a dependency worth relying on.
40
+ #include <cstdint>
41
+ #include <memory>
42
+ #include <mutex>
43
+ #include <string>
44
+ #include <thread>
45
+ #include <utility>
46
+ #include <vector>
47
+
48
+ namespace facebook::react {
49
+
50
+ namespace {
51
+
52
+ void ensureCurlInitialised() {
53
+ static std::once_flag once;
54
+ std::call_once(once, []() { curl_global_init(CURL_GLOBAL_DEFAULT); });
55
+ }
56
+
57
+ // Shared between the caller and the request thread. `cancelled` is the only
58
+ // thing the caller touches after handing the request off.
59
+ struct RequestState {
60
+ std::atomic<bool> cancelled{false};
61
+ };
62
+
63
+ class CurlRequestToken final : public http::IRequestToken {
64
+ public:
65
+ explicit CurlRequestToken(std::shared_ptr<RequestState> state) : state_(std::move(state)) {}
66
+
67
+ void cancel() noexcept override {
68
+ state_->cancelled = true;
69
+ }
70
+
71
+ private:
72
+ std::shared_ptr<RequestState> state_;
73
+ };
74
+
75
+ size_t appendToString(char *data, size_t size, size_t count, void *userData) {
76
+ auto *out = static_cast<std::string *>(userData);
77
+ out->append(data, size * count);
78
+ return size * count;
79
+ }
80
+
81
+ size_t collectHeader(char *data, size_t size, size_t count, void *userData) {
82
+ auto *headers = static_cast<http::Headers *>(userData);
83
+ const std::string line(data, size * count);
84
+
85
+ // curl hands over the status line and the blank terminator too; neither is a
86
+ // header, and only lines with a colon are.
87
+ const auto colon = line.find(':');
88
+ if (colon != std::string::npos) {
89
+ std::string name = line.substr(0, colon);
90
+ std::string value = line.substr(colon + 1);
91
+ const auto notSpace = [](unsigned char c) { return !std::isspace(c); };
92
+ value.erase(value.begin(), std::find_if(value.begin(), value.end(), notSpace));
93
+ value.erase(std::find_if(value.rbegin(), value.rend(), notSpace).base(), value.end());
94
+ headers->emplace_back(std::move(name), std::move(value));
95
+ }
96
+ return size * count;
97
+ }
98
+
99
+ int reportProgress(void *userData,
100
+ curl_off_t downloadTotal,
101
+ curl_off_t downloadNow,
102
+ curl_off_t uploadTotal,
103
+ curl_off_t uploadNow) {
104
+ auto *state = static_cast<RequestState *>(userData);
105
+ (void)downloadTotal;
106
+ (void)downloadNow;
107
+ (void)uploadTotal;
108
+ (void)uploadNow;
109
+ // A non-zero return aborts the transfer, which surfaces as CURLE_ABORTED_BY_CALLBACK.
110
+ return state->cancelled ? 1 : 0;
111
+ }
112
+
113
+ // Runs on the request thread. Always ends in onResponseComplete.
114
+ void performRequest(http::NetworkCallbacks callbacks,
115
+ std::string method,
116
+ std::string url,
117
+ http::Headers requestHeaders,
118
+ std::string requestBody,
119
+ bool hasBody,
120
+ uint32_t timeoutSeconds,
121
+ std::shared_ptr<RequestState> state) {
122
+ CURL *handle = curl_easy_init();
123
+ if (handle == nullptr) {
124
+ if (callbacks.onResponseComplete) {
125
+ callbacks.onResponseComplete("could not initialise libcurl", false);
126
+ }
127
+ return;
128
+ }
129
+
130
+ std::string responseBody;
131
+ http::Headers responseHeaders;
132
+
133
+ curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
134
+ curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, method.c_str());
135
+ curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
136
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, appendToString);
137
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, &responseBody);
138
+ curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, collectHeader);
139
+ curl_easy_setopt(handle, CURLOPT_HEADERDATA, &responseHeaders);
140
+ curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
141
+ curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, reportProgress);
142
+ curl_easy_setopt(handle, CURLOPT_XFERINFODATA, state.get());
143
+ // Without this, libcurl installs a SIGALRM-based resolver timeout that is not
144
+ // safe to use off the main thread.
145
+ curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
146
+
147
+ if (timeoutSeconds > 0) {
148
+ curl_easy_setopt(handle, CURLOPT_TIMEOUT, static_cast<long>(timeoutSeconds));
149
+ }
150
+
151
+ if (hasBody) {
152
+ curl_easy_setopt(handle, CURLOPT_POSTFIELDS, requestBody.c_str());
153
+ curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, static_cast<long>(requestBody.size()));
154
+ }
155
+
156
+ curl_slist *headerList = nullptr;
157
+ for (const auto &[name, value] : requestHeaders) {
158
+ headerList = curl_slist_append(headerList, (name + ": " + value).c_str());
159
+ }
160
+ if (headerList != nullptr) {
161
+ curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headerList);
162
+ }
163
+
164
+ const CURLcode result = curl_easy_perform(handle);
165
+
166
+ long statusCode = 0;
167
+ curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &statusCode);
168
+
169
+ // A failed bundle fetch is the one case where the body must not be delivered.
170
+ // `DevServerHelper` hands whatever arrives to the JS engine without reading
171
+ // the status, so Metro's 500 -- which is how it reports every error in your
172
+ // app -- gets compiled as JavaScript. Reporting it as an error instead means
173
+ // `ReactHost` never sees a script, and core/DevBundle.h keeps the message
174
+ // that was in the body. Only the bundle request: an app's own fetch() of a
175
+ // 404 or a 500 needs its body, which is what the status code is for.
176
+ const bool bundleFailed = result == CURLE_OK && (statusCode < 200 || statusCode >= 300) &&
177
+ basalt::isDevBundleRequest(method, url);
178
+
179
+ if (bundleFailed) {
180
+ basalt::recordDevBundleError(statusCode, url, responseBody);
181
+ if (callbacks.onResponseComplete) {
182
+ callbacks.onResponseComplete("Metro answered " + std::to_string(statusCode), false);
183
+ }
184
+ } else if (result == CURLE_OK) {
185
+ // The other half of the same question: a bundle that *did* come from Metro,
186
+ // so the host can say so rather than naming the file it would have used.
187
+ if (statusCode >= 200 && statusCode < 300 && basalt::isDevBundleRequest(method, url)) {
188
+ basalt::recordDevBundleFetched(url);
189
+ }
190
+ if (callbacks.onResponse) {
191
+ callbacks.onResponse(static_cast<uint16_t>(statusCode), responseHeaders);
192
+ }
193
+ if (callbacks.onBody) {
194
+ callbacks.onBody(folly::IOBuf::copyBuffer(responseBody));
195
+ }
196
+ if (callbacks.onResponseComplete) {
197
+ callbacks.onResponseComplete("", false);
198
+ }
199
+ } else {
200
+ const bool timedOut = result == CURLE_OPERATION_TIMEDOUT;
201
+ std::string error = curl_easy_strerror(result);
202
+ if (result == CURLE_ABORTED_BY_CALLBACK) {
203
+ error = "request cancelled";
204
+ }
205
+ if (callbacks.onResponseComplete) {
206
+ // A timeout reports through the dedicated flag, and DevServerHelper
207
+ // treats an empty error string with that flag set as "Timeout".
208
+ callbacks.onResponseComplete(timedOut ? "" : error, timedOut);
209
+ }
210
+ }
211
+
212
+ if (headerList != nullptr) {
213
+ curl_slist_free_all(headerList);
214
+ }
215
+ curl_easy_cleanup(handle);
216
+ }
217
+
218
+ class CurlHttpClient final : public IHttpClient {
219
+ public:
220
+ std::unique_ptr<http::IRequestToken> sendRequest(
221
+ http::NetworkCallbacks &&callbacks,
222
+ const std::string &method,
223
+ const std::string &url,
224
+ const http::Headers &headers = {},
225
+ const http::Body &body = {},
226
+ uint32_t timeout = 0,
227
+ std::optional<std::string> /*loggingId*/ = std::nullopt) override {
228
+ ensureCurlInitialised();
229
+
230
+ // A string body, or a blob's bytes looked up by id.
231
+ //
232
+ // `http::Body::blob` is typed `std::optional<std::string>` upstream, and
233
+ // JavaScript sends `{blobId, offset, size}` -- an object. So a Blob body
234
+ // cannot currently reach here at all: ReactCxxPlatform's bridging tries to
235
+ // read that object as a string before this code is ever called. Handling it
236
+ // anyway, as an id, because that is what the type says it is and because
237
+ // the day upstream fixes the type this becomes correct rather than needing
238
+ // to be written.
239
+ std::string requestBody = body.string.value_or(std::string{});
240
+ bool hasBody = body.string.has_value();
241
+
242
+ if (body.blob) {
243
+ if (auto bytes = basalt::blobBytes(*body.blob)) {
244
+ requestBody = std::move(*bytes);
245
+ hasBody = true;
246
+ } else {
247
+ LOG(WARNING) << "http: request body names an unknown blob '" << *body.blob << "' ("
248
+ << method << " " << url << ")";
249
+ }
250
+ }
251
+
252
+ // Form-data and base64 bodies come from JS APIs nothing here can reach yet:
253
+ // there is no file picker and no camera.
254
+ if (body.formData || body.base64) {
255
+ LOG(WARNING) << "http: form-data and base64 request bodies are not supported (" << method
256
+ << " " << url << ")";
257
+ }
258
+
259
+ auto state = std::make_shared<RequestState>();
260
+
261
+ std::thread(performRequest,
262
+ std::move(callbacks),
263
+ method,
264
+ url,
265
+ headers,
266
+ std::move(requestBody),
267
+ hasBody,
268
+ timeout,
269
+ state)
270
+ .detach();
271
+
272
+ return std::make_unique<CurlRequestToken>(state);
273
+ }
274
+ };
275
+
276
+ } // namespace
277
+
278
+ HttpClientFactory getHttpClientFactory() {
279
+ return []() { return std::make_unique<CurlHttpClient>(); };
280
+ }
281
+
282
+ } // namespace facebook::react