basalt-navigation 0.0.0-stage → 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vince Vella
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,71 @@
1
- # Temporary Holding Version
1
+ # basalt-navigation
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Native screens for react-navigation on the desktop.
4
+
5
+ ```bash
6
+ npm install basalt-navigation
7
+ ```
8
+
9
+ ```jsx
10
+ import {NavigationScreens} from 'basalt-navigation';
11
+
12
+ <NavigationScreens>
13
+ <NavigationContainer>{/* navigators, as usual */}</NavigationContainer>
14
+ </NavigationScreens>
15
+ ```
16
+
17
+ That is the whole API. Wrap it once, as high as you like.
18
+
19
+ ## What it does
20
+
21
+ react-navigation's native stack renders every screen it has pushed and leaves
22
+ it to the platform to show the top one. Basalt implements the components that
23
+ do that, and on Windows they are used already. On macOS and Linux
24
+ react-native-screens renders plain views instead, so every pushed screen stays
25
+ mounted: invisible, because the screen in front covers it, but still measured
26
+ and still reachable by a screen reader.
27
+
28
+ This makes those two behave like Windows.
29
+
30
+ ## What it is not
31
+
32
+ Not a fork, not a patch, and nothing is rewritten in `node_modules`.
33
+ react-native-screens picks the component it renders for each screen out of a
34
+ React context:
35
+
36
+ ```js
37
+ const ScreenWrapper = React.useContext(ScreenContext) || InnerScreen;
38
+ ```
39
+
40
+ The platform check lives inside `InnerScreen`, so providing a different screen
41
+ through that context is enough, and it is a public extension point rather than
42
+ a crack. `ScreenStack` needs nothing at all: it is not gated and renders its
43
+ native component everywhere already.
44
+
45
+ ## When you will not need it
46
+
47
+ [react-native-screens#4779](https://github.com/software-mansion/react-native-screens/pull/4779)
48
+ proposes letting a platform that supplies the components say so. If it lands,
49
+ this package becomes two calls in your application and can go:
50
+
51
+ ```ts
52
+ provideNativeScreens(); // basalt registers RNSScreen and the rest
53
+ enableScreens(); // use them
54
+ ```
55
+
56
+ Two calls rather than one, and that is the point of them. An earlier revision of
57
+ that pull request reused `enableScreens()` for both, and the review was right to
58
+ refuse it: applications call it unconditionally, and on a platform with no native
59
+ screens it has always meant "use them where they exist" and kept the fallback.
60
+ Reusing it would have made react-native-macos, which has no implementation there
61
+ either, mount components that are not registered.
62
+
63
+ ## The one wart
64
+
65
+ The screen component is taken from `react-native-screens/src/fabric/`, which
66
+ is a path inside the library rather than part of its public API, so a release
67
+ that moves it would break this. Declaring the component here instead was tried
68
+ and is worse: it needs React Native's base view config, and requiring that
69
+ pulled this package into a module cycle where react-native-screens came back
70
+ `undefined` and the application died on a property of undefined. A path that
71
+ can break loudly on upgrade beat a cycle that breaks confusingly at runtime.
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Native screens for react-navigation, on a desktop.
3
+ *
4
+ * ## What this is for
5
+ *
6
+ * react-navigation's native stack renders every screen it has pushed and
7
+ * leaves it to the platform to show the top one. Basalt implements the
8
+ * components that do that, `RNSScreen` and `RNSScreenStack`, and on Windows
9
+ * they are used: `Platform.OS` is `windows`, which react-native-screens has on
10
+ * its own list of platforms it ships native code for.
11
+ *
12
+ * `macos` and `linux` are not on that list, and cannot be, because
13
+ * react-native-macos reports `macos` too and the library has no macOS
14
+ * implementation behind it. So on those two the library renders plain views
15
+ * instead, every pushed screen stays mounted, and a screen reader can reach the
16
+ * one behind the one you are on.
17
+ *
18
+ * ## Why this is not a patch
19
+ *
20
+ * The gate lives inside `InnerScreen`, and `ScreenContext` is the library's own
21
+ * way of replacing that component:
22
+ *
23
+ * const ScreenWrapper = React.useContext(ScreenContext) || InnerScreen;
24
+ *
25
+ * So a provider is enough. Nothing here forks the library, pins a version of
26
+ * it, or rewrites anything in `node_modules`; it uses a public extension point
27
+ * and goes out of the way the moment it is not wrapped around anything.
28
+ *
29
+ * `ScreenStack` needs nothing: it is not gated and renders its native
30
+ * component everywhere already. Only the screens inside it were missing.
31
+ *
32
+ * ## When this stops being necessary
33
+ *
34
+ * software-mansion/react-native-screens#4779 proposes letting a platform that
35
+ * supplies the components say so, with `provideNativeScreens()`. If that lands,
36
+ * this package becomes two calls in an application instead, and the provider can
37
+ * go:
38
+ *
39
+ * provideNativeScreens(); // basalt registers RNSScreen and the rest
40
+ * enableScreens(); // use them
41
+ *
42
+ * It was `enableScreens()` alone in an earlier revision of that pull request, and
43
+ * the review was right to refuse it: that call is unconditional in most
44
+ * applications and on a platform without native screens it has always meant "use
45
+ * them where they exist". Overloading it would have made react-native-macos,
46
+ * which has no implementation there either, start mounting components that are
47
+ * not registered.
48
+ *
49
+ * @format
50
+ */
51
+ import * as React from 'react';
52
+ type ScreenProps = {
53
+ active?: number;
54
+ activityState?: number;
55
+ stackPresentation?: string;
56
+ style?: unknown;
57
+ children?: React.ReactNode;
58
+ [key: string]: unknown;
59
+ };
60
+ /**
61
+ * A screen, rendered natively, skipping the platform check in `InnerScreen`.
62
+ *
63
+ * `activityState` is derived from `active` the way the library derives it, for
64
+ * the older callers that still send the boolean. Everything else is passed
65
+ * through: the props a desktop does not have, the iOS sheet detents and the
66
+ * rest, are filtered out by the view config above rather than here, so this
67
+ * does not have to know which ones those are.
68
+ */
69
+ declare const NativeScreen: React.ForwardRefExoticComponent<Omit<ScreenProps, "ref"> & React.RefAttributes<unknown>>;
70
+ /**
71
+ * Wrap a navigator in this to get native screens on every desktop.
72
+ *
73
+ * <NavigationScreens>
74
+ * <NavigationContainer>{...}</NavigationContainer>
75
+ * </NavigationScreens>
76
+ *
77
+ * Harmless on Windows, where the library already renders the same components,
78
+ * and harmless on iOS and Android for the same reason. An application that
79
+ * renders this on web would be asking for components the web build does not
80
+ * have, which is the one place not to put it.
81
+ */
82
+ export declare function NavigationScreens({ children }: {
83
+ children?: React.ReactNode;
84
+ }): import("react/jsx-runtime").JSX.Element;
85
+ /** The screen component itself, for an application wiring its own provider. */
86
+ export { NativeScreen };
87
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B,KAAK,WAAW,GAAG;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;;;;;;GAQG;AACH,QAAA,MAAM,YAAY,0FASjB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,EAAC,QAAQ,EAAC,EAAE;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAAC,2CAkBzE;AAED,+EAA+E;AAC/E,OAAO,EAAC,YAAY,EAAC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NativeScreen = void 0;
37
+ exports.NavigationScreens = NavigationScreens;
38
+ const jsx_runtime_1 = require("react/jsx-runtime");
39
+ /**
40
+ * Native screens for react-navigation, on a desktop.
41
+ *
42
+ * ## What this is for
43
+ *
44
+ * react-navigation's native stack renders every screen it has pushed and
45
+ * leaves it to the platform to show the top one. Basalt implements the
46
+ * components that do that, `RNSScreen` and `RNSScreenStack`, and on Windows
47
+ * they are used: `Platform.OS` is `windows`, which react-native-screens has on
48
+ * its own list of platforms it ships native code for.
49
+ *
50
+ * `macos` and `linux` are not on that list, and cannot be, because
51
+ * react-native-macos reports `macos` too and the library has no macOS
52
+ * implementation behind it. So on those two the library renders plain views
53
+ * instead, every pushed screen stays mounted, and a screen reader can reach the
54
+ * one behind the one you are on.
55
+ *
56
+ * ## Why this is not a patch
57
+ *
58
+ * The gate lives inside `InnerScreen`, and `ScreenContext` is the library's own
59
+ * way of replacing that component:
60
+ *
61
+ * const ScreenWrapper = React.useContext(ScreenContext) || InnerScreen;
62
+ *
63
+ * So a provider is enough. Nothing here forks the library, pins a version of
64
+ * it, or rewrites anything in `node_modules`; it uses a public extension point
65
+ * and goes out of the way the moment it is not wrapped around anything.
66
+ *
67
+ * `ScreenStack` needs nothing: it is not gated and renders its native
68
+ * component everywhere already. Only the screens inside it were missing.
69
+ *
70
+ * ## When this stops being necessary
71
+ *
72
+ * software-mansion/react-native-screens#4779 proposes letting a platform that
73
+ * supplies the components say so, with `provideNativeScreens()`. If that lands,
74
+ * this package becomes two calls in an application instead, and the provider can
75
+ * go:
76
+ *
77
+ * provideNativeScreens(); // basalt registers RNSScreen and the rest
78
+ * enableScreens(); // use them
79
+ *
80
+ * It was `enableScreens()` alone in an earlier revision of that pull request, and
81
+ * the review was right to refuse it: that call is unconditional in most
82
+ * applications and on a platform without native screens it has always meant "use
83
+ * them where they exist". Overloading it would have made react-native-macos,
84
+ * which has no implementation there either, start mounting components that are
85
+ * not registered.
86
+ *
87
+ * @format
88
+ */
89
+ const React = __importStar(require("react"));
90
+ /**
91
+ * `RNSScreen`, taken from the library rather than declared here.
92
+ *
93
+ * Declaring it needs a base view config, and reaching React Native's through
94
+ * `require` pulled this package into a module cycle: with both this and
95
+ * react-native-screens in one graph, whichever was mid-initialisation came
96
+ * back `undefined`, and the app died on a property of undefined rather than on
97
+ * anything that named the cause.
98
+ *
99
+ * So the component comes from the library that already registered it. It is a
100
+ * path into its `src/`, which is a dependency on a layout that is not ours and
101
+ * is the reason this package pins a minimum version rather than a range.
102
+ */
103
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
104
+ const RNSScreen = require('react-native-screens/src/fabric/ScreenNativeComponent')
105
+ .default;
106
+ /**
107
+ * A screen, rendered natively, skipping the platform check in `InnerScreen`.
108
+ *
109
+ * `activityState` is derived from `active` the way the library derives it, for
110
+ * the older callers that still send the boolean. Everything else is passed
111
+ * through: the props a desktop does not have, the iOS sheet detents and the
112
+ * rest, are filtered out by the view config above rather than here, so this
113
+ * does not have to know which ones those are.
114
+ */
115
+ const NativeScreen = React.forwardRef(function NativeScreen({ active, activityState, children, ...rest }, ref) {
116
+ const state = activityState ?? (active !== 0 ? 2 : 0);
117
+ return ((0, jsx_runtime_1.jsx)(RNSScreen, { ref: ref, activityState: state, ...rest, children: children }));
118
+ });
119
+ exports.NativeScreen = NativeScreen;
120
+ /**
121
+ * Wrap a navigator in this to get native screens on every desktop.
122
+ *
123
+ * <NavigationScreens>
124
+ * <NavigationContainer>{...}</NavigationContainer>
125
+ * </NavigationScreens>
126
+ *
127
+ * Harmless on Windows, where the library already renders the same components,
128
+ * and harmless on iOS and Android for the same reason. An application that
129
+ * renders this on web would be asking for components the web build does not
130
+ * have, which is the one place not to put it.
131
+ */
132
+ function NavigationScreens({ children }) {
133
+ // Resolved at render rather than at import.
134
+ //
135
+ // At module scope this came back undefined, and the app died on
136
+ // "Cannot read property 'ScreenContext' of undefined". Which import in the
137
+ // cycle is unfinished depends on the order the application happens to import
138
+ // things in, and that is not a thing a library should be sensitive to. The
139
+ // context is not needed until something renders, so it is not asked for
140
+ // until then.
141
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
142
+ const { ScreenContext } = require('react-native-screens');
143
+ return ((0, jsx_runtime_1.jsx)(ScreenContext.Provider, { value: NativeScreen, children: children }));
144
+ }
145
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+GA,8CAkBC;;AAjID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,6CAA+B;AAE/B;;;;;;;;;;;;GAYG;AACH,8DAA8D;AAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,uDAAuD,CAAC;KAC/E,OAAuD,CAAC;AAW3D;;;;;;;;GAQG;AACH,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CACnC,SAAS,YAAY,CAAC,EAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAC,EAAE,GAAG;IACnE,MAAM,KAAK,GAAG,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,OAAO,CACL,uBAAC,SAAS,IAAC,GAAG,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,KAAM,IAAI,YAChD,QAAQ,GACC,CACb,CAAC;AACJ,CAAC,CACF,CAAC;AAmCM,oCAAY;AAjCpB;;;;;;;;;;;GAWG;AACH,SAAgB,iBAAiB,CAAC,EAAC,QAAQ,EAA+B;IACxE,4CAA4C;IAC5C,EAAE;IACF,gEAAgE;IAChE,2EAA2E;IAC3E,6EAA6E;IAC7E,2EAA2E;IAC3E,wEAAwE;IACxE,cAAc;IACd,8DAA8D;IAC9D,MAAM,EAAC,aAAa,EAAC,GAAG,OAAO,CAAC,sBAAsB,CAErD,CAAC;IACF,OAAO,CACL,uBAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAqB,YACjD,QAAQ,GACc,CAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ {"root":["../index.tsx","../react-native-screens.d.ts"],"version":"6.0.3"}
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "basalt-navigation",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Native screens for react-navigation on the desktop, through react-native-screens' own ScreenContext. No patch and no fork.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/vincentvella/basalt.git",
9
+ "directory": "packages/basalt-navigation"
10
+ },
11
+ "homepage": "https://basaltjs.dev",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "exports": {
15
+ ".": "./dist/index.js",
16
+ "./package.json": "./package.json"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "LICENSE",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "../../scripts/build_ts.sh",
25
+ "prepack": "../../scripts/build_ts.sh"
26
+ },
27
+ "peerDependencies": {
28
+ "react": "*",
29
+ "react-native": "*",
30
+ "react-native-screens": ">=4"
31
+ }
32
+ }