@granite-js/react-native 0.1.31 → 0.1.33

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 CHANGED
@@ -1,5 +1,37 @@
1
1
  # @granite-js/react-native
2
2
 
3
+ ## 0.1.33
4
+
5
+ ### Patch Changes
6
+
7
+ - fdf55a6: fix(router): type infer incorrect undefined
8
+ - Updated dependencies [fdf55a6]
9
+ - @granite-js/native@0.1.33
10
+ - @granite-js/image@0.1.33
11
+ - @granite-js/jest@0.1.33
12
+ - @granite-js/lottie@0.1.33
13
+ - @granite-js/style-utils@0.1.33
14
+ - @granite-js/cli@0.1.33
15
+ - @granite-js/mpack@0.1.33
16
+ - @granite-js/plugin-core@0.1.33
17
+
18
+ ## 0.1.32
19
+
20
+ ### Patch Changes
21
+
22
+ - 74b2223: fix(react-native): VisibilityChangedProvider only provider
23
+ - 7572713: bump version up babel
24
+ - Updated dependencies [74b2223]
25
+ - Updated dependencies [7572713]
26
+ - @granite-js/native@0.1.32
27
+ - @granite-js/plugin-core@0.1.32
28
+ - @granite-js/style-utils@0.1.32
29
+ - @granite-js/image@0.1.32
30
+ - @granite-js/mpack@0.1.32
31
+ - @granite-js/cli@0.1.32
32
+ - @granite-js/jest@0.1.32
33
+ - @granite-js/lottie@0.1.32
34
+
3
35
  ## 0.1.31
4
36
 
5
37
  ### Patch Changes
@@ -48,13 +48,13 @@ export declare function createRoute<TSchema extends StandardSchemaV1<any, any>>(
48
48
  _path: keyof RegisterScreenInput;
49
49
  useNavigation: typeof useNavigation;
50
50
  useParams: () => InferOutput<TSchema>;
51
- _inputType?: InferInput<TSchema>;
52
- _outputType?: InferOutput<TSchema>;
51
+ _inputType: InferInput<TSchema>;
52
+ _outputType: InferOutput<TSchema>;
53
53
  };
54
54
  export declare function createRoute<T extends Readonly<object | undefined>>(path: keyof RegisterScreenInput, options: RouteOptions<T>): {
55
55
  _path: keyof RegisterScreenInput;
56
56
  useNavigation: typeof useNavigation;
57
57
  useParams: () => T;
58
- _inputType?: T;
59
- _outputType?: T;
58
+ _inputType: T;
59
+ _outputType: T;
60
60
  };
@@ -7,8 +7,9 @@ interface Props {
7
7
  * @name VisibilityProvider
8
8
  * @description
9
9
  * A Provider that manages whether a ReactNative view is currently in the foreground state.
10
+ * It subscribes to the app's `visibilityChanged` event to detect and manage screen visibility.
10
11
  * @param {boolean} isVisible - Whether the app is in the foreground state.
11
- * @param {ReactNode | undefined} children - Child components that observe `AppState`.
12
+ * @param {ReactNode | undefined} children - Child components that observe `visibilityChanged` and `AppState` event.
12
13
  * @returns {ReactElement} - A React Provider component wrapped with `VisibilityChangedProvider`.
13
14
  * @example
14
15
  * ```typescript
@@ -3,8 +3,7 @@ import { PropsWithChildren, ReactElement } from 'react';
3
3
  * @name VisibilityChangedProvider
4
4
  * @kind function
5
5
  * @description
6
- * A Provider that manages whether a React Native screen is visible.
7
- * It subscribes to the app's `visibilityChanged` event to detect and manage screen visibility.
6
+ * A Provider that manages whether a React Native screen is visible provider.
8
7
  *
9
8
  * @param {ReactNode | undefined} children - Child components that check screen visibility.
10
9
  * @param {boolean} isVisible - A boolean value indicating whether the screen is visible.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@granite-js/react-native",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "description": "The Granite Framework",
5
5
  "bin": {
6
6
  "granite": "./bin/cli.js"
@@ -88,10 +88,10 @@
88
88
  "*.d.ts"
89
89
  ],
90
90
  "devDependencies": {
91
- "@babel/core": "^7.24.9",
92
- "@babel/preset-env": "^7.24.8",
93
- "@babel/preset-typescript": "^7.24.7",
94
- "@granite-js/native": "0.1.31",
91
+ "@babel/core": "7.28.5",
92
+ "@babel/preset-env": "7.28.5",
93
+ "@babel/preset-typescript": "7.28.5",
94
+ "@granite-js/native": "0.1.33",
95
95
  "@testing-library/dom": "^10.4.0",
96
96
  "@testing-library/react": "^16.1.0",
97
97
  "@types/babel__core": "^7",
@@ -99,7 +99,7 @@
99
99
  "@types/node": "^22.10.2",
100
100
  "@types/react": "18.3.3",
101
101
  "@types/react-dom": "^18",
102
- "@vitest/coverage-v8": "^2.1.8",
102
+ "@vitest/coverage-v8": "^4.0.12",
103
103
  "esbuild": "0.25.8",
104
104
  "eslint": "^9.7.0",
105
105
  "jsdom": "^25.0.1",
@@ -108,7 +108,7 @@
108
108
  "react-native": "0.72.6",
109
109
  "tsup": "^8.5.0",
110
110
  "typescript": "5.8.3",
111
- "vitest": "^2.1.8",
111
+ "vitest": "^4.0.12",
112
112
  "zod": "^4.1.12"
113
113
  },
114
114
  "peerDependencies": {
@@ -118,13 +118,13 @@
118
118
  "react-native": "*"
119
119
  },
120
120
  "dependencies": {
121
- "@granite-js/cli": "0.1.31",
122
- "@granite-js/image": "0.1.31",
123
- "@granite-js/jest": "0.1.31",
124
- "@granite-js/lottie": "0.1.31",
125
- "@granite-js/mpack": "0.1.31",
126
- "@granite-js/plugin-core": "0.1.31",
127
- "@granite-js/style-utils": "0.1.31",
121
+ "@granite-js/cli": "0.1.33",
122
+ "@granite-js/image": "0.1.33",
123
+ "@granite-js/jest": "0.1.33",
124
+ "@granite-js/lottie": "0.1.33",
125
+ "@granite-js/mpack": "0.1.33",
126
+ "@granite-js/plugin-core": "0.1.33",
127
+ "@granite-js/style-utils": "0.1.33",
128
128
  "@standard-schema/spec": "^1.0.0",
129
129
  "es-toolkit": "^1.39.8",
130
130
  "react-native-url-polyfill": "3.0.0"
@@ -77,6 +77,30 @@ describe('createRoute', () => {
77
77
  // @ts-expect-error Type error should occur since 'from' and 'strict: false' are conflicting options
78
78
  assertType(useParams({ from: '/test', strict: false }));
79
79
  });
80
+
81
+ it('should infer _inputType and _outputType without undefined for function pattern', () => {
82
+ type InputType = (typeof Route)['_inputType'];
83
+ type OutputType = (typeof Route)['_outputType'];
84
+
85
+ // _inputType should be inferred as the exact type, not a union with undefined
86
+ assertType<{
87
+ id: string;
88
+ name: string;
89
+ }>({} as InputType);
90
+
91
+ // _outputType should be inferred as the exact type, not a union with undefined
92
+ assertType<{
93
+ id: string;
94
+ name: string;
95
+ }>({} as OutputType);
96
+
97
+ // Verify that undefined is not part of the union
98
+ type InputHasUndefined = undefined extends InputType ? true : false;
99
+ type OutputHasUndefined = undefined extends OutputType ? true : false;
100
+
101
+ assertType<false>({} as InputHasUndefined);
102
+ assertType<false>({} as OutputHasUndefined);
103
+ });
80
104
  });
81
105
 
82
106
  describe('createRoute with StandardSchema', () => {
@@ -95,7 +119,56 @@ describe('createRoute with StandardSchema', () => {
95
119
  }>(RouteWithSchema.useParams());
96
120
  });
97
121
 
122
+ it('should infer _inputType and _outputType without undefined', () => {
123
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
124
+ const RouteWithSchema = createRoute('/test-schema', {
125
+ component: () => null,
126
+ validateParams: z.object({
127
+ id: z.string(),
128
+ count: z.number(),
129
+ }),
130
+ });
131
+
132
+ type InputType = (typeof RouteWithSchema)['_inputType'];
133
+ type OutputType = (typeof RouteWithSchema)['_outputType'];
134
+ type UseParamsReturnType = ReturnType<(typeof RouteWithSchema)['useParams']>;
135
+
136
+ // _inputType should be inferred as the exact type, not a union with undefined
137
+ assertType<{
138
+ id: string;
139
+ count: number;
140
+ }>({} as InputType);
141
+
142
+ // _outputType should be inferred as the exact type, not a union with undefined
143
+ assertType<{
144
+ id: string;
145
+ count: number;
146
+ }>({} as OutputType);
147
+
148
+ // useParams should return the exact type, not a union with undefined
149
+ assertType<{
150
+ id: string;
151
+ count: number;
152
+ }>({} as UseParamsReturnType);
153
+
154
+ // Verify that undefined is not part of the union for all types
155
+ type InputHasUndefined = undefined extends InputType ? true : false;
156
+ type OutputHasUndefined = undefined extends OutputType ? true : false;
157
+ type UseParamsHasUndefined = undefined extends UseParamsReturnType ? true : false;
158
+
159
+ assertType<false>({} as InputHasUndefined);
160
+ assertType<false>({} as OutputHasUndefined);
161
+ assertType<false>({} as UseParamsHasUndefined);
162
+
163
+ // useNavigation should accept input type for navigate parameters
164
+ const navigation = useNavigation();
165
+
166
+ // Should accept exact input type
167
+ navigation.navigate('/test-schema', { id: 'test', count: 123 });
168
+ });
169
+
98
170
  it('should infer output type from transformation', () => {
171
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
99
172
  const RouteWithTransform = createRoute('/test-transform', {
100
173
  component: () => null,
101
174
  validateParams: z.object({
@@ -103,10 +176,35 @@ describe('createRoute with StandardSchema', () => {
103
176
  }),
104
177
  });
105
178
 
106
- // Should be number (output), not string (input)
179
+ type InputType = (typeof RouteWithTransform)['_inputType'];
180
+ type OutputType = (typeof RouteWithTransform)['_outputType'];
181
+ type UseParamsReturnType = ReturnType<(typeof RouteWithTransform)['useParams']>;
182
+
183
+ // _inputType should be string (before transformation)
184
+ assertType<{
185
+ id: string;
186
+ }>({} as InputType);
187
+
188
+ // _outputType should be number (after transformation)
189
+ assertType<{
190
+ id: number;
191
+ }>({} as OutputType);
192
+
193
+ // useParams should return output type (number)
107
194
  assertType<{
108
195
  id: number;
109
- }>(RouteWithTransform.useParams());
196
+ }>({} as UseParamsReturnType);
197
+
198
+ // useNavigation should accept input type (string)
199
+ const navigation = useNavigation();
200
+ navigation.navigate('/test-transform', { id: 'test-id' });
201
+
202
+ // Verify that input and output types are different
203
+ type InputIsString = InputType extends { id: string } ? true : false;
204
+ type OutputIsNumber = OutputType extends { id: number } ? true : false;
205
+
206
+ assertType<true>({} as InputIsString);
207
+ assertType<true>({} as OutputIsNumber);
110
208
  });
111
209
 
112
210
  it('should work with useParams hook', () => {
@@ -175,8 +175,8 @@ export function createRoute<TSchema extends StandardSchemaV1<any, any>>(
175
175
  _path: keyof RegisterScreenInput;
176
176
  useNavigation: typeof useNavigation;
177
177
  useParams: () => InferOutput<TSchema>;
178
- _inputType?: InferInput<TSchema>;
179
- _outputType?: InferOutput<TSchema>;
178
+ _inputType: InferInput<TSchema>;
179
+ _outputType: InferOutput<TSchema>;
180
180
  };
181
181
 
182
182
  // Overload 2: Function pattern
@@ -187,8 +187,8 @@ export function createRoute<T extends Readonly<object | undefined>>(
187
187
  _path: keyof RegisterScreenInput;
188
188
  useNavigation: typeof useNavigation;
189
189
  useParams: () => T;
190
- _inputType?: T;
191
- _outputType?: T;
190
+ _inputType: T;
191
+ _outputType: T;
192
192
  };
193
193
 
194
194
  // Implementation
@@ -205,5 +205,10 @@ export function createRoute(path: keyof RegisterScreenInput, options: RouteOptio
205
205
  _path,
206
206
  useNavigation,
207
207
  useParams: () => useParams({ from: _path as keyof RegisterScreen, strict: true }),
208
+
209
+ // These properties are only used for type inference in the generated router files
210
+ // The actual values are never accessed at runtime
211
+ _inputType: {},
212
+ _outputType: {},
208
213
  };
209
214
  }
@@ -1,6 +1,7 @@
1
- import { ReactElement, ReactNode } from 'react';
1
+ import { ReactElement, ReactNode, useEffect, useState } from 'react';
2
2
  import { AppStateProvider } from './useIsAppForeground';
3
3
  import { VisibilityChangedProvider } from './useVisibilityChanged';
4
+ import { nativeEventEmitter } from '../native-event-emitter/nativeEventEmitter';
4
5
 
5
6
  interface Props {
6
7
  isVisible: boolean;
@@ -11,8 +12,9 @@ interface Props {
11
12
  * @name VisibilityProvider
12
13
  * @description
13
14
  * A Provider that manages whether a ReactNative view is currently in the foreground state.
15
+ * It subscribes to the app's `visibilityChanged` event to detect and manage screen visibility.
14
16
  * @param {boolean} isVisible - Whether the app is in the foreground state.
15
- * @param {ReactNode | undefined} children - Child components that observe `AppState`.
17
+ * @param {ReactNode | undefined} children - Child components that observe `visibilityChanged` and `AppState` event.
16
18
  * @returns {ReactElement} - A React Provider component wrapped with `VisibilityChangedProvider`.
17
19
  * @example
18
20
  * ```typescript
@@ -28,8 +30,20 @@ interface Props {
28
30
  * ```
29
31
  */
30
32
  export function VisibilityProvider({ isVisible, children }: Props): ReactElement {
33
+ const [visible, setVisible] = useState(isVisible);
34
+
35
+ useEffect(() => {
36
+ const subscription = nativeEventEmitter.addListener('visibilityChanged', (nextVisible) => {
37
+ setVisible(nextVisible);
38
+ });
39
+
40
+ return () => {
41
+ subscription.remove();
42
+ };
43
+ }, []);
44
+
31
45
  return (
32
- <VisibilityChangedProvider isVisible={isVisible}>
46
+ <VisibilityChangedProvider isVisible={visible}>
33
47
  <AppStateProvider>{children}</AppStateProvider>
34
48
  </VisibilityChangedProvider>
35
49
  );
@@ -1,5 +1,4 @@
1
- import { createContext, PropsWithChildren, ReactElement, useContext, useEffect, useState } from 'react';
2
- import { nativeEventEmitter } from '../native-event-emitter';
1
+ import { createContext, PropsWithChildren, ReactElement, useContext } from 'react';
3
2
 
4
3
  const VisibilityChangedContext = createContext<boolean | undefined>(undefined);
5
4
 
@@ -7,8 +6,7 @@ const VisibilityChangedContext = createContext<boolean | undefined>(undefined);
7
6
  * @name VisibilityChangedProvider
8
7
  * @kind function
9
8
  * @description
10
- * A Provider that manages whether a React Native screen is visible.
11
- * It subscribes to the app's `visibilityChanged` event to detect and manage screen visibility.
9
+ * A Provider that manages whether a React Native screen is visible provider.
12
10
  *
13
11
  * @param {ReactNode | undefined} children - Child components that check screen visibility.
14
12
  * @param {boolean} isVisible - A boolean value indicating whether the screen is visible.
@@ -28,19 +26,7 @@ export function VisibilityChangedProvider({
28
26
  children,
29
27
  isVisible,
30
28
  }: PropsWithChildren<{ isVisible: boolean }>): ReactElement {
31
- const [visible, setVisible] = useState(isVisible);
32
-
33
- useEffect(() => {
34
- const subscription = nativeEventEmitter.addListener('visibilityChanged', (nextVisible) => {
35
- setVisible(nextVisible);
36
- });
37
-
38
- return () => {
39
- subscription.remove();
40
- };
41
- }, []);
42
-
43
- return <VisibilityChangedContext.Provider value={visible}>{children}</VisibilityChangedContext.Provider>;
29
+ return <VisibilityChangedContext.Provider value={isVisible}>{children}</VisibilityChangedContext.Provider>;
44
30
  }
45
31
 
46
32
  /**