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,80 @@
|
|
|
1
|
+
// expo-image's view, as a Fabric component.
|
|
2
|
+
//
|
|
3
|
+
// An Expo module's *functions* are an object in `globalThis.expo.modules`; see
|
|
4
|
+
// core/ExpoModules.h. An Expo module's *views* are not. `requireNativeViewManager`
|
|
5
|
+
// asks `globalThis.expo.getViewConfig(moduleName)` for a static view config and
|
|
6
|
+
// registers an ordinary React Native component called
|
|
7
|
+
// `ViewManagerAdapter_<moduleName>` with it. From that point on it is a Fabric
|
|
8
|
+
// component like any other: a name, a props class, a shadow node, a descriptor
|
|
9
|
+
// in the registry, and a mounting peer on each platform.
|
|
10
|
+
//
|
|
11
|
+
// So this file is the second half of the Expo port, and the half that is not
|
|
12
|
+
// Expo-specific at all -- there is nothing here that expo-modules-core has to
|
|
13
|
+
// be present for, which is why it compiles unconditionally. What needs Expo is
|
|
14
|
+
// the view config, and that lives with the rest of the runtime.
|
|
15
|
+
//
|
|
16
|
+
// **The view config is the contract.** React Native filters props against
|
|
17
|
+
// `validAttributes` in JavaScript before they are ever diffed, so a prop absent
|
|
18
|
+
// from the config never reaches C++ -- silently. That is the same trap phase 26
|
|
19
|
+
// found with `shouldNotifyLoadEvents`, and here both sides are ours, so the
|
|
20
|
+
// list in ExpoRuntime and the parsing below have to be read together.
|
|
21
|
+
//
|
|
22
|
+
// What is supported is what this platform can draw: a source, a content fit, a
|
|
23
|
+
// tint. expo-image's placeholder, transition, blurhash, cache policy and SF
|
|
24
|
+
// Symbols are left out of the view config, so they are dropped in JavaScript
|
|
25
|
+
// and never travel. An app using them gets an image without them rather than an
|
|
26
|
+
// error, which is the honest outcome for a prop whose effect is decorative.
|
|
27
|
+
|
|
28
|
+
#pragma once
|
|
29
|
+
|
|
30
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
31
|
+
#include <react/renderer/components/view/ViewEventEmitter.h>
|
|
32
|
+
#include <react/renderer/components/view/ViewProps.h>
|
|
33
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
34
|
+
#include <react/renderer/imagemanager/primitives.h>
|
|
35
|
+
|
|
36
|
+
namespace facebook::react {
|
|
37
|
+
|
|
38
|
+
extern const char ExpoImageComponentName[];
|
|
39
|
+
|
|
40
|
+
class ExpoImageProps final : public ViewProps {
|
|
41
|
+
public:
|
|
42
|
+
ExpoImageProps() = default;
|
|
43
|
+
ExpoImageProps(const PropsParserContext &context,
|
|
44
|
+
const ExpoImageProps &sourceProps,
|
|
45
|
+
const RawProps &rawProps);
|
|
46
|
+
|
|
47
|
+
// expo-image resolves `source` to an array before it reaches native, the same
|
|
48
|
+
// shape React Native's <Image> uses, so the same conversion reads it.
|
|
49
|
+
ImageSources sources{};
|
|
50
|
+
|
|
51
|
+
// expo-image's `contentFit` is CSS object-fit rather than React Native's
|
|
52
|
+
// `resizeMode`, but every value it has maps onto one this platform already
|
|
53
|
+
// draws, so it is translated here rather than carried as a second vocabulary.
|
|
54
|
+
ImageResizeMode contentFit{ImageResizeMode::Cover};
|
|
55
|
+
|
|
56
|
+
SharedColor tintColor{};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// onLoadStart/onLoad/onError, matching the direct event types the view config
|
|
60
|
+
// declares. There is no onLoadEnd here because expo-image's JavaScript raises
|
|
61
|
+
// that one itself, from its own onLoad and onError handlers, and never listens
|
|
62
|
+
// for it natively. Not ImageEventEmitter: that one is bound to React
|
|
63
|
+
// Native's <Image> component and its payload shape, and expo-image's
|
|
64
|
+
// `onLoad` carries `{source: {url, width, height, mediaType}}` rather than
|
|
65
|
+
// `{source: {uri, ...}}`.
|
|
66
|
+
class ExpoImageEventEmitter : public ViewEventEmitter {
|
|
67
|
+
public:
|
|
68
|
+
using ViewEventEmitter::ViewEventEmitter;
|
|
69
|
+
|
|
70
|
+
void onLoadStart() const;
|
|
71
|
+
void onLoad(const ImageSource &source, double width, double height) const;
|
|
72
|
+
void onError(const std::string &message) const;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
using ExpoImageShadowNode =
|
|
76
|
+
ConcreteViewShadowNode<ExpoImageComponentName, ExpoImageProps, ExpoImageEventEmitter>;
|
|
77
|
+
|
|
78
|
+
using ExpoImageComponentDescriptor = ConcreteComponentDescriptor<ExpoImageShadowNode>;
|
|
79
|
+
|
|
80
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
#include "ExpoModules.h"
|
|
2
|
+
|
|
3
|
+
#include "JsRuntimeAccess.h"
|
|
4
|
+
#include "JsiPromise.h"
|
|
5
|
+
#include "PackageModules.h"
|
|
6
|
+
#include "PlatformServices.h"
|
|
7
|
+
|
|
8
|
+
#ifdef BASALT_HAS_EXPO
|
|
9
|
+
#include <EventEmitter.h>
|
|
10
|
+
#include <NativeModule.h>
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
#include <folly/json.h>
|
|
14
|
+
#include <glog/logging.h>
|
|
15
|
+
#include <jsi/JSIDynamic.h>
|
|
16
|
+
|
|
17
|
+
#include <filesystem>
|
|
18
|
+
#include <fstream>
|
|
19
|
+
#include <optional>
|
|
20
|
+
#include <sstream>
|
|
21
|
+
|
|
22
|
+
namespace basalt {
|
|
23
|
+
|
|
24
|
+
namespace {
|
|
25
|
+
|
|
26
|
+
// Parsed once, at load, so a malformed config is reported when it is read
|
|
27
|
+
// rather than when a module happens to ask for it.
|
|
28
|
+
std::optional<folly::dynamic> &appConfig() {
|
|
29
|
+
static std::optional<folly::dynamic> config;
|
|
30
|
+
return config;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
} // namespace
|
|
34
|
+
|
|
35
|
+
void loadExpoAppConfigBeside(const std::string &bundlePath) {
|
|
36
|
+
std::error_code ignored;
|
|
37
|
+
const std::filesystem::path path =
|
|
38
|
+
std::filesystem::absolute(bundlePath, ignored).parent_path() / "app.config.json";
|
|
39
|
+
|
|
40
|
+
std::ifstream file(path);
|
|
41
|
+
if (!file) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
std::ostringstream contents;
|
|
46
|
+
contents << file.rdbuf();
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
folly::dynamic parsed = folly::parseJson(contents.str());
|
|
50
|
+
if (!parsed.isObject()) {
|
|
51
|
+
LOG(WARNING) << "expo app config at " << path.string() << " is not an object; ignoring it";
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
appConfig() = std::move(parsed);
|
|
55
|
+
} catch (const std::exception &error) {
|
|
56
|
+
LOG(WARNING) << "could not read the expo app config at " << path.string() << ": "
|
|
57
|
+
<< error.what();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
std::string expoAppName() {
|
|
62
|
+
const auto &config = appConfig();
|
|
63
|
+
if (!config.has_value()) {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
const folly::dynamic *name = config->get_ptr("name");
|
|
67
|
+
return name != nullptr && name->isString() ? name->getString() : std::string{};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#ifdef BASALT_HAS_EXPO
|
|
71
|
+
|
|
72
|
+
namespace {
|
|
73
|
+
|
|
74
|
+
using facebook::jsi::Array;
|
|
75
|
+
using facebook::jsi::Function;
|
|
76
|
+
using facebook::jsi::Object;
|
|
77
|
+
using facebook::jsi::PropNameID;
|
|
78
|
+
using facebook::jsi::Runtime;
|
|
79
|
+
using facebook::jsi::String;
|
|
80
|
+
using facebook::jsi::Value;
|
|
81
|
+
|
|
82
|
+
// A module is one of expo's own `NativeModule` instances rather than a plain
|
|
83
|
+
// object: that is where `addListener`, `removeListener` and `emit` come from,
|
|
84
|
+
// and expo-linking calls `addListener` whether or not anything ever emits.
|
|
85
|
+
void addFunction(Runtime &runtime,
|
|
86
|
+
Object &module,
|
|
87
|
+
const char *name,
|
|
88
|
+
unsigned argumentCount,
|
|
89
|
+
facebook::jsi::HostFunctionType function) {
|
|
90
|
+
module.setProperty(runtime,
|
|
91
|
+
name,
|
|
92
|
+
Function::createFromHostFunction(runtime,
|
|
93
|
+
PropNameID::forAscii(runtime, name),
|
|
94
|
+
argumentCount,
|
|
95
|
+
std::move(function)));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ExpoClipboard.
|
|
99
|
+
//
|
|
100
|
+
// The same clipboard React Native's own `Clipboard` module uses; see
|
|
101
|
+
// core/PlatformServices.h. Text only: images and URLs are their own pasteboard
|
|
102
|
+
// types on each platform, and the methods for them are deliberately absent so
|
|
103
|
+
// that expo-clipboard's own check reports "not available on this platform"
|
|
104
|
+
// naming the method, rather than a stub returning null.
|
|
105
|
+
Object makeClipboardModule(Runtime &runtime) {
|
|
106
|
+
Object module = expoModule(runtime);
|
|
107
|
+
|
|
108
|
+
addFunction(runtime,
|
|
109
|
+
module,
|
|
110
|
+
"getStringAsync",
|
|
111
|
+
1,
|
|
112
|
+
[](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
113
|
+
return resolved(rt, String::createFromUtf8(rt, clipboardText()));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
addFunction(runtime,
|
|
117
|
+
module,
|
|
118
|
+
"setStringAsync",
|
|
119
|
+
2,
|
|
120
|
+
[](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
121
|
+
if (count < 1 || !args[0].isString()) {
|
|
122
|
+
return rejected(rt, "setStringAsync expects a string");
|
|
123
|
+
}
|
|
124
|
+
setClipboardText(args[0].asString(rt).utf8(rt));
|
|
125
|
+
// The boolean is "did it happen", which it did.
|
|
126
|
+
return resolved(rt, Value(true));
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
addFunction(runtime,
|
|
130
|
+
module,
|
|
131
|
+
"hasStringAsync",
|
|
132
|
+
0,
|
|
133
|
+
[](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
134
|
+
return resolved(rt, Value(!clipboardText().empty()));
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// iOS-only UI, and expo-clipboard reads it unconditionally on every platform.
|
|
138
|
+
module.setProperty(runtime, "isPasteButtonAvailable", Value(false));
|
|
139
|
+
|
|
140
|
+
return module;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ExpoLinking.
|
|
144
|
+
//
|
|
145
|
+
// Only the two functions expo-linking calls on the native module; `openURL` and
|
|
146
|
+
// `canOpenURL` go through React Native's own `Linking`, which this platform
|
|
147
|
+
// already implements.
|
|
148
|
+
//
|
|
149
|
+
// Neither desktop delivers a URL to a running application yet -- macOS needs an
|
|
150
|
+
// Apple Event handler and a registered scheme, Linux a desktop entry and a
|
|
151
|
+
// single-instance activation -- so `getLinkingURL` is honestly null rather than
|
|
152
|
+
// absent: expo-linking calls it without checking, and `useURL()` returning null
|
|
153
|
+
// is exactly what "no deep link brought this app up" means.
|
|
154
|
+
Object makeLinkingModule(Runtime &runtime) {
|
|
155
|
+
Object module = expoModule(runtime);
|
|
156
|
+
|
|
157
|
+
addFunction(runtime,
|
|
158
|
+
module,
|
|
159
|
+
"getLinkingURL",
|
|
160
|
+
0,
|
|
161
|
+
[](Runtime &, const Value &, const Value *, size_t) -> Value {
|
|
162
|
+
return Value::null();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
addFunction(runtime,
|
|
166
|
+
module,
|
|
167
|
+
"clearInitialURL",
|
|
168
|
+
0,
|
|
169
|
+
[](Runtime &, const Value &, const Value *, size_t) -> Value {
|
|
170
|
+
return Value::undefined();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return module;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ExpoImage's module half: the static functions on `Image`, as against its view.
|
|
177
|
+
//
|
|
178
|
+
// The cache functions answer honestly rather than pretending. There is no disk
|
|
179
|
+
// cache here -- images are fetched through the same loader React Native's
|
|
180
|
+
// <Image> uses, which caches in memory for the life of the process -- so
|
|
181
|
+
// `clearDiskCacheAsync` reports false, which is expo-image's own way of saying
|
|
182
|
+
// "nothing was cleared". `prefetch` is not implemented rather than lying about
|
|
183
|
+
// having warmed a cache that does not exist.
|
|
184
|
+
//
|
|
185
|
+
// `ViewPrototypes` is what `requireNativeViewManager` reads to hang native view
|
|
186
|
+
// methods off a ref (`startAnimating`, `lockResourceAsync`). None of them apply
|
|
187
|
+
// to a still image drawn by this platform, so the object is there and empty --
|
|
188
|
+
// which is the difference between "this view has no extra methods" and the
|
|
189
|
+
// TypeError that reading a property of undefined would raise.
|
|
190
|
+
Object makeImageModule(Runtime &runtime) {
|
|
191
|
+
Object module = expoModule(runtime);
|
|
192
|
+
|
|
193
|
+
addFunction(runtime,
|
|
194
|
+
module,
|
|
195
|
+
"clearMemoryCache",
|
|
196
|
+
0,
|
|
197
|
+
[](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
198
|
+
return resolved(rt, Value(false));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
addFunction(runtime,
|
|
202
|
+
module,
|
|
203
|
+
"clearDiskCache",
|
|
204
|
+
0,
|
|
205
|
+
[](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
206
|
+
return resolved(rt, Value(false));
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
module.setProperty(runtime, "ViewPrototypes", Object(runtime));
|
|
210
|
+
|
|
211
|
+
return module;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ExponentConstants, which is expo-constants' native half.
|
|
215
|
+
//
|
|
216
|
+
// Two things live here. The manifest is the app's own Expo config, loaded from
|
|
217
|
+
// beside the bundle; expo-constants exposes it as `Constants.expoConfig`, and
|
|
218
|
+
// treats any object without a `metadata` key as an embedded manifest, which is
|
|
219
|
+
// what this is. Everything else is a native constant, and each one here is
|
|
220
|
+
// either true or absent -- expo-constants spreads this object into `Constants`,
|
|
221
|
+
// so a field invented here is a field an app will read and believe.
|
|
222
|
+
//
|
|
223
|
+
// `executionEnvironment: 'bare'` is the accurate answer: bare is "a native app
|
|
224
|
+
// that happens to use Expo modules", as against running inside Expo Go or a
|
|
225
|
+
// dev client, which a desktop host is not.
|
|
226
|
+
Object makeConstantsModule(Runtime &runtime) {
|
|
227
|
+
Object module = expoModule(runtime);
|
|
228
|
+
|
|
229
|
+
if (appConfig().has_value()) {
|
|
230
|
+
module.setProperty(
|
|
231
|
+
runtime, "manifest", facebook::jsi::valueFromDynamic(runtime, *appConfig()));
|
|
232
|
+
} else {
|
|
233
|
+
// Null rather than absent: expo-constants checks `ExponentConstants.manifest`
|
|
234
|
+
// and warns clearly when it is missing, which is the message a developer
|
|
235
|
+
// needs. Leaving the property off produces the same warning.
|
|
236
|
+
module.setProperty(runtime, "manifest", Value::null());
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.setProperty(runtime, "executionEnvironment", String::createFromUtf8(runtime, "bare"));
|
|
240
|
+
module.setProperty(runtime, "appOwnership", Value::null());
|
|
241
|
+
module.setProperty(runtime, "expoVersion", Value::null());
|
|
242
|
+
// A desktop is not a simulator, and nothing here reports a status bar.
|
|
243
|
+
module.setProperty(runtime, "isDevice", Value(true));
|
|
244
|
+
module.setProperty(runtime, "statusBarHeight", Value(0));
|
|
245
|
+
// Android and iOS fill this with their own device details. There is no shape
|
|
246
|
+
// defined for a desktop, and inventing one would be inventing a field.
|
|
247
|
+
module.setProperty(runtime, "platform", Object(runtime));
|
|
248
|
+
|
|
249
|
+
addFunction(runtime,
|
|
250
|
+
module,
|
|
251
|
+
"getWebViewUserAgentAsync",
|
|
252
|
+
0,
|
|
253
|
+
[](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
254
|
+
return resolved(rt, Value::null());
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return module;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// `expo.getViewConfig(moduleName, viewName)`, which is how an Expo view becomes
|
|
261
|
+
// a React Native component.
|
|
262
|
+
//
|
|
263
|
+
// `requireNativeViewManager` calls this, wraps the answer with React Native's
|
|
264
|
+
// `createViewConfig` -- which merges in the base view config, so style, layout
|
|
265
|
+
// and touch props come free -- and registers the result as a component called
|
|
266
|
+
// `ViewManagerAdapter_<moduleName>`. What is listed here is therefore exactly
|
|
267
|
+
// what reaches C++: a prop that is not in `validAttributes` is dropped in
|
|
268
|
+
// JavaScript, silently, before anything can diff it.
|
|
269
|
+
//
|
|
270
|
+
// Native platforms generate this from the module's own definition. Here it is a
|
|
271
|
+
// table, because here there is no module definition to generate it from -- the
|
|
272
|
+
// views are written directly against Fabric.
|
|
273
|
+
Value viewConfigFor(Runtime &runtime, const std::string &moduleName) {
|
|
274
|
+
if (moduleName != "ExpoImage") {
|
|
275
|
+
return Value::null();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
Object attributes(runtime);
|
|
279
|
+
// What core/ExpoImageComponent.cpp parses. expo-image sends a good deal more
|
|
280
|
+
// -- placeholder, transition, blurhash, cachePolicy, SF Symbol props -- and
|
|
281
|
+
// leaving them out here is what stops them travelling to a platform that
|
|
282
|
+
// would ignore them anyway.
|
|
283
|
+
for (const char *name : {"source", "contentFit", "tintColor"}) {
|
|
284
|
+
attributes.setProperty(runtime, name, Value(true));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
Object events(runtime);
|
|
288
|
+
// "topLoad" rather than "load": EventEmitter::normalizeEventType prefixes
|
|
289
|
+
// what C++ dispatches, and this is the name after that.
|
|
290
|
+
for (const auto &[eventName, handler] :
|
|
291
|
+
{std::pair{"topLoadStart", "onLoadStart"},
|
|
292
|
+
std::pair{"topLoad", "onLoad"},
|
|
293
|
+
std::pair{"topError", "onError"}}) {
|
|
294
|
+
Object registration(runtime);
|
|
295
|
+
registration.setProperty(runtime, "registrationName", String::createFromUtf8(runtime, handler));
|
|
296
|
+
events.setProperty(runtime, eventName, std::move(registration));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
Object config(runtime);
|
|
300
|
+
config.setProperty(runtime, "validAttributes", std::move(attributes));
|
|
301
|
+
config.setProperty(runtime, "directEventTypes", std::move(events));
|
|
302
|
+
return Value(runtime, config);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
} // namespace
|
|
306
|
+
|
|
307
|
+
Object expoModule(Runtime &runtime) {
|
|
308
|
+
return expo::NativeModule::createInstance(runtime);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
void addExpoFunction(Runtime &runtime,
|
|
312
|
+
Object &module,
|
|
313
|
+
const char *name,
|
|
314
|
+
unsigned argumentCount,
|
|
315
|
+
facebook::jsi::HostFunctionType function) {
|
|
316
|
+
addFunction(runtime, module, name, argumentCount, std::move(function));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
bool emitExpoEvent(const std::string &moduleName,
|
|
320
|
+
const std::string &eventName,
|
|
321
|
+
std::function<void(Runtime &, std::vector<Value> &)> arguments) {
|
|
322
|
+
return runOnJsRuntime([moduleName, eventName, arguments = std::move(arguments)](
|
|
323
|
+
Runtime &runtime) {
|
|
324
|
+
// Found by name each time; see the header for why nothing is held.
|
|
325
|
+
const Value expo = runtime.global().getProperty(runtime, "expo");
|
|
326
|
+
if (!expo.isObject()) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const Value modules = expo.asObject(runtime).getProperty(runtime, "modules");
|
|
330
|
+
if (!modules.isObject()) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const Value module =
|
|
334
|
+
modules.asObject(runtime).getProperty(runtime, moduleName.c_str());
|
|
335
|
+
if (!module.isObject()) {
|
|
336
|
+
// Installed later, or never. Not an error: see the header.
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
std::vector<Value> args;
|
|
341
|
+
arguments(runtime, args);
|
|
342
|
+
// A named lvalue: expo's emitEvent takes `jsi::Object &` in some versions
|
|
343
|
+
// and `const jsi::Object &` in others, and only an lvalue binds to both.
|
|
344
|
+
Object emitter = module.asObject(runtime);
|
|
345
|
+
expo::EventEmitter::emitEvent(runtime, emitter, eventName, args);
|
|
346
|
+
} catch (const facebook::jsi::JSIException &error) {
|
|
347
|
+
// A listener that throws is Expo's business -- its emitEvent swallows
|
|
348
|
+
// those deliberately. This is the payload itself failing to build, or the
|
|
349
|
+
// module turning out not to be an emitter, and the thread that asked for
|
|
350
|
+
// the emit is long gone and cannot be told.
|
|
351
|
+
//
|
|
352
|
+
// Caught at all because this runs as a scheduler task: an exception let
|
|
353
|
+
// out here unwinds through the runtime's own loop rather than through
|
|
354
|
+
// anything that could report it. JSIException rather than JSError, which
|
|
355
|
+
// is only one of its two halves.
|
|
356
|
+
LOG(ERROR) << "basalt: emitting " << moduleName << "." << eventName
|
|
357
|
+
<< " failed: " << error.what();
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
void installExpoModules(Runtime &runtime, Object &modules) {
|
|
363
|
+
modules.setProperty(runtime, "ExpoClipboard", makeClipboardModule(runtime));
|
|
364
|
+
modules.setProperty(runtime, "ExpoImage", makeImageModule(runtime));
|
|
365
|
+
modules.setProperty(runtime, "ExpoLinking", makeLinkingModule(runtime));
|
|
366
|
+
// Replaces the empty stub installExpoRuntime puts in for Expo's own start-up.
|
|
367
|
+
modules.setProperty(runtime, "ExponentConstants", makeConstantsModule(runtime));
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
// And whatever capability packages the build discovered. Last, so that a
|
|
371
|
+
// package replacing a built-in is something you can see happening here rather
|
|
372
|
+
// than a name collision resolved by ordering nobody wrote down.
|
|
373
|
+
installPackageExpoModules(runtime, modules);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
void installExpoViewConfigs(Runtime &runtime, Object &expo) {
|
|
377
|
+
expo.setProperty(
|
|
378
|
+
runtime,
|
|
379
|
+
"getViewConfig",
|
|
380
|
+
Function::createFromHostFunction(
|
|
381
|
+
runtime,
|
|
382
|
+
PropNameID::forAscii(runtime, "getViewConfig"),
|
|
383
|
+
2,
|
|
384
|
+
[](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
385
|
+
if (count < 1 || !args[0].isString()) {
|
|
386
|
+
return Value::null();
|
|
387
|
+
}
|
|
388
|
+
return viewConfigFor(rt, args[0].asString(rt).utf8(rt));
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
#else
|
|
393
|
+
|
|
394
|
+
void installExpoModules(facebook::jsi::Runtime & /*runtime*/,
|
|
395
|
+
facebook::jsi::Object & /*modules*/) {}
|
|
396
|
+
|
|
397
|
+
void installExpoViewConfigs(facebook::jsi::Runtime & /*runtime*/,
|
|
398
|
+
facebook::jsi::Object & /*expo*/) {}
|
|
399
|
+
|
|
400
|
+
// Unlike expoModule and addExpoFunction above, this one has a no-op: a package's
|
|
401
|
+
// Expo module is compiled only when there is an Expo, but the native half that
|
|
402
|
+
// *reports* -- a subprocess reader, a device watcher -- is portable code with no
|
|
403
|
+
// reason to know whether Expo exists. It emits, and without an Expo nothing is
|
|
404
|
+
// listening, which is already the ordinary case.
|
|
405
|
+
bool emitExpoEvent(
|
|
406
|
+
const std::string & /*moduleName*/,
|
|
407
|
+
const std::string & /*eventName*/,
|
|
408
|
+
std::function<void(facebook::jsi::Runtime &, std::vector<facebook::jsi::Value> &)>
|
|
409
|
+
/*arguments*/) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
#endif
|
|
414
|
+
|
|
415
|
+
} // namespace basalt
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// This platform's Expo modules, and the thing that was missing until now: a way
|
|
2
|
+
// to have one at all.
|
|
3
|
+
//
|
|
4
|
+
// `requireNativeModule('ExpoClipboard')` looks in three places, in order:
|
|
5
|
+
// `globalThis.expo.modules[name]`, the legacy bridge proxy, and a TurboModule
|
|
6
|
+
// of the same name wrapped by expo-modules-core. The third looks tempting --
|
|
7
|
+
// this project already has a TurboModule for the clipboard -- but the wrapper
|
|
8
|
+
// copies methods off `Object.getPrototypeOf(turboModule)`, and a C++ TurboModule
|
|
9
|
+
// is a jsi host object whose prototype is `Object.prototype`, so what it copies
|
|
10
|
+
// is nothing. The first is the real seam, and the one every native platform
|
|
11
|
+
// uses.
|
|
12
|
+
//
|
|
13
|
+
// So an Expo module here is a `expo.NativeModule` instance -- expo's own class,
|
|
14
|
+
// installed by ExpoRuntime, which is where `addListener` and the event
|
|
15
|
+
// machinery come from -- with host functions set on it. `moduleWithFunctions`
|
|
16
|
+
// below is the whole of the framework; everything else is one module's worth of
|
|
17
|
+
// behaviour, and each of them is a handful of lines because the behaviour is
|
|
18
|
+
// already written. `ExpoClipboard` is core/PlatformServices.h's clipboard, the
|
|
19
|
+
// same one React Native's own `Clipboard` module uses.
|
|
20
|
+
//
|
|
21
|
+
// **What a missing method does is part of the design.** Expo's JavaScript
|
|
22
|
+
// checks for each function before calling it -- `if (!ExpoClipboard.getImageAsync)
|
|
23
|
+
// throw new UnavailabilityError(...)` -- and reports "not available on this
|
|
24
|
+
// platform" naming the method. That is a better answer than a stub returning
|
|
25
|
+
// null, so a method this platform cannot implement is left off rather than
|
|
26
|
+
// faked.
|
|
27
|
+
|
|
28
|
+
#pragma once
|
|
29
|
+
|
|
30
|
+
#include <jsi/jsi.h>
|
|
31
|
+
|
|
32
|
+
#include <functional>
|
|
33
|
+
#include <string>
|
|
34
|
+
#include <vector>
|
|
35
|
+
|
|
36
|
+
namespace basalt {
|
|
37
|
+
|
|
38
|
+
// Adds this platform's Expo modules to `modules`, the object that becomes
|
|
39
|
+
// `globalThis.expo.modules`. Called from installExpoRuntime; there is no reason
|
|
40
|
+
// for anything else to call it.
|
|
41
|
+
//
|
|
42
|
+
// A no-op when the build was not pointed at an expo-modules-core, like
|
|
43
|
+
// everything else Expo here.
|
|
44
|
+
// The whole of the framework, exported because a capability that ships as its
|
|
45
|
+
// own package needs it to build its modules and should not copy it.
|
|
46
|
+
//
|
|
47
|
+
// `expoModule` is an `expo.NativeModule` instance -- expo's own class, installed
|
|
48
|
+
// by ExpoRuntime, which is where `addListener` and the event machinery come
|
|
49
|
+
// from. `addExpoFunction` puts a host function on one. Promises come from
|
|
50
|
+
// core/JsiPromise.h.
|
|
51
|
+
facebook::jsi::Object expoModule(facebook::jsi::Runtime &runtime);
|
|
52
|
+
|
|
53
|
+
void addExpoFunction(facebook::jsi::Runtime &runtime,
|
|
54
|
+
facebook::jsi::Object &module,
|
|
55
|
+
const char *name,
|
|
56
|
+
unsigned argumentCount,
|
|
57
|
+
facebook::jsi::HostFunctionType function);
|
|
58
|
+
|
|
59
|
+
void installExpoModules(facebook::jsi::Runtime &runtime, facebook::jsi::Object &modules);
|
|
60
|
+
|
|
61
|
+
// Emits an event on an already-installed Expo module, from any thread.
|
|
62
|
+
//
|
|
63
|
+
// This is the other half of `addExpoFunction`: a function is how JavaScript
|
|
64
|
+
// reaches native, and an event is how native reaches JavaScript later. Expo's
|
|
65
|
+
// own `NativeModule` is an `EventEmitter`, so `module.addListener('onOutput', f)`
|
|
66
|
+
// already works from JavaScript the moment the module is installed -- there was
|
|
67
|
+
// simply nothing here that ever emitted.
|
|
68
|
+
//
|
|
69
|
+
// **Named rather than captured.** The module is looked up as
|
|
70
|
+
// `globalThis.expo.modules[moduleName]` at the moment of the emit, rather than
|
|
71
|
+
// the caller holding the `jsi::Object` it built at install time. A held object
|
|
72
|
+
// outlives its runtime across a Fast Refresh reload and destroying it then
|
|
73
|
+
// touches a runtime that is gone; a name survives, and finds the new module
|
|
74
|
+
// installed into the new runtime. So a background thread can hold nothing but
|
|
75
|
+
// two strings, which is all a reader thread should have to be careful about.
|
|
76
|
+
//
|
|
77
|
+
// `arguments` builds the event payload and runs on the JavaScript thread, so it
|
|
78
|
+
// may use `runtime` freely. Everything it needs from the emitting thread it must
|
|
79
|
+
// capture by value.
|
|
80
|
+
//
|
|
81
|
+
// False when there is nothing to emit into: no host left a runtime runner (see
|
|
82
|
+
// JsRuntimeAccess.h), which is the tests and the probe. A module that is not
|
|
83
|
+
// installed, or is installed and has no listeners, is not a failure -- an event
|
|
84
|
+
// nobody is listening to is the normal case, and Expo's emitEvent does nothing.
|
|
85
|
+
bool emitExpoEvent(
|
|
86
|
+
const std::string &moduleName,
|
|
87
|
+
const std::string &eventName,
|
|
88
|
+
std::function<void(facebook::jsi::Runtime &, std::vector<facebook::jsi::Value> &)> arguments);
|
|
89
|
+
|
|
90
|
+
// Adds `expo.getViewConfig`, which is how expo-modules-core turns an Expo view
|
|
91
|
+
// into a React Native component. Separate from the modules because it goes on
|
|
92
|
+
// `expo` itself rather than on `expo.modules`.
|
|
93
|
+
void installExpoViewConfigs(facebook::jsi::Runtime &runtime, facebook::jsi::Object &expo);
|
|
94
|
+
|
|
95
|
+
// The app's Expo config -- `app.json` or `app.config.js`, resolved -- which is
|
|
96
|
+
// what `Constants.expoConfig` is and what expo-linking reads to find the app's
|
|
97
|
+
// URI scheme. Without it `Constants.expoConfig` is null and an app that reads
|
|
98
|
+
// `Constants.expoConfig.extra.something` crashes on the property access.
|
|
99
|
+
//
|
|
100
|
+
// iOS and Android embed it in the app bundle at build time, from a script Expo
|
|
101
|
+
// runs during the native build. This platform's equivalent moment is bundling:
|
|
102
|
+
// the bundler writes `app.config.json` beside the bundle, which is why this
|
|
103
|
+
// takes the bundle's path rather than the config's. Nothing being there is not
|
|
104
|
+
// an error -- a plain React Native app has no Expo config and never asks for
|
|
105
|
+
// one.
|
|
106
|
+
//
|
|
107
|
+
// Call before the runtime is installed; the hosts do it as they start.
|
|
108
|
+
void loadExpoAppConfigBeside(const std::string &bundlePath);
|
|
109
|
+
|
|
110
|
+
// The app's name from that config -- `name` in app.json -- or empty when there
|
|
111
|
+
// is no config or it names nothing. What a host titles its window with, rather
|
|
112
|
+
// than with its own name.
|
|
113
|
+
std::string expoAppName();
|
|
114
|
+
|
|
115
|
+
} // namespace basalt
|