@granite-js/react-native 1.0.28 → 1.0.30
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/CHANGELOG.md +30 -0
- package/dist/router/createRoute.d.ts +30 -17
- package/dist/router/createRoute.test-d.d.ts +6 -0
- package/package.json +11 -11
- package/src/router/createRoute.test-d.ts +124 -2
- package/src/router/createRoute.ts +61 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @granite-js/react-native
|
|
2
2
|
|
|
3
|
+
## 1.0.30
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [4b2e737]
|
|
8
|
+
- @granite-js/video@1.0.30
|
|
9
|
+
- @granite-js/native@1.0.30
|
|
10
|
+
- @granite-js/blur-view@1.0.30
|
|
11
|
+
- @granite-js/jest@1.0.30
|
|
12
|
+
- @granite-js/style-utils@1.0.30
|
|
13
|
+
- @granite-js/brownfield-module@1.0.30
|
|
14
|
+
- @granite-js/cli@1.0.30
|
|
15
|
+
- @granite-js/mpack@1.0.30
|
|
16
|
+
- @granite-js/plugin-core@1.0.30
|
|
17
|
+
|
|
18
|
+
## 1.0.29
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- 1b504a1: feat(router): Route.useSetParams
|
|
23
|
+
- @granite-js/blur-view@1.0.29
|
|
24
|
+
- @granite-js/brownfield-module@1.0.29
|
|
25
|
+
- @granite-js/cli@1.0.29
|
|
26
|
+
- @granite-js/jest@1.0.29
|
|
27
|
+
- @granite-js/mpack@1.0.29
|
|
28
|
+
- @granite-js/native@1.0.29
|
|
29
|
+
- @granite-js/plugin-core@1.0.29
|
|
30
|
+
- @granite-js/style-utils@1.0.29
|
|
31
|
+
- @granite-js/video@1.0.29
|
|
32
|
+
|
|
3
33
|
## 1.0.28
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -18,10 +18,10 @@ export interface RegisterScreenInput {
|
|
|
18
18
|
export interface RegisterScreen {
|
|
19
19
|
}
|
|
20
20
|
type RegisteredParamList = keyof RegisterScreenInput extends never ? ParamListBase : RegisterScreenInput;
|
|
21
|
-
type
|
|
22
|
-
export type NavigationProps = Omit<NativeStackNavigationProp<ParamListBase>, keyof NavigationParamsHelpers> & NavigationParamsHelpers;
|
|
21
|
+
export type NavigationProps = NativeStackNavigationProp<RegisteredParamList>;
|
|
23
22
|
export declare function useNavigation(): NavigationProps;
|
|
24
|
-
|
|
23
|
+
type RouteHookScreen = keyof RegisterScreenInput | keyof RegisterScreen;
|
|
24
|
+
export type RouteHooksOptions<TScreen extends RouteHookScreen> = {
|
|
25
25
|
from: TScreen;
|
|
26
26
|
strict?: true;
|
|
27
27
|
} | {
|
|
@@ -36,7 +36,7 @@ export declare const routeMap: Map<keyof RegisterScreenInput, {
|
|
|
36
36
|
params: any;
|
|
37
37
|
}) => NativeStackNavigationOptions);
|
|
38
38
|
}>;
|
|
39
|
-
export declare function useMatchOptions<TScreen extends
|
|
39
|
+
export declare function useMatchOptions<TScreen extends RouteHookScreen>(options: RouteHooksOptions<TScreen>): {
|
|
40
40
|
parserParams: ((params: Record<string, unknown>) => Record<string, unknown>) | typeof defaultParserParams;
|
|
41
41
|
validateParams?: StandardSchemaV1<any, any> | ((params: Readonly<object | undefined>) => any) | undefined;
|
|
42
42
|
} | null;
|
|
@@ -47,20 +47,33 @@ export declare function useParams<TScreen extends keyof RegisterScreen>(options:
|
|
|
47
47
|
export declare function useParams(options: {
|
|
48
48
|
strict: false;
|
|
49
49
|
}): Readonly<object | undefined>;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
type SetParamsFunction<TParams> = (params: TParams extends undefined ? undefined : Partial<TParams>) => void;
|
|
51
|
+
type ReplaceParamsFunction<TParams> = (params: TParams extends undefined ? undefined : TParams) => void;
|
|
52
|
+
type CreatedRoute<TInput, TOutput> = {
|
|
53
53
|
_path: keyof RegisterScreenInput;
|
|
54
54
|
useNavigation: typeof useNavigation;
|
|
55
|
-
useParams: () =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
_path: keyof RegisterScreenInput;
|
|
61
|
-
useNavigation: typeof useNavigation;
|
|
62
|
-
useParams: () => T;
|
|
63
|
-
_inputType: T;
|
|
64
|
-
_outputType: T;
|
|
55
|
+
useParams: () => TOutput;
|
|
56
|
+
useSetParams: () => SetParamsFunction<TInput>;
|
|
57
|
+
useReplaceParams: () => ReplaceParamsFunction<TInput>;
|
|
58
|
+
_inputType: TInput;
|
|
59
|
+
_outputType: TOutput;
|
|
65
60
|
};
|
|
61
|
+
export declare function useSetParams<TScreen extends keyof RegisterScreenInput>(options: {
|
|
62
|
+
from: TScreen;
|
|
63
|
+
strict?: true;
|
|
64
|
+
}): SetParamsFunction<RegisterScreenInput[TScreen]>;
|
|
65
|
+
export declare function useSetParams(options: {
|
|
66
|
+
strict: false;
|
|
67
|
+
}): SetParamsFunction<Readonly<object | undefined>>;
|
|
68
|
+
export declare function useReplaceParams<TScreen extends keyof RegisterScreenInput>(options: {
|
|
69
|
+
from: TScreen;
|
|
70
|
+
strict?: true;
|
|
71
|
+
}): ReplaceParamsFunction<RegisterScreenInput[TScreen]>;
|
|
72
|
+
export declare function useReplaceParams(options: {
|
|
73
|
+
strict: false;
|
|
74
|
+
}): ReplaceParamsFunction<Readonly<object | undefined>>;
|
|
75
|
+
export declare function createRoute<TSchema extends StandardSchemaV1<any, any>>(path: keyof RegisterScreenInput, options: Omit<RouteOptions<any>, 'validateParams'> & {
|
|
76
|
+
validateParams: TSchema;
|
|
77
|
+
}): CreatedRoute<InferInput<TSchema>, InferOutput<TSchema>>;
|
|
78
|
+
export declare function createRoute<T extends Readonly<object | undefined>>(path: keyof RegisterScreenInput, options: RouteOptions<T>): CreatedRoute<T, T>;
|
|
66
79
|
export {};
|
|
@@ -14,6 +14,9 @@ declare module './createRoute' {
|
|
|
14
14
|
'/test-with-defaults': {
|
|
15
15
|
animation?: boolean;
|
|
16
16
|
};
|
|
17
|
+
'/test-optional': {
|
|
18
|
+
uri?: string;
|
|
19
|
+
};
|
|
17
20
|
}
|
|
18
21
|
interface RegisterScreen {
|
|
19
22
|
'/test': {
|
|
@@ -30,6 +33,9 @@ declare module './createRoute' {
|
|
|
30
33
|
'/test-with-defaults': {
|
|
31
34
|
animation: boolean;
|
|
32
35
|
};
|
|
36
|
+
'/test-optional': {
|
|
37
|
+
uri?: string;
|
|
38
|
+
};
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@granite-js/react-native",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"description": "The Granite Framework",
|
|
5
5
|
"bin": {
|
|
6
6
|
"granite": "./bin/cli.js"
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"@babel/core": "7.28.5",
|
|
92
92
|
"@babel/preset-env": "7.28.5",
|
|
93
93
|
"@babel/preset-typescript": "7.28.5",
|
|
94
|
-
"@granite-js/native": "1.0.
|
|
94
|
+
"@granite-js/native": "1.0.30",
|
|
95
95
|
"@testing-library/dom": "^10.4.0",
|
|
96
96
|
"@testing-library/react": "^16.1.0",
|
|
97
97
|
"@types/babel__core": "^7",
|
|
@@ -113,21 +113,21 @@
|
|
|
113
113
|
"zod": "^4.1.12"
|
|
114
114
|
},
|
|
115
115
|
"peerDependencies": {
|
|
116
|
-
"@granite-js/native": "1.0.
|
|
116
|
+
"@granite-js/native": "1.0.30",
|
|
117
117
|
"@types/react": "*",
|
|
118
118
|
"brick-module": "*",
|
|
119
119
|
"react": "*",
|
|
120
120
|
"react-native": "*"
|
|
121
121
|
},
|
|
122
122
|
"dependencies": {
|
|
123
|
-
"@granite-js/blur-view": "1.0.
|
|
124
|
-
"@granite-js/brownfield-module": "1.0.
|
|
125
|
-
"@granite-js/cli": "1.0.
|
|
126
|
-
"@granite-js/jest": "1.0.
|
|
127
|
-
"@granite-js/mpack": "1.0.
|
|
128
|
-
"@granite-js/plugin-core": "1.0.
|
|
129
|
-
"@granite-js/style-utils": "1.0.
|
|
130
|
-
"@granite-js/video": "1.0.
|
|
123
|
+
"@granite-js/blur-view": "1.0.30",
|
|
124
|
+
"@granite-js/brownfield-module": "1.0.30",
|
|
125
|
+
"@granite-js/cli": "1.0.30",
|
|
126
|
+
"@granite-js/jest": "1.0.30",
|
|
127
|
+
"@granite-js/mpack": "1.0.30",
|
|
128
|
+
"@granite-js/plugin-core": "1.0.30",
|
|
129
|
+
"@granite-js/style-utils": "1.0.30",
|
|
130
|
+
"@granite-js/video": "1.0.30",
|
|
131
131
|
"@standard-schema/spec": "^1.0.0",
|
|
132
132
|
"es-toolkit": "^1.39.8",
|
|
133
133
|
"react-native-url-polyfill": "3.0.0"
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { assertType, describe, it } from 'vitest';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createRoute,
|
|
5
|
+
useNavigation,
|
|
6
|
+
useParams,
|
|
7
|
+
useReplaceParams,
|
|
8
|
+
useSetParams,
|
|
9
|
+
} from './createRoute';
|
|
4
10
|
|
|
5
11
|
declare module './createRoute' {
|
|
6
12
|
interface RegisterScreenInput {
|
|
@@ -18,6 +24,9 @@ declare module './createRoute' {
|
|
|
18
24
|
'/test-with-defaults': {
|
|
19
25
|
animation?: boolean;
|
|
20
26
|
};
|
|
27
|
+
'/test-optional': {
|
|
28
|
+
uri?: string;
|
|
29
|
+
};
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
interface RegisterScreen {
|
|
@@ -35,6 +44,9 @@ declare module './createRoute' {
|
|
|
35
44
|
'/test-with-defaults': {
|
|
36
45
|
animation: boolean;
|
|
37
46
|
};
|
|
47
|
+
'/test-optional': {
|
|
48
|
+
uri?: string;
|
|
49
|
+
};
|
|
38
50
|
}
|
|
39
51
|
}
|
|
40
52
|
|
|
@@ -78,6 +90,52 @@ describe('createRoute', () => {
|
|
|
78
90
|
assertType(useParams({ from: '/test', strict: false }));
|
|
79
91
|
});
|
|
80
92
|
|
|
93
|
+
it('useSetParams and useReplaceParams', () => {
|
|
94
|
+
const setRouteParams = Route.useSetParams();
|
|
95
|
+
|
|
96
|
+
assertType<(params: Partial<{ id: string; name: string }>) => void>(setRouteParams);
|
|
97
|
+
setRouteParams({ id: 'test-id' });
|
|
98
|
+
setRouteParams({ name: 'test-name' });
|
|
99
|
+
|
|
100
|
+
// @ts-expect-error Type error should occur when param type is invalid
|
|
101
|
+
setRouteParams({ id: 123 });
|
|
102
|
+
|
|
103
|
+
// @ts-expect-error Type error should occur when param key is invalid
|
|
104
|
+
setRouteParams({ count: 123 });
|
|
105
|
+
|
|
106
|
+
const setParams = useSetParams({ from: '/test' });
|
|
107
|
+
setParams({ id: 'test-id' });
|
|
108
|
+
|
|
109
|
+
// @ts-expect-error Type error should occur when path is not registered
|
|
110
|
+
assertType(useSetParams({ from: '/abcdefg' }));
|
|
111
|
+
|
|
112
|
+
// @ts-expect-error Type error should occur since 'from' and 'strict: false' are conflicting options
|
|
113
|
+
assertType(useSetParams({ from: '/test', strict: false }));
|
|
114
|
+
|
|
115
|
+
const replaceRouteParams = Route.useReplaceParams();
|
|
116
|
+
|
|
117
|
+
assertType<(params: { id: string; name: string }) => void>(replaceRouteParams);
|
|
118
|
+
replaceRouteParams({ id: 'test-id', name: 'test-name' });
|
|
119
|
+
|
|
120
|
+
// @ts-expect-error Type error should occur when required params are missing
|
|
121
|
+
replaceRouteParams({ id: 'test-id' });
|
|
122
|
+
|
|
123
|
+
// @ts-expect-error Type error should occur when param type is invalid
|
|
124
|
+
replaceRouteParams({ id: 123, name: 'test-name' });
|
|
125
|
+
|
|
126
|
+
// @ts-expect-error Type error should occur when param key is invalid
|
|
127
|
+
replaceRouteParams({ id: 'test-id', name: 'test-name', count: 123 });
|
|
128
|
+
|
|
129
|
+
const replaceParams = useReplaceParams({ from: '/test' });
|
|
130
|
+
replaceParams({ id: 'test-id', name: 'test-name' });
|
|
131
|
+
|
|
132
|
+
// @ts-expect-error Type error should occur when path is not registered
|
|
133
|
+
assertType(useReplaceParams({ from: '/abcdefg' }));
|
|
134
|
+
|
|
135
|
+
// @ts-expect-error Type error should occur since 'from' and 'strict: false' are conflicting options
|
|
136
|
+
assertType(useReplaceParams({ from: '/test', strict: false }));
|
|
137
|
+
});
|
|
138
|
+
|
|
81
139
|
it('should infer _inputType and _outputType without undefined for function pattern', () => {
|
|
82
140
|
type InputType = (typeof Route)['_inputType'];
|
|
83
141
|
type OutputType = (typeof Route)['_outputType'];
|
|
@@ -165,10 +223,48 @@ describe('createRoute with StandardSchema', () => {
|
|
|
165
223
|
|
|
166
224
|
// Should accept exact input type
|
|
167
225
|
navigation.navigate('/test-schema', { id: 'test', count: 123 });
|
|
226
|
+
|
|
227
|
+
// @ts-expect-error Type error should occur when a required params object is missing
|
|
228
|
+
navigation.navigate('/test-schema');
|
|
229
|
+
|
|
230
|
+
// @ts-expect-error Type error should occur when navigate param type is invalid
|
|
231
|
+
navigation.navigate('/test-schema', { id: 'test', count: 'invalid' });
|
|
232
|
+
|
|
233
|
+
// @ts-expect-error Type error should occur when navigating to an unregistered path
|
|
234
|
+
navigation.navigate('/abcdefg');
|
|
235
|
+
|
|
236
|
+
navigation.navigate('/test-optional', {});
|
|
237
|
+
navigation.navigate('/test-optional', { uri: 'test-uri' });
|
|
238
|
+
|
|
239
|
+
// @ts-expect-error Type error should occur when navigate params include an unknown key
|
|
240
|
+
navigation.navigate('/test-optional', { name: '123' });
|
|
241
|
+
|
|
242
|
+
navigation.popTo('/test-optional', { uri: 'test-uri' });
|
|
243
|
+
|
|
244
|
+
// @ts-expect-error popTo should already reject unknown param keys
|
|
245
|
+
navigation.popTo('/test-optional', { name: '123' });
|
|
246
|
+
|
|
247
|
+
navigation.push('/test-optional', { uri: 'test-uri' });
|
|
248
|
+
|
|
249
|
+
// @ts-expect-error push should reject unknown param keys
|
|
250
|
+
navigation.push('/test-optional', { name: '123' });
|
|
251
|
+
|
|
252
|
+
navigation.replace('/test-optional', { uri: 'test-uri' });
|
|
253
|
+
|
|
254
|
+
// @ts-expect-error replace should reject unknown param keys
|
|
255
|
+
navigation.replace('/test-optional', { name: '123' });
|
|
256
|
+
|
|
257
|
+
// @ts-expect-error push should require params for required route params
|
|
258
|
+
navigation.push('/test-schema');
|
|
259
|
+
|
|
260
|
+
// @ts-expect-error replace should require params for required route params
|
|
261
|
+
navigation.replace('/test-schema');
|
|
262
|
+
|
|
263
|
+
// @ts-expect-error popTo should require params for required route params
|
|
264
|
+
navigation.popTo('/test-schema');
|
|
168
265
|
});
|
|
169
266
|
|
|
170
267
|
it('should infer output type from transformation', () => {
|
|
171
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
172
268
|
const RouteWithTransform = createRoute('/test-transform', {
|
|
173
269
|
component: () => null,
|
|
174
270
|
validateParams: z.object({
|
|
@@ -199,6 +295,24 @@ describe('createRoute with StandardSchema', () => {
|
|
|
199
295
|
const navigation = useNavigation();
|
|
200
296
|
navigation.navigate('/test-transform', { id: 'test-id' });
|
|
201
297
|
|
|
298
|
+
const setParams = RouteWithTransform.useSetParams();
|
|
299
|
+
setParams({ id: 'test-id' });
|
|
300
|
+
|
|
301
|
+
// @ts-expect-error setParams should accept input type, not output type
|
|
302
|
+
setParams({ id: 123 });
|
|
303
|
+
|
|
304
|
+
const setParamsFromHook = useSetParams({ from: '/test-transform' });
|
|
305
|
+
setParamsFromHook({ id: 'test-id' });
|
|
306
|
+
|
|
307
|
+
// @ts-expect-error useSetParams should accept input type, not output type
|
|
308
|
+
setParamsFromHook({ id: 123 });
|
|
309
|
+
|
|
310
|
+
const replaceParams = RouteWithTransform.useReplaceParams();
|
|
311
|
+
replaceParams({ id: 'test-id' });
|
|
312
|
+
|
|
313
|
+
// @ts-expect-error useReplaceParams should accept input type, not output type
|
|
314
|
+
replaceParams({ id: 123 });
|
|
315
|
+
|
|
202
316
|
// Verify that input and output types are different
|
|
203
317
|
type InputIsString = InputType extends { id: string } ? true : false;
|
|
204
318
|
type OutputIsNumber = OutputType extends { id: number } ? true : false;
|
|
@@ -241,5 +355,13 @@ describe('createRoute with StandardSchema', () => {
|
|
|
241
355
|
|
|
242
356
|
// Should accept without animation parameter (default will be used)
|
|
243
357
|
navigation.navigate('/test-with-defaults', {});
|
|
358
|
+
|
|
359
|
+
const setParams = RouteWithDefaults.useSetParams();
|
|
360
|
+
setParams({});
|
|
361
|
+
setParams({ animation: false });
|
|
362
|
+
|
|
363
|
+
const replaceParams = RouteWithDefaults.useReplaceParams();
|
|
364
|
+
replaceParams({});
|
|
365
|
+
replaceParams({ animation: false });
|
|
244
366
|
});
|
|
245
367
|
});
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
NativeStackNavigationProp,
|
|
9
9
|
} from '@granite-js/native/@react-navigation/native-stack';
|
|
10
10
|
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
11
|
-
import { useMemo } from 'react';
|
|
11
|
+
import { useCallback, useMemo } from 'react';
|
|
12
12
|
import { RESERVED_PATHS } from './constants';
|
|
13
13
|
import type { ErrorComponent } from './types';
|
|
14
14
|
import { defaultParserParams } from './utils/defaultParserParams';
|
|
@@ -31,20 +31,18 @@ export interface RegisterScreen {}
|
|
|
31
31
|
|
|
32
32
|
type RegisteredParamList = keyof RegisterScreenInput extends never ? ParamListBase : RegisterScreenInput;
|
|
33
33
|
|
|
34
|
-
type
|
|
34
|
+
export type NavigationProps = NativeStackNavigationProp<
|
|
35
35
|
// @ts-expect-error - override type
|
|
36
|
-
|
|
37
|
-
'replaceParams' | 'setParams'
|
|
36
|
+
RegisteredParamList
|
|
38
37
|
>;
|
|
39
38
|
|
|
40
|
-
export type NavigationProps = Omit<NativeStackNavigationProp<ParamListBase>, keyof NavigationParamsHelpers> &
|
|
41
|
-
NavigationParamsHelpers;
|
|
42
|
-
|
|
43
39
|
export function useNavigation() {
|
|
44
40
|
return useNavigationNative<NavigationProps>();
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
type RouteHookScreen = keyof RegisterScreenInput | keyof RegisterScreen;
|
|
44
|
+
|
|
45
|
+
export type RouteHooksOptions<TScreen extends RouteHookScreen> =
|
|
48
46
|
| {
|
|
49
47
|
from: TScreen;
|
|
50
48
|
strict?: true;
|
|
@@ -64,7 +62,7 @@ export const routeMap = new Map<
|
|
|
64
62
|
}
|
|
65
63
|
>();
|
|
66
64
|
|
|
67
|
-
export function useMatchOptions<TScreen extends
|
|
65
|
+
export function useMatchOptions<TScreen extends RouteHookScreen>(options: RouteHooksOptions<TScreen>) {
|
|
68
66
|
const route = useRoute();
|
|
69
67
|
const from = 'from' in options ? options.from : (route.name as TScreen);
|
|
70
68
|
const strict = 'from' in options ? true : options.strict;
|
|
@@ -78,11 +76,11 @@ export function useMatchOptions<TScreen extends keyof RegisterScreen>(options: R
|
|
|
78
76
|
return null;
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
if (!(routeMap.has(from) || RESERVED_PATHS.includes(from))) {
|
|
79
|
+
if (!(routeMap.has(from as keyof RegisterScreenInput) || RESERVED_PATHS.includes(from as string))) {
|
|
82
80
|
throw new Error(`Route '${from}' is not registered`);
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
const routeOptions = routeMap.get(from);
|
|
83
|
+
const routeOptions = routeMap.get(from as keyof RegisterScreenInput);
|
|
86
84
|
return {
|
|
87
85
|
...routeOptions?.options,
|
|
88
86
|
parserParams: routeOptions?.options.parserParams ?? defaultParserParams,
|
|
@@ -174,34 +172,69 @@ export function useParams<TScreen extends keyof RegisterScreen>(
|
|
|
174
172
|
return params;
|
|
175
173
|
}
|
|
176
174
|
|
|
175
|
+
type SetParamsFunction<TParams> = (params: TParams extends undefined ? undefined : Partial<TParams>) => void;
|
|
176
|
+
type ReplaceParamsFunction<TParams> = (params: TParams extends undefined ? undefined : TParams) => void;
|
|
177
|
+
|
|
178
|
+
type CreatedRoute<TInput, TOutput> = {
|
|
179
|
+
_path: keyof RegisterScreenInput;
|
|
180
|
+
useNavigation: typeof useNavigation;
|
|
181
|
+
useParams: () => TOutput;
|
|
182
|
+
useSetParams: () => SetParamsFunction<TInput>;
|
|
183
|
+
useReplaceParams: () => ReplaceParamsFunction<TInput>;
|
|
184
|
+
_inputType: TInput;
|
|
185
|
+
_outputType: TOutput;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export function useSetParams<TScreen extends keyof RegisterScreenInput>(options: {
|
|
189
|
+
from: TScreen;
|
|
190
|
+
strict?: true;
|
|
191
|
+
}): SetParamsFunction<RegisterScreenInput[TScreen]>;
|
|
192
|
+
export function useSetParams(options: { strict: false }): SetParamsFunction<Readonly<object | undefined>>;
|
|
193
|
+
|
|
194
|
+
export function useSetParams<TScreen extends keyof RegisterScreenInput>(
|
|
195
|
+
options: RouteHooksOptions<TScreen>
|
|
196
|
+
): SetParamsFunction<RegisterScreenInput[TScreen]> | SetParamsFunction<Readonly<object | undefined>> {
|
|
197
|
+
useMatchOptions(options);
|
|
198
|
+
const navigation = useNavigationNative<NativeStackNavigationProp<ParamListBase>>();
|
|
199
|
+
|
|
200
|
+
return useCallback((params: never) => navigation.setParams(params), [navigation]) as
|
|
201
|
+
| SetParamsFunction<RegisterScreenInput[TScreen]>
|
|
202
|
+
| SetParamsFunction<Readonly<object | undefined>>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function useReplaceParams<TScreen extends keyof RegisterScreenInput>(options: {
|
|
206
|
+
from: TScreen;
|
|
207
|
+
strict?: true;
|
|
208
|
+
}): ReplaceParamsFunction<RegisterScreenInput[TScreen]>;
|
|
209
|
+
export function useReplaceParams(options: { strict: false }): ReplaceParamsFunction<Readonly<object | undefined>>;
|
|
210
|
+
|
|
211
|
+
export function useReplaceParams<TScreen extends keyof RegisterScreenInput>(
|
|
212
|
+
options: RouteHooksOptions<TScreen>
|
|
213
|
+
): ReplaceParamsFunction<RegisterScreenInput[TScreen]> | ReplaceParamsFunction<Readonly<object | undefined>> {
|
|
214
|
+
useMatchOptions(options);
|
|
215
|
+
const navigation = useNavigationNative<NativeStackNavigationProp<ParamListBase>>();
|
|
216
|
+
|
|
217
|
+
return useCallback((params: never) => navigation.replaceParams(params), [navigation]) as
|
|
218
|
+
| ReplaceParamsFunction<RegisterScreenInput[TScreen]>
|
|
219
|
+
| ReplaceParamsFunction<Readonly<object | undefined>>;
|
|
220
|
+
}
|
|
221
|
+
|
|
177
222
|
// Overload 1: StandardSchema pattern
|
|
178
223
|
export function createRoute<TSchema extends StandardSchemaV1<any, any>>(
|
|
179
224
|
path: keyof RegisterScreenInput,
|
|
180
225
|
options: Omit<RouteOptions<any>, 'validateParams'> & {
|
|
181
226
|
validateParams: TSchema;
|
|
182
227
|
}
|
|
183
|
-
):
|
|
184
|
-
_path: keyof RegisterScreenInput;
|
|
185
|
-
useNavigation: typeof useNavigation;
|
|
186
|
-
useParams: () => InferOutput<TSchema>;
|
|
187
|
-
_inputType: InferInput<TSchema>;
|
|
188
|
-
_outputType: InferOutput<TSchema>;
|
|
189
|
-
};
|
|
228
|
+
): CreatedRoute<InferInput<TSchema>, InferOutput<TSchema>>;
|
|
190
229
|
|
|
191
230
|
// Overload 2: Function pattern
|
|
192
231
|
export function createRoute<T extends Readonly<object | undefined>>(
|
|
193
232
|
path: keyof RegisterScreenInput,
|
|
194
233
|
options: RouteOptions<T>
|
|
195
|
-
):
|
|
196
|
-
_path: keyof RegisterScreenInput;
|
|
197
|
-
useNavigation: typeof useNavigation;
|
|
198
|
-
useParams: () => T;
|
|
199
|
-
_inputType: T;
|
|
200
|
-
_outputType: T;
|
|
201
|
-
};
|
|
234
|
+
): CreatedRoute<T, T>;
|
|
202
235
|
|
|
203
236
|
// Implementation
|
|
204
|
-
export function createRoute(path: keyof RegisterScreenInput, options: RouteOptions<any>) {
|
|
237
|
+
export function createRoute(path: keyof RegisterScreenInput, options: RouteOptions<any>): CreatedRoute<any, any> {
|
|
205
238
|
const { component, screenOptions, errorComponent, ...restOptions } = options;
|
|
206
239
|
routeMap.set(path, {
|
|
207
240
|
options: restOptions,
|
|
@@ -215,6 +248,8 @@ export function createRoute(path: keyof RegisterScreenInput, options: RouteOptio
|
|
|
215
248
|
_path,
|
|
216
249
|
useNavigation,
|
|
217
250
|
useParams: () => useParams({ from: _path as keyof RegisterScreen, strict: true }),
|
|
251
|
+
useSetParams: () => useSetParams({ from: _path, strict: true }),
|
|
252
|
+
useReplaceParams: () => useReplaceParams({ from: _path, strict: true }),
|
|
218
253
|
|
|
219
254
|
// These properties are only used for type inference in the generated router files
|
|
220
255
|
// The actual values are never accessed at runtime
|