basalt-core 0.0.0-rc5 → 0.1.0
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/dist/cli/basalt.d.ts.map +1 -1
- package/dist/cli/basalt.js +18 -1
- package/dist/cli/basalt.js.map +1 -1
- package/dist/cli/bundle-cli.js +0 -0
- package/dist/cli/packageApp.d.ts.map +1 -1
- package/dist/cli/packageApp.js +7 -1
- package/dist/cli/packageApp.js.map +1 -1
- package/dist/metro-config.d.ts.map +1 -1
- package/dist/metro-config.js +53 -5
- package/dist/metro-config.js.map +1 -1
- package/dist/src/KeyHandler.d.ts +1 -1
- package/dist/src/KeyHandler.d.ts.map +1 -1
- package/dist/src/KeyHandler.js.map +1 -1
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/overrides/Alert.d.ts +1 -1
- package/dist/src/overrides/Alert.js +1 -1
- package/dist/src/overrides/BaseViewConfig.d.ts +10 -3
- package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -1
- package/dist/src/overrides/BaseViewConfig.js +21 -3
- package/dist/src/overrides/BaseViewConfig.js.map +1 -1
- package/dist/src/overrides/Button.d.ts +81 -0
- package/dist/src/overrides/Button.d.ts.map +1 -0
- package/dist/src/overrides/Button.js +109 -0
- package/dist/src/overrides/Button.js.map +1 -0
- package/dist/src/overrides/ScrollView.d.ts +25 -2
- package/dist/src/overrides/ScrollView.d.ts.map +1 -1
- package/dist/src/overrides/ScrollView.js +64 -7
- package/dist/src/overrides/ScrollView.js.map +1 -1
- package/dist/src/overrides/Settings.d.ts +81 -0
- package/dist/src/overrides/Settings.d.ts.map +1 -0
- package/dist/src/overrides/Settings.js +120 -0
- package/dist/src/overrides/Settings.js.map +1 -0
- package/dist/src/overrides/processDecelerationRate.d.ts +20 -0
- package/dist/src/overrides/processDecelerationRate.d.ts.map +1 -0
- package/dist/src/overrides/processDecelerationRate.js +31 -0
- package/dist/src/overrides/processDecelerationRate.js.map +1 -0
- package/dist/src/useContextMenu.d.ts +57 -6
- package/dist/src/useContextMenu.d.ts.map +1 -1
- package/dist/src/useContextMenu.js +34 -1
- package/dist/src/useContextMenu.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/native/CMakeLists.txt +51 -0
- package/native/core/ActionSheet.cpp +75 -0
- package/native/core/ActionSheet.h +90 -0
- package/native/core/AppStateHost.cpp +76 -0
- package/native/core/AppStateHost.h +68 -0
- package/native/core/BackgroundLayers.h +282 -0
- package/native/core/BlendModes.h +67 -0
- package/native/core/CoreModules.cpp +380 -11
- package/native/core/CoreModules.h +140 -4
- package/native/core/CrashHandler.cpp +246 -0
- package/native/core/CrashHandler.h +65 -0
- package/native/core/CursorNames.h +110 -0
- package/native/core/DevMenu.cpp +6 -5
- package/native/core/DeviceMetrics.cpp +87 -0
- package/native/core/DeviceMetrics.h +80 -0
- package/native/core/Filters.h +336 -0
- package/native/core/FontFitting.h +183 -0
- package/native/core/FontScaling.h +153 -0
- package/native/core/FontVariants.h +148 -0
- package/native/core/Gradients.h +523 -0
- package/native/core/ImageAnimation.h +109 -0
- package/native/core/ImageBytes.cpp +28 -1
- package/native/core/ImageBytes.h +17 -1
- package/native/core/ImageProgress.h +85 -0
- package/native/core/LabelRegistry.h +189 -0
- package/native/core/LegacyShadow.h +90 -0
- package/native/core/LiveRegions.h +114 -0
- package/native/core/MenuModule.cpp +35 -4
- package/native/core/MountingWalk.h +125 -2
- package/native/core/PlatformServices.h +187 -3
- package/native/core/SafeAreaComponent.cpp +115 -0
- package/native/core/SafeAreaComponent.h +105 -0
- package/native/core/ScreensComponent.cpp +201 -0
- package/native/core/ScreensComponent.h +216 -0
- package/native/core/ScrollBounds.cpp +8 -0
- package/native/core/ScrollBounds.h +14 -0
- package/native/core/ScrollIndicator.h +67 -0
- package/native/core/ScrollMomentum.cpp +24 -0
- package/native/core/ScrollMomentum.h +14 -0
- package/native/core/ScrollSnap.cpp +121 -12
- package/native/core/ScrollSnap.h +45 -0
- package/native/core/ScrollVisiblePosition.cpp +68 -0
- package/native/core/ScrollVisiblePosition.h +101 -0
- package/native/core/SettingsStore.cpp +199 -0
- package/native/core/SettingsStore.h +127 -0
- package/native/core/ShadowShape.h +38 -0
- package/native/core/SystemLocale.cpp +103 -0
- package/native/core/SystemLocale.h +86 -0
- package/native/core/TestDialog.cpp +45 -6
- package/native/core/TestDialog.h +15 -0
- package/native/core/TextAlignments.h +240 -0
- package/native/core/TextChecking.h +133 -0
- package/native/core/TextColors.h +83 -0
- package/native/core/TextDecorations.h +101 -0
- package/native/core/TextDirection.cpp +242 -0
- package/native/core/TextDirection.h +88 -0
- package/native/core/TextHighlight.h +30 -0
- package/native/core/TextSelection.cpp +97 -0
- package/native/core/TextSelection.h +161 -0
- package/native/core/TextShadows.h +96 -0
- package/native/core/TextVerticalAlign.h +33 -0
- package/native/core/UIManagerAccess.cpp +36 -0
- package/native/core/UIManagerAccess.h +28 -0
- package/native/core/WindowBoundsCache.cpp +58 -1
- package/native/core/WindowControl.h +24 -0
- package/native/core/WritingDirections.h +52 -0
- package/native/core/portability_probe.cpp +7 -0
- package/native/tests/RenamedFontFile.h +161 -0
- package/native/tests/TestHarness.cpp +18 -0
- package/native/tests/test_action_sheet.cpp +157 -0
- package/native/tests/test_app_state.cpp +60 -0
- package/native/tests/test_background_layers.cpp +281 -0
- package/native/tests/test_blend_modes.cpp +79 -0
- package/native/tests/test_blobs.cpp +1 -1
- package/native/tests/test_device_metrics.cpp +126 -0
- package/native/tests/test_filters.cpp +271 -0
- package/native/tests/test_font_fitting.cpp +172 -0
- package/native/tests/test_font_scaling.cpp +127 -0
- package/native/tests/test_font_variants.cpp +84 -0
- package/native/tests/test_gradients.cpp +390 -0
- package/native/tests/test_image_animation.cpp +105 -0
- package/native/tests/test_image_progress.cpp +94 -0
- package/native/tests/test_label_registry.cpp +262 -0
- package/native/tests/test_legacy_shadow.cpp +165 -0
- package/native/tests/test_live_regions.cpp +108 -0
- package/native/tests/test_menu_entries.cpp +192 -0
- package/native/tests/test_momentum.cpp +45 -0
- package/native/tests/test_scroll_bounds.cpp +42 -0
- package/native/tests/test_scroll_indicator.cpp +61 -0
- package/native/tests/test_scroll_snap.cpp +129 -0
- package/native/tests/test_scroll_visible_position.cpp +121 -0
- package/native/tests/test_settings_store.cpp +257 -0
- package/native/tests/test_shadow_shape.cpp +47 -0
- package/native/tests/test_system_locale.cpp +36 -0
- package/native/tests/test_text_alignment.cpp +299 -0
- package/native/tests/test_text_checking.cpp +31 -0
- package/native/tests/test_text_colors.cpp +92 -0
- package/native/tests/test_text_decorations.cpp +100 -0
- package/native/tests/test_text_selection.cpp +168 -0
- package/native/tests/test_text_shadows.cpp +132 -0
- package/package.json +4 -2
package/native/CMakeLists.txt
CHANGED
|
@@ -38,6 +38,14 @@ get_filename_component(BASALT_THIRD_PARTY "${BASALT_THIRD_PARTY}" ABSOLUTE)
|
|
|
38
38
|
# it alongside its own tests and brings its own `main`; see docs/TESTING.md.
|
|
39
39
|
set(BASALT_TEST_HARNESS ${CMAKE_CURRENT_SOURCE_DIR}/tests/TestHarness.cpp
|
|
40
40
|
CACHE INTERNAL "the toolkit-free test runner")
|
|
41
|
+
# What the harness calls and cannot define: a crashing test prints a stack
|
|
42
|
+
# rather than a silent non-zero exit. It lives in basalt_core, which a suite
|
|
43
|
+
# linking that target gets for free -- and the Windows view layer builds with
|
|
44
|
+
# no React Native and therefore no basalt_core, so that build has to compile
|
|
45
|
+
# this one file itself. Named here, beside the harness that needs it, rather
|
|
46
|
+
# than spelled as a path in the package that happens to hit the problem.
|
|
47
|
+
set(BASALT_CRASH_HANDLER ${CMAKE_CURRENT_SOURCE_DIR}/core/CrashHandler.cpp
|
|
48
|
+
CACHE INTERNAL "the crash handler the test harness installs")
|
|
41
49
|
set(BASALT_TEST_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/tests
|
|
42
50
|
CACHE INTERNAL "where TestHarness.h lives")
|
|
43
51
|
|
|
@@ -52,13 +60,35 @@ set(BASALT_CORE_TESTS
|
|
|
52
60
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_app_paths.cpp
|
|
53
61
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_scroll_animation.cpp
|
|
54
62
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_backface.cpp
|
|
63
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_gradients.cpp
|
|
64
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_label_registry.cpp
|
|
65
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_live_regions.cpp
|
|
66
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_filters.cpp
|
|
67
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_blend_modes.cpp
|
|
68
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_legacy_shadow.cpp
|
|
69
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_shadow_shape.cpp
|
|
70
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_background_layers.cpp
|
|
71
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_text_shadows.cpp
|
|
72
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_font_scaling.cpp
|
|
73
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_text_decorations.cpp
|
|
74
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_text_colors.cpp
|
|
75
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_font_variants.cpp
|
|
76
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_text_checking.cpp
|
|
55
77
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_drag_and_drop.cpp
|
|
56
78
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_quit_file.cpp
|
|
79
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_menu_entries.cpp
|
|
57
80
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_settle.cpp
|
|
58
81
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_key_events.cpp
|
|
59
82
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_js_runtime_access.cpp
|
|
60
83
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_image_cache.cpp
|
|
84
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_image_animation.cpp
|
|
85
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_image_progress.cpp
|
|
86
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_device_metrics.cpp
|
|
87
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_app_state.cpp
|
|
88
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_system_locale.cpp
|
|
89
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_font_fitting.cpp
|
|
61
90
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_scroll_bounds.cpp
|
|
91
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_scroll_visible_position.cpp
|
|
62
92
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_scroll_indicator.cpp
|
|
63
93
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_scroll_snap.cpp
|
|
64
94
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_window_close.cpp
|
|
@@ -71,6 +101,10 @@ set(BASALT_CORE_TESTS
|
|
|
71
101
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_hover.cpp
|
|
72
102
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_momentum.cpp
|
|
73
103
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_share.cpp
|
|
104
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_settings_store.cpp
|
|
105
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_action_sheet.cpp
|
|
106
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_text_alignment.cpp
|
|
107
|
+
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_text_selection.cpp
|
|
74
108
|
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_sourcecode.cpp
|
|
75
109
|
CACHE INTERNAL "core's own tests")
|
|
76
110
|
|
|
@@ -203,7 +237,12 @@ if(DEFINED RN_DIR)
|
|
|
203
237
|
core/ImageCache.cpp
|
|
204
238
|
core/ScrollBounds.cpp
|
|
205
239
|
core/ScrollIndicator.cpp
|
|
240
|
+
core/AppStateHost.cpp
|
|
241
|
+
core/SystemLocale.cpp
|
|
242
|
+
core/DeviceMetrics.cpp
|
|
206
243
|
core/ScrollSnap.cpp
|
|
244
|
+
# Keeping the content still while items are inserted above it.
|
|
245
|
+
core/ScrollVisiblePosition.cpp
|
|
207
246
|
# `Appearance`, and the portable half of light-vs-dark.
|
|
208
247
|
core/AppearanceModule.cpp
|
|
209
248
|
# Blob, File and FileReader -- portable in full.
|
|
@@ -212,6 +251,8 @@ if(DEFINED RN_DIR)
|
|
|
212
251
|
core/ColorScheme.cpp
|
|
213
252
|
# Clipboard, Vibration, Alert, Linking, I18nManager, AccessibilityInfo --
|
|
214
253
|
# the core modules ReactCxxPlatform does not provide.
|
|
254
|
+
# `ActionSheetIOS`, which is a popup menu here; see the header.
|
|
255
|
+
core/ActionSheet.cpp
|
|
215
256
|
core/CoreModules.cpp
|
|
216
257
|
# <ActivityIndicator>, <Switch>, <RefreshControl> and <Modal>: the props
|
|
217
258
|
# three view layers have to read identically, plus the two shadow-node
|
|
@@ -229,6 +270,8 @@ if(DEFINED RN_DIR)
|
|
|
229
270
|
core/DebuggingOverlay.cpp
|
|
230
271
|
core/DevBundle.cpp
|
|
231
272
|
core/ExpoImageComponent.cpp
|
|
273
|
+
core/SafeAreaComponent.cpp
|
|
274
|
+
core/ScreensComponent.cpp
|
|
232
275
|
core/GestureHandlerModule.cpp
|
|
233
276
|
core/Gestures.cpp
|
|
234
277
|
# Hover: the pointer-event path React Native only has on Android.
|
|
@@ -251,9 +294,17 @@ if(DEFINED RN_DIR)
|
|
|
251
294
|
core/ScrollMomentum.cpp
|
|
252
295
|
# A share sheet for the desktops that have none; see the header.
|
|
253
296
|
core/ShareFallback.cpp
|
|
297
|
+
# `Settings`, which is a file here rather than NSUserDefaults; see the header.
|
|
298
|
+
core/SettingsStore.cpp
|
|
299
|
+
# Which way a paragraph runs when the app did not say; see the header.
|
|
300
|
+
core/TextDirection.cpp
|
|
301
|
+
# What a press and a drag mean inside selectable text; see the header.
|
|
302
|
+
core/TextSelection.cpp
|
|
254
303
|
core/SourceCodeModule.cpp
|
|
255
304
|
# Answering a modal dialog without showing one; see the header.
|
|
256
305
|
core/TestDialog.cpp
|
|
306
|
+
# What the host says when it dies, which was nothing; see the header.
|
|
307
|
+
core/CrashHandler.cpp
|
|
257
308
|
# Quitting gracefully when the harness says so, rather than on a budget
|
|
258
309
|
# fixed before launch; see the header.
|
|
259
310
|
core/TestQuitFile.cpp
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#include "ActionSheet.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
|
|
5
|
+
namespace basalt {
|
|
6
|
+
|
|
7
|
+
namespace {
|
|
8
|
+
|
|
9
|
+
MenuEntry disabledEntry(const std::string &label) {
|
|
10
|
+
// Assigned rather than a designated initializer, for the reason
|
|
11
|
+
// MenuEntry::separator() gives: a partial initializer list is an error under
|
|
12
|
+
// the -Werror the GTK build turns on.
|
|
13
|
+
MenuEntry entry;
|
|
14
|
+
entry.label = label;
|
|
15
|
+
entry.enabled = false;
|
|
16
|
+
return entry;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
bool contains(const std::vector<int> &values, int value) {
|
|
20
|
+
return std::find(values.begin(), values.end(), value) != values.end();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
} // namespace
|
|
24
|
+
|
|
25
|
+
ActionSheetMenu actionSheetMenu(const ActionSheetRequest &request) {
|
|
26
|
+
ActionSheetMenu built;
|
|
27
|
+
built.menu.x = request.x;
|
|
28
|
+
built.menu.y = request.y;
|
|
29
|
+
|
|
30
|
+
if (!request.title.empty()) {
|
|
31
|
+
built.menu.entries.push_back(disabledEntry(request.title));
|
|
32
|
+
}
|
|
33
|
+
if (!request.message.empty()) {
|
|
34
|
+
built.menu.entries.push_back(disabledEntry(request.message));
|
|
35
|
+
}
|
|
36
|
+
if (!built.menu.entries.empty()) {
|
|
37
|
+
built.menu.entries.push_back(MenuEntry::separator());
|
|
38
|
+
}
|
|
39
|
+
built.offset = static_cast<int>(built.menu.entries.size());
|
|
40
|
+
|
|
41
|
+
for (size_t index = 0; index < request.options.size(); ++index) {
|
|
42
|
+
MenuEntry entry;
|
|
43
|
+
entry.label = request.options[index];
|
|
44
|
+
entry.enabled = !contains(request.disabledIndices, static_cast<int>(index));
|
|
45
|
+
built.menu.entries.push_back(entry);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return built;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
std::optional<int> actionSheetChoice(const ActionSheetRequest &request,
|
|
52
|
+
const ActionSheetMenu &menu,
|
|
53
|
+
int chosen) {
|
|
54
|
+
const int count = static_cast<int>(request.options.size());
|
|
55
|
+
|
|
56
|
+
if (chosen < 0) {
|
|
57
|
+
// Dismissed. The cancel choice when the app named one, and otherwise
|
|
58
|
+
// nothing at all; see the header.
|
|
59
|
+
if (request.cancelIndex >= 0 && request.cancelIndex < count) {
|
|
60
|
+
return request.cancelIndex;
|
|
61
|
+
}
|
|
62
|
+
return std::nullopt;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const int option = chosen - menu.offset;
|
|
66
|
+
if (option < 0 || option >= count) {
|
|
67
|
+
// A header, or an index no entry of this menu has. Not reported: the app's
|
|
68
|
+
// callback takes an index into the array it passed, and there is nothing
|
|
69
|
+
// here to pass it.
|
|
70
|
+
return std::nullopt;
|
|
71
|
+
}
|
|
72
|
+
return option;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} // namespace basalt
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// `ActionSheetIOS`, which on a desktop is a popup menu.
|
|
2
|
+
//
|
|
3
|
+
// `ActionSheetManager` is a `get` lookup, so its absence was not a crash: the
|
|
4
|
+
// module came back null and `ActionSheetIOS.showActionSheetWithOptions` died on
|
|
5
|
+
// `invariant(RCTActionSheetManager, "ActionSheetManager doesn't exist")` at the
|
|
6
|
+
// first call. Unlike `Settings`, `Share` and `Alert`, there is no JavaScript to
|
|
7
|
+
// replace -- `ActionSheetIOS.js` has no `Platform.OS` branch at all and calls
|
|
8
|
+
// the module directly, which is why this is a module and nothing else. Worth
|
|
9
|
+
// knowing that the two shapes exist: an iOS-named API is not automatically one
|
|
10
|
+
// whose JavaScript refuses to run off iOS.
|
|
11
|
+
//
|
|
12
|
+
// ## A menu rather than a dialog
|
|
13
|
+
//
|
|
14
|
+
// An action sheet is a list of choices, one of which usually cancels, shown
|
|
15
|
+
// because of something the person just did. On a desktop that is a popup menu,
|
|
16
|
+
// and the alternative -- `presentAlert`, which this project already has -- loses
|
|
17
|
+
// more than it gains: a dialog can show the sheet's `title` and `message`, and
|
|
18
|
+
// it cannot show eight choices without looking like a mistake, cannot grey one
|
|
19
|
+
// out, and cannot be dismissed with Escape the way a menu can.
|
|
20
|
+
//
|
|
21
|
+
// So it is `presentMenu`, and the title and message go in as disabled entries
|
|
22
|
+
// at the top. That is a real desktop pattern and it moves the options down the
|
|
23
|
+
// list, which is why `offset` below exists: JavaScript numbers the array it
|
|
24
|
+
// passed, and a menu index counts every entry.
|
|
25
|
+
//
|
|
26
|
+
// ## What a desktop cannot do with it
|
|
27
|
+
//
|
|
28
|
+
// `destructiveButtonIndex` is accepted and ignored. None of the three can style
|
|
29
|
+
// one item of a popup menu as dangerous: GTK's `destructive-action` is a button
|
|
30
|
+
// class, `NSMenuItem` has no such style, and a Win32 menu item has no colour of
|
|
31
|
+
// its own. `tintColor`, `cancelButtonTintColor`, `disabledButtonTintColor` and
|
|
32
|
+
// `userInterfaceStyle` are iOS's own and are likewise ignored rather than
|
|
33
|
+
// refused, so code written for iOS runs unchanged. `disabledButtonIndices` is
|
|
34
|
+
// the one that *does* work, because a menu entry can be greyed.
|
|
35
|
+
|
|
36
|
+
#pragma once
|
|
37
|
+
|
|
38
|
+
#include "PlatformServices.h"
|
|
39
|
+
|
|
40
|
+
#include <optional>
|
|
41
|
+
#include <string>
|
|
42
|
+
#include <vector>
|
|
43
|
+
|
|
44
|
+
namespace basalt {
|
|
45
|
+
|
|
46
|
+
// What the app asked for, read off the options object once.
|
|
47
|
+
struct ActionSheetRequest {
|
|
48
|
+
std::string title;
|
|
49
|
+
std::string message;
|
|
50
|
+
std::vector<std::string> options;
|
|
51
|
+
// Indices into `options`, as `disabledButtonIndices` names them.
|
|
52
|
+
std::vector<int> disabledIndices;
|
|
53
|
+
// `cancelButtonIndex`, or -1 when the app named none. It is what a dismissal
|
|
54
|
+
// reports; see actionSheetChoice.
|
|
55
|
+
int cancelIndex{-1};
|
|
56
|
+
// Where the menu goes, in the window's coordinates. Negative means "wherever
|
|
57
|
+
// the pointer is", which is what MenuRequest means by it and what a sheet with
|
|
58
|
+
// no `anchor` wants.
|
|
59
|
+
double x{-1.0};
|
|
60
|
+
double y{-1.0};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// The popup menu an action sheet becomes, and how to read an answer back out.
|
|
64
|
+
struct ActionSheetMenu {
|
|
65
|
+
MenuRequest menu;
|
|
66
|
+
// How many entries the title, the message and their separator took, which is
|
|
67
|
+
// the difference between a menu index and the option index an app knows.
|
|
68
|
+
int offset{0};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
ActionSheetMenu actionSheetMenu(const ActionSheetRequest &request);
|
|
72
|
+
|
|
73
|
+
// Which option to report for the menu index `chosen`, or nothing when the app's
|
|
74
|
+
// callback should not be called at all.
|
|
75
|
+
//
|
|
76
|
+
// Nothing, rather than -1, because that is iOS's behaviour and it is load
|
|
77
|
+
// bearing: `UIAlertController` invokes the callback from a button's handler, so
|
|
78
|
+
// a sheet that goes away without a button being pressed calls nothing, and an
|
|
79
|
+
// app that would otherwise act on "index -1" never has to.
|
|
80
|
+
//
|
|
81
|
+
// A dismissal is the one case where this platform answers something iOS does
|
|
82
|
+
// not. Escape closing a menu is far more ordinary than an iPad popover being
|
|
83
|
+
// tapped away, and an app that offered a cancel choice has already said what to
|
|
84
|
+
// do with it -- so a dismissal reports `cancelIndex` when there is one, and
|
|
85
|
+
// nothing when there is not.
|
|
86
|
+
std::optional<int> actionSheetChoice(const ActionSheetRequest &request,
|
|
87
|
+
const ActionSheetMenu &menu,
|
|
88
|
+
int chosen);
|
|
89
|
+
|
|
90
|
+
} // namespace basalt
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#include "AppStateHost.h"
|
|
2
|
+
|
|
3
|
+
#include <atomic>
|
|
4
|
+
#include <mutex>
|
|
5
|
+
|
|
6
|
+
namespace basalt {
|
|
7
|
+
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
std::mutex &lock() {
|
|
11
|
+
static std::mutex value;
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
std::atomic<AppStateKind> &state() {
|
|
16
|
+
// Active, not unknown: a host that never reports has still put a window on
|
|
17
|
+
// the screen, and `AppState.currentState` is read before any event can
|
|
18
|
+
// arrive. React Native has an `unknown` for a platform that cannot tell, and
|
|
19
|
+
// all three of these can.
|
|
20
|
+
static std::atomic<AppStateKind> value{AppStateKind::Active};
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
std::function<void(AppStateKind)> &listener() {
|
|
25
|
+
static std::function<void(AppStateKind)> value;
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
} // namespace
|
|
30
|
+
|
|
31
|
+
const char *appStateName(AppStateKind state) {
|
|
32
|
+
switch (state) {
|
|
33
|
+
case AppStateKind::Active:
|
|
34
|
+
return "active";
|
|
35
|
+
case AppStateKind::Inactive:
|
|
36
|
+
return "inactive";
|
|
37
|
+
case AppStateKind::Background:
|
|
38
|
+
return "background";
|
|
39
|
+
}
|
|
40
|
+
return "active";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
AppStateKind appStateFor(bool focused, bool visible) {
|
|
44
|
+
if (!visible) {
|
|
45
|
+
return AppStateKind::Background;
|
|
46
|
+
}
|
|
47
|
+
return focused ? AppStateKind::Active : AppStateKind::Inactive;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
void notifyAppState(AppStateKind next) {
|
|
51
|
+
std::function<void(AppStateKind)> toCall;
|
|
52
|
+
{
|
|
53
|
+
const std::lock_guard<std::mutex> guard(lock());
|
|
54
|
+
if (state().load(std::memory_order_relaxed) == next) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
state().store(next, std::memory_order_relaxed);
|
|
58
|
+
toCall = listener();
|
|
59
|
+
}
|
|
60
|
+
// Outside the lock: it emits into the JavaScript runtime, and holding a lock
|
|
61
|
+
// across that is how a deadlock is built.
|
|
62
|
+
if (toCall) {
|
|
63
|
+
toCall(next);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
AppStateKind currentAppState() {
|
|
68
|
+
return state().load(std::memory_order_relaxed);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void setAppStateListener(std::function<void(AppStateKind)> next) {
|
|
72
|
+
const std::lock_guard<std::mutex> guard(lock());
|
|
73
|
+
listener() = std::move(next);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
} // namespace basalt
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// `AppState`, which told every desktop app nothing at all.
|
|
2
|
+
//
|
|
3
|
+
// ReactCxxPlatform provides an `AppState` module and every method of it is
|
|
4
|
+
// empty: `getConstants` answers `initialAppState: ""`, `getCurrentAppState`
|
|
5
|
+
// calls neither of its callbacks, and `addListener` does nothing. There is a
|
|
6
|
+
// `// TODO: T160890586 Wire up AppState implementation to use real data` where
|
|
7
|
+
// the work would go. So `AppState.currentState` was the empty string -- not
|
|
8
|
+
// `'active'`, not `'unknown'` -- and `AppState.addEventListener('change')`
|
|
9
|
+
// never fired, on all three hosts.
|
|
10
|
+
//
|
|
11
|
+
// That is an API apps use for real work: pausing a poll while the app is not
|
|
12
|
+
// in front, refetching when it comes back, saving a draft on the way out.
|
|
13
|
+
//
|
|
14
|
+
// ## What the three states mean on a desktop
|
|
15
|
+
//
|
|
16
|
+
// React Native's own are iOS's: `active`, `inactive` and `background`. A phone
|
|
17
|
+
// has no focus and no windows, so the mapping has to be chosen, and it is the
|
|
18
|
+
// one react-native-macos uses:
|
|
19
|
+
//
|
|
20
|
+
// active the application is frontmost
|
|
21
|
+
// inactive it is running and visible, and something else has focus
|
|
22
|
+
// background nothing of it is on screen: hidden, or every window minimised
|
|
23
|
+
//
|
|
24
|
+
// `inactive` on iOS is a transition -- a phone call arriving over the app --
|
|
25
|
+
// and the desktop analogue is "another window is in front", which is the same
|
|
26
|
+
// thing an app wants it for: do less, but stay ready.
|
|
27
|
+
//
|
|
28
|
+
// The mapping is here rather than in each host because all three decide it
|
|
29
|
+
// from the same two facts, and only *how they learn them* differs: an
|
|
30
|
+
// `is-active` notification on GTK, `NSApplicationDidBecomeActive` and its
|
|
31
|
+
// siblings on AppKit, `WM_ACTIVATEAPP` on Windows.
|
|
32
|
+
|
|
33
|
+
#pragma once
|
|
34
|
+
|
|
35
|
+
#include <functional>
|
|
36
|
+
|
|
37
|
+
namespace basalt {
|
|
38
|
+
|
|
39
|
+
enum class AppStateKind {
|
|
40
|
+
Active,
|
|
41
|
+
Inactive,
|
|
42
|
+
Background,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// React Native's own spelling, which is what crosses into JavaScript.
|
|
46
|
+
const char *appStateName(AppStateKind state);
|
|
47
|
+
|
|
48
|
+
// The state those two facts mean. Invisible wins over focused: a minimised
|
|
49
|
+
// window that somehow still holds focus is not something an app should treat
|
|
50
|
+
// as frontmost.
|
|
51
|
+
AppStateKind appStateFor(bool focused, bool visible);
|
|
52
|
+
|
|
53
|
+
// Told by the host whenever either fact changes, on the UI thread. Stores the
|
|
54
|
+
// result and calls the listener below, but only when it is different: React
|
|
55
|
+
// Native's `AppState` re-emits whatever it is handed, and an app that refetches
|
|
56
|
+
// on every `active` should not refetch because a window moved.
|
|
57
|
+
void notifyAppState(AppStateKind state);
|
|
58
|
+
|
|
59
|
+
// What was last reported, readable from any thread -- a TurboModule method runs
|
|
60
|
+
// on the JavaScript thread. `Active` before a host has said anything, which is
|
|
61
|
+
// what an application that has just started and drawn a window is.
|
|
62
|
+
AppStateKind currentAppState();
|
|
63
|
+
|
|
64
|
+
// The module's half. Replacing a listener drops the previous one; passing
|
|
65
|
+
// nothing removes it, which is what the module's destructor does.
|
|
66
|
+
void setAppStateListener(std::function<void(AppStateKind)> listener);
|
|
67
|
+
|
|
68
|
+
} // namespace basalt
|