@sigmela/router 0.2.7 → 0.2.8

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/README.md CHANGED
@@ -152,6 +152,47 @@ Key methods:
152
152
  - `addSheet(pathPattern, componentOrStack, options?)` (shorthand for `stackPresentation: 'sheet'`)
153
153
  - `addStack(prefixOrStack, maybeStack?)` — compose nested stacks under a prefix
154
154
 
155
+ #### Provider Context
156
+
157
+ You can wrap an entire stack with a React context provider by passing a `provider` option:
158
+
159
+ ```tsx
160
+ import { ThemeProvider } from './theme';
161
+
162
+ const stack = new NavigationStack({
163
+ header: { largeTitle: true },
164
+ provider: ThemeProvider,
165
+ })
166
+ .addScreen('/feed', FeedScreen)
167
+ .addScreen('/feed/:id', FeedItemScreen);
168
+ ```
169
+
170
+ The `provider` component wraps the entire stack renderer, making the context available to all screens in the stack. This is useful for:
171
+ - **Theme providers**: Apply theme context to all screens
172
+ - **Auth providers**: Share authentication state across screens
173
+ - **Localization**: Provide i18n context to the entire stack
174
+
175
+ **Composing multiple providers:**
176
+
177
+ If you need multiple providers, create a composed component:
178
+
179
+ ```tsx
180
+ const ComposedProvider = ({ children }) => (
181
+ <ThemeProvider>
182
+ <AuthProvider>
183
+ <I18nProvider>
184
+ {children}
185
+ </I18nProvider>
186
+ </AuthProvider>
187
+ </ThemeProvider>
188
+ );
189
+
190
+ const stack = new NavigationStack({ provider: ComposedProvider })
191
+ .addScreen('/', HomeScreen);
192
+ ```
193
+
194
+ **Important:** The provider should be a stable reference (not an inline arrow function) to avoid unnecessary re-renders.
195
+
155
196
  ### Modal Stacks (Stack in Stack)
156
197
 
157
198
  You can pass an entire `NavigationStack` to `addModal()` or `addSheet()` to create a multi-screen flow inside a modal:
@@ -14,10 +14,12 @@ export class NavigationStack {
14
14
  this.stackId = idOrOptions ?? `stack-${nanoid()}`;
15
15
  this.defaultOptions = maybeOptions;
16
16
  this.debugEnabled = maybeDebug ?? false;
17
+ this.provider = maybeOptions?.provider;
17
18
  } else {
18
19
  this.stackId = `stack-${nanoid()}`;
19
20
  this.defaultOptions = idOrOptions;
20
21
  this.debugEnabled = false;
22
+ this.provider = idOrOptions?.provider;
21
23
  }
22
24
  }
23
25
  log(message, data) {
@@ -135,11 +137,16 @@ export class NavigationStack {
135
137
  // eslint-disable-next-line consistent-this
136
138
  const stackInstance = this;
137
139
  const stackId = stackInstance.getId();
140
+ const provider = this.provider;
138
141
  return function NavigationStackRenderer(props) {
139
- return /*#__PURE__*/React.createElement(StackRenderer, {
142
+ const stackElement = /*#__PURE__*/React.createElement(StackRenderer, {
140
143
  stackId: stackId,
141
144
  appearance: props.appearance
142
145
  });
146
+ if (provider) {
147
+ return /*#__PURE__*/React.createElement(provider, null, stackElement);
148
+ }
149
+ return stackElement;
143
150
  };
144
151
  }
145
152
  seed() {
@@ -72,38 +72,24 @@
72
72
 
73
73
  /* Overlay on enter — fade in via transition */
74
74
  .screen-stack-item.modal.transition-entering > .stack-modal-overlay,
75
- .screen-stack-item.modal.phase-active.transition-preEnter > .stack-modal-overlay,
76
75
  .screen-stack-item.modal-right.transition-entering > .stack-modal-overlay,
77
- .screen-stack-item.modal-right.phase-active.transition-preEnter > .stack-modal-overlay,
78
76
  .screen-stack-item.contained-modal.transition-entering > .stack-modal-overlay,
79
- .screen-stack-item.contained-modal.phase-active.transition-preEnter > .stack-modal-overlay,
80
77
  .screen-stack-item.fullscreen-modal.transition-entering > .stack-modal-overlay,
81
- .screen-stack-item.fullscreen-modal.phase-active.transition-preEnter > .stack-modal-overlay,
82
78
  .screen-stack-item.formsheet.transition-entering > .stack-modal-overlay,
83
- .screen-stack-item.formsheet.phase-active.transition-preEnter > .stack-modal-overlay,
84
79
  .screen-stack-item.pagesheet.transition-entering > .stack-modal-overlay,
85
- .screen-stack-item.pagesheet.phase-active.transition-preEnter > .stack-modal-overlay,
86
- .screen-stack-item.sheet.transition-entering > .stack-modal-overlay,
87
- .screen-stack-item.sheet.phase-active.transition-preEnter > .stack-modal-overlay {
80
+ .screen-stack-item.sheet.transition-entering > .stack-modal-overlay {
88
81
  background: rgba(0, 0, 0, 0.5);
89
82
  pointer-events: none;
90
83
  opacity: 0.5;
91
84
  }
92
85
 
93
86
  /* For modal-like in active / entered states — fully visible */
94
- .screen-stack-item.modal.phase-active > .stack-modal-overlay,
95
87
  .screen-stack-item.modal.transition-entered > .stack-modal-overlay,
96
- .screen-stack-item.modal-right.phase-active > .stack-modal-overlay,
97
88
  .screen-stack-item.modal-right.transition-entered > .stack-modal-overlay,
98
- .screen-stack-item.contained-modal.phase-active > .stack-modal-overlay,
99
89
  .screen-stack-item.contained-modal.transition-entered > .stack-modal-overlay,
100
- .screen-stack-item.fullscreen-modal.phase-active > .stack-modal-overlay,
101
90
  .screen-stack-item.fullscreen-modal.transition-entered > .stack-modal-overlay,
102
- .screen-stack-item.formsheet.phase-active > .stack-modal-overlay,
103
91
  .screen-stack-item.formsheet.transition-entered > .stack-modal-overlay,
104
- .screen-stack-item.pagesheet.phase-active > .stack-modal-overlay,
105
92
  .screen-stack-item.pagesheet.transition-entered > .stack-modal-overlay,
106
- .screen-stack-item.sheet.phase-active > .stack-modal-overlay,
107
93
  .screen-stack-item.sheet.transition-entered > .stack-modal-overlay {
108
94
  opacity: 0.5;
109
95
  background: rgba(0, 0, 0, 0.5);
@@ -1,4 +1,4 @@
1
- import type { ScreenOptions } from './types';
1
+ import type { ScreenOptions, NavigationStackOptions } from './types';
2
2
  import React from 'react';
3
3
  import { type MixedComponent } from './createController';
4
4
  import type { NavigationNode, NodeRoute, NodeChild } from './navigationNode';
@@ -10,11 +10,12 @@ export declare class NavigationStack implements NavigationNode {
10
10
  private readonly children;
11
11
  private readonly defaultOptions;
12
12
  private readonly debugEnabled;
13
+ private readonly provider;
13
14
  constructor();
14
15
  constructor(id: string);
15
- constructor(defaultOptions: ScreenOptions);
16
- constructor(id: string, defaultOptions: ScreenOptions);
17
- constructor(id: string, defaultOptions: ScreenOptions, debug: boolean);
16
+ constructor(defaultOptions: NavigationStackOptions);
17
+ constructor(id: string, defaultOptions: NavigationStackOptions);
18
+ constructor(id: string, defaultOptions: NavigationStackOptions, debug: boolean);
18
19
  private log;
19
20
  getId(): string;
20
21
  addScreen(pathPattern: string, mixedComponent: MixedComponent | NavigationNode, options?: ScreenOptions): NavigationStack;
@@ -43,6 +43,15 @@ export type ScreenOptions = Partial<Omit<RNSScreenProps, 'stackPresentation'>> &
43
43
  */
44
44
  maxWidth?: number;
45
45
  };
46
+ export type NavigationStackOptions = ScreenOptions & {
47
+ /**
48
+ * Optional React component to wrap the entire stack renderer.
49
+ * Useful for providing context (theme, auth, etc.) to all screens in the stack.
50
+ */
51
+ provider?: React.ComponentType<{
52
+ children: React.ReactNode;
53
+ }>;
54
+ };
46
55
  export type HistoryItem = {
47
56
  key: string;
48
57
  routeId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigmela/router",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "React Native Router",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",