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.
Files changed (143) hide show
  1. package/dist/cli/basalt.d.ts.map +1 -1
  2. package/dist/cli/basalt.js +18 -1
  3. package/dist/cli/basalt.js.map +1 -1
  4. package/dist/cli/bundle-cli.js +0 -0
  5. package/dist/cli/packageApp.d.ts.map +1 -1
  6. package/dist/cli/packageApp.js +7 -1
  7. package/dist/cli/packageApp.js.map +1 -1
  8. package/dist/metro-config.d.ts.map +1 -1
  9. package/dist/metro-config.js +53 -5
  10. package/dist/metro-config.js.map +1 -1
  11. package/dist/src/KeyHandler.d.ts +1 -1
  12. package/dist/src/KeyHandler.d.ts.map +1 -1
  13. package/dist/src/KeyHandler.js.map +1 -1
  14. package/dist/src/index.d.ts +5 -0
  15. package/dist/src/index.d.ts.map +1 -1
  16. package/dist/src/overrides/Alert.d.ts +1 -1
  17. package/dist/src/overrides/Alert.js +1 -1
  18. package/dist/src/overrides/BaseViewConfig.d.ts +10 -3
  19. package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -1
  20. package/dist/src/overrides/BaseViewConfig.js +21 -3
  21. package/dist/src/overrides/BaseViewConfig.js.map +1 -1
  22. package/dist/src/overrides/Button.d.ts +81 -0
  23. package/dist/src/overrides/Button.d.ts.map +1 -0
  24. package/dist/src/overrides/Button.js +109 -0
  25. package/dist/src/overrides/Button.js.map +1 -0
  26. package/dist/src/overrides/ScrollView.d.ts +25 -2
  27. package/dist/src/overrides/ScrollView.d.ts.map +1 -1
  28. package/dist/src/overrides/ScrollView.js +64 -7
  29. package/dist/src/overrides/ScrollView.js.map +1 -1
  30. package/dist/src/overrides/Settings.d.ts +81 -0
  31. package/dist/src/overrides/Settings.d.ts.map +1 -0
  32. package/dist/src/overrides/Settings.js +120 -0
  33. package/dist/src/overrides/Settings.js.map +1 -0
  34. package/dist/src/overrides/processDecelerationRate.d.ts +20 -0
  35. package/dist/src/overrides/processDecelerationRate.d.ts.map +1 -0
  36. package/dist/src/overrides/processDecelerationRate.js +31 -0
  37. package/dist/src/overrides/processDecelerationRate.js.map +1 -0
  38. package/dist/src/useContextMenu.d.ts +57 -6
  39. package/dist/src/useContextMenu.d.ts.map +1 -1
  40. package/dist/src/useContextMenu.js +34 -1
  41. package/dist/src/useContextMenu.js.map +1 -1
  42. package/dist/tsconfig.tsbuildinfo +1 -1
  43. package/native/CMakeLists.txt +51 -0
  44. package/native/core/ActionSheet.cpp +75 -0
  45. package/native/core/ActionSheet.h +90 -0
  46. package/native/core/AppStateHost.cpp +76 -0
  47. package/native/core/AppStateHost.h +68 -0
  48. package/native/core/BackgroundLayers.h +282 -0
  49. package/native/core/BlendModes.h +67 -0
  50. package/native/core/CoreModules.cpp +380 -11
  51. package/native/core/CoreModules.h +140 -4
  52. package/native/core/CrashHandler.cpp +246 -0
  53. package/native/core/CrashHandler.h +65 -0
  54. package/native/core/CursorNames.h +110 -0
  55. package/native/core/DevMenu.cpp +6 -5
  56. package/native/core/DeviceMetrics.cpp +87 -0
  57. package/native/core/DeviceMetrics.h +80 -0
  58. package/native/core/Filters.h +336 -0
  59. package/native/core/FontFitting.h +183 -0
  60. package/native/core/FontScaling.h +153 -0
  61. package/native/core/FontVariants.h +148 -0
  62. package/native/core/Gradients.h +523 -0
  63. package/native/core/ImageAnimation.h +109 -0
  64. package/native/core/ImageBytes.cpp +28 -1
  65. package/native/core/ImageBytes.h +17 -1
  66. package/native/core/ImageProgress.h +85 -0
  67. package/native/core/LabelRegistry.h +189 -0
  68. package/native/core/LegacyShadow.h +90 -0
  69. package/native/core/LiveRegions.h +114 -0
  70. package/native/core/MenuModule.cpp +35 -4
  71. package/native/core/MountingWalk.h +125 -2
  72. package/native/core/PlatformServices.h +187 -3
  73. package/native/core/SafeAreaComponent.cpp +115 -0
  74. package/native/core/SafeAreaComponent.h +105 -0
  75. package/native/core/ScreensComponent.cpp +201 -0
  76. package/native/core/ScreensComponent.h +216 -0
  77. package/native/core/ScrollBounds.cpp +8 -0
  78. package/native/core/ScrollBounds.h +14 -0
  79. package/native/core/ScrollIndicator.h +67 -0
  80. package/native/core/ScrollMomentum.cpp +24 -0
  81. package/native/core/ScrollMomentum.h +14 -0
  82. package/native/core/ScrollSnap.cpp +121 -12
  83. package/native/core/ScrollSnap.h +45 -0
  84. package/native/core/ScrollVisiblePosition.cpp +68 -0
  85. package/native/core/ScrollVisiblePosition.h +101 -0
  86. package/native/core/SettingsStore.cpp +199 -0
  87. package/native/core/SettingsStore.h +127 -0
  88. package/native/core/ShadowShape.h +38 -0
  89. package/native/core/SystemLocale.cpp +103 -0
  90. package/native/core/SystemLocale.h +86 -0
  91. package/native/core/TestDialog.cpp +45 -6
  92. package/native/core/TestDialog.h +15 -0
  93. package/native/core/TextAlignments.h +240 -0
  94. package/native/core/TextChecking.h +133 -0
  95. package/native/core/TextColors.h +83 -0
  96. package/native/core/TextDecorations.h +101 -0
  97. package/native/core/TextDirection.cpp +242 -0
  98. package/native/core/TextDirection.h +88 -0
  99. package/native/core/TextHighlight.h +30 -0
  100. package/native/core/TextSelection.cpp +97 -0
  101. package/native/core/TextSelection.h +161 -0
  102. package/native/core/TextShadows.h +96 -0
  103. package/native/core/TextVerticalAlign.h +33 -0
  104. package/native/core/UIManagerAccess.cpp +36 -0
  105. package/native/core/UIManagerAccess.h +28 -0
  106. package/native/core/WindowBoundsCache.cpp +58 -1
  107. package/native/core/WindowControl.h +24 -0
  108. package/native/core/WritingDirections.h +52 -0
  109. package/native/core/portability_probe.cpp +7 -0
  110. package/native/tests/RenamedFontFile.h +161 -0
  111. package/native/tests/TestHarness.cpp +18 -0
  112. package/native/tests/test_action_sheet.cpp +157 -0
  113. package/native/tests/test_app_state.cpp +60 -0
  114. package/native/tests/test_background_layers.cpp +281 -0
  115. package/native/tests/test_blend_modes.cpp +79 -0
  116. package/native/tests/test_blobs.cpp +1 -1
  117. package/native/tests/test_device_metrics.cpp +126 -0
  118. package/native/tests/test_filters.cpp +271 -0
  119. package/native/tests/test_font_fitting.cpp +172 -0
  120. package/native/tests/test_font_scaling.cpp +127 -0
  121. package/native/tests/test_font_variants.cpp +84 -0
  122. package/native/tests/test_gradients.cpp +390 -0
  123. package/native/tests/test_image_animation.cpp +105 -0
  124. package/native/tests/test_image_progress.cpp +94 -0
  125. package/native/tests/test_label_registry.cpp +262 -0
  126. package/native/tests/test_legacy_shadow.cpp +165 -0
  127. package/native/tests/test_live_regions.cpp +108 -0
  128. package/native/tests/test_menu_entries.cpp +192 -0
  129. package/native/tests/test_momentum.cpp +45 -0
  130. package/native/tests/test_scroll_bounds.cpp +42 -0
  131. package/native/tests/test_scroll_indicator.cpp +61 -0
  132. package/native/tests/test_scroll_snap.cpp +129 -0
  133. package/native/tests/test_scroll_visible_position.cpp +121 -0
  134. package/native/tests/test_settings_store.cpp +257 -0
  135. package/native/tests/test_shadow_shape.cpp +47 -0
  136. package/native/tests/test_system_locale.cpp +36 -0
  137. package/native/tests/test_text_alignment.cpp +299 -0
  138. package/native/tests/test_text_checking.cpp +31 -0
  139. package/native/tests/test_text_colors.cpp +92 -0
  140. package/native/tests/test_text_decorations.cpp +100 -0
  141. package/native/tests/test_text_selection.cpp +168 -0
  142. package/native/tests/test_text_shadows.cpp +132 -0
  143. package/package.json +4 -2
@@ -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