@granite-js/react-native 0.0.0-dev-20250725013859

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.
Files changed (217) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +24 -0
  3. package/bin/cli.js +3 -0
  4. package/cli.d.ts +1 -0
  5. package/cli.js +4 -0
  6. package/config.d.ts +2 -0
  7. package/config.js +5 -0
  8. package/dist/app/App/index.android.d.ts +2 -0
  9. package/dist/app/App/index.ios.d.ts +6 -0
  10. package/dist/app/AppRoot.d.ts +1 -0
  11. package/dist/app/Granite.d.ts +61 -0
  12. package/dist/app/HostAppRoot.d.ts +1 -0
  13. package/dist/app/index.d.ts +2 -0
  14. package/dist/async-bridges.d.ts +2 -0
  15. package/dist/blur/BlurView.d.ts +78 -0
  16. package/dist/blur/ReactNativeBlurModule.d.ts +6 -0
  17. package/dist/blur/constants.d.ts +1 -0
  18. package/dist/blur/index.d.ts +1 -0
  19. package/dist/constant-bridges.d.ts +1 -0
  20. package/dist/constants.d.ts +1 -0
  21. package/dist/dev-entrypoint/index.d.ts +2 -0
  22. package/dist/event/abstract.d.ts +42 -0
  23. package/dist/event/index.d.ts +2 -0
  24. package/dist/event/useGraniteEvent.d.ts +14 -0
  25. package/dist/impression-area/ImpressionArea.d.ts +231 -0
  26. package/dist/impression-area/index.d.ts +1 -0
  27. package/dist/index.d.ts +21 -0
  28. package/dist/initial-props/InitialProps.d.ts +92 -0
  29. package/dist/initial-props/index.d.ts +1 -0
  30. package/dist/intersection-observer/IOContext.d.ts +10 -0
  31. package/dist/intersection-observer/IOFlatList.d.ts +55 -0
  32. package/dist/intersection-observer/IOManager.d.ts +24 -0
  33. package/dist/intersection-observer/IOScrollView.d.ts +59 -0
  34. package/dist/intersection-observer/InView.d.ts +107 -0
  35. package/dist/intersection-observer/IntersectionObserver.d.ts +67 -0
  36. package/dist/intersection-observer/index.d.ts +8 -0
  37. package/dist/intersection-observer/withIO.d.ts +20 -0
  38. package/dist/jest/index.d.ts +1 -0
  39. package/dist/jest/index.js +32 -0
  40. package/dist/keyboard/KeyboardAboveView.d.ts +40 -0
  41. package/dist/keyboard/index.d.ts +2 -0
  42. package/dist/keyboard/useKeyboardAnimatedHeight.d.ts +20 -0
  43. package/dist/native-event-emitter/eventEmitters/index.d.ts +2 -0
  44. package/dist/native-event-emitter/eventEmitters/types.d.ts +4 -0
  45. package/dist/native-event-emitter/eventEmitters/visibilityChanged.d.ts +10 -0
  46. package/dist/native-event-emitter/index.d.ts +1 -0
  47. package/dist/native-event-emitter/nativeEventEmitter.d.ts +15 -0
  48. package/dist/native-modules/core/GraniteCoreModule.d.ts +8 -0
  49. package/dist/native-modules/index.d.ts +3 -0
  50. package/dist/native-modules/natives/GraniteModule.d.ts +7 -0
  51. package/dist/native-modules/natives/closeView.d.ts +21 -0
  52. package/dist/native-modules/natives/getSchemeUri.d.ts +23 -0
  53. package/dist/native-modules/natives/index.d.ts +3 -0
  54. package/dist/native-modules/natives/openURL.d.ts +36 -0
  55. package/dist/react/index.d.ts +1 -0
  56. package/dist/react/useWaitForReturnNavigator.d.ts +39 -0
  57. package/dist/rn-polyfills/index.d.ts +1 -0
  58. package/dist/rn-polyfills/symbol-asynciterator/index.d.ts +9 -0
  59. package/dist/rn-polyfills/url/index.d.ts +1 -0
  60. package/dist/router/Router.d.ts +59 -0
  61. package/dist/router/components/BackButton.d.ts +7 -0
  62. package/dist/router/components/CanGoBackGuard.d.ts +6 -0
  63. package/dist/router/components/RouterBackButton.d.ts +9 -0
  64. package/dist/router/components/StackNavigator.d.ts +54 -0
  65. package/dist/router/constants.d.ts +2 -0
  66. package/dist/router/createRoute.d.ts +39 -0
  67. package/dist/router/createRoute.test-d.d.ts +9 -0
  68. package/dist/router/hooks/useInitialRouteName.d.ts +1 -0
  69. package/dist/router/hooks/useIsInitialScreen.d.ts +1 -0
  70. package/dist/router/hooks/useRouterControls.d.ts +11 -0
  71. package/dist/router/index.d.ts +3 -0
  72. package/dist/router/types/RequireContext.d.ts +7 -0
  73. package/dist/router/types/RouteScreen.d.ts +16 -0
  74. package/dist/router/types/Screen.d.ts +23 -0
  75. package/dist/router/types/index.d.ts +3 -0
  76. package/dist/router/types/screen-option.d.ts +4 -0
  77. package/dist/router/utils/createParentRouteScreenMap.d.ts +8 -0
  78. package/dist/router/utils/defaultParserParams.d.ts +9 -0
  79. package/dist/router/utils/index.d.ts +2 -0
  80. package/dist/router/utils/matchers.d.ts +2 -0
  81. package/dist/router/utils/mergeParentLayoutScreen.d.ts +18 -0
  82. package/dist/router/utils/path.d.ts +53 -0
  83. package/dist/router/utils/screen.d.ts +37 -0
  84. package/dist/scroll-view-inertial-background/ScrollViewInertialBackground.d.ts +49 -0
  85. package/dist/scroll-view-inertial-background/index.d.ts +1 -0
  86. package/dist/status-bar/StatusBar.android.d.ts +3 -0
  87. package/dist/status-bar/StatusBar.ios.d.ts +3 -0
  88. package/dist/status-bar/index.d.ts +2 -0
  89. package/dist/status-bar/types.d.ts +20 -0
  90. package/dist/status-bar/utils.d.ts +3 -0
  91. package/dist/types/global.d.ts +14 -0
  92. package/dist/use-back-event/index.d.ts +1 -0
  93. package/dist/use-back-event/useBackEvent.d.ts +135 -0
  94. package/dist/utils/noop.d.ts +1 -0
  95. package/dist/utils/usePreservedCallback.d.ts +1 -0
  96. package/dist/video/Video.d.ts +67 -0
  97. package/dist/video/index.d.ts +1 -0
  98. package/dist/video/instance.d.ts +9 -0
  99. package/dist/visibility/VisibilityProvider.d.ts +27 -0
  100. package/dist/visibility/index.d.ts +6 -0
  101. package/dist/visibility/react-navigation/index.d.ts +2 -0
  102. package/dist/visibility/react-navigation/useIsFocusedSafely.d.ts +20 -0
  103. package/dist/visibility/react-navigation/useNavigationSafely.d.ts +19 -0
  104. package/dist/visibility/useIsAppForeground.d.ts +39 -0
  105. package/dist/visibility/useVisibility.d.ts +35 -0
  106. package/dist/visibility/useVisibilityChange.d.ts +51 -0
  107. package/dist/visibility/useVisibilityChanged.d.ts +41 -0
  108. package/dist/visibility/utils/usePrevious.d.ts +15 -0
  109. package/jest.d.ts +1 -0
  110. package/package.json +94 -0
  111. package/presets.d.ts +1 -0
  112. package/src/app/App/index.android.tsx +6 -0
  113. package/src/app/App/index.d.ts +6 -0
  114. package/src/app/App/index.ios.tsx +13 -0
  115. package/src/app/AppRoot.tsx +39 -0
  116. package/src/app/Granite.tsx +128 -0
  117. package/src/app/HostAppRoot.tsx +19 -0
  118. package/src/app/index.ts +2 -0
  119. package/src/async-bridges.ts +2 -0
  120. package/src/blur/BlurView.tsx +103 -0
  121. package/src/blur/ReactNativeBlurModule.ts +19 -0
  122. package/src/blur/constants.ts +3 -0
  123. package/src/blur/index.ts +1 -0
  124. package/src/constant-bridges.ts +1 -0
  125. package/src/constants.ts +1 -0
  126. package/src/dev-entrypoint/index.tsx +17 -0
  127. package/src/event/abstract.ts +130 -0
  128. package/src/event/index.ts +2 -0
  129. package/src/event/useGraniteEvent.ts +34 -0
  130. package/src/impression-area/ImpressionArea.tsx +341 -0
  131. package/src/impression-area/index.ts +1 -0
  132. package/src/index.ts +24 -0
  133. package/src/initial-props/InitialProps.ts +95 -0
  134. package/src/initial-props/index.ts +1 -0
  135. package/src/intersection-observer/IOContext.ts +16 -0
  136. package/src/intersection-observer/IOFlatList.ts +72 -0
  137. package/src/intersection-observer/IOManager.ts +73 -0
  138. package/src/intersection-observer/IOScrollView.ts +69 -0
  139. package/src/intersection-observer/InView.tsx +205 -0
  140. package/src/intersection-observer/IntersectionObserver.ts +212 -0
  141. package/src/intersection-observer/index.ts +24 -0
  142. package/src/intersection-observer/withIO.tsx +151 -0
  143. package/src/jest/index.ts +1 -0
  144. package/src/keyboard/KeyboardAboveView.tsx +62 -0
  145. package/src/keyboard/index.ts +2 -0
  146. package/src/keyboard/useKeyboardAnimatedHeight.tsx +81 -0
  147. package/src/native-event-emitter/eventEmitters/index.ts +3 -0
  148. package/src/native-event-emitter/eventEmitters/types.ts +4 -0
  149. package/src/native-event-emitter/eventEmitters/visibilityChanged.ts +11 -0
  150. package/src/native-event-emitter/index.ts +1 -0
  151. package/src/native-event-emitter/nativeEventEmitter.ts +18 -0
  152. package/src/native-modules/core/GraniteCoreModule.ts +9 -0
  153. package/src/native-modules/index.ts +3 -0
  154. package/src/native-modules/natives/GraniteModule.ts +8 -0
  155. package/src/native-modules/natives/closeView.ts +25 -0
  156. package/src/native-modules/natives/getSchemeUri.ts +27 -0
  157. package/src/native-modules/natives/index.ts +3 -0
  158. package/src/native-modules/natives/openURL.ts +40 -0
  159. package/src/react/index.ts +1 -0
  160. package/src/react/useWaitForReturnNavigator.ts +75 -0
  161. package/src/rn-polyfills/index.ts +7 -0
  162. package/src/rn-polyfills/symbol-asynciterator/index.ts +15 -0
  163. package/src/rn-polyfills/url/index.ts +1 -0
  164. package/src/router/Router.tsx +164 -0
  165. package/src/router/components/BackButton.tsx +58 -0
  166. package/src/router/components/CanGoBackGuard.tsx +31 -0
  167. package/src/router/components/RouterBackButton.tsx +32 -0
  168. package/src/router/components/StackNavigator.tsx +12 -0
  169. package/src/router/constants.ts +3 -0
  170. package/src/router/createRoute.test-d.ts +52 -0
  171. package/src/router/createRoute.ts +161 -0
  172. package/src/router/hooks/useInitialRouteName.tsx +22 -0
  173. package/src/router/hooks/useIsInitialScreen.ts +7 -0
  174. package/src/router/hooks/useRouterControls.tsx +72 -0
  175. package/src/router/index.ts +3 -0
  176. package/src/router/types/RequireContext.ts +7 -0
  177. package/src/router/types/RouteScreen.ts +17 -0
  178. package/src/router/types/Screen.tsx +24 -0
  179. package/src/router/types/index.ts +3 -0
  180. package/src/router/types/screen-option.ts +23 -0
  181. package/src/router/utils/createParentRouteScreenMap.spec.ts +166 -0
  182. package/src/router/utils/createParentRouteScreenMap.ts +136 -0
  183. package/src/router/utils/defaultParserParams.spec.ts +46 -0
  184. package/src/router/utils/defaultParserParams.ts +19 -0
  185. package/src/router/utils/index.ts +2 -0
  186. package/src/router/utils/matchers.ts +5 -0
  187. package/src/router/utils/mergeParentLayoutScreen.spec.tsx +112 -0
  188. package/src/router/utils/mergeParentLayoutScreen.tsx +43 -0
  189. package/src/router/utils/path.spec.ts +135 -0
  190. package/src/router/utils/path.ts +105 -0
  191. package/src/router/utils/screen.tsx +95 -0
  192. package/src/scroll-view-inertial-background/ScrollViewInertialBackground.tsx +99 -0
  193. package/src/scroll-view-inertial-background/index.ts +1 -0
  194. package/src/status-bar/StatusBar.android.tsx +36 -0
  195. package/src/status-bar/StatusBar.d.ts +4 -0
  196. package/src/status-bar/StatusBar.ios.tsx +34 -0
  197. package/src/status-bar/index.ts +2 -0
  198. package/src/status-bar/types.ts +21 -0
  199. package/src/status-bar/utils.ts +20 -0
  200. package/src/types/global.ts +21 -0
  201. package/src/use-back-event/index.ts +1 -0
  202. package/src/use-back-event/useBackEvent.tsx +260 -0
  203. package/src/utils/noop.ts +1 -0
  204. package/src/utils/usePreservedCallback.ts +16 -0
  205. package/src/video/Video.tsx +104 -0
  206. package/src/video/index.ts +1 -0
  207. package/src/video/instance.tsx +28 -0
  208. package/src/visibility/VisibilityProvider.tsx +36 -0
  209. package/src/visibility/index.ts +6 -0
  210. package/src/visibility/react-navigation/index.ts +2 -0
  211. package/src/visibility/react-navigation/useIsFocusedSafely.tsx +58 -0
  212. package/src/visibility/react-navigation/useNavigationSafely.tsx +30 -0
  213. package/src/visibility/useIsAppForeground.tsx +73 -0
  214. package/src/visibility/useVisibility.tsx +54 -0
  215. package/src/visibility/useVisibilityChange.ts +69 -0
  216. package/src/visibility/useVisibilityChanged.tsx +69 -0
  217. package/src/visibility/utils/usePrevious.tsx +24 -0
@@ -0,0 +1,51 @@
1
+ /**
2
+ * String representing whether the screen is visible.
3
+ * @typedef {string} VisibilityState
4
+ * @property {'visible'} visible - The screen is visible.
5
+ * @property {'hidden'} hidden - The screen is not visible.
6
+ */
7
+ export type VisibilityState = 'visible' | 'hidden';
8
+ /**
9
+ * @callback VisibilityCallback
10
+ * @param {VisibilityState} state - String representing the visibility state of the screen.
11
+ */
12
+ export type VisibilityCallback = (state: VisibilityState) => void;
13
+ /**
14
+ * @public
15
+ * @category Screen Control
16
+ * @name useVisibilityChange
17
+ * @kind function
18
+ * @description
19
+ * Calls a callback function with the visibility state when the screen's visibility changes.
20
+ * The callback function receives the return value from [useVisibility](/en/reference/react-native/Screen%20Control/useVisibility). If the return value is `true`, it passes 'visible', and if `false`, it passes 'hidden'.
21
+ *
22
+ * @param {VisibilityCallback} callback - Calls a callback function that receives visibility changes when the screen's visibility changes.
23
+ * @example
24
+ *
25
+ * ### Example of logging when screen visibility changes
26
+ *
27
+ * ```tsx
28
+ * import { useState } from 'react';
29
+ * import { Text, View } from 'react-native';
30
+ * import { useVisibilityChange, VisibilityState } from '@granite-js/react-native';
31
+ *
32
+ * export function UseVisibilityChangeExample() {
33
+ * const [visibilityHistory, setVisibilityHistory] = useState<VisibilityState[]>([]);
34
+ *
35
+ * useVisibilityChange((visibility) => {
36
+ * setVisibilityHistory((prev) => [...prev, visibility]);
37
+ * });
38
+ *
39
+ * return (
40
+ * <View>
41
+ * <Text>Logs are created when leaving and returning to the home screen.</Text>
42
+ *
43
+ * {visibilityHistory.map((visibility, index) => (
44
+ * <Text key={index}>{JSON.stringify(visibility)}</Text>
45
+ * ))}
46
+ * </View>
47
+ * );
48
+ * }
49
+ * ```
50
+ */
51
+ export declare function useVisibilityChange(callback: VisibilityCallback): void;
@@ -0,0 +1,41 @@
1
+ import { PropsWithChildren, ReactElement } from 'react';
2
+ /**
3
+ * @name VisibilityChangedProvider
4
+ * @kind function
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.
8
+ *
9
+ * @param {ReactNode | undefined} children - Child components that check screen visibility.
10
+ * @param {boolean} isVisible - A boolean value indicating whether the screen is visible.
11
+ * @returns {ReactElement} - A React Provider component wrapped with `VisibilityChangedContext.Provider`.
12
+ * @example
13
+ * ```typescript
14
+ * export function VisibilityProvider({ isVisible, children }: Props) {
15
+ * return (
16
+ * <VisibilityChangedProvider isVisible={isVisible}>
17
+ * {children}
18
+ * </VisibilityChangedProvider>
19
+ * );
20
+ * }
21
+ * ```
22
+ */
23
+ export declare function VisibilityChangedProvider({ children, isVisible, }: PropsWithChildren<{
24
+ isVisible: boolean;
25
+ }>): ReactElement;
26
+ /**
27
+ * @name useVisibilityChanged
28
+ * @category Hooks
29
+ * @kind function
30
+ * @description
31
+ * A Hook that returns whether a React Native screen is visible.
32
+ * @returns {boolean} - Returns whether the screen is visible.
33
+ * @throws {Error} Throws an error when not used within a `VisibilityChangedProvider`.
34
+ * @example
35
+ * ```typescript
36
+ * const isVisible = useVisibilityChanged();
37
+ * console.log(isVisible);
38
+ * // true or false
39
+ * ```
40
+ */
41
+ export declare function useVisibilityChanged(): boolean;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @name usePrevious
3
+ * @category Hooks
4
+ * @kind function
5
+ * @description
6
+ * A Hook that returns the previous value.
7
+ * @param {T} value - The value to return the previous value of.
8
+ * @returns {T} - Returns the previous value.
9
+ * @example
10
+ * ```typescript
11
+ * const isVisible = useVisibility();
12
+ * const prevValue = usePrevious<boolean>(isVisible) ?? false;
13
+ * ```
14
+ */
15
+ export declare function usePrevious<T>(value: T): T;
package/jest.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/jest';
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "@granite-js/react-native",
3
+ "version": "0.0.0-dev-20250725013859",
4
+ "description": "The Granite Framework",
5
+ "bin": {
6
+ "granite": "./bin/cli.js"
7
+ },
8
+ "scripts": {
9
+ "typecheck": "tsc --noEmit",
10
+ "test": "vitest --no-watch --coverage",
11
+ "lint": "eslint .",
12
+ "build": "tsup && tsc -p tsconfig.build.json",
13
+ "prepack": "yarn build"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./src/index.ts"
21
+ },
22
+ "./async-bridges": {
23
+ "types": "./src/async-bridges.ts",
24
+ "default": "./src/async-bridges.ts"
25
+ },
26
+ "./constant-bridges": {
27
+ "types": "./src/constant-bridges.ts",
28
+ "default": "./src/constant-bridges.ts"
29
+ },
30
+ "./jest": {
31
+ "types": "./dist/jest/index.d.ts",
32
+ "default": "./dist/jest/index.js"
33
+ },
34
+ "./cli": {
35
+ "types": "./cli.d.ts",
36
+ "default": "./cli.js"
37
+ },
38
+ "./config": {
39
+ "types": "./config.d.ts",
40
+ "default": "./config.js"
41
+ },
42
+ "./types": {
43
+ "types": "./dist/types/global.d.ts"
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "files": [
48
+ "src",
49
+ "dist",
50
+ "bin",
51
+ "config.js",
52
+ "cli.js",
53
+ "*.d.ts"
54
+ ],
55
+ "devDependencies": {
56
+ "@babel/core": "^7.24.9",
57
+ "@babel/preset-env": "^7.24.8",
58
+ "@babel/preset-typescript": "^7.24.7",
59
+ "@granite-js/native": "workspace:*",
60
+ "@testing-library/dom": "^10.4.0",
61
+ "@testing-library/react": "^16.1.0",
62
+ "@types/babel__core": "^7",
63
+ "@types/babel__preset-env": "^7",
64
+ "@types/node": "^22.10.2",
65
+ "@types/react": "18.3.3",
66
+ "@types/react-dom": "^18",
67
+ "@vitest/coverage-v8": "^2.1.8",
68
+ "esbuild": "^0.25.4",
69
+ "eslint": "^9.7.0",
70
+ "jsdom": "^25.0.1",
71
+ "react": "18.2.0",
72
+ "react-dom": "18.2.0",
73
+ "react-native": "0.72.6",
74
+ "tsup": "^8.5.0",
75
+ "typescript": "5.8.3",
76
+ "vitest": "^2.1.8"
77
+ },
78
+ "peerDependencies": {
79
+ "@granite-js/native": "0.0.0-dev-20250725013859",
80
+ "@types/react": "*",
81
+ "react": "*",
82
+ "react-native": "*"
83
+ },
84
+ "dependencies": {
85
+ "@granite-js/cli": "workspace:*",
86
+ "@granite-js/image": "workspace:*",
87
+ "@granite-js/jest": "workspace:*",
88
+ "@granite-js/lottie": "workspace:*",
89
+ "@granite-js/mpack": "workspace:*",
90
+ "@granite-js/style-utils": "workspace:*",
91
+ "es-toolkit": "^1.34.1",
92
+ "react-native-url-polyfill": "1.3.0"
93
+ }
94
+ }
package/presets.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/presets';
@@ -0,0 +1,6 @@
1
+ import { VisibilityProvider } from '../../visibility';
2
+ import { Props } from '.';
3
+
4
+ export function App({ children }: Props) {
5
+ return <VisibilityProvider isVisible={true}>{children}</VisibilityProvider>;
6
+ }
@@ -0,0 +1,6 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { InitialProps } from '../../initial-props';
3
+
4
+ export type Props = PropsWithChildren<InitialProps>;
5
+
6
+ export declare function App(props: Props): JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { useMemo } from 'react';
2
+ import { VisibilityProvider } from '../../visibility';
3
+ import { Props } from '.';
4
+
5
+ type IOSInitialProps = Props & {
6
+ isVisible: boolean;
7
+ };
8
+
9
+ export function App({ children, ...props }: IOSInitialProps) {
10
+ const { isVisible } = useMemo(() => props, [props]);
11
+
12
+ return <VisibilityProvider isVisible={isVisible}>{children}</VisibilityProvider>;
13
+ }
@@ -0,0 +1,39 @@
1
+ import { SafeAreaProvider } from '@granite-js/native/react-native-safe-area-context';
2
+ import type { ComponentType, PropsWithChildren } from 'react';
3
+ import type { GraniteProps } from './Granite';
4
+ import type { InitialProps } from '../initial-props';
5
+ import { BackEventProvider, useBackEventState } from '../use-back-event';
6
+ import { App } from './App';
7
+ import { Router } from '../router';
8
+
9
+ /**
10
+ * @internal
11
+ */
12
+ interface AppRootProps extends GraniteProps {
13
+ container: ComponentType<PropsWithChildren<InitialProps>>;
14
+ initialProps: InitialProps;
15
+ }
16
+
17
+ export function AppRoot({ appName, context, container: Container, initialProps, router }: AppRootProps) {
18
+ const backEventState = useBackEventState();
19
+ const scheme = global.__granite.app.scheme;
20
+ const baseScheme = `${scheme}://${appName}`;
21
+
22
+ return (
23
+ <App {...initialProps}>
24
+ <SafeAreaProvider>
25
+ <BackEventProvider backEvent={backEventState}>
26
+ <Router
27
+ context={context}
28
+ initialProps={initialProps}
29
+ container={Container}
30
+ canGoBack={!backEventState.hasBackEvent}
31
+ onBack={backEventState.onBack}
32
+ prefix={baseScheme}
33
+ {...router}
34
+ />
35
+ </BackEventProvider>
36
+ </SafeAreaProvider>
37
+ </App>
38
+ );
39
+ }
@@ -0,0 +1,128 @@
1
+ import { ComponentType, PropsWithChildren } from 'react';
2
+ import { AppRegistry } from 'react-native';
3
+ import { ENTRY_BUNDLE_NAME } from '../constants';
4
+ import type { InitialProps } from '../initial-props';
5
+ import type { RouterProps, RequireContext } from '../router';
6
+ import { AppRoot } from './AppRoot';
7
+ import { HostAppRoot } from './HostAppRoot';
8
+
9
+ export interface GraniteProps {
10
+ /**
11
+ * @description
12
+ * The name of the app.
13
+ */
14
+ appName: string;
15
+ /**
16
+ * @description
17
+ * The context of the app.
18
+ *
19
+ * @TODO Hide context
20
+ */
21
+ context: RequireContext;
22
+ /**
23
+ * @description
24
+ * Configuration object to be passed to the router.
25
+ */
26
+ router?: RouterProps;
27
+ }
28
+
29
+ const createApp = () => {
30
+ let _appName: string | null = null;
31
+
32
+ function registerComponent(appKey: string, component: React.ComponentType<any>): string {
33
+ if (AppRegistry.getAppKeys().includes(appKey)) {
34
+ throw new Error(`App with key '${appKey}' already registered`);
35
+ }
36
+
37
+ return AppRegistry.registerComponent(appKey, () => component);
38
+ }
39
+
40
+ return {
41
+ registerApp(
42
+ AppContainer: ComponentType<PropsWithChildren<InitialProps>>,
43
+ { appName, context, router }: GraniteProps
44
+ ): (initialProps: InitialProps) => JSX.Element {
45
+ if (appName === ENTRY_BUNDLE_NAME) {
46
+ throw new Error(`Reserved app name 'shared' cannot be used`);
47
+ }
48
+
49
+ function Root(initialProps: InitialProps) {
50
+ return (
51
+ <AppRoot
52
+ container={AppContainer}
53
+ initialProps={initialProps}
54
+ appName={appName}
55
+ context={context}
56
+ router={router}
57
+ />
58
+ );
59
+ }
60
+
61
+ registerComponent(appName, Root);
62
+ _appName = appName;
63
+
64
+ return Root;
65
+ },
66
+
67
+ registerHostApp(
68
+ AppContainer: ComponentType<PropsWithChildren<InitialProps>>,
69
+ { appName }: Pick<GraniteProps, 'appName'>
70
+ ): (initialProps: InitialProps) => JSX.Element {
71
+ if (appName !== ENTRY_BUNDLE_NAME) {
72
+ throw new Error(`Host appName must be 'shared'`);
73
+ }
74
+
75
+ function Root(initialProps: InitialProps) {
76
+ return <HostAppRoot container={AppContainer} initialProps={initialProps} />;
77
+ }
78
+
79
+ registerComponent(appName, Root);
80
+ _appName = appName;
81
+
82
+ return Root;
83
+ },
84
+
85
+ get appName(): string {
86
+ if (_appName === null) {
87
+ throw new Error('Granite.appName can only be used after registerApp or registerHostApp has been called.');
88
+ }
89
+ return _appName;
90
+ },
91
+ };
92
+ };
93
+
94
+ /**
95
+ * @public
96
+ * @category Core
97
+ * @name Granite
98
+ * @description
99
+ *
100
+ * @property {RegisterService} registerApp - This function sets up the basic environment for your service and helps you start service development quickly without needing complex configuration. By just passing `appName`, you can immediately use various features such as file-based routing, query parameter handling, and back navigation control.
101
+ *
102
+ * The features provided by the `Granite.registerApp` function are as follows:
103
+ * - Routing: URLs are automatically mapped according to file paths. It works similarly to Next.js's file-based routing. For example, the `/my-service/pages/index.ts` file can be accessed at `scheme://my-service`, and the `/my-service/pages/home.ts` file can be accessed at `scheme://my-service/home`.
104
+ * - Query Parameters: You can easily use query parameters received through URL schemes. For example, you can receive a `referrer` parameter and log it.
105
+ * - Back Navigation Control: You can control back navigation events. For example, when a user presses back on a screen, you can show a dialog or close the screen.
106
+ * - Screen Visibility: You can determine whether a screen is visible or hidden from the user. For example, you can use this value to handle specific actions when a user leaves for the home screen.
107
+ *
108
+ * @example
109
+ *
110
+ * ### Example of creating with the `Granite` component
111
+ *
112
+ * ```tsx
113
+ * import { PropsWithChildren } from 'react';
114
+ * import { Granite, InitialProps } from '@granite-js/react-native';
115
+ * import { context } from '../require.context';
116
+ *
117
+ * function AppContainer({ children }: PropsWithChildren<InitialProps>) {
118
+ * return <>{children}</>;
119
+ * }
120
+ *
121
+ * export default Granite.registerApp(AppContainer, {
122
+ * appName: 'my-app',
123
+ * context,
124
+ * });
125
+ *
126
+ * ```
127
+ */
128
+ export const Granite = createApp();
@@ -0,0 +1,19 @@
1
+ import type { ComponentType, PropsWithChildren } from 'react';
2
+ import type { InitialProps } from '../initial-props';
3
+ import { App } from './App';
4
+
5
+ /**
6
+ * @internal
7
+ */
8
+ interface HostAppRootProps {
9
+ container: ComponentType<PropsWithChildren<InitialProps>>;
10
+ initialProps: InitialProps;
11
+ }
12
+
13
+ export function HostAppRoot({ container: Container, initialProps }: HostAppRootProps) {
14
+ return (
15
+ <App {...initialProps}>
16
+ <Container {...initialProps} />
17
+ </App>
18
+ );
19
+ }
@@ -0,0 +1,2 @@
1
+ export { Granite } from './Granite';
2
+ export type { GraniteProps } from './Granite';
@@ -0,0 +1,2 @@
1
+ export * from './native-modules/natives/closeView';
2
+ export * from './native-modules/natives/openURL';
@@ -0,0 +1,103 @@
1
+ import type { BlurViewProps as InternalBlurViewProps } from '@granite-js/native/@react-native-community/blur';
2
+ import { View, ViewProps } from 'react-native';
3
+ import { ReactNativeBlurModule } from './ReactNativeBlurModule';
4
+ import { isBlurNativeModuleSupported } from './constants';
5
+
6
+ export type BlurType = InternalBlurViewProps['blurType'];
7
+
8
+ export interface BlurViewProps extends ViewProps {
9
+ blurType?: BlurType;
10
+ blurAmount?: number;
11
+ vibrancyEffect?: boolean;
12
+ reducedTransparencyFallbackColor?: string;
13
+ }
14
+
15
+ /**
16
+ * @public
17
+ * @category UI
18
+ * @name BlurView
19
+ * @description
20
+ * `BlurView` adds a blurred background effect, primarily on iOS. It creates a visual blur on the background view.
21
+ *
22
+ * This component is supported only on iOS. On Android, it simply renders a regular [`View`](https://reactnative.dev/docs/0.72/view) without any blur effect.
23
+ *
24
+ * You can control the blur intensity and optionally enable the [vibrancy effect](https://developer.apple.com/documentation/uikit/uivibrancyeffect?language=objc), which enhances the visual impact of content displayed over a blurred background.
25
+ *
26
+ * If blur is not supported or doesn't render properly, you can use the `reducedTransparencyFallbackColor` prop to set a fallback background color.
27
+ *
28
+ * Use the `isSupported` property to check whether the current device supports blur. Blur is available on iOS from version 5.126.0 and not supported on Android.
29
+ *
30
+ * @param {BlurViewProps} [props] The props you can pass to `BlurView`. It extends `react-native`'s `ViewProps`, so you can use layout and style properties. The props align with those of [`@react-native-community/blur`](https://github.com/Kureev/react-native-blur/tree/v4.3.2?tab=readme-ov-file#blurview).
31
+ * @param {BlurType} [props.blurType] Type of blur to apply, such as `light`, `dark`, or `extraDark`.
32
+ * @param {number} [props.blurAmount=10] Intensity of the blur effect. Higher values make the blur stronger. Accepts values from `0` to `100`. Default is `10`.
33
+ * @param {boolean} [props.vibrancyEffect=false] Enables the vibrancy effect. This effect enhances content displayed on top of the blur. Only supported on iOS. Default is `false`.
34
+ * @param {string} [props.reducedTransparencyFallbackColor] Fallback background color used when blur cannot be applied due to system settings or device limitations.
35
+ *
36
+ * @returns {JSX.Element} On iOS, returns a blurred `BlurView` or `VibrancyView` component. On Android, returns a regular `View` without blur.
37
+ *
38
+ * ::: warning Note
39
+ * `BlurView` is only supported on iOS. On Android, it renders a regular `View` without any blur effect.
40
+ * :::
41
+ *
42
+ * @example
43
+ *
44
+ * ### Blurring background behind a text
45
+ *
46
+ * ```tsx
47
+ * import { BlurView } from '@granite-js/react-native';
48
+ * import { View, Text, StyleSheet } from 'react-native';
49
+ *
50
+ * export function BlurViewExample() {
51
+ * return (
52
+ * <View style={styles.container}>
53
+ * <Text style={styles.absolute}>Blurred Text</Text>
54
+ * <BlurView style={styles.absolute} blurType="light" blurAmount={1} />
55
+ * <Text>Non Blurred Text</Text>
56
+ * </View>
57
+ * );
58
+ * }
59
+ *
60
+ * const styles = StyleSheet.create({
61
+ * container: {
62
+ * justifyContent: 'center',
63
+ * alignItems: 'center',
64
+ * width: '100%',
65
+ * height: 300,
66
+ * },
67
+ * absolute: {
68
+ * position: 'absolute',
69
+ * top: 0,
70
+ * left: 0,
71
+ * bottom: 0,
72
+ * right: 0,
73
+ * },
74
+ * });
75
+ * ```
76
+ *
77
+ * @see [iOS Vibrancy Effect Documentation](https://developer.apple.com/documentation/uikit/uivibrancyeffect)
78
+ * @see [Zeddios Blog Explanation](https://zeddios.tistory.com/1140)
79
+ */
80
+ export function BlurView({
81
+ blurType,
82
+ blurAmount = 10,
83
+ reducedTransparencyFallbackColor,
84
+ vibrancyEffect = false,
85
+ ...viewProps
86
+ }: BlurViewProps) {
87
+ if (!isBlurNativeModuleSupported || ReactNativeBlurModule == null) {
88
+ return <View {...viewProps} />;
89
+ }
90
+
91
+ const Component = vibrancyEffect ? ReactNativeBlurModule.VibrancyView : ReactNativeBlurModule.BlurView;
92
+
93
+ return (
94
+ <Component
95
+ blurAmount={blurAmount}
96
+ blurType={blurType}
97
+ reducedTransparencyFallbackColor={reducedTransparencyFallbackColor}
98
+ {...viewProps}
99
+ />
100
+ );
101
+ }
102
+
103
+ BlurView.isSupported = isBlurNativeModuleSupported;
@@ -0,0 +1,19 @@
1
+ import type { BlurView, VibrancyView } from '@granite-js/native/@react-native-community/blur';
2
+ import { isBlurNativeModuleSupported } from './constants';
3
+
4
+ const ReactNativeBlurModule = (() => {
5
+ if (!isBlurNativeModuleSupported) {
6
+ return undefined;
7
+ }
8
+
9
+ try {
10
+ return require('@granite-js/native/@react-native-community/blur') as {
11
+ BlurView: typeof BlurView;
12
+ VibrancyView: typeof VibrancyView;
13
+ };
14
+ } catch {
15
+ return undefined;
16
+ }
17
+ })();
18
+
19
+ export { ReactNativeBlurModule };
@@ -0,0 +1,3 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ export const isBlurNativeModuleSupported = Platform.OS === 'ios';
@@ -0,0 +1 @@
1
+ export * from './BlurView';
@@ -0,0 +1 @@
1
+ export * from './native-modules/natives/getSchemeUri';
@@ -0,0 +1 @@
1
+ export const ENTRY_BUNDLE_NAME = 'shared';
@@ -0,0 +1,17 @@
1
+ import type { ComponentType } from 'react';
2
+ import { AppRegistry } from 'react-native';
3
+ import { ENTRY_BUNDLE_NAME } from '../constants';
4
+ import { setup } from '../rn-polyfills';
5
+
6
+ setup();
7
+
8
+ export function register(Component: ComponentType<any>) {
9
+ if (AppRegistry.getAppKeys().includes(ENTRY_BUNDLE_NAME)) {
10
+ console.warn('Granite entrypoint is already registered');
11
+ return;
12
+ }
13
+
14
+ const component = (props: any) => <Component {...props} />;
15
+
16
+ AppRegistry.registerComponent(ENTRY_BUNDLE_NAME, () => component);
17
+ }