@idealyst/navigation 1.1.7 → 1.1.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/package.json +17 -5
- package/src/context/NavigatorContext.native.tsx +75 -27
- package/src/context/NavigatorContext.web.tsx +7 -0
- package/src/context/types.ts +7 -0
- package/src/examples/ExampleNavigationRouter.tsx +4 -0
- package/src/examples/ExampleSidebar.tsx +3 -0
- package/src/examples/ExampleWebLayout.tsx +3 -2
- package/src/examples/HeaderRight.tsx +4 -3
- package/src/routing/router.native.tsx +1 -67
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idealyst/navigation",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "Cross-platform navigation library for React and React Native",
|
|
5
5
|
"readme": "README.md",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -43,8 +43,10 @@
|
|
|
43
43
|
"publish:npm": "npm publish"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@idealyst/
|
|
47
|
-
"@idealyst/
|
|
46
|
+
"@idealyst/camera": "^1.1.6",
|
|
47
|
+
"@idealyst/components": "^1.1.8",
|
|
48
|
+
"@idealyst/microphone": "^1.1.7",
|
|
49
|
+
"@idealyst/theme": "^1.1.8",
|
|
48
50
|
"@react-navigation/bottom-tabs": ">=7.0.0",
|
|
49
51
|
"@react-navigation/drawer": ">=7.0.0",
|
|
50
52
|
"@react-navigation/native": ">=7.0.0",
|
|
@@ -59,11 +61,21 @@
|
|
|
59
61
|
"react-router": ">=6.0.0",
|
|
60
62
|
"react-router-dom": ">=6.0.0"
|
|
61
63
|
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@idealyst/camera": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"@idealyst/microphone": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
62
72
|
"devDependencies": {
|
|
63
|
-
"@idealyst/
|
|
73
|
+
"@idealyst/camera": "^1.1.6",
|
|
74
|
+
"@idealyst/components": "^1.1.8",
|
|
64
75
|
"@idealyst/datagrid": "^1.0.93",
|
|
65
76
|
"@idealyst/datepicker": "^1.0.93",
|
|
66
|
-
"@idealyst/
|
|
77
|
+
"@idealyst/microphone": "^1.1.7",
|
|
78
|
+
"@idealyst/theme": "^1.1.8",
|
|
67
79
|
"@types/react": "^19.1.8",
|
|
68
80
|
"@types/react-dom": "^19.1.6",
|
|
69
81
|
"react": "^19.1.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { createContext, memo, useContext, useMemo } from 'react';
|
|
2
2
|
import { NavigateParams, NavigatorProviderProps, NavigatorContextValue } from './types';
|
|
3
|
-
import { useNavigation, DarkTheme, DefaultTheme, NavigationContainer, CommonActions } from '@react-navigation/native';
|
|
3
|
+
import { useNavigation, DarkTheme, DefaultTheme, NavigationContainer, CommonActions, StackActions } from '@react-navigation/native';
|
|
4
4
|
import { buildNavigator, NavigatorParam, NOT_FOUND_SCREEN_NAME } from '../routing';
|
|
5
5
|
import { useUnistyles } from 'react-native-unistyles';
|
|
6
6
|
|
|
@@ -126,35 +126,40 @@ const parseParameterizedPath = (path: string, rootRoute: any): { routeName: stri
|
|
|
126
126
|
const cleanPath = route.path.startsWith('/') ? route.path.slice(1) : route.path;
|
|
127
127
|
const fullRoutePath = pathPrefix ? `${pathPrefix}/${cleanPath}` : route.path;
|
|
128
128
|
|
|
129
|
-
if
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
// Check if route segments match the path segments at current position
|
|
130
|
+
const remainingSegments = segments.length - startIndex;
|
|
131
|
+
|
|
132
|
+
// Check if this route's segments match as a prefix (for nested routes) or exactly
|
|
133
|
+
let prefixMatches = routeSegments.length <= remainingSegments;
|
|
134
|
+
const extractedParams: Record<string, string> = {};
|
|
135
|
+
|
|
136
|
+
if (prefixMatches) {
|
|
133
137
|
for (let i = 0; i < routeSegments.length; i++) {
|
|
134
138
|
const routeSegment = routeSegments[i];
|
|
135
139
|
const pathSegment = segments[startIndex + i];
|
|
136
|
-
|
|
140
|
+
|
|
137
141
|
if (routeSegment.startsWith(':')) {
|
|
138
142
|
// Parameter segment - extract value
|
|
139
143
|
const paramName = routeSegment.slice(1);
|
|
140
144
|
extractedParams[paramName] = pathSegment;
|
|
141
145
|
} else if (routeSegment !== pathSegment) {
|
|
142
146
|
// Literal segment must match exactly
|
|
143
|
-
|
|
147
|
+
prefixMatches = false;
|
|
144
148
|
break;
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
|
-
|
|
148
|
-
if (isMatch) {
|
|
149
|
-
return { route, params: extractedParams, fullPath: fullRoutePath };
|
|
150
|
-
}
|
|
151
151
|
}
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
if (
|
|
152
|
+
|
|
153
|
+
// Exact match - route segments consume all remaining path segments
|
|
154
|
+
if (prefixMatches && routeSegments.length === remainingSegments) {
|
|
155
|
+
return { route, params: extractedParams, fullPath: fullRoutePath };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Check nested routes ONLY if this route's path is a prefix of the target path
|
|
159
|
+
if (prefixMatches && route.routes) {
|
|
155
160
|
const nestedMatch = findMatchingRoute(
|
|
156
|
-
route.routes,
|
|
157
|
-
segments,
|
|
161
|
+
route.routes,
|
|
162
|
+
segments,
|
|
158
163
|
startIndex + routeSegments.length,
|
|
159
164
|
fullRoutePath
|
|
160
165
|
);
|
|
@@ -230,12 +235,9 @@ const UnwrappedNavigatorProvider = ({ route }: NavigatorProviderProps) => {
|
|
|
230
235
|
};
|
|
231
236
|
|
|
232
237
|
if (params.replace) {
|
|
233
|
-
// Use
|
|
238
|
+
// Use StackActions.replace to replace the current screen in the stack
|
|
234
239
|
navigation.dispatch(
|
|
235
|
-
|
|
236
|
-
index: 0,
|
|
237
|
-
routes: [{ name: parsed.routeName, params: navigationParams }],
|
|
238
|
-
})
|
|
240
|
+
StackActions.replace(parsed.routeName, navigationParams)
|
|
239
241
|
);
|
|
240
242
|
} else {
|
|
241
243
|
// Navigate to the pattern route with extracted parameters
|
|
@@ -243,6 +245,30 @@ const UnwrappedNavigatorProvider = ({ route }: NavigatorProviderProps) => {
|
|
|
243
245
|
}
|
|
244
246
|
};
|
|
245
247
|
|
|
248
|
+
const replace = (params: Omit<NavigateParams, 'replace'>) => {
|
|
249
|
+
// Normalize path and substitute variables
|
|
250
|
+
const normalizedPath = normalizePath(params.path, params.vars);
|
|
251
|
+
|
|
252
|
+
// Parse parameterized path for mobile
|
|
253
|
+
const parsed = parseParameterizedPath(normalizedPath, route);
|
|
254
|
+
|
|
255
|
+
if (!parsed) {
|
|
256
|
+
console.warn(`Navigation: Cannot replace to invalid route "${normalizedPath}".`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Merge route params with navigation state
|
|
261
|
+
const navigationParams = {
|
|
262
|
+
...parsed.params,
|
|
263
|
+
...(params.state || {}),
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// Use StackActions.replace to replace the current screen
|
|
267
|
+
navigation.dispatch(
|
|
268
|
+
StackActions.replace(parsed.routeName, navigationParams)
|
|
269
|
+
);
|
|
270
|
+
};
|
|
271
|
+
|
|
246
272
|
const RouteComponent = useMemo(() => {
|
|
247
273
|
// Memoize the navigator to prevent unnecessary re-renders
|
|
248
274
|
return memo(buildNavigator(route));
|
|
@@ -260,6 +286,7 @@ const UnwrappedNavigatorProvider = ({ route }: NavigatorProviderProps) => {
|
|
|
260
286
|
<NavigatorContext.Provider value={{
|
|
261
287
|
route,
|
|
262
288
|
navigate,
|
|
289
|
+
replace,
|
|
263
290
|
canGoBack,
|
|
264
291
|
goBack,
|
|
265
292
|
}}>
|
|
@@ -330,12 +357,9 @@ const DrawerNavigatorProvider = ({ navigation, route, children }: { navigation:
|
|
|
330
357
|
};
|
|
331
358
|
|
|
332
359
|
if (params.replace) {
|
|
333
|
-
// Use
|
|
360
|
+
// Use StackActions.replace to replace the current screen in the stack
|
|
334
361
|
navigation.dispatch(
|
|
335
|
-
|
|
336
|
-
index: 0,
|
|
337
|
-
routes: [{ name: parsed.routeName, params: navigationParams }],
|
|
338
|
-
})
|
|
362
|
+
StackActions.replace(parsed.routeName, navigationParams)
|
|
339
363
|
);
|
|
340
364
|
} else {
|
|
341
365
|
// Navigate to the pattern route with extracted parameters
|
|
@@ -343,6 +367,30 @@ const DrawerNavigatorProvider = ({ navigation, route, children }: { navigation:
|
|
|
343
367
|
}
|
|
344
368
|
};
|
|
345
369
|
|
|
370
|
+
const replace = (params: Omit<NavigateParams, 'replace'>) => {
|
|
371
|
+
// Normalize path and substitute variables
|
|
372
|
+
const normalizedPath = normalizePath(params.path, params.vars);
|
|
373
|
+
|
|
374
|
+
// Parse parameterized path for mobile
|
|
375
|
+
const parsed = parseParameterizedPath(normalizedPath, route);
|
|
376
|
+
|
|
377
|
+
if (!parsed) {
|
|
378
|
+
console.warn(`Navigation: Cannot replace to invalid route "${normalizedPath}".`);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Merge route params with navigation state
|
|
383
|
+
const navigationParams = {
|
|
384
|
+
...parsed.params,
|
|
385
|
+
...(params.state || {}),
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// Use StackActions.replace to replace the current screen
|
|
389
|
+
navigation.dispatch(
|
|
390
|
+
StackActions.replace(parsed.routeName, navigationParams)
|
|
391
|
+
);
|
|
392
|
+
};
|
|
393
|
+
|
|
346
394
|
const canGoBack = () => navigation.canGoBack();
|
|
347
395
|
|
|
348
396
|
const goBack = () => {
|
|
@@ -352,7 +400,7 @@ const DrawerNavigatorProvider = ({ navigation, route, children }: { navigation:
|
|
|
352
400
|
};
|
|
353
401
|
|
|
354
402
|
return (
|
|
355
|
-
<DrawerNavigatorContext.Provider value={{ navigate, route, canGoBack, goBack }}>
|
|
403
|
+
<DrawerNavigatorContext.Provider value={{ navigate, replace, route, canGoBack, goBack }}>
|
|
356
404
|
{children}
|
|
357
405
|
</DrawerNavigatorContext.Provider>
|
|
358
406
|
);
|
|
@@ -5,6 +5,7 @@ import { buildNavigator, NavigatorParam } from '../routing';
|
|
|
5
5
|
|
|
6
6
|
const NavigatorContext = createContext<NavigatorContextValue>({
|
|
7
7
|
navigate: () => {},
|
|
8
|
+
replace: () => {},
|
|
8
9
|
route: undefined,
|
|
9
10
|
canGoBack: () => false,
|
|
10
11
|
goBack: () => {},
|
|
@@ -278,10 +279,16 @@ export const NavigatorProvider = ({
|
|
|
278
279
|
}
|
|
279
280
|
};
|
|
280
281
|
|
|
282
|
+
const replace = (params: Omit<NavigateParams, 'replace'>) => {
|
|
283
|
+
// On web, replace just delegates to navigate (no special handling needed)
|
|
284
|
+
navigateFunction(params);
|
|
285
|
+
};
|
|
286
|
+
|
|
281
287
|
return (
|
|
282
288
|
<NavigatorContext.Provider value={{
|
|
283
289
|
route,
|
|
284
290
|
navigate: navigateFunction,
|
|
291
|
+
replace,
|
|
285
292
|
canGoBack,
|
|
286
293
|
goBack,
|
|
287
294
|
}}>
|
package/src/context/types.ts
CHANGED
|
@@ -34,6 +34,13 @@ export type NavigatorProviderProps = {
|
|
|
34
34
|
export type NavigatorContextValue = {
|
|
35
35
|
route: NavigatorParam | undefined;
|
|
36
36
|
navigate: (params: NavigateParams) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Replace the current screen with a new one. The current screen unmounts
|
|
39
|
+
* and the new screen takes its place in the navigation stack.
|
|
40
|
+
* On native, this uses StackActions.replace() to swap the current screen.
|
|
41
|
+
* On web, this behaves the same as navigate (no special handling needed).
|
|
42
|
+
*/
|
|
43
|
+
replace: (params: Omit<NavigateParams, 'replace'>) => void;
|
|
37
44
|
/**
|
|
38
45
|
* Returns true if there is a parent route in the route hierarchy to navigate back to.
|
|
39
46
|
* On web, this checks for parent routes (not browser history).
|
|
@@ -2,6 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { AvatarExamples, BadgeExamples, ButtonExamples, CardExamples, CheckboxExamples, DialogExamples, DividerExamples, IconExamples, InputExamples, LinkExamples, PopoverExamples, ScreenExamples, SelectExamples, SliderExamples, SVGImageExamples, TextExamples, ViewExamples, ThemeExtensionExamples, SwitchExamples, RadioButtonExamples, ProgressExamples, TextAreaExamples, TabBarExamples, TooltipExamples, AccordionExamples, ListExamples, TableExamples, MenuExamples, ImageExamples, VideoExamples, AlertExamples, SkeletonExamples, ChipExamples, BreadcrumbExamples } from '@idealyst/components/examples';
|
|
3
3
|
import { DataGridShowcase } from '@idealyst/datagrid/examples';
|
|
4
4
|
import { DatePickerExamples } from '@idealyst/datepicker/examples';
|
|
5
|
+
import { CameraExamples } from '@idealyst/camera/examples';
|
|
6
|
+
import { MicrophoneExamples } from '@idealyst/microphone/examples';
|
|
5
7
|
import { Text, View, Card, Screen, Icon, Button } from '@idealyst/components';
|
|
6
8
|
import { NavigatorParam, RouteParam, NotFoundComponentProps } from '../routing';
|
|
7
9
|
import { ExampleWebLayout } from './ExampleWebLayout';
|
|
@@ -329,6 +331,8 @@ const ExampleNavigationRouter: NavigatorParam = {
|
|
|
329
331
|
{ path: "breadcrumb", type: 'screen', component: BreadcrumbExamples, options: { title: "Breadcrumb" } },
|
|
330
332
|
{ path: "image", type: 'screen', component: ImageExamples, options: { title: "Image" } },
|
|
331
333
|
{ path: "video", type: 'screen', component: VideoExamples, options: { title: "Video" } },
|
|
334
|
+
{ path: "camera", type: 'screen', component: CameraExamples, options: { title: "Camera" } },
|
|
335
|
+
{ path: "microphone", type: 'screen', component: MicrophoneExamples, options: { title: "Microphone" } },
|
|
332
336
|
{ path: "datagrid", type: 'screen', component: DataGridShowcase, options: { title: "Data Grid" } },
|
|
333
337
|
{ path: "datepicker", type: 'screen', component: DatePickerExamples, options: { title: "Date Picker" } },
|
|
334
338
|
{ path: "theme-extension", type: 'screen', component: ThemeExtensionExamples, options: { title: "Theme Extension" } },
|
|
@@ -77,6 +77,8 @@ const componentGroups: ComponentGroup[] = [
|
|
|
77
77
|
{ label: 'Image', path: '/image', icon: 'image' },
|
|
78
78
|
{ label: 'SVG Image', path: '/svg-image', icon: 'image' },
|
|
79
79
|
{ label: 'Video', path: '/video', icon: 'video' },
|
|
80
|
+
{ label: 'Camera', path: '/camera', icon: 'camera' },
|
|
81
|
+
{ label: 'Microphone', path: '/microphone', icon: 'microphone' },
|
|
80
82
|
],
|
|
81
83
|
},
|
|
82
84
|
{
|
|
@@ -91,6 +93,7 @@ const componentGroups: ComponentGroup[] = [
|
|
|
91
93
|
title: 'Theme',
|
|
92
94
|
items: [
|
|
93
95
|
{ label: 'Theme Extension', path: '/theme-extension', icon: 'palette' },
|
|
96
|
+
{ label: 'StyleBuilder Test', path: '/stylebuilder-test', icon: 'test-tube' },
|
|
94
97
|
],
|
|
95
98
|
},
|
|
96
99
|
];
|
|
@@ -13,10 +13,11 @@ export const ExampleWebLayout: React.FC = () => {
|
|
|
13
13
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
|
14
14
|
const [showSearch, setShowSearch] = useState(false);
|
|
15
15
|
const currentTheme = UnistylesRuntime.themeName || 'light';
|
|
16
|
-
const { theme } = useUnistyles();
|
|
17
16
|
|
|
17
|
+
const { theme } = useUnistyles();
|
|
18
|
+
|
|
18
19
|
const cycleTheme = () => {
|
|
19
|
-
const nextTheme =
|
|
20
|
+
const nextTheme = UnistylesRuntime.themeName === 'light' ? 'dark' : 'light';
|
|
20
21
|
UnistylesRuntime.setTheme(nextTheme as any);
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -4,13 +4,14 @@ import { UnistylesRuntime } from 'react-native-unistyles';
|
|
|
4
4
|
import ExampleSearchDialog from './ExampleSearchDialog';
|
|
5
5
|
|
|
6
6
|
export default function HeaderRight() {
|
|
7
|
-
const [isDark, setIsDark] = useState(false);
|
|
7
|
+
// const [isDark, setIsDark] = useState(false);
|
|
8
8
|
const [showDialog, setShowDialog] = useState(false);
|
|
9
|
+
const isDark = false
|
|
9
10
|
|
|
10
11
|
const toggleTheme = () => {
|
|
11
|
-
const newTheme =
|
|
12
|
+
const newTheme = UnistylesRuntime.themeName === 'light' ? 'dark' : 'light';
|
|
12
13
|
UnistylesRuntime.setTheme(newTheme);
|
|
13
|
-
setIsDark(!isDark);
|
|
14
|
+
// setIsDark(!isDark);
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
return (
|
|
@@ -7,73 +7,7 @@ import { createDrawerNavigator } from "@react-navigation/drawer";
|
|
|
7
7
|
import { DrawerContentWrapper } from './DrawerContentWrapper.native';
|
|
8
8
|
import { HeaderWrapper } from './HeaderWrapper.native';
|
|
9
9
|
import React from 'react';
|
|
10
|
-
import { useUnistyles } from 'react-native-unistyles';
|
|
11
|
-
import { useIsFocused } from '@react-navigation/native';
|
|
12
10
|
|
|
13
|
-
/**
|
|
14
|
-
* Wrapper that makes screen components reactive to theme changes
|
|
15
|
-
* Only updates when the screen is focused
|
|
16
|
-
*/
|
|
17
|
-
const ThemeAwareScreenWrapper: React.FC<{
|
|
18
|
-
Component: React.ComponentType<any>;
|
|
19
|
-
[key: string]: any;
|
|
20
|
-
}> = ({ Component, ...props }) => {
|
|
21
|
-
const isFocused = useIsFocused();
|
|
22
|
-
|
|
23
|
-
// Force update mechanism
|
|
24
|
-
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
|
25
|
-
|
|
26
|
-
// Subscribe to theme changes
|
|
27
|
-
const { rt } = useUnistyles();
|
|
28
|
-
|
|
29
|
-
// Force re-render when theme changes (only when focused)
|
|
30
|
-
React.useEffect(() => {
|
|
31
|
-
if (isFocused) {
|
|
32
|
-
console.log('[ThemeAwareScreenWrapper] Theme changed, forcing update. New theme:', rt.themeName);
|
|
33
|
-
forceUpdate();
|
|
34
|
-
}
|
|
35
|
-
}, [rt.themeName, isFocused]);
|
|
36
|
-
|
|
37
|
-
// Log when component renders
|
|
38
|
-
React.useEffect(() => {
|
|
39
|
-
if (isFocused) {
|
|
40
|
-
console.log('[ThemeAwareScreenWrapper] Screen rendered with theme:', rt.themeName);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Only render when focused to optimize performance
|
|
45
|
-
if (!isFocused) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return <Component {...props} />;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Cache for wrapped components to maintain stable references across renders
|
|
54
|
-
*/
|
|
55
|
-
const wrappedComponentCache = new WeakMap<React.ComponentType<any>, React.ComponentType<any>>();
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Creates a theme-aware component wrapper with a stable reference
|
|
59
|
-
* This prevents React Navigation warnings about inline components
|
|
60
|
-
*/
|
|
61
|
-
const createThemeAwareComponent = (OriginalComponent: React.ComponentType<any>) => {
|
|
62
|
-
// Check cache first to return the same wrapped component reference
|
|
63
|
-
if (wrappedComponentCache.has(OriginalComponent)) {
|
|
64
|
-
return wrappedComponentCache.get(OriginalComponent)!;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const Wrapped = React.memo((props: any) => (
|
|
68
|
-
<ThemeAwareScreenWrapper Component={OriginalComponent} {...props} />
|
|
69
|
-
));
|
|
70
|
-
Wrapped.displayName = `ThemeAware(${OriginalComponent.displayName || OriginalComponent.name || 'Component'})`;
|
|
71
|
-
|
|
72
|
-
// Store in cache for future lookups
|
|
73
|
-
wrappedComponentCache.set(OriginalComponent, Wrapped);
|
|
74
|
-
|
|
75
|
-
return Wrapped;
|
|
76
|
-
};
|
|
77
11
|
|
|
78
12
|
/**
|
|
79
13
|
* Internal screen name for 404 pages
|
|
@@ -208,7 +142,7 @@ const buildScreen = (params: RouteParam, Navigator: TypedNavigator, parentPath =
|
|
|
208
142
|
// Determine the component - wrap screens with ThemeAwareScreenWrapper
|
|
209
143
|
let component: React.ComponentType<any>;
|
|
210
144
|
if (params.type === 'screen') {
|
|
211
|
-
component =
|
|
145
|
+
component = params.component
|
|
212
146
|
} else {
|
|
213
147
|
component = buildNavigator(params, fullPath);
|
|
214
148
|
}
|