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.
- package/LICENSE +21 -0
- package/dist/cli/basalt.d.ts +3 -0
- package/dist/cli/basalt.d.ts.map +1 -0
- package/dist/cli/basalt.js +47 -0
- package/dist/cli/basalt.js.map +1 -0
- package/dist/cli/bundle-cli.d.ts +12 -0
- package/dist/cli/bundle-cli.d.ts.map +1 -0
- package/dist/cli/bundle-cli.js +124 -0
- package/dist/cli/bundle-cli.js.map +1 -0
- package/dist/cli/bundleWithAssets.d.ts +79 -0
- package/dist/cli/bundleWithAssets.d.ts.map +1 -0
- package/dist/cli/bundleWithAssets.js +198 -0
- package/dist/cli/bundleWithAssets.js.map +1 -0
- package/dist/cli/desktop.d.ts +339 -0
- package/dist/cli/desktop.d.ts.map +1 -0
- package/dist/cli/desktop.js +1029 -0
- package/dist/cli/desktop.js.map +1 -0
- package/dist/cli/doctor.d.ts +31 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +283 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.d.ts +77 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +442 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/metro.d.ts +49 -0
- package/dist/cli/metro.d.ts.map +1 -0
- package/dist/cli/metro.js +148 -0
- package/dist/cli/metro.js.map +1 -0
- package/dist/cli/packageApp.d.ts +102 -0
- package/dist/cli/packageApp.d.ts.map +1 -0
- package/dist/cli/packageApp.js +319 -0
- package/dist/cli/packageApp.js.map +1 -0
- package/dist/cli/steps.d.ts +34 -0
- package/dist/cli/steps.d.ts.map +1 -0
- package/dist/cli/steps.js +53 -0
- package/dist/cli/steps.js.map +1 -0
- package/dist/metro-config.d.ts +168 -0
- package/dist/metro-config.d.ts.map +1 -0
- package/dist/metro-config.js +671 -0
- package/dist/metro-config.js.map +1 -0
- package/dist/react-native.config.d.ts +7 -0
- package/dist/react-native.config.d.ts.map +1 -0
- package/dist/react-native.config.js +80 -0
- package/dist/react-native.config.js.map +1 -0
- package/dist/src/DragSource.d.ts +52 -0
- package/dist/src/DragSource.d.ts.map +1 -0
- package/dist/src/DragSource.js +97 -0
- package/dist/src/DragSource.js.map +1 -0
- package/dist/src/DropTarget.d.ts +58 -0
- package/dist/src/DropTarget.d.ts.map +1 -0
- package/dist/src/DropTarget.js +131 -0
- package/dist/src/DropTarget.js.map +1 -0
- package/dist/src/KeyHandler.d.ts +57 -0
- package/dist/src/KeyHandler.d.ts.map +1 -0
- package/dist/src/KeyHandler.js +48 -0
- package/dist/src/KeyHandler.js.map +1 -0
- package/dist/src/Menu.d.ts +72 -0
- package/dist/src/Menu.d.ts.map +1 -0
- package/dist/src/Menu.js +179 -0
- package/dist/src/Menu.js.map +1 -0
- package/dist/src/TitleBar.d.ts +75 -0
- package/dist/src/TitleBar.d.ts.map +1 -0
- package/dist/src/TitleBar.js +236 -0
- package/dist/src/TitleBar.js.map +1 -0
- package/dist/src/Window.d.ts +87 -0
- package/dist/src/Window.d.ts.map +1 -0
- package/dist/src/Window.js +248 -0
- package/dist/src/Window.js.map +1 -0
- package/dist/src/closeRequest.d.ts +55 -0
- package/dist/src/closeRequest.d.ts.map +1 -0
- package/dist/src/closeRequest.js +134 -0
- package/dist/src/closeRequest.js.map +1 -0
- package/dist/src/index.d.ts +45 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +92 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/overrides/Alert.d.ts +69 -0
- package/dist/src/overrides/Alert.d.ts.map +1 -0
- package/dist/src/overrides/Alert.js +112 -0
- package/dist/src/overrides/Alert.js.map +1 -0
- package/dist/src/overrides/BaseViewConfig.d.ts +28 -0
- package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -0
- package/dist/src/overrides/BaseViewConfig.js +72 -0
- package/dist/src/overrides/BaseViewConfig.js.map +1 -0
- package/dist/src/overrides/Platform.linux.d.ts +10 -0
- package/dist/src/overrides/Platform.linux.d.ts.map +1 -0
- package/dist/src/overrides/Platform.linux.js +15 -0
- package/dist/src/overrides/Platform.linux.js.map +1 -0
- package/dist/src/overrides/Platform.macos.d.ts +10 -0
- package/dist/src/overrides/Platform.macos.d.ts.map +1 -0
- package/dist/src/overrides/Platform.macos.js +15 -0
- package/dist/src/overrides/Platform.macos.js.map +1 -0
- package/dist/src/overrides/Platform.windows.d.ts +10 -0
- package/dist/src/overrides/Platform.windows.d.ts.map +1 -0
- package/dist/src/overrides/Platform.windows.js +15 -0
- package/dist/src/overrides/Platform.windows.js.map +1 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts +24 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts.map +1 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.js +30 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.js.map +1 -0
- package/dist/src/overrides/RefreshControl.d.ts +52 -0
- package/dist/src/overrides/RefreshControl.d.ts.map +1 -0
- package/dist/src/overrides/RefreshControl.js +92 -0
- package/dist/src/overrides/RefreshControl.js.map +1 -0
- package/dist/src/overrides/ScrollView.d.ts +39 -0
- package/dist/src/overrides/ScrollView.d.ts.map +1 -0
- package/dist/src/overrides/ScrollView.js +59 -0
- package/dist/src/overrides/ScrollView.js.map +1 -0
- package/dist/src/overrides/Share.d.ts +96 -0
- package/dist/src/overrides/Share.d.ts.map +1 -0
- package/dist/src/overrides/Share.js +97 -0
- package/dist/src/overrides/Share.js.map +1 -0
- package/dist/src/overrides/TextInput.d.ts +81 -0
- package/dist/src/overrides/TextInput.d.ts.map +1 -0
- package/dist/src/overrides/TextInput.js +213 -0
- package/dist/src/overrides/TextInput.js.map +1 -0
- package/dist/src/overrides/View.d.ts +36 -0
- package/dist/src/overrides/View.d.ts.map +1 -0
- package/dist/src/overrides/View.js +99 -0
- package/dist/src/overrides/View.js.map +1 -0
- package/dist/src/overrides/createPlatform.d.ts +32 -0
- package/dist/src/overrides/createPlatform.d.ts.map +1 -0
- package/dist/src/overrides/createPlatform.js +84 -0
- package/dist/src/overrides/createPlatform.js.map +1 -0
- package/dist/src/overrides/setUpDeveloperTools.d.ts +28 -0
- package/dist/src/overrides/setUpDeveloperTools.d.ts.map +1 -0
- package/dist/src/overrides/setUpDeveloperTools.js +84 -0
- package/dist/src/overrides/setUpDeveloperTools.js.map +1 -0
- package/dist/src/overrides/setUpXHR.d.ts +46 -0
- package/dist/src/overrides/setUpXHR.d.ts.map +1 -0
- package/dist/src/overrides/setUpXHR.js +236 -0
- package/dist/src/overrides/setUpXHR.js.map +1 -0
- package/dist/src/quitRequest.d.ts +55 -0
- package/dist/src/quitRequest.d.ts.map +1 -0
- package/dist/src/quitRequest.js +121 -0
- package/dist/src/quitRequest.js.map +1 -0
- package/dist/src/resourcePath.d.ts +18 -0
- package/dist/src/resourcePath.d.ts.map +1 -0
- package/dist/src/resourcePath.js +31 -0
- package/dist/src/resourcePath.js.map +1 -0
- package/dist/src/responseBody.d.ts +76 -0
- package/dist/src/responseBody.d.ts.map +1 -0
- package/dist/src/responseBody.js +94 -0
- package/dist/src/responseBody.js.map +1 -0
- package/dist/src/responseHeaders.d.ts +40 -0
- package/dist/src/responseHeaders.d.ts.map +1 -0
- package/dist/src/responseHeaders.js +75 -0
- package/dist/src/responseHeaders.js.map +1 -0
- package/dist/src/titleBarState.d.ts +43 -0
- package/dist/src/titleBarState.d.ts.map +1 -0
- package/dist/src/titleBarState.js +77 -0
- package/dist/src/titleBarState.js.map +1 -0
- package/dist/src/useContextMenu.d.ts +113 -0
- package/dist/src/useContextMenu.d.ts.map +1 -0
- package/dist/src/useContextMenu.js +109 -0
- package/dist/src/useContextMenu.js.map +1 -0
- package/dist/src/useDialog.d.ts +98 -0
- package/dist/src/useDialog.d.ts.map +1 -0
- package/dist/src/useDialog.js +112 -0
- package/dist/src/useDialog.js.map +1 -0
- package/dist/src/useDisplays.d.ts +70 -0
- package/dist/src/useDisplays.d.ts.map +1 -0
- package/dist/src/useDisplays.js +118 -0
- package/dist/src/useDisplays.js.map +1 -0
- package/dist/src/useHandledKeys.d.ts +38 -0
- package/dist/src/useHandledKeys.d.ts.map +1 -0
- package/dist/src/useHandledKeys.js +70 -0
- package/dist/src/useHandledKeys.js.map +1 -0
- package/dist/src/useWindow.d.ts +140 -0
- package/dist/src/useWindow.d.ts.map +1 -0
- package/dist/src/useWindow.js +233 -0
- package/dist/src/useWindow.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/native/CMakeLists.txt +355 -0
- package/native/bootstrap.sh +613 -0
- package/native/cmake/CompilerFlags.cmake +49 -0
- package/native/cmake/Expo.cmake +125 -0
- package/native/cmake/ReactNativeCore.cmake +612 -0
- package/native/cmake/Reanimated.cmake +108 -0
- package/native/cmake/Skia.cmake +379 -0
- package/native/cmake/ThirdParty.cmake +290 -0
- package/native/cmake/Worklets.cmake +67 -0
- package/native/cmake/codegen/CMakeLists.txt +32 -0
- package/native/core/AppIdentity.cpp +85 -0
- package/native/core/AppIdentity.h +59 -0
- package/native/core/AppPaths.cpp +96 -0
- package/native/core/AppPaths.h +53 -0
- package/native/core/AppearanceModule.cpp +60 -0
- package/native/core/AppearanceModule.h +40 -0
- package/native/core/Backface.h +59 -0
- package/native/core/BlobModule.cpp +283 -0
- package/native/core/BlobModule.h +76 -0
- package/native/core/BlobRegistry.cpp +75 -0
- package/native/core/BlobRegistry.h +44 -0
- package/native/core/ColorScheme.cpp +105 -0
- package/native/core/ColorScheme.h +59 -0
- package/native/core/ComponentRegistry.h +30 -0
- package/native/core/ControlMetrics.h +37 -0
- package/native/core/CoreModules.cpp +592 -0
- package/native/core/CoreModules.h +308 -0
- package/native/core/DebuggingOverlay.cpp +106 -0
- package/native/core/DebuggingOverlay.h +65 -0
- package/native/core/DesktopControls.cpp +232 -0
- package/native/core/DesktopControls.h +170 -0
- package/native/core/DevBundle.cpp +108 -0
- package/native/core/DevBundle.h +69 -0
- package/native/core/DevMenu.cpp +99 -0
- package/native/core/DevMenu.h +75 -0
- package/native/core/DialogModule.cpp +150 -0
- package/native/core/DialogModule.h +51 -0
- package/native/core/DragAndDrop.cpp +45 -0
- package/native/core/DragAndDrop.h +225 -0
- package/native/core/ExpoImageComponent.cpp +79 -0
- package/native/core/ExpoImageComponent.h +80 -0
- package/native/core/ExpoModules.cpp +415 -0
- package/native/core/ExpoModules.h +115 -0
- package/native/core/ExpoRuntime.cpp +366 -0
- package/native/core/ExpoRuntime.h +42 -0
- package/native/core/FocusRing.h +36 -0
- package/native/core/FontRegistry.h +51 -0
- package/native/core/GestureHandlerModule.cpp +136 -0
- package/native/core/GestureHandlerModule.h +71 -0
- package/native/core/Gestures.cpp +533 -0
- package/native/core/Gestures.h +145 -0
- package/native/core/HoverTracker.cpp +69 -0
- package/native/core/HoverTracker.h +109 -0
- package/native/core/HttpClient.cpp +282 -0
- package/native/core/ImageBytes.cpp +205 -0
- package/native/core/ImageBytes.h +29 -0
- package/native/core/ImageCache.cpp +51 -0
- package/native/core/ImageCache.h +89 -0
- package/native/core/JsRuntimeAccess.cpp +70 -0
- package/native/core/JsRuntimeAccess.h +60 -0
- package/native/core/JsiPromise.h +51 -0
- package/native/core/KeyEvents.cpp +116 -0
- package/native/core/KeyEvents.h +144 -0
- package/native/core/LogBoxSurface.cpp +46 -0
- package/native/core/LogBoxSurface.h +68 -0
- package/native/core/MenuModel.h +117 -0
- package/native/core/MenuModule.cpp +209 -0
- package/native/core/MenuModule.h +66 -0
- package/native/core/MountingWalk.h +524 -0
- package/native/core/PackageModules.cpp.in +25 -0
- package/native/core/PackageModules.h +50 -0
- package/native/core/PlatformConstantsModule.cpp +63 -0
- package/native/core/PlatformConstantsModule.h +64 -0
- package/native/core/PlatformServices.h +213 -0
- package/native/core/PointerButtons.h +63 -0
- package/native/core/PullToRefresh.cpp +57 -0
- package/native/core/PullToRefresh.h +73 -0
- package/native/core/ReanimatedCompat.h +47 -0
- package/native/core/ReanimatedModule.cpp +203 -0
- package/native/core/ReanimatedModule.h +55 -0
- package/native/core/ScrollAnimation.cpp +59 -0
- package/native/core/ScrollAnimation.h +70 -0
- package/native/core/ScrollBounds.cpp +26 -0
- package/native/core/ScrollBounds.h +68 -0
- package/native/core/ScrollIndicator.cpp +50 -0
- package/native/core/ScrollIndicator.h +69 -0
- package/native/core/ScrollMomentum.cpp +71 -0
- package/native/core/ScrollMomentum.h +73 -0
- package/native/core/ScrollSnap.cpp +123 -0
- package/native/core/ScrollSnap.h +80 -0
- package/native/core/ShareFallback.cpp +101 -0
- package/native/core/ShareFallback.h +45 -0
- package/native/core/SkiaPictureViewComponent.cpp +11 -0
- package/native/core/SkiaPictureViewComponent.h +47 -0
- package/native/core/SourceCodeModule.cpp +55 -0
- package/native/core/SourceCodeModule.h +53 -0
- package/native/core/StatusBarModule.cpp +23 -0
- package/native/core/StatusBarModule.h +42 -0
- package/native/core/TestDialog.cpp +148 -0
- package/native/core/TestDialog.h +96 -0
- package/native/core/TestKeys.cpp +78 -0
- package/native/core/TestKeys.h +50 -0
- package/native/core/TestQuitFile.cpp +33 -0
- package/native/core/TestQuitFile.h +60 -0
- package/native/core/TestSettle.h +192 -0
- package/native/core/TitleBarRegions.h +31 -0
- package/native/core/TurboModuleProxy.cpp +51 -0
- package/native/core/TurboModuleProxy.h +46 -0
- package/native/core/UIManagerAccess.cpp +43 -0
- package/native/core/UIManagerAccess.h +43 -0
- package/native/core/WindowBoundsCache.cpp +319 -0
- package/native/core/WindowControl.h +235 -0
- package/native/core/WindowHost.h +158 -0
- package/native/core/WindowMethods.cpp +167 -0
- package/native/core/WindowMethods.h +84 -0
- package/native/core/WindowsModule.cpp +448 -0
- package/native/core/WindowsModule.h +133 -0
- package/native/core/WorkletsModule.cpp +199 -0
- package/native/core/WorkletsModule.h +57 -0
- package/native/core/portability_probe.cpp +210 -0
- package/native/tests/EventRecorder.h +124 -0
- package/native/tests/TestHarness.cpp +109 -0
- package/native/tests/TestHarness.h +89 -0
- package/native/tests/TreeDump.h +49 -0
- package/native/tests/test_app_identity.cpp +114 -0
- package/native/tests/test_app_paths.cpp +48 -0
- package/native/tests/test_appearance.cpp +107 -0
- package/native/tests/test_backface.cpp +79 -0
- package/native/tests/test_blobs.cpp +157 -0
- package/native/tests/test_controls.cpp +185 -0
- package/native/tests/test_devbundle.cpp +103 -0
- package/native/tests/test_drag_and_drop.cpp +143 -0
- package/native/tests/test_gestures.cpp +331 -0
- package/native/tests/test_hover.cpp +92 -0
- package/native/tests/test_image_cache.cpp +109 -0
- package/native/tests/test_js_runtime_access.cpp +137 -0
- package/native/tests/test_key_events.cpp +235 -0
- package/native/tests/test_momentum.cpp +138 -0
- package/native/tests/test_quit_file.cpp +104 -0
- package/native/tests/test_scroll_animation.cpp +120 -0
- package/native/tests/test_scroll_bounds.cpp +66 -0
- package/native/tests/test_scroll_indicator.cpp +149 -0
- package/native/tests/test_scroll_snap.cpp +112 -0
- package/native/tests/test_settle.cpp +115 -0
- package/native/tests/test_share.cpp +75 -0
- package/native/tests/test_sourcecode.cpp +62 -0
- package/native/tests/test_window_close.cpp +119 -0
- package/native/tests/test_window_limits.cpp +123 -0
- package/package.json +43 -0
- package/react-native.config.js +86 -0
- package/supported-versions.json +66 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// A fling, after the fingers have gone.
|
|
2
|
+
//
|
|
3
|
+
// The two desktops divide this differently, and the split is the whole reason
|
|
4
|
+
// this file exists rather than one platform's private helper.
|
|
5
|
+
//
|
|
6
|
+
// macOS does the deceleration itself. An `NSEvent` carries a `momentumPhase`
|
|
7
|
+
// alongside its ordinary phase, and the system keeps delivering scroll deltas
|
|
8
|
+
// after the fingers lift, tapering off on its own. So the AppKit host models
|
|
9
|
+
// nothing: it reports what it is handed, and `onMomentumScrollBegin` and
|
|
10
|
+
// `onMomentumScrollEnd` are that report.
|
|
11
|
+
//
|
|
12
|
+
// GTK does not. `GtkEventControllerScroll` with the kinetic flag emits one
|
|
13
|
+
// `decelerate` signal carrying the velocity the gesture ended at, and then
|
|
14
|
+
// stops -- the coasting is the application's to run. So there has to be a
|
|
15
|
+
// model, and this is it.
|
|
16
|
+
//
|
|
17
|
+
// ## The model
|
|
18
|
+
//
|
|
19
|
+
// Exponential friction, which is what UIScrollView, Android's OverScroller and
|
|
20
|
+
// every browser use: velocity is multiplied by a constant per millisecond, so
|
|
21
|
+
// distance falls off smoothly and the fling has no fixed duration. React Native
|
|
22
|
+
// already names the constant -- `decelerationRate`, 0.998 for `'normal'` and
|
|
23
|
+
// 0.99 for `'fast'` -- and it is a per-millisecond factor, so the two
|
|
24
|
+
// implementations agree on what a fling feels like without either quoting a
|
|
25
|
+
// number the other does not have.
|
|
26
|
+
//
|
|
27
|
+
// It is deliberately not a spring or a fixed-duration curve. Both would need a
|
|
28
|
+
// target offset up front, and a fling does not have one: where it lands is a
|
|
29
|
+
// consequence of how hard it was thrown.
|
|
30
|
+
|
|
31
|
+
#pragma once
|
|
32
|
+
|
|
33
|
+
namespace basalt {
|
|
34
|
+
|
|
35
|
+
class ScrollMomentum {
|
|
36
|
+
public:
|
|
37
|
+
// React Native's own two, as its `decelerationRate` prop resolves them. The
|
|
38
|
+
// prop is a float, so an app can pass anything between; these are the values
|
|
39
|
+
// `'normal'` and `'fast'` mean.
|
|
40
|
+
static constexpr double kNormalDeceleration = 0.998;
|
|
41
|
+
static constexpr double kFastDeceleration = 0.99;
|
|
42
|
+
|
|
43
|
+
// Begins a fling at a velocity in pixels per second, with the same sign
|
|
44
|
+
// convention as a scroll offset: positive moves the content offset up.
|
|
45
|
+
//
|
|
46
|
+
// Returns false, and starts nothing, for a fling too slow to be worth
|
|
47
|
+
// animating. That check is here rather than in a caller because the threshold
|
|
48
|
+
// and the stopping condition are the same number, and a fling that stops on
|
|
49
|
+
// its first frame is worse than one that never started -- it would report a
|
|
50
|
+
// momentum scroll beginning and ending with nothing in between.
|
|
51
|
+
bool start(double velocityX, double velocityY, double decelerationRate);
|
|
52
|
+
|
|
53
|
+
// Advances the fling by `seconds` and reports how far the offset should move.
|
|
54
|
+
// Returns false once it has stopped, in which case the deltas are the last
|
|
55
|
+
// step and the caller should apply them and finish.
|
|
56
|
+
bool advance(double seconds, double &dx, double &dy);
|
|
57
|
+
|
|
58
|
+
// Stops without reporting a final step. For a fling interrupted by a new
|
|
59
|
+
// gesture, or by the view going away.
|
|
60
|
+
void stop();
|
|
61
|
+
|
|
62
|
+
bool isRunning() const {
|
|
63
|
+
return running_;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private:
|
|
67
|
+
bool running_{false};
|
|
68
|
+
double velocityX_{0};
|
|
69
|
+
double velocityY_{0};
|
|
70
|
+
double decelerationRate_{kNormalDeceleration};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
} // namespace basalt
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#include "ScrollSnap.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cmath>
|
|
5
|
+
|
|
6
|
+
namespace basalt {
|
|
7
|
+
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
// What the alignment shifts by: a centred snap lines the middle of the
|
|
11
|
+
// container up with a point, an end-aligned one lines up its trailing edge.
|
|
12
|
+
double alignmentShift(ScrollSnapAlignment alignment, double containerLength) {
|
|
13
|
+
switch (alignment) {
|
|
14
|
+
case ScrollSnapAlignment::Start:
|
|
15
|
+
return 0.0;
|
|
16
|
+
case ScrollSnapAlignment::Center:
|
|
17
|
+
return containerLength / 2.0;
|
|
18
|
+
case ScrollSnapAlignment::End:
|
|
19
|
+
return containerLength;
|
|
20
|
+
}
|
|
21
|
+
return 0.0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
double clampToContent(double offset, double containerLength, double contentLength) {
|
|
25
|
+
const double furthest = std::max(0.0, contentLength - containerLength);
|
|
26
|
+
return std::clamp(offset, 0.0, furthest);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The nearest of an explicit list, with a flick moving at least one entry.
|
|
30
|
+
std::optional<double> nearestOffset(const std::vector<double> &offsets,
|
|
31
|
+
double offset,
|
|
32
|
+
double velocity) {
|
|
33
|
+
if (offsets.empty()) {
|
|
34
|
+
return std::nullopt;
|
|
35
|
+
}
|
|
36
|
+
std::vector<double> sorted = offsets;
|
|
37
|
+
std::sort(sorted.begin(), sorted.end());
|
|
38
|
+
|
|
39
|
+
auto nearest = sorted.begin();
|
|
40
|
+
double best = std::abs(sorted.front() - offset);
|
|
41
|
+
for (auto it = sorted.begin(); it != sorted.end(); ++it) {
|
|
42
|
+
const double distance = std::abs(*it - offset);
|
|
43
|
+
if (distance < best) {
|
|
44
|
+
best = distance;
|
|
45
|
+
nearest = it;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (velocity > kScrollSnapFlickVelocity) {
|
|
50
|
+
// The first entry strictly past where we are. A flick forwards must not
|
|
51
|
+
// settle back on the point it started from.
|
|
52
|
+
for (auto it = sorted.begin(); it != sorted.end(); ++it) {
|
|
53
|
+
if (*it > offset) {
|
|
54
|
+
return *it;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return sorted.back();
|
|
58
|
+
}
|
|
59
|
+
if (velocity < -kScrollSnapFlickVelocity) {
|
|
60
|
+
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) {
|
|
61
|
+
if (*it < offset) {
|
|
62
|
+
return *it;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return sorted.front();
|
|
66
|
+
}
|
|
67
|
+
return *nearest;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} // namespace
|
|
71
|
+
|
|
72
|
+
std::optional<double> scrollSnapTarget(const ScrollSnapConfig &config,
|
|
73
|
+
double offset,
|
|
74
|
+
double velocity,
|
|
75
|
+
double containerLength,
|
|
76
|
+
double contentLength) {
|
|
77
|
+
if (!config.enabled()) {
|
|
78
|
+
return std::nullopt;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// An explicit list wins over a spacing, and a spacing over paging only when
|
|
82
|
+
// paging is off: `pagingEnabled` is the coarsest statement and iOS lets it
|
|
83
|
+
// take precedence.
|
|
84
|
+
if (!config.paging && !config.offsets.empty()) {
|
|
85
|
+
const auto target = nearestOffset(config.offsets, offset, velocity);
|
|
86
|
+
if (!target) {
|
|
87
|
+
return std::nullopt;
|
|
88
|
+
}
|
|
89
|
+
return clampToContent(*target, containerLength, contentLength);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const double interval = config.paging ? containerLength : config.interval;
|
|
93
|
+
if (interval <= 0.0) {
|
|
94
|
+
return std::nullopt;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Aligned snapping is the same arithmetic about a shifted point: what lines
|
|
98
|
+
// up with a multiple is the container's leading edge, its middle, or its
|
|
99
|
+
// trailing edge.
|
|
100
|
+
const double shift = alignmentShift(config.alignment, containerLength);
|
|
101
|
+
const double aligned = offset + shift;
|
|
102
|
+
|
|
103
|
+
double index = std::floor(aligned / interval);
|
|
104
|
+
const double within = aligned - index * interval;
|
|
105
|
+
|
|
106
|
+
if (velocity > kScrollSnapFlickVelocity) {
|
|
107
|
+
index += 1.0;
|
|
108
|
+
} else if (velocity < -kScrollSnapFlickVelocity) {
|
|
109
|
+
// Already past a boundary by less than half means the flick backwards is
|
|
110
|
+
// to the boundary itself rather than the one before it.
|
|
111
|
+
if (within > 0.0) {
|
|
112
|
+
// index already floors to the boundary behind us.
|
|
113
|
+
} else {
|
|
114
|
+
index -= 1.0;
|
|
115
|
+
}
|
|
116
|
+
} else if (within > interval / 2.0) {
|
|
117
|
+
index += 1.0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return clampToContent(index * interval - shift, containerLength, contentLength);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
} // namespace basalt
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Where a scroll should come to rest.
|
|
2
|
+
//
|
|
3
|
+
// `pagingEnabled`, `snapToInterval` and `snapToOffsets` are how a carousel, a
|
|
4
|
+
// paged list and a stop-at-each-card list are written in React Native, and none
|
|
5
|
+
// of them did anything here: a drag ended wherever the fingers left it.
|
|
6
|
+
//
|
|
7
|
+
// ## Why this is arithmetic and not a host's business
|
|
8
|
+
//
|
|
9
|
+
// Choosing the resting point needs the offset, the velocity, the container, the
|
|
10
|
+
// content and the props -- and nothing from a toolkit. So it is decided here,
|
|
11
|
+
// once, and each host does the same two things with the answer: stop the fling
|
|
12
|
+
// and animate to it, which is what `core/ScrollAnimation.h` is for.
|
|
13
|
+
//
|
|
14
|
+
// That also makes it testable. Almost nothing about a scroll view on these
|
|
15
|
+
// hosts can be asserted without a display; this can.
|
|
16
|
+
//
|
|
17
|
+
// ## The rules
|
|
18
|
+
//
|
|
19
|
+
// A flick settles on the next point in the direction it was flicked, even when
|
|
20
|
+
// the finger left nearer the point behind. That is what makes a carousel feel
|
|
21
|
+
// like a carousel rather than a list that sometimes changes page -- and it is
|
|
22
|
+
// why velocity is a parameter rather than the caller simply passing the offset
|
|
23
|
+
// it landed on.
|
|
24
|
+
//
|
|
25
|
+
// "Next in that direction" rather than "a whole page on": twenty pixels into a
|
|
26
|
+
// page, flicked back, the answer is that page's start and not the one before
|
|
27
|
+
// it. The rule is symmetric -- forwards from the same place is the page ahead --
|
|
28
|
+
// and a small flick must not be able to travel further than a large one.
|
|
29
|
+
//
|
|
30
|
+
// Below that threshold the nearest point wins, which is the behaviour of
|
|
31
|
+
// letting go without meaning anything by it.
|
|
32
|
+
|
|
33
|
+
#pragma once
|
|
34
|
+
|
|
35
|
+
#include <optional>
|
|
36
|
+
#include <vector>
|
|
37
|
+
|
|
38
|
+
namespace basalt {
|
|
39
|
+
|
|
40
|
+
// Where in the container a snap point should line up, as React Native's
|
|
41
|
+
// `snapToAlignment` names it.
|
|
42
|
+
enum class ScrollSnapAlignment {
|
|
43
|
+
Start,
|
|
44
|
+
Center,
|
|
45
|
+
End,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
struct ScrollSnapConfig {
|
|
49
|
+
// `pagingEnabled`: the interval is the container's own length, so a page is a
|
|
50
|
+
// screenful. Takes precedence over the two below, as it does on iOS.
|
|
51
|
+
bool paging{false};
|
|
52
|
+
// `snapToInterval`, in points. Zero means unused.
|
|
53
|
+
double interval{0.0};
|
|
54
|
+
// `snapToOffsets`. Empty means unused; when set it wins over `interval`,
|
|
55
|
+
// because a list of explicit points is a more specific statement than a
|
|
56
|
+
// spacing.
|
|
57
|
+
std::vector<double> offsets;
|
|
58
|
+
ScrollSnapAlignment alignment{ScrollSnapAlignment::Start};
|
|
59
|
+
|
|
60
|
+
bool enabled() const {
|
|
61
|
+
return paging || interval > 0.0 || !offsets.empty();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Pixels per second past which a gesture counts as a flick rather than a
|
|
66
|
+
// release. Low enough that a deliberate flick always carries, high enough that
|
|
67
|
+
// the wobble of letting go does not.
|
|
68
|
+
inline constexpr double kScrollSnapFlickVelocity = 250.0;
|
|
69
|
+
|
|
70
|
+
// The offset to settle at, or nothing when no snapping is configured.
|
|
71
|
+
//
|
|
72
|
+
// `velocity` is in pixels per second, positive meaning the content offset is
|
|
73
|
+
// growing -- the same sign convention as everything else here.
|
|
74
|
+
std::optional<double> scrollSnapTarget(const ScrollSnapConfig &config,
|
|
75
|
+
double offset,
|
|
76
|
+
double velocity,
|
|
77
|
+
double containerLength,
|
|
78
|
+
double contentLength);
|
|
79
|
+
|
|
80
|
+
} // namespace basalt
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#include "ShareFallback.h"
|
|
2
|
+
|
|
3
|
+
#include "TestDialog.h"
|
|
4
|
+
|
|
5
|
+
#include <array>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
namespace basalt {
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
// RFC 3986's unreserved set, plus nothing. A `mailto:` is built by
|
|
13
|
+
// concatenation, so anything else has to be encoded or it changes the meaning
|
|
14
|
+
// of the URL rather than appearing in it -- an `&` in a message being the case
|
|
15
|
+
// that actually bites, because it ends the body and starts a header.
|
|
16
|
+
bool isUnreserved(unsigned char c) {
|
|
17
|
+
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' ||
|
|
18
|
+
c == '_' || c == '.' || c == '~';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
std::string percentEncode(const std::string &text) {
|
|
22
|
+
static constexpr std::array<char, 16> kHex{
|
|
23
|
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|
24
|
+
std::string out;
|
|
25
|
+
out.reserve(text.size());
|
|
26
|
+
for (const char raw : text) {
|
|
27
|
+
const auto c = static_cast<unsigned char>(raw);
|
|
28
|
+
if (isUnreserved(c)) {
|
|
29
|
+
out.push_back(raw);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
out.push_back('%');
|
|
33
|
+
out.push_back(kHex[c >> 4U]);
|
|
34
|
+
out.push_back(kHex[c & 0x0FU]);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The two buttons and the way out, in the order the alert shows them. React
|
|
40
|
+
// Native's alerts put the cancelling one last on both desktops, so this does
|
|
41
|
+
// too.
|
|
42
|
+
constexpr int kCopyButton = 0;
|
|
43
|
+
constexpr int kEmailButton = 1;
|
|
44
|
+
|
|
45
|
+
} // namespace
|
|
46
|
+
|
|
47
|
+
std::string shareClipboardText(const ShareRequest &request) {
|
|
48
|
+
// Both, when an app gave both: a link with a sentence explaining it is what
|
|
49
|
+
// most calls to Share are, and dropping either would be dropping half of what
|
|
50
|
+
// was asked for.
|
|
51
|
+
if (request.message.empty()) {
|
|
52
|
+
return request.url;
|
|
53
|
+
}
|
|
54
|
+
if (request.url.empty()) {
|
|
55
|
+
return request.message;
|
|
56
|
+
}
|
|
57
|
+
return request.message + "\n" + request.url;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
std::string shareMailtoUrl(const ShareRequest &request) {
|
|
61
|
+
std::string url = "mailto:?body=" + percentEncode(shareClipboardText(request));
|
|
62
|
+
if (!request.title.empty()) {
|
|
63
|
+
url += "&subject=" + percentEncode(request.title);
|
|
64
|
+
}
|
|
65
|
+
return url;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void shareThroughFallbackPicker(const ShareRequest &request, ShareCallback onDone) {
|
|
69
|
+
AlertRequest alert;
|
|
70
|
+
// The app's own words for the picker when it gave any, which is what
|
|
71
|
+
// `options.dialogTitle` is for.
|
|
72
|
+
alert.title = request.dialogTitle.empty() ? "Share" : request.dialogTitle;
|
|
73
|
+
// The content, so a person can see what they are about to send. A share sheet
|
|
74
|
+
// shows a preview and this is the plainest form of one.
|
|
75
|
+
alert.message = shareClipboardText(request);
|
|
76
|
+
alert.buttons = {"Copy", "Email", "Cancel"};
|
|
77
|
+
|
|
78
|
+
presentAlert(alert, [request, onDone = std::move(onDone)](int button, const std::string &) {
|
|
79
|
+
switch (button) {
|
|
80
|
+
case kCopyButton:
|
|
81
|
+
setClipboardText(shareClipboardText(request));
|
|
82
|
+
onDone(ShareOutcome::Shared, "");
|
|
83
|
+
return;
|
|
84
|
+
case kEmailButton:
|
|
85
|
+
if (openUrl(shareMailtoUrl(request))) {
|
|
86
|
+
onDone(ShareOutcome::Shared, "");
|
|
87
|
+
} else {
|
|
88
|
+
// No mail client, or nothing registered for `mailto:`. A failure
|
|
89
|
+
// rather than a dismissal: the person chose to send it and it did not
|
|
90
|
+
// go, which is not the same as changing their mind.
|
|
91
|
+
onDone(ShareOutcome::Failed, "no application is registered for mailto:");
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
default:
|
|
95
|
+
onDone(ShareOutcome::Dismissed, "");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
} // namespace basalt
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// A share sheet for the desktops that do not have one.
|
|
2
|
+
//
|
|
3
|
+
// `Share.share()` promises a picker. macOS has `NSSharingServicePicker` and
|
|
4
|
+
// means it. Windows has the `DataTransferManager` share UI, reachable through
|
|
5
|
+
// WinRT interop. Linux has neither: there is no share portal, GNOME and KDE
|
|
6
|
+
// expose no such API, and the nearest thing in the freedesktop specifications
|
|
7
|
+
// is `xdg-email`, which is one destination rather than a choice of them.
|
|
8
|
+
//
|
|
9
|
+
// So the options were to reject on the desktops with no service, or to build
|
|
10
|
+
// the smallest honest picker out of what every desktop does have. This is the
|
|
11
|
+
// second. A share sheet is a list of places to send something, and the two
|
|
12
|
+
// entries on it that every desktop can actually perform are *the clipboard* and
|
|
13
|
+
// *an email*. Both already have seams here -- `setClipboardText` and `openUrl`
|
|
14
|
+
// -- so this file is a dialog and a `mailto:` and nothing platform-specific at
|
|
15
|
+
// all.
|
|
16
|
+
//
|
|
17
|
+
// It is deliberately not dressed up as a native share sheet. A person sees a
|
|
18
|
+
// dialog with the message in it and two things they can do with it, which is
|
|
19
|
+
// what is true; pretending to be a service picker that does not exist would be
|
|
20
|
+
// worse than being a plain one that does.
|
|
21
|
+
//
|
|
22
|
+
// An implementation that wants the real thing on Windows should replace its
|
|
23
|
+
// `shareContent` and leave this alone; see docs/BACKLOG.md.
|
|
24
|
+
|
|
25
|
+
#pragma once
|
|
26
|
+
|
|
27
|
+
#include "PlatformServices.h"
|
|
28
|
+
|
|
29
|
+
namespace basalt {
|
|
30
|
+
|
|
31
|
+
// The text a share puts on the clipboard: the message and the URL, whichever of
|
|
32
|
+
// them the app supplied, one per line. Exposed for the tests, because it is the
|
|
33
|
+
// only part of this with an answer that can be wrong.
|
|
34
|
+
std::string shareClipboardText(const ShareRequest &request);
|
|
35
|
+
|
|
36
|
+
// `mailto:` for the same content, with the title as the subject. Percent-encoded
|
|
37
|
+
// as RFC 6068 requires, which matters more than it looks: a message with an
|
|
38
|
+
// ampersand in it silently truncates the body of the draft otherwise.
|
|
39
|
+
std::string shareMailtoUrl(const ShareRequest &request);
|
|
40
|
+
|
|
41
|
+
// Shows the picker and reports what was chosen. The implementation of
|
|
42
|
+
// `shareContent` on every desktop that has no service of its own.
|
|
43
|
+
void shareThroughFallbackPicker(const ShareRequest &request, ShareCallback onDone);
|
|
44
|
+
|
|
45
|
+
} // namespace basalt
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#include "SkiaPictureViewComponent.h"
|
|
2
|
+
|
|
3
|
+
namespace facebook::react {
|
|
4
|
+
|
|
5
|
+
// The name the package's JavaScript registers, from
|
|
6
|
+
// `codegenNativeComponent<NativeProps>("SkiaPictureView")`. No adapter prefix:
|
|
7
|
+
// this is a codegen component rather than an Expo view manager, so the name is
|
|
8
|
+
// the name.
|
|
9
|
+
extern const char SkiaPictureViewComponentName[] = "SkiaPictureView";
|
|
10
|
+
|
|
11
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// `SkiaPictureView`, which is what a `<Canvas>` from @shopify/react-native-skia
|
|
2
|
+
// mounts.
|
|
3
|
+
//
|
|
4
|
+
// Plain `ViewProps`, unlike core/ExpoImageComponent.h which needed its own props
|
|
5
|
+
// class -- and for a reason worth stating, because it looks like a shortcut and
|
|
6
|
+
// is not. A `<Canvas>` does not carry its content in props. It renders a
|
|
7
|
+
// `SkPicture` in JavaScript and pushes it through the Skia JSI API keyed by an
|
|
8
|
+
// id, and the only thing the native side needs from props is which id it is:
|
|
9
|
+
//
|
|
10
|
+
// <SkiaPictureViewNativeComponent nativeID={`${nativeId}`} ... />
|
|
11
|
+
//
|
|
12
|
+
// `nativeID` is an ordinary `ViewProps` field, so it arrives on any component
|
|
13
|
+
// whatever its view config says. That sidesteps the trap ExpoImageComponent.h
|
|
14
|
+
// spends a paragraph on: a prop absent from the JavaScript view config is
|
|
15
|
+
// dropped before it is ever diffed, silently. Here there is nothing to drop.
|
|
16
|
+
//
|
|
17
|
+
// What *is* dropped: `debug`, `opaque`, `colorSpace` and `highBitDepth`, the four
|
|
18
|
+
// props the package's spec declares. They are decoration -- an FPS overlay, an
|
|
19
|
+
// opaque backing, P3, ten bits a channel -- and a canvas without them draws the
|
|
20
|
+
// same picture. The same call ExpoImage makes about placeholders and blurhash.
|
|
21
|
+
// When one is wanted, it belongs in a props class here and in the peer.
|
|
22
|
+
//
|
|
23
|
+
// Registered unconditionally, like ExpoImage and for the same reason: it costs a
|
|
24
|
+
// name in a registry, and the alternative is a host that has to be rebuilt to
|
|
25
|
+
// run an app that draws. Without Skia in the build the view mounts and stays
|
|
26
|
+
// empty -- but an app that draws will already have failed at
|
|
27
|
+
// `getEnforcing('RNSkiaModule')` long before, which is the error that says what
|
|
28
|
+
// is actually missing.
|
|
29
|
+
|
|
30
|
+
#pragma once
|
|
31
|
+
|
|
32
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
33
|
+
#include <react/renderer/components/view/ViewEventEmitter.h>
|
|
34
|
+
#include <react/renderer/components/view/ViewProps.h>
|
|
35
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
36
|
+
|
|
37
|
+
namespace facebook::react {
|
|
38
|
+
|
|
39
|
+
extern const char SkiaPictureViewComponentName[];
|
|
40
|
+
|
|
41
|
+
using SkiaPictureViewShadowNode =
|
|
42
|
+
ConcreteViewShadowNode<SkiaPictureViewComponentName, ViewProps, ViewEventEmitter>;
|
|
43
|
+
|
|
44
|
+
using SkiaPictureViewComponentDescriptor =
|
|
45
|
+
ConcreteComponentDescriptor<SkiaPictureViewShadowNode>;
|
|
46
|
+
|
|
47
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#include "SourceCodeModule.h"
|
|
2
|
+
|
|
3
|
+
#include <filesystem>
|
|
4
|
+
|
|
5
|
+
namespace basalt {
|
|
6
|
+
|
|
7
|
+
facebook::jsi::Object DesktopSourceCodeModule::getConstants(facebook::jsi::Runtime &rt) {
|
|
8
|
+
facebook::jsi::Object constants(rt);
|
|
9
|
+
constants.setProperty(rt, "scriptURL", facebook::jsi::String::createFromUtf8(rt, scriptURL_));
|
|
10
|
+
return constants;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
std::string scriptURLFor(const std::string &bundlePath,
|
|
14
|
+
bool devMode,
|
|
15
|
+
const std::string &devHost,
|
|
16
|
+
unsigned int devPort,
|
|
17
|
+
const std::string &devEntry,
|
|
18
|
+
const std::string &platform) {
|
|
19
|
+
if (devMode) {
|
|
20
|
+
// Shaped like the URL the dev server actually served, because React Native
|
|
21
|
+
// recovers the server's address by stripping the path off this. Assets then
|
|
22
|
+
// resolve to that server, which is what makes them work in development
|
|
23
|
+
// without anything being copied anywhere. And the platform is the host's
|
|
24
|
+
// own, because HMRClient registers this URL for Fast Refresh; see the
|
|
25
|
+
// header.
|
|
26
|
+
return "http://" + devHost + ":" + std::to_string(devPort) + "/" + devEntry +
|
|
27
|
+
".bundle?platform=" + platform + "&dev=true";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Absolute and fully formed: React Native tests this with
|
|
31
|
+
// startsWith('file://') and then takes the directory beside it, so a relative
|
|
32
|
+
// path silently produces an asset URL that resolves nowhere.
|
|
33
|
+
std::error_code ignored;
|
|
34
|
+
const std::filesystem::path absolute = std::filesystem::absolute(bundlePath, ignored);
|
|
35
|
+
|
|
36
|
+
// `generic_string`, not `string`: on Windows the native form is
|
|
37
|
+
// `D:\build\x.js`, and `resolveAssetSource` finds the bundle's directory
|
|
38
|
+
// with `scriptURL.lastIndexOf('/')`. With no forward slash in it that is -1,
|
|
39
|
+
// the directory comes out empty, and every `require()`d image resolves to
|
|
40
|
+
// `file://assets/...` -- a URI with an authority and no path, which opens
|
|
41
|
+
// nothing. It cost a green Linux run and a red Windows one to find, and it
|
|
42
|
+
// was never about LogBox: it is every asset on that platform.
|
|
43
|
+
std::string path = absolute.lexically_normal().generic_string();
|
|
44
|
+
|
|
45
|
+
// And the third slash. A POSIX path already starts with one, so `file://` and
|
|
46
|
+
// `/Users/x` make `file:///Users/x`; a Windows path starts at the drive
|
|
47
|
+
// letter and has to be given one, which is what every browser and URI library
|
|
48
|
+
// does with `file:///C:/x`.
|
|
49
|
+
if (path.empty() || path.front() != '/') {
|
|
50
|
+
path.insert(path.begin(), '/');
|
|
51
|
+
}
|
|
52
|
+
return "file://" + path;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
} // namespace basalt
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// `SourceCode`, which is how JavaScript learns where the bundle came from.
|
|
2
|
+
//
|
|
3
|
+
// It sounds like diagnostics and is not: React Native's asset resolution is
|
|
4
|
+
// built on it. `AssetSourceResolver` asks whether the script came from a server
|
|
5
|
+
// or from a file, and answers `require('./logo.png')` with either a URL on that
|
|
6
|
+
// server or a path beside that file. With no script URL, every asset resolves
|
|
7
|
+
// to nonsense -- `file://assets/assets/logo.png`, in the case that led here.
|
|
8
|
+
//
|
|
9
|
+
// ReactCxxPlatform ships a SourceCode module, and on React Native 0.86 it is
|
|
10
|
+
// always handed an empty string: `ReactHost` has no `sourceURL_` at all, and
|
|
11
|
+
// 0.87 added one. Rather than support this on the versions that happen to fill
|
|
12
|
+
// it in, the host reports the URL itself, which it has known all along.
|
|
13
|
+
|
|
14
|
+
#pragma once
|
|
15
|
+
|
|
16
|
+
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
|
|
17
|
+
|
|
18
|
+
#include <string>
|
|
19
|
+
|
|
20
|
+
namespace basalt {
|
|
21
|
+
|
|
22
|
+
class DesktopSourceCodeModule
|
|
23
|
+
: public facebook::react::NativeSourceCodeCxxSpec<DesktopSourceCodeModule> {
|
|
24
|
+
public:
|
|
25
|
+
DesktopSourceCodeModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker, std::string scriptURL)
|
|
26
|
+
: NativeSourceCodeCxxSpec(std::move(jsInvoker)), scriptURL_(std::move(scriptURL)) {}
|
|
27
|
+
|
|
28
|
+
facebook::jsi::Object getConstants(facebook::jsi::Runtime &rt);
|
|
29
|
+
|
|
30
|
+
private:
|
|
31
|
+
std::string scriptURL_;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// The URL to report for a bundle loaded from `bundlePath`, or from a dev server
|
|
35
|
+
// when one is in use.
|
|
36
|
+
//
|
|
37
|
+
// A file URL has to be absolute and fully formed: React Native tests it with
|
|
38
|
+
// `startsWith('file://')` and then takes the directory beside it, so a relative
|
|
39
|
+
// path silently produces an asset URL that resolves nowhere.
|
|
40
|
+
//
|
|
41
|
+
// A dev server URL has to name the host's platform. React Native's HMRClient
|
|
42
|
+
// registers exactly this URL with Metro, and Metro keys the module graph it
|
|
43
|
+
// sends updates for by the platform in it. This used to say `linux` on every
|
|
44
|
+
// host, so on Windows Metro dutifully sent Fast Refresh updates for a Linux
|
|
45
|
+
// graph that the running app did not have, and no edit ever appeared.
|
|
46
|
+
std::string scriptURLFor(const std::string &bundlePath,
|
|
47
|
+
bool devMode,
|
|
48
|
+
const std::string &devHost,
|
|
49
|
+
unsigned int devPort,
|
|
50
|
+
const std::string &devEntry,
|
|
51
|
+
const std::string &platform);
|
|
52
|
+
|
|
53
|
+
} // namespace basalt
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#include "StatusBarModule.h"
|
|
2
|
+
|
|
3
|
+
namespace basalt {
|
|
4
|
+
|
|
5
|
+
using facebook::jsi::Object;
|
|
6
|
+
using facebook::jsi::Runtime;
|
|
7
|
+
|
|
8
|
+
Object DesktopStatusBarModule::getConstants(Runtime &rt) {
|
|
9
|
+
Object constants(rt);
|
|
10
|
+
// Zero, and meant literally. React Native's own JavaScript lays out around
|
|
11
|
+
// this value, so reporting a plausible-looking phone height would push every
|
|
12
|
+
// app's content down by a status bar that is not there.
|
|
13
|
+
constants.setProperty(rt, "HEIGHT", 0.0);
|
|
14
|
+
constants.setProperty(rt, "DEFAULT_BACKGROUND_COLOR", 0.0);
|
|
15
|
+
return constants;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void DesktopStatusBarModule::setColor(Runtime & /*rt*/, double /*color*/, bool /*animated*/) {}
|
|
19
|
+
void DesktopStatusBarModule::setTranslucent(Runtime & /*rt*/, bool /*translucent*/) {}
|
|
20
|
+
void DesktopStatusBarModule::setStyle(Runtime & /*rt*/, std::optional<std::string> /*style*/) {}
|
|
21
|
+
void DesktopStatusBarModule::setHidden(Runtime & /*rt*/, bool /*hidden*/) {}
|
|
22
|
+
|
|
23
|
+
} // namespace basalt
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// `StatusBarManager`, which a desktop does not have.
|
|
2
|
+
//
|
|
3
|
+
// React Native's <StatusBar> resolves to this module, and `expo-status-bar`
|
|
4
|
+
// wraps it, so the component that a blank Expo app puts on screen by default
|
|
5
|
+
// reaches for it before rendering. It is looked up with getEnforcing, so its
|
|
6
|
+
// absence is not a quiet no-op -- it throws, and takes the app's first render
|
|
7
|
+
// with it.
|
|
8
|
+
//
|
|
9
|
+
// So the module exists and does nothing, which is the truthful implementation
|
|
10
|
+
// rather than a placeholder. There is no status bar on a desktop: its height is
|
|
11
|
+
// zero, and hiding or styling something with no pixels is a no-op in the
|
|
12
|
+
// strongest sense, not a stub waiting to be filled in.
|
|
13
|
+
//
|
|
14
|
+
// The Android spec is the one implemented, for the same reason the platform
|
|
15
|
+
// constants module answers the Android shape: this platform reports Android
|
|
16
|
+
// constants and shares Android's JavaScript. The iOS spec carries methods about
|
|
17
|
+
// network activity indicators that mean even less here.
|
|
18
|
+
|
|
19
|
+
#pragma once
|
|
20
|
+
|
|
21
|
+
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
|
|
22
|
+
|
|
23
|
+
#include <optional>
|
|
24
|
+
#include <string>
|
|
25
|
+
|
|
26
|
+
namespace basalt {
|
|
27
|
+
|
|
28
|
+
class DesktopStatusBarModule
|
|
29
|
+
: public facebook::react::NativeStatusBarManagerAndroidCxxSpec<DesktopStatusBarModule> {
|
|
30
|
+
public:
|
|
31
|
+
explicit DesktopStatusBarModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker)
|
|
32
|
+
: NativeStatusBarManagerAndroidCxxSpec(std::move(jsInvoker)) {}
|
|
33
|
+
|
|
34
|
+
facebook::jsi::Object getConstants(facebook::jsi::Runtime &rt);
|
|
35
|
+
|
|
36
|
+
void setColor(facebook::jsi::Runtime &rt, double color, bool animated);
|
|
37
|
+
void setTranslucent(facebook::jsi::Runtime &rt, bool translucent);
|
|
38
|
+
void setStyle(facebook::jsi::Runtime &rt, std::optional<std::string> statusBarStyle);
|
|
39
|
+
void setHidden(facebook::jsi::Runtime &rt, bool hidden);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
} // namespace basalt
|