basalt-core 0.0.0-rc5 → 0.2.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 (149) 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/desktop.d.ts.map +1 -1
  6. package/dist/cli/desktop.js +53 -4
  7. package/dist/cli/desktop.js.map +1 -1
  8. package/dist/cli/packageApp.d.ts.map +1 -1
  9. package/dist/cli/packageApp.js +7 -1
  10. package/dist/cli/packageApp.js.map +1 -1
  11. package/dist/metro-config.d.ts.map +1 -1
  12. package/dist/metro-config.js +53 -5
  13. package/dist/metro-config.js.map +1 -1
  14. package/dist/src/KeyHandler.d.ts +1 -1
  15. package/dist/src/KeyHandler.d.ts.map +1 -1
  16. package/dist/src/KeyHandler.js.map +1 -1
  17. package/dist/src/index.d.ts +5 -0
  18. package/dist/src/index.d.ts.map +1 -1
  19. package/dist/src/overrides/Alert.d.ts +1 -1
  20. package/dist/src/overrides/Alert.js +1 -1
  21. package/dist/src/overrides/BaseViewConfig.d.ts +10 -3
  22. package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -1
  23. package/dist/src/overrides/BaseViewConfig.js +21 -3
  24. package/dist/src/overrides/BaseViewConfig.js.map +1 -1
  25. package/dist/src/overrides/Button.d.ts +81 -0
  26. package/dist/src/overrides/Button.d.ts.map +1 -0
  27. package/dist/src/overrides/Button.js +109 -0
  28. package/dist/src/overrides/Button.js.map +1 -0
  29. package/dist/src/overrides/ScrollView.d.ts +25 -2
  30. package/dist/src/overrides/ScrollView.d.ts.map +1 -1
  31. package/dist/src/overrides/ScrollView.js +64 -7
  32. package/dist/src/overrides/ScrollView.js.map +1 -1
  33. package/dist/src/overrides/Settings.d.ts +81 -0
  34. package/dist/src/overrides/Settings.d.ts.map +1 -0
  35. package/dist/src/overrides/Settings.js +120 -0
  36. package/dist/src/overrides/Settings.js.map +1 -0
  37. package/dist/src/overrides/processDecelerationRate.d.ts +20 -0
  38. package/dist/src/overrides/processDecelerationRate.d.ts.map +1 -0
  39. package/dist/src/overrides/processDecelerationRate.js +31 -0
  40. package/dist/src/overrides/processDecelerationRate.js.map +1 -0
  41. package/dist/src/useContextMenu.d.ts +57 -6
  42. package/dist/src/useContextMenu.d.ts.map +1 -1
  43. package/dist/src/useContextMenu.js +34 -1
  44. package/dist/src/useContextMenu.js.map +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/native/CMakeLists.txt +85 -1
  47. package/native/cmake/Skia.cmake +29 -6
  48. package/native/core/ActionSheet.cpp +75 -0
  49. package/native/core/ActionSheet.h +90 -0
  50. package/native/core/AppStateHost.cpp +76 -0
  51. package/native/core/AppStateHost.h +68 -0
  52. package/native/core/BackgroundLayers.h +282 -0
  53. package/native/core/BlendModes.h +67 -0
  54. package/native/core/CoreModules.cpp +380 -11
  55. package/native/core/CoreModules.h +140 -4
  56. package/native/core/CrashHandler.cpp +246 -0
  57. package/native/core/CrashHandler.h +65 -0
  58. package/native/core/CursorNames.h +110 -0
  59. package/native/core/DevMenu.cpp +6 -5
  60. package/native/core/DeviceMetrics.cpp +87 -0
  61. package/native/core/DeviceMetrics.h +80 -0
  62. package/native/core/Filters.h +336 -0
  63. package/native/core/FontFitting.h +183 -0
  64. package/native/core/FontScaling.h +153 -0
  65. package/native/core/FontVariants.h +148 -0
  66. package/native/core/Gradients.h +523 -0
  67. package/native/core/ImageAnimation.h +109 -0
  68. package/native/core/ImageBytes.cpp +28 -1
  69. package/native/core/ImageBytes.h +17 -1
  70. package/native/core/ImageProgress.h +85 -0
  71. package/native/core/LabelRegistry.h +189 -0
  72. package/native/core/LegacyShadow.h +90 -0
  73. package/native/core/LiveRegions.h +114 -0
  74. package/native/core/MenuModule.cpp +35 -4
  75. package/native/core/MountingWalk.h +125 -2
  76. package/native/core/PlatformServices.h +187 -3
  77. package/native/core/SafeAreaComponent.cpp +115 -0
  78. package/native/core/SafeAreaComponent.h +105 -0
  79. package/native/core/ScreensComponent.cpp +201 -0
  80. package/native/core/ScreensComponent.h +216 -0
  81. package/native/core/ScrollBounds.cpp +8 -0
  82. package/native/core/ScrollBounds.h +14 -0
  83. package/native/core/ScrollIndicator.h +67 -0
  84. package/native/core/ScrollMomentum.cpp +24 -0
  85. package/native/core/ScrollMomentum.h +14 -0
  86. package/native/core/ScrollSnap.cpp +121 -12
  87. package/native/core/ScrollSnap.h +45 -0
  88. package/native/core/ScrollVisiblePosition.cpp +68 -0
  89. package/native/core/ScrollVisiblePosition.h +101 -0
  90. package/native/core/SettingsStore.cpp +199 -0
  91. package/native/core/SettingsStore.h +127 -0
  92. package/native/core/ShadowShape.h +38 -0
  93. package/native/core/SkiaViewComponent.cpp +11 -0
  94. package/native/core/SkiaViewComponent.h +50 -0
  95. package/native/core/SystemLocale.cpp +103 -0
  96. package/native/core/SystemLocale.h +86 -0
  97. package/native/core/TestDialog.cpp +45 -6
  98. package/native/core/TestDialog.h +15 -0
  99. package/native/core/TextAlignments.h +240 -0
  100. package/native/core/TextChecking.h +133 -0
  101. package/native/core/TextColors.h +83 -0
  102. package/native/core/TextDecorations.h +101 -0
  103. package/native/core/TextDirection.cpp +242 -0
  104. package/native/core/TextDirection.h +88 -0
  105. package/native/core/TextHighlight.h +30 -0
  106. package/native/core/TextSelection.cpp +97 -0
  107. package/native/core/TextSelection.h +161 -0
  108. package/native/core/TextShadows.h +96 -0
  109. package/native/core/TextVerticalAlign.h +33 -0
  110. package/native/core/UIManagerAccess.cpp +36 -0
  111. package/native/core/UIManagerAccess.h +28 -0
  112. package/native/core/WindowBoundsCache.cpp +58 -1
  113. package/native/core/WindowControl.h +24 -0
  114. package/native/core/WritingDirections.h +52 -0
  115. package/native/core/portability_probe.cpp +7 -0
  116. package/native/tests/RenamedFontFile.h +161 -0
  117. package/native/tests/TestHarness.cpp +18 -0
  118. package/native/tests/test_action_sheet.cpp +157 -0
  119. package/native/tests/test_app_state.cpp +60 -0
  120. package/native/tests/test_background_layers.cpp +281 -0
  121. package/native/tests/test_blend_modes.cpp +79 -0
  122. package/native/tests/test_blobs.cpp +1 -1
  123. package/native/tests/test_device_metrics.cpp +126 -0
  124. package/native/tests/test_filters.cpp +271 -0
  125. package/native/tests/test_font_fitting.cpp +172 -0
  126. package/native/tests/test_font_scaling.cpp +127 -0
  127. package/native/tests/test_font_variants.cpp +84 -0
  128. package/native/tests/test_gradients.cpp +390 -0
  129. package/native/tests/test_image_animation.cpp +105 -0
  130. package/native/tests/test_image_progress.cpp +94 -0
  131. package/native/tests/test_label_registry.cpp +262 -0
  132. package/native/tests/test_legacy_shadow.cpp +165 -0
  133. package/native/tests/test_live_regions.cpp +108 -0
  134. package/native/tests/test_menu_entries.cpp +192 -0
  135. package/native/tests/test_momentum.cpp +45 -0
  136. package/native/tests/test_scroll_bounds.cpp +42 -0
  137. package/native/tests/test_scroll_indicator.cpp +61 -0
  138. package/native/tests/test_scroll_snap.cpp +129 -0
  139. package/native/tests/test_scroll_visible_position.cpp +121 -0
  140. package/native/tests/test_settings_store.cpp +257 -0
  141. package/native/tests/test_shadow_shape.cpp +47 -0
  142. package/native/tests/test_system_locale.cpp +36 -0
  143. package/native/tests/test_text_alignment.cpp +299 -0
  144. package/native/tests/test_text_checking.cpp +31 -0
  145. package/native/tests/test_text_colors.cpp +92 -0
  146. package/native/tests/test_text_decorations.cpp +100 -0
  147. package/native/tests/test_text_selection.cpp +168 -0
  148. package/native/tests/test_text_shadows.cpp +132 -0
  149. package/package.json +4 -2
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ /**
3
+ * `decelerationRate`, for a desktop React Native platform.
4
+ *
5
+ * Not a shim, and the same failure as `<Button>`'s: React Native's own file is
6
+ * two `Platform.select({ios, android})` tables with no `default`, so on
7
+ * `linux`, `macos` or `windows` both of the prop's documented spellings --
8
+ * `'normal'` and `'fast'` -- resolve to `undefined`. `BaseScrollViewProps`
9
+ * then keeps its own default of 0.998, so `decelerationRate="fast"` scrolled
10
+ * at the normal rate and nothing said otherwise. Only a raw number worked.
11
+ *
12
+ * iOS's pair, because they are the pair this platform's own fling already
13
+ * uses: `core/ScrollMomentum.h` names 0.998 and 0.99 as what `'normal'` and
14
+ * `'fast'` mean, and a per-millisecond friction factor is the same model
15
+ * UIScrollView and every browser use. Android's 0.985 and 0.9 are a different
16
+ * curve's constants and would make a fling stop in a third of the distance.
17
+ *
18
+ * @format
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.default = processDecelerationRate;
22
+ function processDecelerationRate(decelerationRate) {
23
+ if (decelerationRate === 'normal') {
24
+ return 0.998;
25
+ }
26
+ if (decelerationRate === 'fast') {
27
+ return 0.99;
28
+ }
29
+ return decelerationRate;
30
+ }
31
+ //# sourceMappingURL=processDecelerationRate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processDecelerationRate.js","sourceRoot":"","sources":["../../../src/overrides/processDecelerationRate.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;AAEH,0CAUC;AAVD,SAAwB,uBAAuB,CAC7C,gBAA4C;IAE5C,IAAI,gBAAgB,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,gBAAgB,KAAK,MAAM,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
@@ -63,20 +63,71 @@
63
63
  * @format
64
64
  */
65
65
  /**
66
- * One item in a context menu, as `native/core/MenuModel.h` reads it, plus the
67
- * handler this file calls.
66
+ * One item in a context menu: the four fields `entriesFrom` in
67
+ * `native/core/MenuModule.cpp` reads into a `MenuEntry`, plus the handler this
68
+ * file calls.
69
+ *
70
+ * A popup menu is a flat list on all three desktops, so there is no `submenu`
71
+ * and no `role` here -- nesting and the platform roles are what a menu *bar*
72
+ * is for, and `<Menu.Item>` is where they live.
68
73
  *
69
74
  * `onSelect` is the only field the native side does not see: the promise
70
75
  * carries the index back, and this calls the handler before settling it.
71
76
  */
72
77
  export type ContextMenuItem = {
73
78
  label?: string;
74
- /** One of the platform roles; see native/core/MenuModel.h. */
75
- role?: string;
76
- /** "CmdOrCtrl+O", in Electron's spelling. Ignored for a role. */
77
- accelerator?: string;
79
+ /**
80
+ * Drawn beside the label -- "Cmd+C", "Del". Decoration only: nothing here
81
+ * binds a key. Note the menu *bar* spells the same idea `accelerator`,
82
+ * because there it really does bind one.
83
+ */
84
+ shortcut?: string;
78
85
  enabled?: boolean;
79
86
  separator?: boolean;
87
+ /**
88
+ * One of the platform roles, in Electron's spelling: `about`, `quit`, `undo`,
89
+ * `redo`, `cut`, `copy`, `paste`, `delete`, `selectAll`, `minimize`, `zoom`,
90
+ * `close`, `togglefullscreen`. The platform performs it -- the Copy that
91
+ * actually copies the field the person was in -- and `onSelect` still runs, so
92
+ * an app can both get the behaviour and hear about it.
93
+ *
94
+ * **A role this desktop cannot perform is left out of the menu**, rather than
95
+ * shown doing nothing. It keeps its index though: what comes back is an index
96
+ * into the list you passed, so adding a role that one platform lacks does not
97
+ * renumber the items after it.
98
+ *
99
+ * The three do not agree. macOS has all thirteen; Linux and Windows have
100
+ * twelve, both missing `about`, neither having a platform about panel to ask
101
+ * for -- that window is an app's own to show, and an ordinary item with an
102
+ * `onSelect` is how to open it.
103
+ */
104
+ role?: string;
105
+ /**
106
+ * A tick or a radio mark beside the label.
107
+ *
108
+ * `checked` on its own means a checkbox, so the common case is one word. The
109
+ * kind is a separate field because it has to be: a GMenu item carries no
110
+ * checked attribute, and GTK picks a tick or a circle from the shape of the
111
+ * action behind it, which a boolean cannot express.
112
+ *
113
+ * `'radio'` is a drawing hint, not a capability. Windows draws a bullet and
114
+ * Linux a circle; macOS draws a tick, `NSMenu` having no radio item and a tick
115
+ * being what Apple's guidance prescribes for a chosen member of a group.
116
+ *
117
+ * A group is a run of adjacent `'radio'` items, ended by a separator or by any
118
+ * other kind of item. There is no group name to pass. Exclusivity is yours:
119
+ * the menu is built fresh each time it opens, so it draws the marks you give
120
+ * it and keeping one member checked is the caller's.
121
+ */
122
+ type?: 'checkbox' | 'radio';
123
+ checked?: boolean;
124
+ /**
125
+ * Nested items. The parent is not choosable: it opens its children.
126
+ *
127
+ * Both a `submenu` and a `role` on one item is a mistake, and the submenu
128
+ * wins. A parent whose children are all roles this desktop cannot perform is
129
+ * left out with them, an empty submenu being a dead end rather than an item.
130
+ */
80
131
  submenu?: ReadonlyArray<ContextMenuItem>;
81
132
  onSelect?: () => void;
82
133
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useContextMenu.d.ts","sourceRoot":"","sources":["../../src/useContextMenu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAKH;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAYF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,SAAsC,CAAC;AAE/D,iBAAe,IAAI,CACjB,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW;;;EAAqC,CAAC;AAE9D,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC;AAE7C,wBAAgB,cAAc,IAAI,WAAW,CAK5C"}
1
+ {"version":3,"file":"useContextMenu.d.ts","sourceRoot":"","sources":["../../src/useContextMenu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAKH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAYF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,SAAsC,CAAC;AAE/D,iBAAe,IAAI,CACjB,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB;AAyCD;;;GAGG;AACH,eAAO,MAAM,WAAW;;;EAAqC,CAAC;AAE9D,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC;AAE7C,wBAAgB,cAAc,IAAI,WAAW,CAK5C"}
@@ -92,9 +92,42 @@ async function show(items, where) {
92
92
  }
93
93
  // Called before the promise settles, so that an app which only wants
94
94
  // `onSelect` never has to await anything.
95
- items[index]?.onSelect?.();
95
+ itemAt(items, index)?.onSelect?.();
96
96
  return index;
97
97
  }
98
+ /**
99
+ * The item an index names, which is its position in a pre-order walk of the
100
+ * whole menu: an item, then its children, then the next item, counting
101
+ * separators and parents.
102
+ *
103
+ * For a flat list that is the position in the array, which is what this answered
104
+ * when a popup could only be flat, so an index means what it has always meant.
105
+ * The native side numbers its items the same way; see `walkMenuEntries` in
106
+ * core/PlatformServices.h, which is the other half of this contract.
107
+ *
108
+ * An item the platform left out still counts, which is what lets both sides
109
+ * agree without this knowing which roles the platform has: the native side
110
+ * numbers every entry it was given and draws only the ones it can. See
111
+ * `menuEntryShown` beside it.
112
+ */
113
+ function itemAt(items, index) {
114
+ let next = 0;
115
+ const walk = (level) => {
116
+ for (const item of level) {
117
+ if (next++ === index) {
118
+ return item;
119
+ }
120
+ if (item.submenu != null && item.submenu.length > 0) {
121
+ const found = walk(item.submenu);
122
+ if (found != null) {
123
+ return found;
124
+ }
125
+ }
126
+ }
127
+ return undefined;
128
+ };
129
+ return walk(items);
130
+ }
98
131
  /**
99
132
  * The imperative half, usable outside a component -- the same arrangement
100
133
  * `useDialog()` and `windowControl` have.
@@ -1 +1 @@
1
- {"version":3,"file":"useContextMenu.js","sourceRoot":"","sources":["../../src/useContextMenu.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;;;AAuFH,wCAKC;AAzFD,+CAAiD;AAyCjD,MAAM,UAAU,GAAG,kCAAmB,CAAC,GAAG,CAAmB,YAAY,CAAC,CAAC;AAE3E;;;;;GAKG;AACU,QAAA,WAAW,GAAG,UAAU,EAAE,eAAe,IAAI,IAAI,CAAC;AAE/D,KAAK,UAAU,IAAI,CACjB,KAAqC,EACrC,KAA+B;IAE/B,IAAI,CAAC,mBAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,4EAA4E;IAC5E,6EAA6E;IAC7E,2CAA2C;IAC3C,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;IAEzC,6EAA6E;IAC7E,8EAA8E;IAC9E,MAAM,KAAK,GAAG,MAAM,UAAW,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,qEAAqE;IACrE,0CAA0C;IAC1C,KAAK,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC;IAC3B,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACU,QAAA,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,EAAC,IAAI,EAAE,WAAW,EAAX,mBAAW,EAAC,CAAC,CAAC;AAI9D,SAAgB,cAAc;IAC5B,0EAA0E;IAC1E,8EAA8E;IAC9E,2BAA2B;IAC3B,OAAO,mBAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"useContextMenu.js","sourceRoot":"","sources":["../../src/useContextMenu.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;;;AAiLH,wCAKC;AAnLD,+CAAiD;AA4FjD,MAAM,UAAU,GAAG,kCAAmB,CAAC,GAAG,CAAmB,YAAY,CAAC,CAAC;AAE3E;;;;;GAKG;AACU,QAAA,WAAW,GAAG,UAAU,EAAE,eAAe,IAAI,IAAI,CAAC;AAE/D,KAAK,UAAU,IAAI,CACjB,KAAqC,EACrC,KAA+B;IAE/B,IAAI,CAAC,mBAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,4EAA4E;IAC5E,6EAA6E;IAC7E,2CAA2C;IAC3C,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;IAEzC,6EAA6E;IAC7E,8EAA8E;IAC9E,MAAM,KAAK,GAAG,MAAM,UAAW,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,qEAAqE;IACrE,0CAA0C;IAC1C,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC;IACnC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,MAAM,CACb,KAAqC,EACrC,KAAa;IAEb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,IAAI,GAAG,CACX,KAAqC,EACR,EAAE;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACjC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IACF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;AACrB,CAAC;AAED;;;GAGG;AACU,QAAA,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,EAAC,IAAI,EAAE,WAAW,EAAX,mBAAW,EAAC,CAAC,CAAC;AAI9D,SAAgB,cAAc;IAC5B,0EAA0E;IAC1E,8EAA8E;IAC9E,2BAA2B;IAC3B,OAAO,mBAAW,CAAC;AACrB,CAAC"}
@@ -1 +1 @@
1
- {"root":["../src/dragsource.tsx","../src/droptarget.tsx","../src/keyhandler.tsx","../src/menu.tsx","../src/titlebar.tsx","../src/window.tsx","../src/closerequest.ts","../src/globals.d.ts","../src/index.ts","../src/quitrequest.ts","../src/resourcepath.ts","../src/responsebody.ts","../src/responseheaders.ts","../src/titlebarstate.ts","../src/usecontextmenu.ts","../src/usedialog.ts","../src/usedisplays.ts","../src/usehandledkeys.ts","../src/usewindow.ts","../src/overrides/alert.ts","../src/overrides/baseviewconfig.ts","../src/overrides/platform.d.ts","../src/overrides/platform.linux.ts","../src/overrides/platform.macos.ts","../src/overrides/platform.windows.ts","../src/overrides/reactdevtoolssettingsmanager.ts","../src/overrides/refreshcontrol.tsx","../src/overrides/scrollview.tsx","../src/overrides/share.ts","../src/overrides/textinput.tsx","../src/overrides/view.tsx","../src/overrides/createplatform.ts","../src/overrides/setupdevelopertools.ts","../src/overrides/setupxhr.ts","../src/overrides/upstream.d.ts","../cli/basalt.ts","../cli/bundle-cli.ts","../cli/bundlewithassets.ts","../cli/desktop.ts","../cli/doctor.ts","../cli/init.ts","../cli/metro.ts","../cli/packageapp.ts","../cli/steps.ts","../react-native.config.js"],"version":"6.0.3"}
1
+ {"root":["../src/DragSource.tsx","../src/DropTarget.tsx","../src/KeyHandler.tsx","../src/Menu.tsx","../src/TitleBar.tsx","../src/Window.tsx","../src/closeRequest.ts","../src/globals.d.ts","../src/index.ts","../src/quitRequest.ts","../src/resourcePath.ts","../src/responseBody.ts","../src/responseHeaders.ts","../src/titleBarState.ts","../src/useContextMenu.ts","../src/useDialog.ts","../src/useDisplays.ts","../src/useHandledKeys.ts","../src/useWindow.ts","../src/overrides/Alert.ts","../src/overrides/BaseViewConfig.ts","../src/overrides/Button.tsx","../src/overrides/Platform.d.ts","../src/overrides/Platform.linux.ts","../src/overrides/Platform.macos.ts","../src/overrides/Platform.windows.ts","../src/overrides/ReactDevToolsSettingsManager.ts","../src/overrides/RefreshControl.tsx","../src/overrides/ScrollView.tsx","../src/overrides/Settings.ts","../src/overrides/Share.ts","../src/overrides/TextInput.tsx","../src/overrides/View.tsx","../src/overrides/createPlatform.ts","../src/overrides/processDecelerationRate.ts","../src/overrides/setUpDeveloperTools.ts","../src/overrides/setUpXHR.ts","../src/overrides/upstream.d.ts","../cli/basalt.ts","../cli/bundle-cli.ts","../cli/bundleWithAssets.ts","../cli/desktop.ts","../cli/doctor.ts","../cli/init.ts","../cli/metro.ts","../cli/packageApp.ts","../cli/steps.ts","../react-native.config.js"],"version":"6.0.3"}
@@ -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
 
@@ -159,6 +193,22 @@ if(DEFINED RN_DIR)
159
193
  get_property(basalt_package_installers GLOBAL PROPERTY BASALT_PACKAGE_EXPO_INSTALLERS)
160
194
  get_property(basalt_package_core_sources GLOBAL PROPERTY BASALT_PACKAGE_CORE_SOURCES)
161
195
  get_property(basalt_package_includes GLOBAL PROPERTY BASALT_PACKAGE_INCLUDES)
196
+ # And the ones that are somebody else's headers, which cannot be held to
197
+ # this project's warnings: Skia's trip `-Wpedantic` on a variadic macro, as
198
+ # React Native's own trip several, which is why those are `SYSTEM` too. A
199
+ # package says which of its include directories are its own and which are a
200
+ # dependency's.
201
+ get_property(basalt_package_system_includes GLOBAL PROPERTY BASALT_PACKAGE_SYSTEM_INCLUDES)
202
+ # And what a package wants *said* about itself, as preprocessor definitions.
203
+ #
204
+ # The hosts already have `BASALT_HAS_SKIA` and `BASALT_HAS_WORKLETS`, both set
205
+ # by a cmake/ file in this package for a dependency this package knows about.
206
+ # A capability package in somebody else's node_modules cannot reach either, and
207
+ # the first one that needed to is basalt-skia: whether the installed Skia is
208
+ # Graphite decides which of two canvases the AppKit mounting manager calls, and
209
+ # which surface the platform context makes. PUBLIC, so it reaches the host
210
+ # packages and their tests and not only core's own sources.
211
+ get_property(basalt_package_definitions GLOBAL PROPERTY BASALT_PACKAGE_DEFINITIONS)
162
212
 
163
213
  # A semicolon by character code: CMake treats `;` as a list separator, and
164
214
  # escaping it as `\;` survives into the generated file rather than becoming
@@ -203,7 +253,12 @@ if(DEFINED RN_DIR)
203
253
  core/ImageCache.cpp
204
254
  core/ScrollBounds.cpp
205
255
  core/ScrollIndicator.cpp
256
+ core/AppStateHost.cpp
257
+ core/SystemLocale.cpp
258
+ core/DeviceMetrics.cpp
206
259
  core/ScrollSnap.cpp
260
+ # Keeping the content still while items are inserted above it.
261
+ core/ScrollVisiblePosition.cpp
207
262
  # `Appearance`, and the portable half of light-vs-dark.
208
263
  core/AppearanceModule.cpp
209
264
  # Blob, File and FileReader -- portable in full.
@@ -212,6 +267,8 @@ if(DEFINED RN_DIR)
212
267
  core/ColorScheme.cpp
213
268
  # Clipboard, Vibration, Alert, Linking, I18nManager, AccessibilityInfo --
214
269
  # the core modules ReactCxxPlatform does not provide.
270
+ # `ActionSheetIOS`, which is a popup menu here; see the header.
271
+ core/ActionSheet.cpp
215
272
  core/CoreModules.cpp
216
273
  # <ActivityIndicator>, <Switch>, <RefreshControl> and <Modal>: the props
217
274
  # three view layers have to read identically, plus the two shadow-node
@@ -229,6 +286,8 @@ if(DEFINED RN_DIR)
229
286
  core/DebuggingOverlay.cpp
230
287
  core/DevBundle.cpp
231
288
  core/ExpoImageComponent.cpp
289
+ core/SafeAreaComponent.cpp
290
+ core/ScreensComponent.cpp
232
291
  core/GestureHandlerModule.cpp
233
292
  core/Gestures.cpp
234
293
  # Hover: the pointer-event path React Native only has on Android.
@@ -251,14 +310,23 @@ if(DEFINED RN_DIR)
251
310
  core/ScrollMomentum.cpp
252
311
  # A share sheet for the desktops that have none; see the header.
253
312
  core/ShareFallback.cpp
313
+ # `Settings`, which is a file here rather than NSUserDefaults; see the header.
314
+ core/SettingsStore.cpp
315
+ # Which way a paragraph runs when the app did not say; see the header.
316
+ core/TextDirection.cpp
317
+ # What a press and a drag mean inside selectable text; see the header.
318
+ core/TextSelection.cpp
254
319
  core/SourceCodeModule.cpp
255
320
  # Answering a modal dialog without showing one; see the header.
256
321
  core/TestDialog.cpp
322
+ # What the host says when it dies, which was nothing; see the header.
323
+ core/CrashHandler.cpp
257
324
  # Quitting gracefully when the harness says so, rather than on a budget
258
325
  # fixed before launch; see the header.
259
326
  core/TestQuitFile.cpp
260
327
  # What a <Canvas> from @shopify/react-native-skia mounts; see the header.
261
328
  core/SkiaPictureViewComponent.cpp
329
+ core/SkiaViewComponent.cpp
262
330
  # globalThis.__turboModuleProxy, which a bridgeless runtime does not get; see
263
331
  # the header.
264
332
  core/TurboModuleProxy.cpp
@@ -303,7 +371,13 @@ if(DEFINED RN_DIR)
303
371
  target_compile_definitions(basalt_core PUBLIC
304
372
  BASALT_REACT_NATIVE_VERSION="${RN_VERSION}"
305
373
  BASALT_RN_MINOR=${RN_MINOR})
374
+ if(basalt_package_definitions)
375
+ target_compile_definitions(basalt_core PUBLIC ${basalt_package_definitions})
376
+ endif()
306
377
  target_include_directories(basalt_core PUBLIC core ${basalt_package_includes})
378
+ if(basalt_package_system_includes)
379
+ target_include_directories(basalt_core SYSTEM PUBLIC ${basalt_package_system_includes})
380
+ endif()
307
381
  target_include_directories(basalt_core SYSTEM PUBLIC
308
382
  ${RN_DIR}/ReactCommon
309
383
  ${RN_DIR}/ReactCommon/jsi
@@ -316,7 +390,17 @@ if(DEFINED RN_DIR)
316
390
  # "iosswitch" and which are ordinary portable C++ apart from the one
317
391
  # measurement core/DesktopControls.cpp supplies. Android's needs fbjni;
318
392
  # this one needs nothing.
319
- ${RN_DIR}/ReactCommon/react/renderer/components/switch/iosswitch)
393
+ ${RN_DIR}/ReactCommon/react/renderer/components/switch/iosswitch
394
+ # Hermes' public headers, which core already links and until now only its
395
+ # own directory could include. `include_directories()` in ThirdParty.cmake
396
+ # is directory-scoped, so a test in a *host* package linking core could
397
+ # call into Hermes and not include <hermes/hermes.h> -- which is what a
398
+ # test that wants a real jsi::Runtime needs, and the first one that wanted
399
+ # one is basalt-skia's. The same two directories ThirdParty.cmake names,
400
+ # for the same reason: RN's jsi is used rather than Hermes' vendored copy,
401
+ # so API/ and public/ only.
402
+ ${HERMES_DIR}/API
403
+ ${HERMES_DIR}/public)
320
404
  # libcurl, because core/HttpClient.cpp is here. It used to be named only on
321
405
  # basalt_gtk_mounting, which worked for exactly as long as the GTK host was the only
322
406
  # thing linking core: the archive member goes unreferenced until something
@@ -65,9 +65,35 @@ endif()
65
65
 
66
66
  if(NOT EXISTS ${SKIA_CPP_DIR}/rnskia/RNSkManager.cpp)
67
67
  message(FATAL_ERROR
68
- "no @shopify/react-native-skia C++ at ${SKIA_CPP_DIR}.\n"
69
- "BASALT_SKIA should name an installed @shopify/react-native-skia, "
70
- "the one in the app's node_modules.")
68
+ "no React Native Skia C++ at ${SKIA_CPP_DIR}.\n"
69
+ "BASALT_SKIA should name an installed react-native-skia or "
70
+ "@shopify/react-native-skia, the one in the app's node_modules.")
71
+ endif()
72
+
73
+ file(READ ${SKIA_DIR}/package.json SKIA_PACKAGE_JSON)
74
+ string(JSON SKIA_VERSION GET "${SKIA_PACKAGE_JSON}" version)
75
+
76
+ # 3.x is a different renderer, not a newer one.
77
+ #
78
+ # It replaced Ganesh with Skia Graphite over Dawn, and this file is the Ganesh
79
+ # half: six of the seven Apple sources it borrows below do not exist in 3.x, and
80
+ # their replacement -- RNSkWindowSurface, which is portable C++ rather than
81
+ # Objective-C++ -- configures a CAMetalLayer or an ANativeWindow as a Dawn
82
+ # surface and nothing else, so neither GTK nor Win32 can use it as shipped
83
+ # either. backlog/compatibility.md records what each of the three would take.
84
+ #
85
+ # Said here as well as in the CLI because BASALT_SKIA can be set by hand, and
86
+ # the failure it saves is a bad one: `MetalContext.mm does not exist`, from a
87
+ # source list, naming a file nobody deleted. A version is the actual reason and
88
+ # this is the first place that knows it.
89
+ string(REGEX MATCH "^[0-9]+" SKIA_MAJOR "${SKIA_VERSION}")
90
+ if(SKIA_MAJOR AND SKIA_MAJOR GREATER_EQUAL 3)
91
+ message(FATAL_ERROR
92
+ "Skia ${SKIA_VERSION} at ${SKIA_DIR} is Graphite over Dawn, and this "
93
+ "platform's half is Ganesh.\n"
94
+ "Install the 2.x line -- `react-native-skia@release-2.x`, or "
95
+ "`@shopify/react-native-skia` -- or configure without BASALT_SKIA, "
96
+ "until basalt-skia carries the Graphite half.")
71
97
  endif()
72
98
 
73
99
  # The binaries are not in the package's `files`: they are downloaded, by the
@@ -96,9 +122,6 @@ if(NOT APPLE AND NOT WIN32 AND NOT EXISTS ${SKIA_LIBS_DIR}/libskia.a)
96
122
  "its libs/linux/x86_64 here.")
97
123
  endif()
98
124
 
99
- file(READ ${SKIA_DIR}/package.json SKIA_PACKAGE_JSON)
100
- string(JSON SKIA_VERSION GET "${SKIA_PACKAGE_JSON}" version)
101
-
102
125
  # Every prebuilt archive the package imports on Apple, each a universal slice.
103
126
  # Named rather than globbed: a missing one is a link error in somebody else's
104
127
  # symbols, and a list says which we expected.
@@ -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