@react-router-modules/runtime 1.0.0 → 2.0.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/README.md +20 -3
- package/dist/index.d.ts +91 -204
- package/dist/index.js +86 -190
- package/dist/index.js.map +1 -1
- package/package.json +10 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @react-router-modules/runtime
|
|
2
2
|
|
|
3
|
-
Application assembly layer for the
|
|
3
|
+
Application assembly layer for the modular-react framework (React Router integration). Takes modules and configuration, produces a running app with routing, slots, zones, navigation, and provider wiring.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,6 +8,14 @@ Application assembly layer for the reactive framework. Takes modules and configu
|
|
|
8
8
|
npm install @react-router-modules/runtime
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## What's included
|
|
12
|
+
|
|
13
|
+
- **Registry**: `createRegistry` — assembles modules into a running app
|
|
14
|
+
- **Zones**: `useZones` (reads zone components from matched route `handle`), `useActiveZones` (merges route zones with active module zones)
|
|
15
|
+
- **Types**: `ModuleRegistry`, `ResolveOptions`, `RegistryConfig`, `ApplicationManifest`
|
|
16
|
+
- **Re-exported from `@modular-react/core`**: `buildSlotsManifest`, `collectDynamicSlotFactories`, `evaluateDynamicSlots`, `buildNavigationManifest`, `validateNoDuplicateIds`, `validateDependencies`, `NavigationGroup`, `NavigationManifest`, `ModuleEntry`, `DynamicSlotFactory`, `SlotFilter`
|
|
17
|
+
- **Re-exported from `@modular-react/react`**: `useNavigation`, `useSlots`, `useRecalculateSlots`, `useModules`, `getModuleMeta`, `ModuleErrorBoundary`, `NavigationContext`, `SlotsContext`, `RecalculateSlotsContext`, `ModulesContext`, `DynamicSlotsProvider`, `createSlotsSignal`
|
|
18
|
+
|
|
11
19
|
## Usage
|
|
12
20
|
|
|
13
21
|
```typescript
|
|
@@ -22,10 +30,19 @@ const registry = createRegistry<AppDependencies, AppSlots>({
|
|
|
22
30
|
|
|
23
31
|
registry.register(billingModule);
|
|
24
32
|
|
|
25
|
-
const { App } = registry.resolve({
|
|
33
|
+
const { App, recalculateSlots } = registry.resolve({
|
|
26
34
|
rootComponent: Layout,
|
|
27
35
|
indexComponent: HomePage,
|
|
28
36
|
});
|
|
37
|
+
|
|
38
|
+
// Re-evaluate dynamic slots after auth state changes
|
|
39
|
+
authStore.subscribe((state, prev) => {
|
|
40
|
+
if (state.isAuthenticated !== prev.isAuthenticated) {
|
|
41
|
+
recalculateSlots();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
29
44
|
```
|
|
30
45
|
|
|
31
|
-
|
|
46
|
+
Modules can contribute conditional slot entries via `dynamicSlots` and trigger re-evaluation from components via `useRecalculateSlots()`. The shell can apply cross-cutting filters via `slotFilter` on `resolve()`.
|
|
47
|
+
|
|
48
|
+
See the [main documentation](https://github.com/kibertoad/modular-react#readme) for the full guide.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,124 +1,106 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { buildNavigationManifest } from '@modular-react/core';
|
|
2
|
+
import { buildSlotsManifest } from '@modular-react/core';
|
|
3
|
+
import { collectDynamicSlotFactories } from '@modular-react/core';
|
|
4
|
+
import { createSlotsSignal } from '@modular-react/react';
|
|
3
5
|
import { DataRouter } from 'react-router';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
6
|
+
import { DynamicSlotFactory } from '@modular-react/core';
|
|
7
|
+
import { DynamicSlotsProvider } from '@modular-react/react';
|
|
8
|
+
import { evaluateDynamicSlots } from '@modular-react/core';
|
|
9
|
+
import { getModuleMeta } from '@modular-react/react';
|
|
7
10
|
import { LazyModuleDescriptor } from '@react-router-modules/core';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
11
|
+
import { ModuleDescriptor } from '@react-router-modules/core';
|
|
12
|
+
import { ModuleEntry } from '@modular-react/core';
|
|
13
|
+
import { ModuleErrorBoundary } from '@modular-react/react';
|
|
14
|
+
import { ModulesContext } from '@modular-react/react';
|
|
15
|
+
import { NavigationContext } from '@modular-react/react';
|
|
16
|
+
import { NavigationGroup } from '@modular-react/core';
|
|
17
|
+
import { NavigationManifest } from '@modular-react/core';
|
|
18
|
+
import { ReactiveService } from '@modular-react/core';
|
|
19
|
+
import { RecalculateSlotsContext } from '@modular-react/react';
|
|
14
20
|
import { RouteObject } from 'react-router';
|
|
21
|
+
import { SlotFilter } from '@modular-react/core';
|
|
15
22
|
import { SlotMap } from '@react-router-modules/core';
|
|
23
|
+
import { SlotMap as SlotMap_2 } from '@modular-react/core';
|
|
16
24
|
import { SlotMapOf } from '@react-router-modules/core';
|
|
25
|
+
import { SlotMapOf as SlotMapOf_2 } from '@modular-react/core';
|
|
26
|
+
import { SlotsContext } from '@modular-react/react';
|
|
27
|
+
import { SlotsSignal } from '@modular-react/react';
|
|
17
28
|
import { StoreApi } from 'zustand';
|
|
29
|
+
import { useModules } from '@modular-react/react';
|
|
30
|
+
import { useNavigation } from '@modular-react/react';
|
|
31
|
+
import { useRecalculateSlots } from '@modular-react/react';
|
|
32
|
+
import { useSlots } from '@modular-react/react';
|
|
33
|
+
import { validateDependencies } from '@modular-react/core';
|
|
34
|
+
import { validateNoDuplicateIds } from '@modular-react/core';
|
|
18
35
|
import { ZoneMapOf } from '@react-router-modules/core';
|
|
19
36
|
|
|
20
|
-
export declare interface ApplicationManifest<TSlots extends
|
|
37
|
+
export declare interface ApplicationManifest<TSlots extends SlotMapOf_2<TSlots> = SlotMap_2> {
|
|
21
38
|
/** The root React component with all providers wired */
|
|
22
39
|
readonly App: React.ComponentType;
|
|
23
40
|
/** The React Router instance — pass to <RouterProvider /> if needed */
|
|
24
41
|
readonly router: DataRouter;
|
|
25
42
|
/** Auto-generated navigation manifest from all modules */
|
|
26
43
|
readonly navigation: NavigationManifest;
|
|
27
|
-
/** Collected slot contributions from all modules */
|
|
44
|
+
/** Collected slot contributions from all modules (static base — does not include dynamic) */
|
|
28
45
|
readonly slots: TSlots;
|
|
29
46
|
/** Registered module summaries — use useModules() to access in components */
|
|
30
47
|
readonly modules: readonly ModuleEntry[];
|
|
48
|
+
/**
|
|
49
|
+
* Trigger re-evaluation of dynamic slots.
|
|
50
|
+
*
|
|
51
|
+
* Call this after a state change that affects `dynamicSlots` or `slotFilter`
|
|
52
|
+
* results — for example after login, role change, or feature flag update.
|
|
53
|
+
* Components consuming `useSlots()` will re-render with the new values.
|
|
54
|
+
*
|
|
55
|
+
* No-op when no module uses `dynamicSlots` and no `slotFilter` is configured.
|
|
56
|
+
*/
|
|
57
|
+
readonly recalculateSlots: () => void;
|
|
31
58
|
}
|
|
32
59
|
|
|
33
|
-
|
|
34
|
-
* Collects slot contributions from all registered modules.
|
|
35
|
-
* Arrays are concatenated per slot key across modules.
|
|
36
|
-
*
|
|
37
|
-
* When defaults are provided, every key in defaults is guaranteed to exist
|
|
38
|
-
* in the result — even if no module contributes to it.
|
|
39
|
-
*/
|
|
40
|
-
export declare function buildSlotsManifest<TSlots extends {
|
|
41
|
-
[K in keyof TSlots]: readonly unknown[];
|
|
42
|
-
}>(modules: readonly ReactiveModuleDescriptor<any, TSlots>[], defaults?: Partial<{
|
|
43
|
-
[K in keyof TSlots]: TSlots[K];
|
|
44
|
-
}>): TSlots;
|
|
60
|
+
export { buildNavigationManifest }
|
|
45
61
|
|
|
46
|
-
export
|
|
62
|
+
export { buildSlotsManifest }
|
|
47
63
|
|
|
48
|
-
|
|
49
|
-
* Type-safe accessor for module metadata.
|
|
50
|
-
* Use this when the shell defines a known meta shape and wants to read it
|
|
51
|
-
* without casting every field.
|
|
52
|
-
*
|
|
53
|
-
* Returns undefined if the module has no meta.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* interface JourneyMeta { name: string; category: string; icon: string }
|
|
57
|
-
* const meta = getModuleMeta<JourneyMeta>(mod)
|
|
58
|
-
* if (meta) console.log(meta.name) // typed, no cast
|
|
59
|
-
*/
|
|
60
|
-
export declare function getModuleMeta<TMeta extends {
|
|
61
|
-
[K in keyof TMeta]: unknown;
|
|
62
|
-
}>(entry: ModuleEntry): Readonly<TMeta> | undefined;
|
|
64
|
+
export { collectDynamicSlotFactories }
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
* A summary of a registered module exposed to the shell.
|
|
66
|
-
* Includes the module's identity, metadata, and optional component.
|
|
67
|
-
*/
|
|
68
|
-
export declare interface ModuleEntry {
|
|
69
|
-
/** Unique module identifier */
|
|
70
|
-
readonly id: string;
|
|
71
|
-
/** SemVer version string */
|
|
72
|
-
readonly version: string;
|
|
73
|
-
/** Catalog metadata (description, icon, category, etc.) */
|
|
74
|
-
readonly meta?: Readonly<Record<string, unknown>>;
|
|
75
|
-
/** A React component the shell can render outside of routes */
|
|
76
|
-
readonly component?: React.ComponentType<any>;
|
|
77
|
-
/** Zone components contributed when this module is active in a workspace tab */
|
|
78
|
-
readonly zones?: Readonly<Record<string, React.ComponentType<any>>>;
|
|
79
|
-
}
|
|
66
|
+
export declare function createRegistry<TSharedDependencies extends Record<string, any>, TSlots extends SlotMapOf<TSlots> = SlotMap>(config: RegistryConfig<TSharedDependencies, TSlots>): ModuleRegistry<TSharedDependencies, TSlots>;
|
|
80
67
|
|
|
81
|
-
export
|
|
82
|
-
state: State;
|
|
83
|
-
static getDerivedStateFromError(error: Error): State;
|
|
84
|
-
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
85
|
-
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | JSX.Element | null | undefined;
|
|
86
|
-
}
|
|
68
|
+
export { createSlotsSignal }
|
|
87
69
|
|
|
88
|
-
export
|
|
70
|
+
export { DynamicSlotFactory }
|
|
89
71
|
|
|
90
|
-
export
|
|
91
|
-
readonly group: string;
|
|
92
|
-
readonly items: readonly NavigationItem[];
|
|
93
|
-
}
|
|
72
|
+
export { DynamicSlotsProvider }
|
|
94
73
|
|
|
95
|
-
export
|
|
96
|
-
/** All navigation items flat */
|
|
97
|
-
readonly items: readonly NavigationItem[];
|
|
98
|
-
/** Items grouped by their group key, sorted by order within each group */
|
|
99
|
-
readonly groups: readonly NavigationGroup[];
|
|
100
|
-
/** Ungrouped items (no group key) */
|
|
101
|
-
readonly ungrouped: readonly NavigationItem[];
|
|
102
|
-
}
|
|
74
|
+
export { evaluateDynamicSlots }
|
|
103
75
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
children: ReactNode;
|
|
108
|
-
}
|
|
76
|
+
export { getModuleMeta }
|
|
77
|
+
|
|
78
|
+
export { ModuleEntry }
|
|
109
79
|
|
|
110
|
-
export
|
|
80
|
+
export { ModuleErrorBoundary }
|
|
81
|
+
|
|
82
|
+
export declare interface ModuleRegistry<TSharedDependencies extends Record<string, any>, TSlots extends SlotMapOf<TSlots> = SlotMap> {
|
|
111
83
|
/** Register an eager module */
|
|
112
|
-
register(module:
|
|
84
|
+
register(module: ModuleDescriptor<TSharedDependencies, TSlots>): void;
|
|
113
85
|
/** Register a lazily-loaded module */
|
|
114
86
|
registerLazy(descriptor: LazyModuleDescriptor<TSharedDependencies, TSlots>): void;
|
|
115
87
|
/**
|
|
116
88
|
* Resolve all modules and produce the application manifest.
|
|
117
89
|
* Validates dependencies and builds the route tree.
|
|
118
90
|
*/
|
|
119
|
-
resolve(options?: ResolveOptions): ApplicationManifest<TSlots>;
|
|
91
|
+
resolve(options?: ResolveOptions<TSharedDependencies, TSlots>): ApplicationManifest<TSlots>;
|
|
120
92
|
}
|
|
121
93
|
|
|
94
|
+
export { ModulesContext }
|
|
95
|
+
|
|
96
|
+
export { NavigationContext }
|
|
97
|
+
|
|
98
|
+
export { NavigationGroup }
|
|
99
|
+
|
|
100
|
+
export { NavigationManifest }
|
|
101
|
+
|
|
102
|
+
export { RecalculateSlotsContext }
|
|
103
|
+
|
|
122
104
|
/**
|
|
123
105
|
* Configuration for creating a registry.
|
|
124
106
|
*
|
|
@@ -127,7 +109,7 @@ export declare interface ReactiveRegistry<TSharedDependencies extends Record<str
|
|
|
127
109
|
* - **services** — plain objects (non-reactive, static references)
|
|
128
110
|
* - **reactiveServices** — external sources with subscribe/getSnapshot (reactive via useSyncExternalStore)
|
|
129
111
|
*/
|
|
130
|
-
export declare interface RegistryConfig<TSharedDependencies extends Record<string, any>, TSlots extends
|
|
112
|
+
export declare interface RegistryConfig<TSharedDependencies extends Record<string, any>, TSlots extends SlotMapOf_2<TSlots> = SlotMap_2> {
|
|
131
113
|
/** Zustand stores — state you own and mutate */
|
|
132
114
|
stores?: {
|
|
133
115
|
[K in keyof TSharedDependencies]?: StoreApi<TSharedDependencies[K]>;
|
|
@@ -150,13 +132,11 @@ export declare interface RegistryConfig<TSharedDependencies extends Record<strin
|
|
|
150
132
|
};
|
|
151
133
|
}
|
|
152
134
|
|
|
153
|
-
export declare interface ResolveOptions {
|
|
135
|
+
export declare interface ResolveOptions<TSharedDependencies extends Record<string, any> = Record<string, any>, TSlots extends SlotMapOf<TSlots> = SlotMap> {
|
|
154
136
|
/** Root layout component (renders <Outlet /> for child routes) */
|
|
155
137
|
rootComponent?: () => React.JSX.Element;
|
|
156
138
|
/**
|
|
157
139
|
* Pre-built root route — if provided, used instead of auto-creating one.
|
|
158
|
-
* Use this when you need full control over the root route config
|
|
159
|
-
* (loader, errorElement, etc.).
|
|
160
140
|
* Mutually exclusive with rootComponent/notFoundComponent/loader.
|
|
161
141
|
*/
|
|
162
142
|
rootRoute?: RouteObject;
|
|
@@ -167,11 +147,7 @@ export declare interface ResolveOptions {
|
|
|
167
147
|
/**
|
|
168
148
|
* Called before every route loads — for observability, analytics, feature flags.
|
|
169
149
|
* Runs for ALL routes including public ones like /login.
|
|
170
|
-
*
|
|
171
|
-
* Ignored if rootRoute is provided (configure loader on your root route instead).
|
|
172
|
-
*
|
|
173
|
-
* For auth guards, use `authenticatedRoute` instead — it creates a layout route
|
|
174
|
-
* boundary that only wraps protected routes.
|
|
150
|
+
* Ignored if rootRoute is provided.
|
|
175
151
|
*/
|
|
176
152
|
loader?: (args: {
|
|
177
153
|
request: Request;
|
|
@@ -179,34 +155,7 @@ export declare interface ResolveOptions {
|
|
|
179
155
|
}) => any;
|
|
180
156
|
/**
|
|
181
157
|
* Auth boundary — a pathless layout route that guards module routes and
|
|
182
|
-
* the index route. Shell routes
|
|
183
|
-
* boundary and are NOT guarded.
|
|
184
|
-
*
|
|
185
|
-
* Follows React Router's recommended layout route pattern:
|
|
186
|
-
* ```
|
|
187
|
-
* Root (loader runs for ALL routes — observability, etc.)
|
|
188
|
-
* ├── shellRoutes (public — /login, /signup)
|
|
189
|
-
* └── _authenticated (layout — auth guard)
|
|
190
|
-
* ├── / (indexComponent)
|
|
191
|
-
* └── module routes
|
|
192
|
-
* ```
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* ```ts
|
|
196
|
-
* registry.resolve({
|
|
197
|
-
* authenticatedRoute: {
|
|
198
|
-
* loader: async () => {
|
|
199
|
-
* const res = await fetch('/api/auth/session')
|
|
200
|
-
* if (!res.ok) throw redirect('/login')
|
|
201
|
-
* return null
|
|
202
|
-
* },
|
|
203
|
-
* Component: ShellLayout,
|
|
204
|
-
* },
|
|
205
|
-
* shellRoutes: () => [
|
|
206
|
-
* { path: '/login', Component: LoginPage },
|
|
207
|
-
* ],
|
|
208
|
-
* })
|
|
209
|
-
* ```
|
|
158
|
+
* the index route. Shell routes sit outside this boundary.
|
|
210
159
|
*/
|
|
211
160
|
authenticatedRoute?: {
|
|
212
161
|
/** Auth guard — throw redirect() to deny access */
|
|
@@ -217,50 +166,27 @@ export declare interface ResolveOptions {
|
|
|
217
166
|
/** Layout component for authenticated pages. Defaults to <Outlet />. */
|
|
218
167
|
Component?: () => React.JSX.Element;
|
|
219
168
|
};
|
|
220
|
-
/**
|
|
221
|
-
* Additional routes owned by the shell (login, error pages, onboarding, etc.)
|
|
222
|
-
* that sit alongside module routes at the root level.
|
|
223
|
-
*
|
|
224
|
-
* When `authenticatedRoute` is used, shell routes are NOT guarded — they
|
|
225
|
-
* are siblings of the auth layout, not children. This is the natural place
|
|
226
|
-
* for public pages like /login.
|
|
227
|
-
*/
|
|
169
|
+
/** Additional routes owned by the shell (login, error pages, etc.) */
|
|
228
170
|
shellRoutes?: () => RouteObject[];
|
|
229
171
|
/**
|
|
230
172
|
* Additional React providers to wrap around the app tree.
|
|
231
|
-
*
|
|
232
|
-
* **Nesting order:** First element is outermost. `[A, B, C]` produces:
|
|
233
|
-
* ```tsx
|
|
234
|
-
* <A>
|
|
235
|
-
* <B>
|
|
236
|
-
* <C>
|
|
237
|
-
* ...app...
|
|
238
|
-
* </C>
|
|
239
|
-
* </B>
|
|
240
|
-
* </A>
|
|
241
|
-
* ```
|
|
242
|
-
*
|
|
243
|
-
* Place providers that other providers depend on **first** in the array.
|
|
244
|
-
* For example, if your data-fetching provider reads from a theme context,
|
|
245
|
-
* list the theme provider before the data-fetching provider.
|
|
246
|
-
*
|
|
247
|
-
* @example
|
|
248
|
-
* ```ts
|
|
249
|
-
* providers: [SWRConfigProvider, ThemeProvider, TooltipProvider]
|
|
250
|
-
* // Produces: <SWRConfigProvider><ThemeProvider><TooltipProvider>...app...</TooltipProvider></ThemeProvider></SWRConfigProvider>
|
|
251
|
-
* ```
|
|
173
|
+
* First element is outermost.
|
|
252
174
|
*/
|
|
253
175
|
providers?: React.ComponentType<{
|
|
254
176
|
children: React.ReactNode;
|
|
255
177
|
}>[];
|
|
178
|
+
/**
|
|
179
|
+
* Global filter applied to the fully resolved slot manifest (static + dynamic)
|
|
180
|
+
* on every `recalculateSlots()` call.
|
|
181
|
+
*/
|
|
182
|
+
slotFilter?: (slots: TSlots, deps: TSharedDependencies) => TSlots;
|
|
256
183
|
}
|
|
257
184
|
|
|
258
|
-
export
|
|
185
|
+
export { SlotFilter }
|
|
259
186
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
187
|
+
export { SlotsContext }
|
|
188
|
+
|
|
189
|
+
export { SlotsSignal }
|
|
264
190
|
|
|
265
191
|
/**
|
|
266
192
|
* Read zone components from both the matched route hierarchy AND the
|
|
@@ -271,60 +197,17 @@ declare interface State {
|
|
|
271
197
|
* - **Tab-based modules** contribute zones via the `zones` field on their descriptor
|
|
272
198
|
*
|
|
273
199
|
* When both sources provide a value for the same zone key, the module's
|
|
274
|
-
* contribution wins
|
|
275
|
-
* relevant than the underlying route's.
|
|
276
|
-
*
|
|
277
|
-
* @param activeModuleId - The id of the module that is currently active in the
|
|
278
|
-
* workspace (e.g. the journey tab's moduleId). Pass `null` or `undefined`
|
|
279
|
-
* when no module tab is active — only route zones are returned.
|
|
280
|
-
*
|
|
281
|
-
* @example
|
|
282
|
-
* // In the shell layout:
|
|
283
|
-
* const activeTab = getActiveTab(interactionId)
|
|
284
|
-
* const moduleId = activeTab?.type === 'native-journey' ? activeTab.journeyId : null
|
|
285
|
-
* const zones = useActiveZones<AppZones>(moduleId)
|
|
286
|
-
* const Panel = zones.contextualPanel
|
|
287
|
-
*
|
|
288
|
-
* return (
|
|
289
|
-
* <aside>{Panel ? <Panel /> : <DefaultPanel />}</aside>
|
|
290
|
-
* )
|
|
200
|
+
* contribution wins.
|
|
291
201
|
*/
|
|
292
202
|
export declare function useActiveZones<TZones extends ZoneMapOf<TZones>>(activeModuleId?: string | null): Partial<TZones>;
|
|
293
203
|
|
|
294
|
-
|
|
295
|
-
* Access the list of registered modules with their metadata and components.
|
|
296
|
-
* Must be used within a <ReactiveApp /> provider tree.
|
|
297
|
-
*
|
|
298
|
-
* Use this to build discovery UIs (directory pages, search, catalogs)
|
|
299
|
-
* and to render module components in workspace tabs or panels.
|
|
300
|
-
*
|
|
301
|
-
* @example
|
|
302
|
-
* const modules = useModules()
|
|
303
|
-
* const journeys = modules.filter(m => m.meta?.category === 'payments')
|
|
304
|
-
*
|
|
305
|
-
* @example
|
|
306
|
-
* const mod = modules.find(m => m.id === activeTab.moduleId)
|
|
307
|
-
* if (mod?.component) return <mod.component {...props} />
|
|
308
|
-
*/
|
|
309
|
-
export declare function useModules(): readonly ModuleEntry[];
|
|
204
|
+
export { useModules }
|
|
310
205
|
|
|
311
|
-
|
|
312
|
-
* Access the auto-generated navigation manifest from registered modules.
|
|
313
|
-
* Use this in layout components to render sidebar/nav items.
|
|
314
|
-
*/
|
|
315
|
-
export declare function useNavigation(): NavigationManifest;
|
|
206
|
+
export { useNavigation }
|
|
316
207
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
*
|
|
321
|
-
* @example
|
|
322
|
-
* const slots = useSlots<AppSlots>()
|
|
323
|
-
* const commands = slots.commands // CommandDefinition[] from all modules
|
|
324
|
-
*/
|
|
325
|
-
export declare function useSlots<TSlots extends {
|
|
326
|
-
[K in keyof TSlots]: readonly unknown[];
|
|
327
|
-
}>(): TSlots;
|
|
208
|
+
export { useRecalculateSlots }
|
|
209
|
+
|
|
210
|
+
export { useSlots }
|
|
328
211
|
|
|
329
212
|
/**
|
|
330
213
|
* Read zone components contributed by the currently matched route hierarchy.
|
|
@@ -357,4 +240,8 @@ export declare function useSlots<TSlots extends {
|
|
|
357
240
|
*/
|
|
358
241
|
export declare function useZones<TZones extends ZoneMapOf<TZones>>(): Partial<TZones>;
|
|
359
242
|
|
|
243
|
+
export { validateDependencies }
|
|
244
|
+
|
|
245
|
+
export { validateNoDuplicateIds }
|
|
246
|
+
|
|
360
247
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,64 +1,11 @@
|
|
|
1
1
|
import { Outlet as e, RouterProvider as t, createBrowserRouter as n, createMemoryRouter as r, useMatches as i, useRoutes as a } from "react-router";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let n = /* @__PURE__ */ new Set();
|
|
8
|
-
for (let t of e) {
|
|
9
|
-
if (n.has(t.id)) throw Error(`[@react-router-modules/runtime] Duplicate module ID "${t.id}". Each module must have a unique ID.`);
|
|
10
|
-
n.add(t.id);
|
|
11
|
-
}
|
|
12
|
-
for (let e of t) {
|
|
13
|
-
if (n.has(e.id)) throw Error(`[@react-router-modules/runtime] Duplicate module ID "${e.id}". Each module must have a unique ID.`);
|
|
14
|
-
n.add(e.id);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function m(e, t) {
|
|
18
|
-
for (let n of e) {
|
|
19
|
-
if (n.requires) {
|
|
20
|
-
let e = n.requires.filter((e) => !t.has(e));
|
|
21
|
-
if (e.length > 0) throw Error(`[@react-router-modules/runtime] Module "${n.id}" requires dependencies not provided by the registry: ${e.map(String).join(", ")}. Available: ${[...t].join(", ") || "(none)"}`);
|
|
22
|
-
}
|
|
23
|
-
if (n.optionalRequires) {
|
|
24
|
-
let e = n.optionalRequires.filter((e) => !t.has(e));
|
|
25
|
-
e.length > 0 && console.warn(`[@react-router-modules/runtime] Module "${n.id}" has optional dependencies not provided: ${e.map(String).join(", ")}. The module will still load but may have reduced functionality.`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/navigation.ts
|
|
31
|
-
function h(e) {
|
|
32
|
-
let t = [];
|
|
33
|
-
for (let n of e) n.navigation && t.push(...n.navigation);
|
|
34
|
-
let n = [...t].sort((e, t) => {
|
|
35
|
-
let n = (e.order ?? 999) - (t.order ?? 999);
|
|
36
|
-
return n === 0 ? e.label.localeCompare(t.label) : n;
|
|
37
|
-
}), r = /* @__PURE__ */ new Map(), i = [];
|
|
38
|
-
for (let e of n) if (e.group) {
|
|
39
|
-
let t = r.get(e.group);
|
|
40
|
-
t || (t = [], r.set(e.group, t)), t.push(e);
|
|
41
|
-
} else i.push(e);
|
|
42
|
-
return {
|
|
43
|
-
items: n,
|
|
44
|
-
groups: [...r.entries()].map(([e, t]) => ({
|
|
45
|
-
group: e,
|
|
46
|
-
items: t
|
|
47
|
-
})),
|
|
48
|
-
ungrouped: i
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
//#endregion
|
|
52
|
-
//#region src/slots.ts
|
|
53
|
-
function g(e, t) {
|
|
54
|
-
let n = {};
|
|
55
|
-
if (t) for (let [e, r] of Object.entries(t)) n[e] = Array.isArray(r) ? [...r] : [];
|
|
56
|
-
for (let t of e) if (t.slots) for (let [e, r] of Object.entries(t.slots)) n[e] || (n[e] = []), Array.isArray(r) && n[e].push(...r);
|
|
57
|
-
return n;
|
|
58
|
-
}
|
|
59
|
-
//#endregion
|
|
2
|
+
import { buildNavigationManifest as o, buildNavigationManifest as s, buildSlotsManifest as c, buildSlotsManifest as l, collectDynamicSlotFactories as u, collectDynamicSlotFactories as d, evaluateDynamicSlots as f, validateDependencies as p, validateDependencies as m, validateNoDuplicateIds as h, validateNoDuplicateIds as g } from "@modular-react/core";
|
|
3
|
+
import { DynamicSlotsProvider as _, DynamicSlotsProvider as v, ModuleErrorBoundary as y, ModulesContext as b, ModulesContext as x, NavigationContext as S, NavigationContext as C, RecalculateSlotsContext as w, RecalculateSlotsContext as T, SlotsContext as E, SlotsContext as D, createSlotsSignal as O, createSlotsSignal as k, getModuleMeta as A, useModules as j, useModules as M, useNavigation as N, useRecalculateSlots as P, useSlots as F } from "@modular-react/react";
|
|
4
|
+
import { jsx as I } from "react/jsx-runtime";
|
|
5
|
+
import { useMemo as L } from "react";
|
|
6
|
+
import { SharedDependenciesContext as R } from "@react-router-modules/core";
|
|
60
7
|
//#region src/route-builder.tsx
|
|
61
|
-
function
|
|
8
|
+
function z(e, t, n) {
|
|
62
9
|
if (n?.rootRoute) {
|
|
63
10
|
let r = [...n.rootRoute.children ?? []];
|
|
64
11
|
n?.shellRoutes && r.push(...n.shellRoutes());
|
|
@@ -73,8 +20,8 @@ function _(e, t, n) {
|
|
|
73
20
|
if (!e) throw Error(`[@react-router-modules/runtime] Module "${t.id}" createRoutes() returned a falsy value.`);
|
|
74
21
|
i.push(...Array.isArray(e) ? e : [e]);
|
|
75
22
|
}
|
|
76
|
-
for (let e of t) i.push(
|
|
77
|
-
return n?.authenticatedRoute ? r.push(
|
|
23
|
+
for (let e of t) i.push(V(e));
|
|
24
|
+
return n?.authenticatedRoute ? r.push(B(n.authenticatedRoute, i)) : r.push(...i), n.rootRoute.children = r, [n.rootRoute];
|
|
78
25
|
}
|
|
79
26
|
let r = [];
|
|
80
27
|
n?.shellRoutes && r.push(...n.shellRoutes());
|
|
@@ -89,8 +36,8 @@ function _(e, t, n) {
|
|
|
89
36
|
if (!e) throw Error(`[@react-router-modules/runtime] Module "${t.id}" createRoutes() returned a falsy value.`);
|
|
90
37
|
i.push(...Array.isArray(e) ? e : [e]);
|
|
91
38
|
}
|
|
92
|
-
for (let e of t) i.push(
|
|
93
|
-
return n?.authenticatedRoute ? r.push(
|
|
39
|
+
for (let e of t) i.push(V(e));
|
|
40
|
+
return n?.authenticatedRoute ? r.push(B(n.authenticatedRoute, i)) : r.push(...i), n?.notFoundComponent && r.push({
|
|
94
41
|
path: "*",
|
|
95
42
|
Component: n.notFoundComponent
|
|
96
43
|
}), [{
|
|
@@ -100,15 +47,15 @@ function _(e, t, n) {
|
|
|
100
47
|
children: r
|
|
101
48
|
}];
|
|
102
49
|
}
|
|
103
|
-
function
|
|
50
|
+
function B(t, n) {
|
|
104
51
|
return {
|
|
105
52
|
id: "_authenticated",
|
|
106
|
-
Component: t.Component ?? (() => /* @__PURE__ */
|
|
53
|
+
Component: t.Component ?? (() => /* @__PURE__ */ I(e, {})),
|
|
107
54
|
loader: t.loader,
|
|
108
55
|
children: n
|
|
109
56
|
};
|
|
110
57
|
}
|
|
111
|
-
function
|
|
58
|
+
function V(e) {
|
|
112
59
|
let t = null;
|
|
113
60
|
return {
|
|
114
61
|
path: e.basePath.replace(/^\//, "") + "/*",
|
|
@@ -128,64 +75,52 @@ function y(e) {
|
|
|
128
75
|
};
|
|
129
76
|
}
|
|
130
77
|
//#endregion
|
|
131
|
-
//#region src/navigation-context.tsx
|
|
132
|
-
var b = l(null);
|
|
133
|
-
function x() {
|
|
134
|
-
let e = u(b);
|
|
135
|
-
if (!e) throw Error("[@react-router-modules/runtime] useNavigation must be used within a <ReactiveApp />.");
|
|
136
|
-
return e;
|
|
137
|
-
}
|
|
138
|
-
//#endregion
|
|
139
|
-
//#region src/slots-context.tsx
|
|
140
|
-
var S = l(null);
|
|
141
|
-
function C() {
|
|
142
|
-
let e = u(S);
|
|
143
|
-
if (!e) throw Error("[@react-router-modules/runtime] useSlots must be used within a <ReactiveApp />.");
|
|
144
|
-
return e;
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
//#region src/modules-context.ts
|
|
148
|
-
var w = l(null);
|
|
149
|
-
function T() {
|
|
150
|
-
let e = u(w);
|
|
151
|
-
if (!e) throw Error("[@react-router-modules/runtime] useModules must be used within a <ReactiveApp />.");
|
|
152
|
-
return e;
|
|
153
|
-
}
|
|
154
|
-
function E(e) {
|
|
155
|
-
return e.meta;
|
|
156
|
-
}
|
|
157
|
-
//#endregion
|
|
158
78
|
//#region src/app.tsx
|
|
159
|
-
function
|
|
160
|
-
let
|
|
79
|
+
function H({ router: e, stores: n, services: r, reactiveServices: i, navigation: a, slots: o, modules: s, providers: c, dynamicSlotFactories: l, slotFilter: u, slotsSignal: d, recalculateSlots: f }) {
|
|
80
|
+
let p = {
|
|
161
81
|
stores: n,
|
|
162
82
|
services: r,
|
|
163
83
|
reactiveServices: i
|
|
164
|
-
};
|
|
165
|
-
function
|
|
166
|
-
return
|
|
167
|
-
let
|
|
168
|
-
value:
|
|
169
|
-
children: /* @__PURE__ */
|
|
84
|
+
}, m = l.length > 0 || u != null;
|
|
85
|
+
function h() {
|
|
86
|
+
return L(() => {
|
|
87
|
+
let h = /* @__PURE__ */ I(R, {
|
|
88
|
+
value: p,
|
|
89
|
+
children: /* @__PURE__ */ I(C, {
|
|
170
90
|
value: a,
|
|
171
|
-
children: /* @__PURE__ */
|
|
172
|
-
value:
|
|
173
|
-
children: /* @__PURE__ */
|
|
174
|
-
|
|
175
|
-
|
|
91
|
+
children: /* @__PURE__ */ I(T, {
|
|
92
|
+
value: f,
|
|
93
|
+
children: m ? /* @__PURE__ */ I(v, {
|
|
94
|
+
baseSlots: o,
|
|
95
|
+
factories: l,
|
|
96
|
+
filter: u,
|
|
97
|
+
stores: n,
|
|
98
|
+
services: r,
|
|
99
|
+
reactiveServices: i,
|
|
100
|
+
signal: d,
|
|
101
|
+
children: /* @__PURE__ */ I(x, {
|
|
102
|
+
value: s,
|
|
103
|
+
children: /* @__PURE__ */ I(t, { router: e })
|
|
104
|
+
})
|
|
105
|
+
}) : /* @__PURE__ */ I(D, {
|
|
106
|
+
value: o,
|
|
107
|
+
children: /* @__PURE__ */ I(x, {
|
|
108
|
+
value: s,
|
|
109
|
+
children: /* @__PURE__ */ I(t, { router: e })
|
|
110
|
+
})
|
|
176
111
|
})
|
|
177
112
|
})
|
|
178
113
|
})
|
|
179
114
|
});
|
|
180
|
-
if (
|
|
181
|
-
return
|
|
115
|
+
if (c) for (let e of [...c].reverse()) h = /* @__PURE__ */ I(e, { children: h });
|
|
116
|
+
return h;
|
|
182
117
|
}, []);
|
|
183
118
|
}
|
|
184
|
-
return
|
|
119
|
+
return h.displayName = "ModularApp", h;
|
|
185
120
|
}
|
|
186
121
|
//#endregion
|
|
187
122
|
//#region src/registry.ts
|
|
188
|
-
function
|
|
123
|
+
function U(e) {
|
|
189
124
|
let t = [], i = [], a = !1, o = new Set([
|
|
190
125
|
...Object.keys(e.stores ?? {}),
|
|
191
126
|
...Object.keys(e.services ?? {}),
|
|
@@ -200,53 +135,59 @@ function O(e) {
|
|
|
200
135
|
if (a) throw Error("[@react-router-modules/runtime] Cannot register modules after resolve() has been called.");
|
|
201
136
|
i.push(e);
|
|
202
137
|
},
|
|
203
|
-
resolve(
|
|
138
|
+
resolve(c) {
|
|
204
139
|
if (a) throw Error("[@react-router-modules/runtime] resolve() can only be called once.");
|
|
205
|
-
a = !0,
|
|
206
|
-
let
|
|
140
|
+
a = !0, g(t, i), m(t, o);
|
|
141
|
+
let u = W(e);
|
|
207
142
|
for (let e of t) try {
|
|
208
|
-
e.lifecycle?.onRegister?.(
|
|
143
|
+
e.lifecycle?.onRegister?.(u);
|
|
209
144
|
} catch (t) {
|
|
210
145
|
throw Error(`[@react-router-modules/runtime] Module "${e.id}" lifecycle.onRegister() failed: ${t instanceof Error ? t.message : String(t)}`, { cause: t });
|
|
211
146
|
}
|
|
212
|
-
let
|
|
213
|
-
rootRoute:
|
|
214
|
-
rootComponent:
|
|
215
|
-
indexComponent:
|
|
216
|
-
notFoundComponent:
|
|
217
|
-
loader:
|
|
218
|
-
authenticatedRoute:
|
|
219
|
-
shellRoutes:
|
|
220
|
-
}),
|
|
147
|
+
let f = z(t, i, {
|
|
148
|
+
rootRoute: c?.rootRoute,
|
|
149
|
+
rootComponent: c?.rootComponent,
|
|
150
|
+
indexComponent: c?.indexComponent,
|
|
151
|
+
notFoundComponent: c?.notFoundComponent,
|
|
152
|
+
loader: c?.loader,
|
|
153
|
+
authenticatedRoute: c?.authenticatedRoute,
|
|
154
|
+
shellRoutes: c?.shellRoutes
|
|
155
|
+
}), p = typeof document < "u" ? n(f) : r(f), h = s(t), _ = l(t, e.slots), v = d(t), y = c?.slotFilter, b = t.map((e) => ({
|
|
221
156
|
id: e.id,
|
|
222
157
|
version: e.version,
|
|
223
158
|
meta: e.meta,
|
|
224
159
|
component: e.component,
|
|
225
160
|
zones: e.zones
|
|
226
|
-
})),
|
|
227
|
-
if (e.stores) for (let [t, n] of Object.entries(e.stores)) n && (
|
|
228
|
-
if (e.services) for (let [t, n] of Object.entries(e.services)) n !== void 0 && (
|
|
229
|
-
if (e.reactiveServices) for (let [t, n] of Object.entries(e.reactiveServices)) n && (
|
|
161
|
+
})), x = {}, S = {}, C = {};
|
|
162
|
+
if (e.stores) for (let [t, n] of Object.entries(e.stores)) n && (x[t] = n);
|
|
163
|
+
if (e.services) for (let [t, n] of Object.entries(e.services)) n !== void 0 && (S[t] = n);
|
|
164
|
+
if (e.reactiveServices) for (let [t, n] of Object.entries(e.reactiveServices)) n && (C[t] = n);
|
|
165
|
+
let w = k(), T = v.length > 0 || y != null ? () => w.notify() : () => {};
|
|
230
166
|
return {
|
|
231
|
-
App:
|
|
232
|
-
router:
|
|
233
|
-
stores:
|
|
234
|
-
services:
|
|
235
|
-
reactiveServices:
|
|
236
|
-
navigation:
|
|
237
|
-
slots:
|
|
238
|
-
modules:
|
|
239
|
-
providers:
|
|
167
|
+
App: H({
|
|
168
|
+
router: p,
|
|
169
|
+
stores: x,
|
|
170
|
+
services: S,
|
|
171
|
+
reactiveServices: C,
|
|
172
|
+
navigation: h,
|
|
173
|
+
slots: _,
|
|
174
|
+
modules: b,
|
|
175
|
+
providers: c?.providers,
|
|
176
|
+
dynamicSlotFactories: v,
|
|
177
|
+
slotFilter: y,
|
|
178
|
+
slotsSignal: w,
|
|
179
|
+
recalculateSlots: T
|
|
240
180
|
}),
|
|
241
|
-
router:
|
|
242
|
-
navigation:
|
|
243
|
-
slots:
|
|
244
|
-
modules:
|
|
181
|
+
router: p,
|
|
182
|
+
navigation: h,
|
|
183
|
+
slots: _,
|
|
184
|
+
modules: b,
|
|
185
|
+
recalculateSlots: T
|
|
245
186
|
};
|
|
246
187
|
}
|
|
247
188
|
};
|
|
248
189
|
}
|
|
249
|
-
function
|
|
190
|
+
function W(e) {
|
|
250
191
|
let t = {};
|
|
251
192
|
if (e.stores) for (let [n, r] of Object.entries(e.stores)) r && (t[n] = r.getState());
|
|
252
193
|
if (e.services) for (let [n, r] of Object.entries(e.services)) r !== void 0 && (t[n] = r);
|
|
@@ -255,7 +196,7 @@ function k(e) {
|
|
|
255
196
|
}
|
|
256
197
|
//#endregion
|
|
257
198
|
//#region src/zones.ts
|
|
258
|
-
function
|
|
199
|
+
function G() {
|
|
259
200
|
let e = i(), t = {};
|
|
260
201
|
for (let n of e) {
|
|
261
202
|
let e = n.handle;
|
|
@@ -265,8 +206,8 @@ function A() {
|
|
|
265
206
|
}
|
|
266
207
|
//#endregion
|
|
267
208
|
//#region src/active-zones.ts
|
|
268
|
-
function
|
|
269
|
-
let t =
|
|
209
|
+
function K(e) {
|
|
210
|
+
let t = G(), n = M();
|
|
270
211
|
if (!e) return t;
|
|
271
212
|
let r = n.find((t) => t.id === e);
|
|
272
213
|
return r?.zones ? {
|
|
@@ -275,51 +216,6 @@ function j(e) {
|
|
|
275
216
|
} : t;
|
|
276
217
|
}
|
|
277
218
|
//#endregion
|
|
278
|
-
|
|
279
|
-
var M = class extends c {
|
|
280
|
-
state = {
|
|
281
|
-
hasError: !1,
|
|
282
|
-
error: null
|
|
283
|
-
};
|
|
284
|
-
static getDerivedStateFromError(e) {
|
|
285
|
-
return {
|
|
286
|
-
hasError: !0,
|
|
287
|
-
error: e
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
componentDidCatch(e, t) {
|
|
291
|
-
console.error(`[@react-router-modules/runtime] Module "${this.props.moduleId}" encountered an error:`, e, t);
|
|
292
|
-
}
|
|
293
|
-
render() {
|
|
294
|
-
return this.state.hasError ? this.props.fallback ? this.props.fallback : /* @__PURE__ */ s("div", {
|
|
295
|
-
style: {
|
|
296
|
-
padding: "1rem",
|
|
297
|
-
border: "1px solid #e53e3e",
|
|
298
|
-
borderRadius: "0.5rem",
|
|
299
|
-
margin: "1rem"
|
|
300
|
-
},
|
|
301
|
-
children: [/* @__PURE__ */ s("h3", {
|
|
302
|
-
style: {
|
|
303
|
-
color: "#e53e3e",
|
|
304
|
-
margin: "0 0 0.5rem 0"
|
|
305
|
-
},
|
|
306
|
-
children: [
|
|
307
|
-
"Module \"",
|
|
308
|
-
this.props.moduleId,
|
|
309
|
-
"\" encountered an error"
|
|
310
|
-
]
|
|
311
|
-
}), /* @__PURE__ */ o("pre", {
|
|
312
|
-
style: {
|
|
313
|
-
fontSize: "0.875rem",
|
|
314
|
-
color: "#718096",
|
|
315
|
-
whiteSpace: "pre-wrap"
|
|
316
|
-
},
|
|
317
|
-
children: this.state.error?.message
|
|
318
|
-
})]
|
|
319
|
-
}) : this.props.children;
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
//#endregion
|
|
323
|
-
export { M as ModuleErrorBoundary, w as ModulesContext, S as SlotsContext, g as buildSlotsManifest, O as createRegistry, E as getModuleMeta, j as useActiveZones, T as useModules, x as useNavigation, C as useSlots, A as useZones };
|
|
219
|
+
export { _ as DynamicSlotsProvider, y as ModuleErrorBoundary, b as ModulesContext, S as NavigationContext, w as RecalculateSlotsContext, E as SlotsContext, o as buildNavigationManifest, c as buildSlotsManifest, u as collectDynamicSlotFactories, U as createRegistry, O as createSlotsSignal, f as evaluateDynamicSlots, A as getModuleMeta, K as useActiveZones, j as useModules, N as useNavigation, P as useRecalculateSlots, F as useSlots, G as useZones, p as validateDependencies, h as validateNoDuplicateIds };
|
|
324
220
|
|
|
325
221
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/validation.ts","../src/navigation.ts","../src/slots.ts","../src/route-builder.tsx","../src/navigation-context.tsx","../src/slots-context.tsx","../src/modules-context.ts","../src/app.tsx","../src/registry.ts","../src/zones.ts","../src/active-zones.ts","../src/error-boundary.tsx"],"sourcesContent":["import type { ReactiveModuleDescriptor, LazyModuleDescriptor } from \"@react-router-modules/core\";\r\n\r\nexport function validateNoDuplicateIds(\r\n modules: ReactiveModuleDescriptor[],\r\n lazyModules: LazyModuleDescriptor[],\r\n): void {\r\n const ids = new Set<string>();\r\n for (const mod of modules) {\r\n if (ids.has(mod.id)) {\r\n throw new Error(\r\n `[@react-router-modules/runtime] Duplicate module ID \"${mod.id}\". Each module must have a unique ID.`,\r\n );\r\n }\r\n ids.add(mod.id);\r\n }\r\n for (const mod of lazyModules) {\r\n if (ids.has(mod.id)) {\r\n throw new Error(\r\n `[@react-router-modules/runtime] Duplicate module ID \"${mod.id}\". Each module must have a unique ID.`,\r\n );\r\n }\r\n ids.add(mod.id);\r\n }\r\n}\r\n\r\nexport function validateDependencies(\r\n modules: ReactiveModuleDescriptor[],\r\n availableKeys: Set<string>,\r\n): void {\r\n for (const mod of modules) {\r\n if (mod.requires) {\r\n const missing = mod.requires.filter((key) => !availableKeys.has(key as string));\r\n if (missing.length > 0) {\r\n throw new Error(\r\n `[@react-router-modules/runtime] Module \"${mod.id}\" requires dependencies not provided by the registry: ` +\r\n `${missing.map(String).join(\", \")}. ` +\r\n `Available: ${[...availableKeys].join(\", \") || \"(none)\"}`,\r\n );\r\n }\r\n }\r\n\r\n if (mod.optionalRequires) {\r\n const missing = mod.optionalRequires.filter((key) => !availableKeys.has(key as string));\r\n if (missing.length > 0) {\r\n console.warn(\r\n `[@react-router-modules/runtime] Module \"${mod.id}\" has optional dependencies not provided: ` +\r\n `${missing.map(String).join(\", \")}. The module will still load but may have reduced functionality.`,\r\n );\r\n }\r\n }\r\n }\r\n}\r\n","import type { ReactiveModuleDescriptor, NavigationItem } from \"@react-router-modules/core\";\r\nimport type { NavigationManifest, NavigationGroup } from \"./types.js\";\r\n\r\nexport function buildNavigationManifest(modules: ReactiveModuleDescriptor[]): NavigationManifest {\r\n const allItems: NavigationItem[] = [];\r\n\r\n for (const mod of modules) {\r\n if (mod.navigation) {\r\n allItems.push(...mod.navigation);\r\n }\r\n }\r\n\r\n // Sort by order (lower first), then by label alphabetically\r\n const sorted = [...allItems].sort((a, b) => {\r\n const orderDiff = (a.order ?? 999) - (b.order ?? 999);\r\n if (orderDiff !== 0) return orderDiff;\r\n return a.label.localeCompare(b.label);\r\n });\r\n\r\n // Group items\r\n const groupMap = new Map<string, NavigationItem[]>();\r\n const ungrouped: NavigationItem[] = [];\r\n\r\n for (const item of sorted) {\r\n if (item.group) {\r\n let group = groupMap.get(item.group);\r\n if (!group) {\r\n group = [];\r\n groupMap.set(item.group, group);\r\n }\r\n group.push(item);\r\n } else {\r\n ungrouped.push(item);\r\n }\r\n }\r\n\r\n const groups: NavigationGroup[] = [...groupMap.entries()].map(([group, items]) => ({\r\n group,\r\n items,\r\n }));\r\n\r\n return { items: sorted, groups, ungrouped };\r\n}\r\n","import type { ReactiveModuleDescriptor } from \"@react-router-modules/core\";\r\n\r\n/**\r\n * Collects slot contributions from all registered modules.\r\n * Arrays are concatenated per slot key across modules.\r\n *\r\n * When defaults are provided, every key in defaults is guaranteed to exist\r\n * in the result — even if no module contributes to it.\r\n */\r\nexport function buildSlotsManifest<TSlots extends { [K in keyof TSlots]: readonly unknown[] }>(\r\n modules: readonly ReactiveModuleDescriptor<any, TSlots>[],\r\n defaults?: Partial<{ [K in keyof TSlots]: TSlots[K] }>,\r\n): TSlots {\r\n const result: Record<string, unknown[]> = {};\r\n\r\n // Initialize from defaults so every declared key exists\r\n if (defaults) {\r\n for (const [key, items] of Object.entries(defaults)) {\r\n result[key] = Array.isArray(items) ? [...items] : [];\r\n }\r\n }\r\n\r\n for (const mod of modules) {\r\n if (!mod.slots) continue;\r\n for (const [key, items] of Object.entries(mod.slots)) {\r\n if (!result[key]) result[key] = [];\r\n if (Array.isArray(items)) {\r\n result[key].push(...items);\r\n }\r\n }\r\n }\r\n\r\n return result as unknown as TSlots;\r\n}\r\n","import { Outlet, useRoutes } from \"react-router\";\r\nimport type { RouteObject } from \"react-router\";\r\nimport type { ReactiveModuleDescriptor, LazyModuleDescriptor } from \"@react-router-modules/core\";\r\n\r\nexport interface RouteBuilderOptions {\r\n /**\r\n * Pre-built root route. If provided, rootComponent/notFoundComponent/loader\r\n * are ignored — configure them directly on this route instead.\r\n */\r\n rootRoute?: RouteObject;\r\n /** Component for the root layout (renders <Outlet /> for child routes) */\r\n rootComponent?: () => React.JSX.Element;\r\n /** Component for the index route (/) */\r\n indexComponent?: () => React.JSX.Element;\r\n /** Component for the 404 / not-found route */\r\n notFoundComponent?: () => React.JSX.Element;\r\n /**\r\n * Called before every route loads — for observability, feature flags, etc.\r\n * Runs for ALL routes including public ones.\r\n * Ignored if rootRoute is provided.\r\n */\r\n loader?: (args: { request: Request; params: Record<string, string | undefined> }) => any;\r\n /**\r\n * Auth boundary — a pathless layout route that wraps module routes and\r\n * the index route. Shell routes (login, error pages) sit outside this\r\n * boundary and are NOT guarded.\r\n *\r\n * Follows React Router's recommended layout route pattern.\r\n *\r\n * When provided, the route tree becomes:\r\n * ```\r\n * Root (loader runs for ALL routes)\r\n * ├── shellRoutes (public — /login, /signup, etc.)\r\n * └── _authenticated (layout — loader guards children)\r\n * ├── / (indexComponent)\r\n * └── module routes\r\n * ```\r\n *\r\n * When omitted, all routes are direct children of root (no auth boundary).\r\n */\r\n authenticatedRoute?: {\r\n /** Auth guard — throw redirect() to deny access */\r\n loader: (args: { request: Request; params: Record<string, string | undefined> }) => any;\r\n /** Layout component for authenticated pages. Defaults to <Outlet />. */\r\n Component?: () => React.JSX.Element;\r\n };\r\n /** Additional routes owned by the shell (login, error pages, etc.) */\r\n shellRoutes?: () => RouteObject[];\r\n}\r\n\r\n/**\r\n * Composes all module route subtrees into a React Router route tree.\r\n * Modules without createRoutes are skipped (headless modules).\r\n */\r\nexport function buildRouteTree(\r\n modules: ReactiveModuleDescriptor[],\r\n lazyModules: LazyModuleDescriptor[],\r\n options?: RouteBuilderOptions,\r\n): RouteObject[] {\r\n // If a custom root route is provided, use it as the base\r\n if (options?.rootRoute) {\r\n const rootChildren: RouteObject[] = [...(options.rootRoute.children ?? [])];\r\n\r\n // Shell-owned routes (login, error pages) — always direct children of root\r\n if (options?.shellRoutes) {\r\n rootChildren.push(...options.shellRoutes());\r\n }\r\n\r\n const protectedChildren: RouteObject[] = [];\r\n\r\n // Add index route if provided\r\n if (options?.indexComponent) {\r\n protectedChildren.push({\r\n index: true,\r\n Component: options.indexComponent,\r\n });\r\n }\r\n\r\n // Eager modules\r\n for (const mod of modules) {\r\n if (!mod.createRoutes) continue;\r\n const routes = mod.createRoutes();\r\n if (!routes) {\r\n throw new Error(\r\n `[@react-router-modules/runtime] Module \"${mod.id}\" createRoutes() returned a falsy value.`,\r\n );\r\n }\r\n protectedChildren.push(...(Array.isArray(routes) ? routes : [routes]));\r\n }\r\n\r\n // Lazy modules\r\n for (const lazyMod of lazyModules) {\r\n protectedChildren.push(createLazyModuleRoute(lazyMod));\r\n }\r\n\r\n if (options?.authenticatedRoute) {\r\n rootChildren.push(\r\n createAuthenticatedLayoutRoute(options.authenticatedRoute, protectedChildren),\r\n );\r\n } else {\r\n rootChildren.push(...protectedChildren);\r\n }\r\n\r\n options.rootRoute.children = rootChildren;\r\n return [options.rootRoute];\r\n }\r\n\r\n // Build root route from options\r\n const rootChildren: RouteObject[] = [];\r\n\r\n // Shell-owned routes (login, error pages) — always direct children of root\r\n if (options?.shellRoutes) {\r\n rootChildren.push(...options.shellRoutes());\r\n }\r\n\r\n const protectedChildren: RouteObject[] = [];\r\n\r\n // Add index route if provided\r\n if (options?.indexComponent) {\r\n protectedChildren.push({\r\n index: true,\r\n Component: options.indexComponent,\r\n });\r\n }\r\n\r\n // Eager modules: call createRoutes\r\n for (const mod of modules) {\r\n if (!mod.createRoutes) continue;\r\n const routes = mod.createRoutes();\r\n if (!routes) {\r\n throw new Error(\r\n `[@react-router-modules/runtime] Module \"${mod.id}\" createRoutes() returned a falsy value.`,\r\n );\r\n }\r\n protectedChildren.push(...(Array.isArray(routes) ? routes : [routes]));\r\n }\r\n\r\n // Lazy modules\r\n for (const lazyMod of lazyModules) {\r\n protectedChildren.push(createLazyModuleRoute(lazyMod));\r\n }\r\n\r\n if (options?.authenticatedRoute) {\r\n rootChildren.push(\r\n createAuthenticatedLayoutRoute(options.authenticatedRoute, protectedChildren),\r\n );\r\n } else {\r\n rootChildren.push(...protectedChildren);\r\n }\r\n\r\n // Not-found catch-all\r\n if (options?.notFoundComponent) {\r\n rootChildren.push({\r\n path: \"*\",\r\n Component: options.notFoundComponent,\r\n });\r\n }\r\n\r\n const rootRoute: RouteObject = {\r\n path: \"/\",\r\n Component: options?.rootComponent,\r\n loader: options?.loader,\r\n children: rootChildren,\r\n };\r\n\r\n return [rootRoute];\r\n}\r\n\r\nfunction createAuthenticatedLayoutRoute(\r\n auth: NonNullable<RouteBuilderOptions[\"authenticatedRoute\"]>,\r\n children: RouteObject[],\r\n): RouteObject {\r\n return {\r\n id: \"_authenticated\",\r\n Component: auth.Component ?? (() => <Outlet />),\r\n loader: auth.loader,\r\n children,\r\n };\r\n}\r\n\r\n/**\r\n * Creates a catch-all route for a lazily-loaded module.\r\n * On first navigation, the module descriptor is loaded and its routes\r\n * are rendered as descendant routes via useRoutes().\r\n */\r\nfunction createLazyModuleRoute(lazyMod: LazyModuleDescriptor): RouteObject {\r\n // Capture the loaded routes so they're resolved only once\r\n let cachedRoutes: RouteObject[] | null = null;\r\n\r\n return {\r\n path: lazyMod.basePath.replace(/^\\//, \"\") + \"/*\",\r\n lazy: async () => {\r\n if (!cachedRoutes) {\r\n const { default: descriptor } = await lazyMod.load();\r\n if (descriptor.createRoutes) {\r\n const routes = descriptor.createRoutes();\r\n cachedRoutes = Array.isArray(routes) ? routes : [routes];\r\n } else {\r\n cachedRoutes = [];\r\n }\r\n }\r\n const routes = cachedRoutes;\r\n return {\r\n Component: function LazyModule() {\r\n return useRoutes(routes);\r\n },\r\n };\r\n },\r\n };\r\n}\r\n","import { createContext, useContext } from \"react\";\r\nimport type { NavigationManifest } from \"./types.js\";\r\n\r\nexport const NavigationContext = createContext<NavigationManifest | null>(null);\r\n\r\n/**\r\n * Access the auto-generated navigation manifest from registered modules.\r\n * Use this in layout components to render sidebar/nav items.\r\n */\r\nexport function useNavigation(): NavigationManifest {\r\n const nav = useContext(NavigationContext);\r\n if (!nav) {\r\n throw new Error(\r\n \"[@react-router-modules/runtime] useNavigation must be used within a <ReactiveApp />.\",\r\n );\r\n }\r\n return nav;\r\n}\r\n","import { createContext, useContext } from \"react\";\r\n\r\nexport const SlotsContext = createContext<object | null>(null);\r\n\r\n/**\r\n * Access the collected slot contributions from all registered modules.\r\n * Must be used within a <ReactiveApp /> provider tree.\r\n *\r\n * @example\r\n * const slots = useSlots<AppSlots>()\r\n * const commands = slots.commands // CommandDefinition[] from all modules\r\n */\r\nexport function useSlots<TSlots extends { [K in keyof TSlots]: readonly unknown[] }>(): TSlots {\r\n const slots = useContext(SlotsContext);\r\n if (!slots) {\r\n throw new Error(\r\n \"[@react-router-modules/runtime] useSlots must be used within a <ReactiveApp />.\",\r\n );\r\n }\r\n return slots as TSlots;\r\n}\r\n","import { createContext, useContext } from \"react\";\r\nimport type { ModuleEntry } from \"./types.js\";\r\n\r\nexport const ModulesContext = createContext<readonly ModuleEntry[] | null>(null);\r\n\r\n/**\r\n * Access the list of registered modules with their metadata and components.\r\n * Must be used within a <ReactiveApp /> provider tree.\r\n *\r\n * Use this to build discovery UIs (directory pages, search, catalogs)\r\n * and to render module components in workspace tabs or panels.\r\n *\r\n * @example\r\n * const modules = useModules()\r\n * const journeys = modules.filter(m => m.meta?.category === 'payments')\r\n *\r\n * @example\r\n * const mod = modules.find(m => m.id === activeTab.moduleId)\r\n * if (mod?.component) return <mod.component {...props} />\r\n */\r\nexport function useModules(): readonly ModuleEntry[] {\r\n const modules = useContext(ModulesContext);\r\n if (!modules) {\r\n throw new Error(\r\n \"[@react-router-modules/runtime] useModules must be used within a <ReactiveApp />.\",\r\n );\r\n }\r\n return modules;\r\n}\r\n\r\n/**\r\n * Type-safe accessor for module metadata.\r\n * Use this when the shell defines a known meta shape and wants to read it\r\n * without casting every field.\r\n *\r\n * Returns undefined if the module has no meta.\r\n *\r\n * @example\r\n * interface JourneyMeta { name: string; category: string; icon: string }\r\n * const meta = getModuleMeta<JourneyMeta>(mod)\r\n * if (meta) console.log(meta.name) // typed, no cast\r\n */\r\nexport function getModuleMeta<TMeta extends { [K in keyof TMeta]: unknown }>(\r\n entry: ModuleEntry,\r\n): Readonly<TMeta> | undefined {\r\n return entry.meta as Readonly<TMeta> | undefined;\r\n}\r\n","import { useMemo } from \"react\";\r\nimport { RouterProvider } from \"react-router\";\r\nimport type { DataRouter } from \"react-router\";\r\nimport type { StoreApi } from \"zustand\";\r\nimport type { ReactiveService } from \"@react-router-modules/core\";\r\nimport { SharedDependenciesContext } from \"@react-router-modules/core\";\r\nimport { NavigationContext } from \"./navigation-context.js\";\r\nimport { SlotsContext } from \"./slots-context.js\";\r\nimport { ModulesContext } from \"./modules-context.js\";\r\nimport type { NavigationManifest, ModuleEntry } from \"./types.js\";\r\n\r\ninterface AppProps {\r\n router: DataRouter;\r\n stores: Record<string, StoreApi<unknown>>;\r\n services: Record<string, unknown>;\r\n reactiveServices: Record<string, ReactiveService<unknown>>;\r\n navigation: NavigationManifest;\r\n slots: object;\r\n modules: readonly ModuleEntry[];\r\n providers?: React.ComponentType<{ children: React.ReactNode }>[];\r\n}\r\n\r\nexport function createAppComponent({\r\n router,\r\n stores,\r\n services,\r\n reactiveServices,\r\n navigation,\r\n slots,\r\n modules,\r\n providers,\r\n}: AppProps) {\r\n // All values captured in closure are stable references created once at resolve() time.\r\n // Wrap in a stable object so context consumers don't re-render on parent renders.\r\n const depsValue = { stores, services, reactiveServices };\r\n\r\n function App() {\r\n const tree = useMemo(() => {\r\n let node: React.ReactNode = (\r\n <SharedDependenciesContext value={depsValue}>\r\n <NavigationContext value={navigation}>\r\n <SlotsContext value={slots}>\r\n <ModulesContext value={modules}>\r\n <RouterProvider router={router} />\r\n </ModulesContext>\r\n </SlotsContext>\r\n </NavigationContext>\r\n </SharedDependenciesContext>\r\n );\r\n\r\n // Wrap with user-supplied providers (first element = outermost wrapper)\r\n if (providers) {\r\n for (const Provider of [...providers].reverse()) {\r\n node = <Provider>{node}</Provider>;\r\n }\r\n }\r\n\r\n return node;\r\n }, []);\r\n\r\n return tree;\r\n }\r\n\r\n App.displayName = \"ReactiveApp\";\r\n return App;\r\n}\r\n","import { createBrowserRouter, createMemoryRouter } from \"react-router\";\r\nimport type { RouteObject } from \"react-router\";\r\nimport type { StoreApi } from \"zustand\";\r\nimport type {\r\n ReactiveModuleDescriptor,\r\n LazyModuleDescriptor,\r\n ReactiveService,\r\n SlotMap,\r\n SlotMapOf,\r\n} from \"@react-router-modules/core\";\r\n\r\nimport type {\r\n RegistryConfig,\r\n ApplicationManifest,\r\n NavigationManifest,\r\n ModuleEntry,\r\n} from \"./types.js\";\r\nimport { validateNoDuplicateIds, validateDependencies } from \"./validation.js\";\r\nimport { buildNavigationManifest } from \"./navigation.js\";\r\nimport { buildSlotsManifest } from \"./slots.js\";\r\nimport { buildRouteTree, type RouteBuilderOptions } from \"./route-builder.js\";\r\nimport { createAppComponent } from \"./app.js\";\r\n\r\nexport interface ReactiveRegistry<\r\n TSharedDependencies extends Record<string, any>,\r\n TSlots extends SlotMapOf<TSlots> = SlotMap,\r\n> {\r\n /** Register an eager module */\r\n register(module: ReactiveModuleDescriptor<TSharedDependencies, TSlots>): void;\r\n\r\n /** Register a lazily-loaded module */\r\n registerLazy(descriptor: LazyModuleDescriptor<TSharedDependencies, TSlots>): void;\r\n\r\n /**\r\n * Resolve all modules and produce the application manifest.\r\n * Validates dependencies and builds the route tree.\r\n */\r\n resolve(options?: ResolveOptions): ApplicationManifest<TSlots>;\r\n}\r\n\r\nexport interface ResolveOptions {\r\n /** Root layout component (renders <Outlet /> for child routes) */\r\n rootComponent?: () => React.JSX.Element;\r\n\r\n /**\r\n * Pre-built root route — if provided, used instead of auto-creating one.\r\n * Use this when you need full control over the root route config\r\n * (loader, errorElement, etc.).\r\n * Mutually exclusive with rootComponent/notFoundComponent/loader.\r\n */\r\n rootRoute?: RouteObject;\r\n\r\n /** Component for the index route (/) */\r\n indexComponent?: () => React.JSX.Element;\r\n\r\n /** Component for 404 / not-found */\r\n notFoundComponent?: () => React.JSX.Element;\r\n\r\n /**\r\n * Called before every route loads — for observability, analytics, feature flags.\r\n * Runs for ALL routes including public ones like /login.\r\n * Throw a `redirect()` from react-router to redirect.\r\n * Ignored if rootRoute is provided (configure loader on your root route instead).\r\n *\r\n * For auth guards, use `authenticatedRoute` instead — it creates a layout route\r\n * boundary that only wraps protected routes.\r\n */\r\n loader?: (args: { request: Request; params: Record<string, string | undefined> }) => any;\r\n\r\n /**\r\n * Auth boundary — a pathless layout route that guards module routes and\r\n * the index route. Shell routes (login, error pages) sit outside this\r\n * boundary and are NOT guarded.\r\n *\r\n * Follows React Router's recommended layout route pattern:\r\n * ```\r\n * Root (loader runs for ALL routes — observability, etc.)\r\n * ├── shellRoutes (public — /login, /signup)\r\n * └── _authenticated (layout — auth guard)\r\n * ├── / (indexComponent)\r\n * └── module routes\r\n * ```\r\n *\r\n * @example\r\n * ```ts\r\n * registry.resolve({\r\n * authenticatedRoute: {\r\n * loader: async () => {\r\n * const res = await fetch('/api/auth/session')\r\n * if (!res.ok) throw redirect('/login')\r\n * return null\r\n * },\r\n * Component: ShellLayout,\r\n * },\r\n * shellRoutes: () => [\r\n * { path: '/login', Component: LoginPage },\r\n * ],\r\n * })\r\n * ```\r\n */\r\n authenticatedRoute?: {\r\n /** Auth guard — throw redirect() to deny access */\r\n loader: (args: { request: Request; params: Record<string, string | undefined> }) => any;\r\n /** Layout component for authenticated pages. Defaults to <Outlet />. */\r\n Component?: () => React.JSX.Element;\r\n };\r\n\r\n /**\r\n * Additional routes owned by the shell (login, error pages, onboarding, etc.)\r\n * that sit alongside module routes at the root level.\r\n *\r\n * When `authenticatedRoute` is used, shell routes are NOT guarded — they\r\n * are siblings of the auth layout, not children. This is the natural place\r\n * for public pages like /login.\r\n */\r\n shellRoutes?: () => RouteObject[];\r\n\r\n /**\r\n * Additional React providers to wrap around the app tree.\r\n *\r\n * **Nesting order:** First element is outermost. `[A, B, C]` produces:\r\n * ```tsx\r\n * <A>\r\n * <B>\r\n * <C>\r\n * ...app...\r\n * </C>\r\n * </B>\r\n * </A>\r\n * ```\r\n *\r\n * Place providers that other providers depend on **first** in the array.\r\n * For example, if your data-fetching provider reads from a theme context,\r\n * list the theme provider before the data-fetching provider.\r\n *\r\n * @example\r\n * ```ts\r\n * providers: [SWRConfigProvider, ThemeProvider, TooltipProvider]\r\n * // Produces: <SWRConfigProvider><ThemeProvider><TooltipProvider>...app...</TooltipProvider></ThemeProvider></SWRConfigProvider>\r\n * ```\r\n */\r\n providers?: React.ComponentType<{ children: React.ReactNode }>[];\r\n}\r\n\r\nexport function createRegistry<\r\n TSharedDependencies extends Record<string, any>,\r\n TSlots extends SlotMapOf<TSlots> = SlotMap,\r\n>(\r\n config: RegistryConfig<TSharedDependencies, TSlots>,\r\n): ReactiveRegistry<TSharedDependencies, TSlots> {\r\n const modules: ReactiveModuleDescriptor<TSharedDependencies, TSlots>[] = [];\r\n const lazyModules: LazyModuleDescriptor<TSharedDependencies, TSlots>[] = [];\r\n let resolved = false;\r\n\r\n // Collect all available dependency keys from all three buckets\r\n const availableKeys = new Set<string>([\r\n ...Object.keys(config.stores ?? {}),\r\n ...Object.keys(config.services ?? {}),\r\n ...Object.keys(config.reactiveServices ?? {}),\r\n ]);\r\n\r\n return {\r\n register(module) {\r\n if (resolved) {\r\n throw new Error(\r\n \"[@react-router-modules/runtime] Cannot register modules after resolve() has been called.\",\r\n );\r\n }\r\n modules.push(module);\r\n },\r\n\r\n registerLazy(descriptor) {\r\n if (resolved) {\r\n throw new Error(\r\n \"[@react-router-modules/runtime] Cannot register modules after resolve() has been called.\",\r\n );\r\n }\r\n lazyModules.push(descriptor);\r\n },\r\n\r\n resolve(options?: ResolveOptions) {\r\n if (resolved) {\r\n throw new Error(\"[@react-router-modules/runtime] resolve() can only be called once.\");\r\n }\r\n resolved = true;\r\n\r\n // Validate — cast is safe since validation only reads structural properties (id, requires)\r\n validateNoDuplicateIds(\r\n modules as ReactiveModuleDescriptor[],\r\n lazyModules as LazyModuleDescriptor[],\r\n );\r\n validateDependencies(modules as ReactiveModuleDescriptor[], availableKeys);\r\n\r\n // Run onRegister lifecycle hooks\r\n const deps = buildDepsObject<TSharedDependencies>(config);\r\n for (const mod of modules) {\r\n try {\r\n mod.lifecycle?.onRegister?.(deps);\r\n } catch (err) {\r\n throw new Error(\r\n `[@react-router-modules/runtime] Module \"${mod.id}\" lifecycle.onRegister() failed: ${err instanceof Error ? err.message : String(err)}`,\r\n { cause: err },\r\n );\r\n }\r\n }\r\n\r\n // Build route tree\r\n const routeBuilderOptions: RouteBuilderOptions = {\r\n rootRoute: options?.rootRoute,\r\n rootComponent: options?.rootComponent,\r\n indexComponent: options?.indexComponent,\r\n notFoundComponent: options?.notFoundComponent,\r\n loader: options?.loader,\r\n authenticatedRoute: options?.authenticatedRoute,\r\n shellRoutes: options?.shellRoutes,\r\n };\r\n const routes = buildRouteTree(\r\n modules as ReactiveModuleDescriptor[],\r\n lazyModules as LazyModuleDescriptor[],\r\n routeBuilderOptions,\r\n );\r\n\r\n // Create React Router instance (use memory router when DOM is unavailable, e.g. tests)\r\n const router =\r\n typeof document !== \"undefined\" ? createBrowserRouter(routes) : createMemoryRouter(routes);\r\n\r\n // Build navigation, slots, and module entries\r\n const navigation: NavigationManifest = buildNavigationManifest(\r\n modules as ReactiveModuleDescriptor[],\r\n );\r\n const slots = buildSlotsManifest<TSlots>(modules, config.slots);\r\n const moduleEntries: ModuleEntry[] = modules.map((mod) => ({\r\n id: mod.id,\r\n version: mod.version,\r\n meta: mod.meta,\r\n component: mod.component,\r\n zones: mod.zones,\r\n }));\r\n\r\n // Build stores, services, and reactive services maps for the context\r\n const stores: Record<string, StoreApi<unknown>> = {};\r\n const services: Record<string, unknown> = {};\r\n const reactiveServices: Record<string, ReactiveService<unknown>> = {};\r\n\r\n if (config.stores) {\r\n for (const [key, store] of Object.entries(config.stores)) {\r\n if (store) stores[key] = store as StoreApi<unknown>;\r\n }\r\n }\r\n if (config.services) {\r\n for (const [key, service] of Object.entries(config.services)) {\r\n if (service !== undefined) services[key] = service;\r\n }\r\n }\r\n if (config.reactiveServices) {\r\n for (const [key, rs] of Object.entries(config.reactiveServices)) {\r\n if (rs) reactiveServices[key] = rs as ReactiveService<unknown>;\r\n }\r\n }\r\n\r\n // Create App component\r\n const App = createAppComponent({\r\n router,\r\n stores,\r\n services,\r\n reactiveServices,\r\n navigation,\r\n slots,\r\n modules: moduleEntries,\r\n providers: options?.providers,\r\n });\r\n\r\n return { App, router, navigation, slots, modules: moduleEntries };\r\n },\r\n };\r\n}\r\n\r\nfunction buildDepsObject<TSharedDependencies extends Record<string, any>>(\r\n config: RegistryConfig<TSharedDependencies, any>,\r\n): TSharedDependencies {\r\n const deps: Record<string, unknown> = {};\r\n\r\n // For stores, get current state as the deps value\r\n // (lifecycle hooks get a snapshot, components use useStore for reactivity)\r\n if (config.stores) {\r\n for (const [key, store] of Object.entries(config.stores)) {\r\n if (store) {\r\n deps[key] = (store as StoreApi<unknown>).getState();\r\n }\r\n }\r\n }\r\n if (config.services) {\r\n for (const [key, service] of Object.entries(config.services)) {\r\n if (service !== undefined) deps[key] = service;\r\n }\r\n }\r\n // For reactive services, get current snapshot\r\n if (config.reactiveServices) {\r\n for (const [key, rs] of Object.entries(config.reactiveServices)) {\r\n if (rs) {\r\n deps[key] = (rs as ReactiveService<unknown>).getSnapshot();\r\n }\r\n }\r\n }\r\n\r\n return deps as TSharedDependencies;\r\n}\r\n","import { useMatches } from \"react-router\";\r\nimport type { ZoneMapOf } from \"@react-router-modules/core\";\r\n\r\n/**\r\n * Read zone components contributed by the currently matched route hierarchy.\r\n *\r\n * Zones are set via React Router's `handle` on individual routes.\r\n * This hook walks all matched routes from root to leaf and returns a merged\r\n * map where the deepest match wins for each zone key.\r\n *\r\n * @example\r\n * // In the shell layout:\r\n * const zones = useZones<AppZones>()\r\n * const DetailPanel = zones.detailPanel\r\n *\r\n * return (\r\n * <div className=\"grid\">\r\n * <main><Outlet /></main>\r\n * <aside>{DetailPanel && <DetailPanel />}</aside>\r\n * </div>\r\n * )\r\n *\r\n * @example\r\n * // In a module's route definition:\r\n * {\r\n * path: ':userId',\r\n * Component: UserDetailPage,\r\n * handle: {\r\n * detailPanel: UserDetailSidebar,\r\n * },\r\n * }\r\n */\r\nexport function useZones<TZones extends ZoneMapOf<TZones>>(): Partial<TZones> {\r\n const matches = useMatches();\r\n const merged: Record<string, unknown> = {};\r\n for (const match of matches) {\r\n const data = (match as any).handle;\r\n if (data && typeof data === \"object\") {\r\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\r\n if (value !== undefined) {\r\n merged[key] = value;\r\n }\r\n }\r\n }\r\n }\r\n return merged as Partial<TZones>;\r\n}\r\n","import type { ZoneMapOf } from \"@react-router-modules/core\";\r\nimport { useZones } from \"./zones.js\";\r\nimport { useModules } from \"./modules-context.js\";\r\n\r\n/**\r\n * Read zone components from both the matched route hierarchy AND the\r\n * currently active module (identified by `activeModuleId`).\r\n *\r\n * This unifies two zone contribution patterns:\r\n * - **Route-based modules** contribute zones via React Router's `handle`\r\n * - **Tab-based modules** contribute zones via the `zones` field on their descriptor\r\n *\r\n * When both sources provide a value for the same zone key, the module's\r\n * contribution wins — the assumption is that the active tab's content is more\r\n * relevant than the underlying route's.\r\n *\r\n * @param activeModuleId - The id of the module that is currently active in the\r\n * workspace (e.g. the journey tab's moduleId). Pass `null` or `undefined`\r\n * when no module tab is active — only route zones are returned.\r\n *\r\n * @example\r\n * // In the shell layout:\r\n * const activeTab = getActiveTab(interactionId)\r\n * const moduleId = activeTab?.type === 'native-journey' ? activeTab.journeyId : null\r\n * const zones = useActiveZones<AppZones>(moduleId)\r\n * const Panel = zones.contextualPanel\r\n *\r\n * return (\r\n * <aside>{Panel ? <Panel /> : <DefaultPanel />}</aside>\r\n * )\r\n */\r\nexport function useActiveZones<TZones extends ZoneMapOf<TZones>>(\r\n activeModuleId?: string | null,\r\n): Partial<TZones> {\r\n const routeZones = useZones<TZones>();\r\n const modules = useModules();\r\n\r\n if (!activeModuleId) {\r\n return routeZones;\r\n }\r\n\r\n const activeMod = modules.find((m) => m.id === activeModuleId);\r\n if (!activeMod?.zones) {\r\n return routeZones;\r\n }\r\n\r\n // Module zones override route zones for the same key\r\n return { ...routeZones, ...activeMod.zones } as Partial<TZones>;\r\n}\r\n","import { Component } from \"react\";\r\nimport type { ErrorInfo, ReactNode } from \"react\";\r\n\r\ninterface Props {\r\n moduleId: string;\r\n fallback?: ReactNode;\r\n children: ReactNode;\r\n}\r\n\r\ninterface State {\r\n hasError: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport class ModuleErrorBoundary extends Component<Props, State> {\r\n override state: State = { hasError: false, error: null };\r\n\r\n static getDerivedStateFromError(error: Error): State {\r\n return { hasError: true, error };\r\n }\r\n\r\n override componentDidCatch(error: Error, info: ErrorInfo) {\r\n console.error(\r\n `[@react-router-modules/runtime] Module \"${this.props.moduleId}\" encountered an error:`,\r\n error,\r\n info,\r\n );\r\n }\r\n\r\n override render() {\r\n if (this.state.hasError) {\r\n if (this.props.fallback) {\r\n return this.props.fallback;\r\n }\r\n return (\r\n <div\r\n style={{\r\n padding: \"1rem\",\r\n border: \"1px solid #e53e3e\",\r\n borderRadius: \"0.5rem\",\r\n margin: \"1rem\",\r\n }}\r\n >\r\n <h3 style={{ color: \"#e53e3e\", margin: \"0 0 0.5rem 0\" }}>\r\n Module "{this.props.moduleId}" encountered an error\r\n </h3>\r\n <pre style={{ fontSize: \"0.875rem\", color: \"#718096\", whiteSpace: \"pre-wrap\" }}>\r\n {this.state.error?.message}\r\n </pre>\r\n </div>\r\n );\r\n }\r\n return this.props.children;\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/route-builder.tsx","../src/app.tsx","../src/registry.ts","../src/zones.ts","../src/active-zones.ts"],"sourcesContent":["import { Outlet, useRoutes } from \"react-router\";\nimport type { RouteObject } from \"react-router\";\nimport type { ModuleDescriptor, LazyModuleDescriptor } from \"@react-router-modules/core\";\n\nexport interface RouteBuilderOptions {\n /**\n * Pre-built root route. If provided, rootComponent/notFoundComponent/loader\n * are ignored — configure them directly on this route instead.\n */\n rootRoute?: RouteObject;\n /** Component for the root layout (renders <Outlet /> for child routes) */\n rootComponent?: () => React.JSX.Element;\n /** Component for the index route (/) */\n indexComponent?: () => React.JSX.Element;\n /** Component for the 404 / not-found route */\n notFoundComponent?: () => React.JSX.Element;\n /**\n * Called before every route loads — for observability, feature flags, etc.\n * Runs for ALL routes including public ones.\n * Ignored if rootRoute is provided.\n */\n loader?: (args: { request: Request; params: Record<string, string | undefined> }) => any;\n /**\n * Auth boundary — a pathless layout route that wraps module routes and\n * the index route. Shell routes (login, error pages) sit outside this\n * boundary and are NOT guarded.\n *\n * Follows React Router's recommended layout route pattern.\n *\n * When provided, the route tree becomes:\n * ```\n * Root (loader runs for ALL routes)\n * ├── shellRoutes (public — /login, /signup, etc.)\n * └── _authenticated (layout — loader guards children)\n * ├── / (indexComponent)\n * └── module routes\n * ```\n *\n * When omitted, all routes are direct children of root (no auth boundary).\n */\n authenticatedRoute?: {\n /** Auth guard — throw redirect() to deny access */\n loader: (args: { request: Request; params: Record<string, string | undefined> }) => any;\n /** Layout component for authenticated pages. Defaults to <Outlet />. */\n Component?: () => React.JSX.Element;\n };\n /** Additional routes owned by the shell (login, error pages, etc.) */\n shellRoutes?: () => RouteObject[];\n}\n\n/**\n * Composes all module route subtrees into a React Router route tree.\n * Modules without createRoutes are skipped (headless modules).\n */\nexport function buildRouteTree(\n modules: ModuleDescriptor[],\n lazyModules: LazyModuleDescriptor[],\n options?: RouteBuilderOptions,\n): RouteObject[] {\n // If a custom root route is provided, use it as the base\n if (options?.rootRoute) {\n const rootChildren: RouteObject[] = [...(options.rootRoute.children ?? [])];\n\n // Shell-owned routes (login, error pages) — always direct children of root\n if (options?.shellRoutes) {\n rootChildren.push(...options.shellRoutes());\n }\n\n const protectedChildren: RouteObject[] = [];\n\n // Add index route if provided\n if (options?.indexComponent) {\n protectedChildren.push({\n index: true,\n Component: options.indexComponent,\n });\n }\n\n // Eager modules\n for (const mod of modules) {\n if (!mod.createRoutes) continue;\n const routes = mod.createRoutes();\n if (!routes) {\n throw new Error(\n `[@react-router-modules/runtime] Module \"${mod.id}\" createRoutes() returned a falsy value.`,\n );\n }\n protectedChildren.push(...(Array.isArray(routes) ? routes : [routes]));\n }\n\n // Lazy modules\n for (const lazyMod of lazyModules) {\n protectedChildren.push(createLazyModuleRoute(lazyMod));\n }\n\n if (options?.authenticatedRoute) {\n rootChildren.push(\n createAuthenticatedLayoutRoute(options.authenticatedRoute, protectedChildren),\n );\n } else {\n rootChildren.push(...protectedChildren);\n }\n\n options.rootRoute.children = rootChildren;\n return [options.rootRoute];\n }\n\n // Build root route from options\n const rootChildren: RouteObject[] = [];\n\n // Shell-owned routes (login, error pages) — always direct children of root\n if (options?.shellRoutes) {\n rootChildren.push(...options.shellRoutes());\n }\n\n const protectedChildren: RouteObject[] = [];\n\n // Add index route if provided\n if (options?.indexComponent) {\n protectedChildren.push({\n index: true,\n Component: options.indexComponent,\n });\n }\n\n // Eager modules: call createRoutes\n for (const mod of modules) {\n if (!mod.createRoutes) continue;\n const routes = mod.createRoutes();\n if (!routes) {\n throw new Error(\n `[@react-router-modules/runtime] Module \"${mod.id}\" createRoutes() returned a falsy value.`,\n );\n }\n protectedChildren.push(...(Array.isArray(routes) ? routes : [routes]));\n }\n\n // Lazy modules\n for (const lazyMod of lazyModules) {\n protectedChildren.push(createLazyModuleRoute(lazyMod));\n }\n\n if (options?.authenticatedRoute) {\n rootChildren.push(\n createAuthenticatedLayoutRoute(options.authenticatedRoute, protectedChildren),\n );\n } else {\n rootChildren.push(...protectedChildren);\n }\n\n // Not-found catch-all\n if (options?.notFoundComponent) {\n rootChildren.push({\n path: \"*\",\n Component: options.notFoundComponent,\n });\n }\n\n const rootRoute: RouteObject = {\n path: \"/\",\n Component: options?.rootComponent,\n loader: options?.loader,\n children: rootChildren,\n };\n\n return [rootRoute];\n}\n\nfunction createAuthenticatedLayoutRoute(\n auth: NonNullable<RouteBuilderOptions[\"authenticatedRoute\"]>,\n children: RouteObject[],\n): RouteObject {\n return {\n id: \"_authenticated\",\n Component: auth.Component ?? (() => <Outlet />),\n loader: auth.loader,\n children,\n };\n}\n\n/**\n * Creates a catch-all route for a lazily-loaded module.\n * On first navigation, the module descriptor is loaded and its routes\n * are rendered as descendant routes via useRoutes().\n */\nfunction createLazyModuleRoute(lazyMod: LazyModuleDescriptor): RouteObject {\n // Capture the loaded routes so they're resolved only once\n let cachedRoutes: RouteObject[] | null = null;\n\n return {\n path: lazyMod.basePath.replace(/^\\//, \"\") + \"/*\",\n lazy: async () => {\n if (!cachedRoutes) {\n const { default: descriptor } = await lazyMod.load();\n if (descriptor.createRoutes) {\n const routes = descriptor.createRoutes();\n cachedRoutes = Array.isArray(routes) ? routes : [routes];\n } else {\n cachedRoutes = [];\n }\n }\n const routes = cachedRoutes;\n return {\n Component: function LazyModule() {\n return useRoutes(routes);\n },\n };\n },\n };\n}\n","import { useMemo } from \"react\";\nimport { RouterProvider } from \"react-router\";\nimport type { DataRouter } from \"react-router\";\nimport type { StoreApi } from \"zustand\";\nimport type { ReactiveService } from \"@react-router-modules/core\";\nimport { SharedDependenciesContext } from \"@react-router-modules/core\";\nimport type {\n DynamicSlotFactory,\n SlotFilter,\n NavigationManifest,\n ModuleEntry,\n} from \"@modular-react/core\";\nimport {\n NavigationContext,\n SlotsContext,\n RecalculateSlotsContext,\n ModulesContext,\n DynamicSlotsProvider,\n} from \"@modular-react/react\";\nimport type { SlotsSignal } from \"@modular-react/react\";\n\ninterface AppProps {\n router: DataRouter;\n stores: Record<string, StoreApi<unknown>>;\n services: Record<string, unknown>;\n reactiveServices: Record<string, ReactiveService<unknown>>;\n navigation: NavigationManifest;\n slots: object;\n modules: readonly ModuleEntry[];\n providers?: React.ComponentType<{ children: React.ReactNode }>[];\n dynamicSlotFactories: DynamicSlotFactory[];\n slotFilter?: SlotFilter;\n slotsSignal: SlotsSignal;\n recalculateSlots: () => void;\n}\n\nexport function createAppComponent({\n router,\n stores,\n services,\n reactiveServices,\n navigation,\n slots,\n modules,\n providers,\n dynamicSlotFactories,\n slotFilter,\n slotsSignal,\n recalculateSlots,\n}: AppProps) {\n // All values captured in closure are stable references created once at resolve() time.\n // Wrap in a stable object so context consumers don't re-render on parent renders.\n const depsValue = { stores, services, reactiveServices };\n const hasDynamicSlots = dynamicSlotFactories.length > 0 || slotFilter != null;\n\n function App() {\n const tree = useMemo(() => {\n // When dynamic slots exist, use a provider that re-evaluates\n // on recalculateSlots(). Otherwise, use static context for zero overhead.\n const slotsProvider = hasDynamicSlots ? (\n <DynamicSlotsProvider\n baseSlots={slots}\n factories={dynamicSlotFactories}\n filter={slotFilter}\n stores={stores}\n services={services}\n reactiveServices={reactiveServices}\n signal={slotsSignal}\n >\n <ModulesContext value={modules}>\n <RouterProvider router={router} />\n </ModulesContext>\n </DynamicSlotsProvider>\n ) : (\n <SlotsContext value={slots}>\n <ModulesContext value={modules}>\n <RouterProvider router={router} />\n </ModulesContext>\n </SlotsContext>\n );\n\n let node: React.ReactNode = (\n <SharedDependenciesContext value={depsValue}>\n <NavigationContext value={navigation}>\n <RecalculateSlotsContext value={recalculateSlots}>\n {slotsProvider}\n </RecalculateSlotsContext>\n </NavigationContext>\n </SharedDependenciesContext>\n );\n\n // Wrap with user-supplied providers (first element = outermost wrapper)\n if (providers) {\n for (const Provider of [...providers].reverse()) {\n node = <Provider>{node}</Provider>;\n }\n }\n\n return node;\n }, []);\n\n return tree;\n }\n\n App.displayName = \"ModularApp\";\n return App;\n}\n","import { createBrowserRouter, createMemoryRouter } from \"react-router\";\nimport type { RouteObject } from \"react-router\";\nimport type { StoreApi } from \"zustand\";\nimport type {\n ModuleDescriptor,\n LazyModuleDescriptor,\n ReactiveService,\n SlotMap,\n SlotMapOf,\n} from \"@react-router-modules/core\";\nimport {\n buildNavigationManifest,\n buildSlotsManifest,\n collectDynamicSlotFactories,\n validateNoDuplicateIds,\n validateDependencies,\n} from \"@modular-react/core\";\nimport type { SlotFilter, NavigationManifest, ModuleEntry } from \"@modular-react/core\";\nimport { createSlotsSignal } from \"@modular-react/react\";\n\nimport type { RegistryConfig, ApplicationManifest } from \"./types.js\";\nimport { buildRouteTree, type RouteBuilderOptions } from \"./route-builder.js\";\nimport { createAppComponent } from \"./app.js\";\n\nexport interface ModuleRegistry<\n TSharedDependencies extends Record<string, any>,\n TSlots extends SlotMapOf<TSlots> = SlotMap,\n> {\n /** Register an eager module */\n register(module: ModuleDescriptor<TSharedDependencies, TSlots>): void;\n\n /** Register a lazily-loaded module */\n registerLazy(descriptor: LazyModuleDescriptor<TSharedDependencies, TSlots>): void;\n\n /**\n * Resolve all modules and produce the application manifest.\n * Validates dependencies and builds the route tree.\n */\n resolve(options?: ResolveOptions<TSharedDependencies, TSlots>): ApplicationManifest<TSlots>;\n}\n\nexport interface ResolveOptions<\n TSharedDependencies extends Record<string, any> = Record<string, any>,\n TSlots extends SlotMapOf<TSlots> = SlotMap,\n> {\n /** Root layout component (renders <Outlet /> for child routes) */\n rootComponent?: () => React.JSX.Element;\n\n /**\n * Pre-built root route — if provided, used instead of auto-creating one.\n * Mutually exclusive with rootComponent/notFoundComponent/loader.\n */\n rootRoute?: RouteObject;\n\n /** Component for the index route (/) */\n indexComponent?: () => React.JSX.Element;\n\n /** Component for 404 / not-found */\n notFoundComponent?: () => React.JSX.Element;\n\n /**\n * Called before every route loads — for observability, analytics, feature flags.\n * Runs for ALL routes including public ones like /login.\n * Ignored if rootRoute is provided.\n */\n loader?: (args: { request: Request; params: Record<string, string | undefined> }) => any;\n\n /**\n * Auth boundary — a pathless layout route that guards module routes and\n * the index route. Shell routes sit outside this boundary.\n */\n authenticatedRoute?: {\n /** Auth guard — throw redirect() to deny access */\n loader: (args: { request: Request; params: Record<string, string | undefined> }) => any;\n /** Layout component for authenticated pages. Defaults to <Outlet />. */\n Component?: () => React.JSX.Element;\n };\n\n /** Additional routes owned by the shell (login, error pages, etc.) */\n shellRoutes?: () => RouteObject[];\n\n /**\n * Additional React providers to wrap around the app tree.\n * First element is outermost.\n */\n providers?: React.ComponentType<{ children: React.ReactNode }>[];\n\n /**\n * Global filter applied to the fully resolved slot manifest (static + dynamic)\n * on every `recalculateSlots()` call.\n */\n slotFilter?: (slots: TSlots, deps: TSharedDependencies) => TSlots;\n}\n\nexport function createRegistry<\n TSharedDependencies extends Record<string, any>,\n TSlots extends SlotMapOf<TSlots> = SlotMap,\n>(\n config: RegistryConfig<TSharedDependencies, TSlots>,\n): ModuleRegistry<TSharedDependencies, TSlots> {\n const modules: ModuleDescriptor<TSharedDependencies, TSlots>[] = [];\n const lazyModules: LazyModuleDescriptor<TSharedDependencies, TSlots>[] = [];\n let resolved = false;\n\n // Collect all available dependency keys from all three buckets\n const availableKeys = new Set<string>([\n ...Object.keys(config.stores ?? {}),\n ...Object.keys(config.services ?? {}),\n ...Object.keys(config.reactiveServices ?? {}),\n ]);\n\n return {\n register(module) {\n if (resolved) {\n throw new Error(\n \"[@react-router-modules/runtime] Cannot register modules after resolve() has been called.\",\n );\n }\n modules.push(module);\n },\n\n registerLazy(descriptor) {\n if (resolved) {\n throw new Error(\n \"[@react-router-modules/runtime] Cannot register modules after resolve() has been called.\",\n );\n }\n lazyModules.push(descriptor);\n },\n\n resolve(options?: ResolveOptions<TSharedDependencies, TSlots>) {\n if (resolved) {\n throw new Error(\"[@react-router-modules/runtime] resolve() can only be called once.\");\n }\n resolved = true;\n\n // Validate — cast is safe since validation only reads structural properties (id, requires)\n validateNoDuplicateIds(modules as ModuleDescriptor[], lazyModules as LazyModuleDescriptor[]);\n validateDependencies(modules as ModuleDescriptor[], availableKeys);\n\n // Run onRegister lifecycle hooks\n const deps = buildDepsObject<TSharedDependencies>(config);\n for (const mod of modules) {\n try {\n mod.lifecycle?.onRegister?.(deps);\n } catch (err) {\n throw new Error(\n `[@react-router-modules/runtime] Module \"${mod.id}\" lifecycle.onRegister() failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n }\n }\n\n // Build route tree\n const routeBuilderOptions: RouteBuilderOptions = {\n rootRoute: options?.rootRoute,\n rootComponent: options?.rootComponent,\n indexComponent: options?.indexComponent,\n notFoundComponent: options?.notFoundComponent,\n loader: options?.loader,\n authenticatedRoute: options?.authenticatedRoute,\n shellRoutes: options?.shellRoutes,\n };\n const routes = buildRouteTree(\n modules as ModuleDescriptor[],\n lazyModules as LazyModuleDescriptor[],\n routeBuilderOptions,\n );\n\n // Create React Router instance (use memory router when DOM is unavailable, e.g. tests)\n const router =\n typeof document !== \"undefined\" ? createBrowserRouter(routes) : createMemoryRouter(routes);\n\n // Build navigation, slots, and module entries\n const navigation: NavigationManifest = buildNavigationManifest(modules as ModuleDescriptor[]);\n const slots = buildSlotsManifest<TSlots>(modules, config.slots);\n const dynamicSlotFactories = collectDynamicSlotFactories(modules as ModuleDescriptor[]);\n const slotFilter = options?.slotFilter as SlotFilter | undefined;\n const moduleEntries: ModuleEntry[] = modules.map((mod) => ({\n id: mod.id,\n version: mod.version,\n meta: mod.meta,\n component: mod.component,\n zones: mod.zones,\n }));\n\n // Build stores, services, and reactive services maps for the context\n const stores: Record<string, StoreApi<unknown>> = {};\n const services: Record<string, unknown> = {};\n const reactiveServices: Record<string, ReactiveService<unknown>> = {};\n\n if (config.stores) {\n for (const [key, store] of Object.entries(config.stores)) {\n if (store) stores[key] = store as StoreApi<unknown>;\n }\n }\n if (config.services) {\n for (const [key, service] of Object.entries(config.services)) {\n if (service !== undefined) services[key] = service;\n }\n }\n if (config.reactiveServices) {\n for (const [key, rs] of Object.entries(config.reactiveServices)) {\n if (rs) reactiveServices[key] = rs as ReactiveService<unknown>;\n }\n }\n\n // Create signal for imperative recalculation of dynamic slots\n const slotsSignal = createSlotsSignal();\n const hasDynamicSlots = dynamicSlotFactories.length > 0 || slotFilter != null;\n const recalculateSlots = hasDynamicSlots ? () => slotsSignal.notify() : () => {};\n\n // Create App component\n const App = createAppComponent({\n router,\n stores,\n services,\n reactiveServices,\n navigation,\n slots,\n modules: moduleEntries,\n providers: options?.providers,\n dynamicSlotFactories,\n slotFilter,\n slotsSignal,\n recalculateSlots,\n });\n\n return { App, router, navigation, slots, modules: moduleEntries, recalculateSlots };\n },\n };\n}\n\nfunction buildDepsObject<TSharedDependencies extends Record<string, any>>(\n config: RegistryConfig<TSharedDependencies, any>,\n): TSharedDependencies {\n const deps: Record<string, unknown> = {};\n\n if (config.stores) {\n for (const [key, store] of Object.entries(config.stores)) {\n if (store) {\n deps[key] = (store as StoreApi<unknown>).getState();\n }\n }\n }\n if (config.services) {\n for (const [key, service] of Object.entries(config.services)) {\n if (service !== undefined) deps[key] = service;\n }\n }\n if (config.reactiveServices) {\n for (const [key, rs] of Object.entries(config.reactiveServices)) {\n if (rs) {\n deps[key] = (rs as ReactiveService<unknown>).getSnapshot();\n }\n }\n }\n\n return deps as TSharedDependencies;\n}\n","import { useMatches } from \"react-router\";\nimport type { ZoneMapOf } from \"@react-router-modules/core\";\n\n/**\n * Read zone components contributed by the currently matched route hierarchy.\n *\n * Zones are set via React Router's `handle` on individual routes.\n * This hook walks all matched routes from root to leaf and returns a merged\n * map where the deepest match wins for each zone key.\n *\n * @example\n * // In the shell layout:\n * const zones = useZones<AppZones>()\n * const DetailPanel = zones.detailPanel\n *\n * return (\n * <div className=\"grid\">\n * <main><Outlet /></main>\n * <aside>{DetailPanel && <DetailPanel />}</aside>\n * </div>\n * )\n *\n * @example\n * // In a module's route definition:\n * {\n * path: ':userId',\n * Component: UserDetailPage,\n * handle: {\n * detailPanel: UserDetailSidebar,\n * },\n * }\n */\nexport function useZones<TZones extends ZoneMapOf<TZones>>(): Partial<TZones> {\n const matches = useMatches();\n const merged: Record<string, unknown> = {};\n for (const match of matches) {\n const data = (match as any).handle;\n if (data && typeof data === \"object\") {\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n }\n }\n return merged as Partial<TZones>;\n}\n","import type { ZoneMapOf } from \"@react-router-modules/core\";\nimport { useModules } from \"@modular-react/react\";\nimport { useZones } from \"./zones.js\";\n\n/**\n * Read zone components from both the matched route hierarchy AND the\n * currently active module (identified by `activeModuleId`).\n *\n * This unifies two zone contribution patterns:\n * - **Route-based modules** contribute zones via React Router's `handle`\n * - **Tab-based modules** contribute zones via the `zones` field on their descriptor\n *\n * When both sources provide a value for the same zone key, the module's\n * contribution wins.\n */\nexport function useActiveZones<TZones extends ZoneMapOf<TZones>>(\n activeModuleId?: string | null,\n): Partial<TZones> {\n const routeZones = useZones<TZones>();\n const modules = useModules();\n\n if (!activeModuleId) {\n return routeZones;\n }\n\n const activeMod = modules.find((m) => m.id === activeModuleId);\n if (!activeMod?.zones) {\n return routeZones;\n }\n\n // Module zones override route zones for the same key\n return { ...routeZones, ...activeMod.zones } as Partial<TZones>;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-router-modules/runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
|
-
"url": "git+https://github.com/kibertoad/
|
|
7
|
-
"directory": "packages/runtime"
|
|
6
|
+
"url": "git+https://github.com/kibertoad/modular-react.git",
|
|
7
|
+
"directory": "packages/react-router-runtime"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist"
|
|
@@ -24,10 +24,14 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "vite build",
|
|
26
26
|
"dev": "vite build --watch",
|
|
27
|
-
"
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"prepublishOnly": "pnpm build",
|
|
29
|
+
"typecheck": "tsc --noEmit"
|
|
28
30
|
},
|
|
29
31
|
"dependencies": {
|
|
30
|
-
"@react
|
|
32
|
+
"@modular-react/core": "workspace:*",
|
|
33
|
+
"@modular-react/react": "workspace:*",
|
|
34
|
+
"@react-router-modules/core": "workspace:*"
|
|
31
35
|
},
|
|
32
36
|
"devDependencies": {
|
|
33
37
|
"@types/react": "^19.0.0",
|
|
@@ -38,6 +42,7 @@
|
|
|
38
42
|
"typescript": "^6.0.2",
|
|
39
43
|
"vite": "^8.0.3",
|
|
40
44
|
"vite-plugin-dts": "^4.5.0",
|
|
45
|
+
"vitest": "^4.1.0",
|
|
41
46
|
"zustand": "^5.0.0"
|
|
42
47
|
},
|
|
43
48
|
"peerDependencies": {
|