@granite-js/react-native 0.0.1

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 (189) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +202 -0
  3. package/README.md +24 -0
  4. package/bin/cli.js +3 -0
  5. package/cli.d.ts +1 -0
  6. package/cli.js +4 -0
  7. package/config.d.ts +2 -0
  8. package/config.js +5 -0
  9. package/dist/app/App/index.android.d.ts +2 -0
  10. package/dist/app/App/index.ios.d.ts +6 -0
  11. package/dist/app/Granite.d.ts +60 -0
  12. package/dist/app/index.d.ts +2 -0
  13. package/dist/app/registerPage.d.ts +20 -0
  14. package/dist/async-bridges.d.ts +2 -0
  15. package/dist/constant-bridges.d.ts +1 -0
  16. package/dist/dev-entrypoint/index.d.ts +2 -0
  17. package/dist/event/abstract.d.ts +42 -0
  18. package/dist/event/index.d.ts +2 -0
  19. package/dist/event/useGraniteEvent.d.ts +14 -0
  20. package/dist/impression-area/ImpressionArea.d.ts +231 -0
  21. package/dist/impression-area/index.d.ts +1 -0
  22. package/dist/index.d.ts +17 -0
  23. package/dist/initial-props/InitialProps.d.ts +127 -0
  24. package/dist/initial-props/index.d.ts +1 -0
  25. package/dist/intersection-observer/IOContext.d.ts +10 -0
  26. package/dist/intersection-observer/IOFlatList.d.ts +55 -0
  27. package/dist/intersection-observer/IOManager.d.ts +24 -0
  28. package/dist/intersection-observer/IOScrollView.d.ts +59 -0
  29. package/dist/intersection-observer/InView.d.ts +107 -0
  30. package/dist/intersection-observer/IntersectionObserver.d.ts +67 -0
  31. package/dist/intersection-observer/index.d.ts +8 -0
  32. package/dist/intersection-observer/withIO.d.ts +20 -0
  33. package/dist/jest/index.d.ts +1 -0
  34. package/dist/jest/index.js +32 -0
  35. package/dist/keyboard/KeyboardAboveView.d.ts +40 -0
  36. package/dist/keyboard/index.d.ts +1 -0
  37. package/dist/keyboard/useKeyboardAnimatedHeight.d.ts +20 -0
  38. package/dist/native-event-emitter/eventEmitters/index.d.ts +2 -0
  39. package/dist/native-event-emitter/eventEmitters/types.d.ts +4 -0
  40. package/dist/native-event-emitter/eventEmitters/visibilityChanged.d.ts +10 -0
  41. package/dist/native-event-emitter/index.d.ts +1 -0
  42. package/dist/native-event-emitter/nativeEventEmitter.d.ts +15 -0
  43. package/dist/native-modules/core/GraniteCoreModule.d.ts +8 -0
  44. package/dist/native-modules/index.d.ts +3 -0
  45. package/dist/native-modules/natives/GraniteModule.d.ts +7 -0
  46. package/dist/native-modules/natives/closeView.d.ts +21 -0
  47. package/dist/native-modules/natives/getSchemeUri.d.ts +23 -0
  48. package/dist/native-modules/natives/index.d.ts +3 -0
  49. package/dist/native-modules/natives/openURL.d.ts +36 -0
  50. package/dist/react/index.d.ts +1 -0
  51. package/dist/react/useWaitForReturnNavigator.d.ts +39 -0
  52. package/dist/rn-polyfills/index.d.ts +1 -0
  53. package/dist/rn-polyfills/symbol-asynciterator/index.d.ts +9 -0
  54. package/dist/rn-polyfills/url/index.d.ts +1 -0
  55. package/dist/router/Router.d.ts +59 -0
  56. package/dist/router/components/BackButton.d.ts +7 -0
  57. package/dist/router/components/CanGoBackGuard.d.ts +6 -0
  58. package/dist/router/components/RouterBackButton.d.ts +9 -0
  59. package/dist/router/components/StackNavigator.d.ts +54 -0
  60. package/dist/router/constants.d.ts +2 -0
  61. package/dist/router/createRoute.d.ts +39 -0
  62. package/dist/router/createRoute.test-d.d.ts +9 -0
  63. package/dist/router/hooks/useInitialRouteName.d.ts +1 -0
  64. package/dist/router/hooks/useIsInitialScreen.d.ts +1 -0
  65. package/dist/router/hooks/useRouterControls.d.ts +11 -0
  66. package/dist/router/index.d.ts +3 -0
  67. package/dist/router/types/RequireContext.d.ts +7 -0
  68. package/dist/router/types/RouteScreen.d.ts +16 -0
  69. package/dist/router/types/Screen.d.ts +23 -0
  70. package/dist/router/types/index.d.ts +3 -0
  71. package/dist/router/types/screen-option.d.ts +4 -0
  72. package/dist/router/utils/createParentRouteScreenMap.d.ts +8 -0
  73. package/dist/router/utils/defaultParserParams.d.ts +9 -0
  74. package/dist/router/utils/index.d.ts +2 -0
  75. package/dist/router/utils/matchers.d.ts +2 -0
  76. package/dist/router/utils/mergeParentLayoutScreen.d.ts +18 -0
  77. package/dist/router/utils/path.d.ts +53 -0
  78. package/dist/router/utils/screen.d.ts +53 -0
  79. package/dist/scroll-view-inertial-background/ScrollViewInertialBackground.d.ts +49 -0
  80. package/dist/scroll-view-inertial-background/index.d.ts +1 -0
  81. package/dist/types/global.d.ts +18 -0
  82. package/dist/use-back-event/index.d.ts +1 -0
  83. package/dist/use-back-event/useBackEvent.d.ts +135 -0
  84. package/dist/utils/noop.d.ts +1 -0
  85. package/dist/utils/usePreservedCallback.d.ts +1 -0
  86. package/dist/visibility/VisibilityProvider.d.ts +27 -0
  87. package/dist/visibility/index.d.ts +6 -0
  88. package/dist/visibility/react-navigation/index.d.ts +2 -0
  89. package/dist/visibility/react-navigation/useIsFocusedSafely.d.ts +20 -0
  90. package/dist/visibility/react-navigation/useNavigationSafely.d.ts +19 -0
  91. package/dist/visibility/useIsAppForeground.d.ts +39 -0
  92. package/dist/visibility/useVisibility.d.ts +35 -0
  93. package/dist/visibility/useVisibilityChange.d.ts +51 -0
  94. package/dist/visibility/useVisibilityChanged.d.ts +41 -0
  95. package/dist/visibility/utils/usePrevious.d.ts +15 -0
  96. package/jest.d.ts +1 -0
  97. package/package.json +92 -0
  98. package/presets.d.ts +1 -0
  99. package/src/app/App/index.android.tsx +6 -0
  100. package/src/app/App/index.d.ts +6 -0
  101. package/src/app/App/index.ios.tsx +13 -0
  102. package/src/app/Granite.tsx +130 -0
  103. package/src/app/index.ts +2 -0
  104. package/src/app/registerPage.ts +29 -0
  105. package/src/async-bridges.ts +2 -0
  106. package/src/constant-bridges.ts +1 -0
  107. package/src/dev-entrypoint/index.tsx +21 -0
  108. package/src/event/abstract.ts +130 -0
  109. package/src/event/index.ts +2 -0
  110. package/src/event/useGraniteEvent.ts +34 -0
  111. package/src/impression-area/ImpressionArea.tsx +341 -0
  112. package/src/impression-area/index.ts +1 -0
  113. package/src/index.ts +19 -0
  114. package/src/initial-props/InitialProps.ts +144 -0
  115. package/src/initial-props/index.ts +1 -0
  116. package/src/intersection-observer/IOContext.ts +16 -0
  117. package/src/intersection-observer/IOFlatList.ts +72 -0
  118. package/src/intersection-observer/IOManager.ts +73 -0
  119. package/src/intersection-observer/IOScrollView.ts +69 -0
  120. package/src/intersection-observer/InView.tsx +205 -0
  121. package/src/intersection-observer/IntersectionObserver.ts +212 -0
  122. package/src/intersection-observer/index.ts +24 -0
  123. package/src/intersection-observer/withIO.tsx +151 -0
  124. package/src/jest/index.ts +1 -0
  125. package/src/keyboard/KeyboardAboveView.tsx +62 -0
  126. package/src/keyboard/index.ts +1 -0
  127. package/src/keyboard/useKeyboardAnimatedHeight.tsx +81 -0
  128. package/src/native-event-emitter/eventEmitters/index.ts +3 -0
  129. package/src/native-event-emitter/eventEmitters/types.ts +4 -0
  130. package/src/native-event-emitter/eventEmitters/visibilityChanged.ts +11 -0
  131. package/src/native-event-emitter/index.ts +1 -0
  132. package/src/native-event-emitter/nativeEventEmitter.ts +18 -0
  133. package/src/native-modules/core/GraniteCoreModule.ts +9 -0
  134. package/src/native-modules/index.ts +3 -0
  135. package/src/native-modules/natives/GraniteModule.ts +8 -0
  136. package/src/native-modules/natives/closeView.ts +25 -0
  137. package/src/native-modules/natives/getSchemeUri.ts +27 -0
  138. package/src/native-modules/natives/index.ts +3 -0
  139. package/src/native-modules/natives/openURL.ts +40 -0
  140. package/src/react/index.ts +1 -0
  141. package/src/react/useWaitForReturnNavigator.ts +75 -0
  142. package/src/rn-polyfills/index.ts +7 -0
  143. package/src/rn-polyfills/symbol-asynciterator/index.ts +15 -0
  144. package/src/rn-polyfills/url/index.ts +1 -0
  145. package/src/router/Router.tsx +164 -0
  146. package/src/router/components/BackButton.tsx +58 -0
  147. package/src/router/components/CanGoBackGuard.tsx +31 -0
  148. package/src/router/components/RouterBackButton.tsx +32 -0
  149. package/src/router/components/StackNavigator.tsx +12 -0
  150. package/src/router/constants.ts +3 -0
  151. package/src/router/createRoute.test-d.ts +52 -0
  152. package/src/router/createRoute.ts +161 -0
  153. package/src/router/hooks/useInitialRouteName.tsx +22 -0
  154. package/src/router/hooks/useIsInitialScreen.ts +7 -0
  155. package/src/router/hooks/useRouterControls.tsx +72 -0
  156. package/src/router/index.ts +3 -0
  157. package/src/router/types/RequireContext.ts +7 -0
  158. package/src/router/types/RouteScreen.ts +17 -0
  159. package/src/router/types/Screen.tsx +24 -0
  160. package/src/router/types/index.ts +3 -0
  161. package/src/router/types/screen-option.ts +23 -0
  162. package/src/router/utils/createParentRouteScreenMap.spec.ts +166 -0
  163. package/src/router/utils/createParentRouteScreenMap.ts +136 -0
  164. package/src/router/utils/defaultParserParams.spec.ts +46 -0
  165. package/src/router/utils/defaultParserParams.ts +19 -0
  166. package/src/router/utils/index.ts +2 -0
  167. package/src/router/utils/matchers.ts +5 -0
  168. package/src/router/utils/mergeParentLayoutScreen.spec.tsx +112 -0
  169. package/src/router/utils/mergeParentLayoutScreen.tsx +43 -0
  170. package/src/router/utils/path.spec.ts +135 -0
  171. package/src/router/utils/path.ts +105 -0
  172. package/src/router/utils/screen.tsx +111 -0
  173. package/src/scroll-view-inertial-background/ScrollViewInertialBackground.tsx +99 -0
  174. package/src/scroll-view-inertial-background/index.ts +1 -0
  175. package/src/types/global.ts +31 -0
  176. package/src/use-back-event/index.ts +1 -0
  177. package/src/use-back-event/useBackEvent.tsx +260 -0
  178. package/src/utils/noop.ts +1 -0
  179. package/src/utils/usePreservedCallback.ts +16 -0
  180. package/src/visibility/VisibilityProvider.tsx +36 -0
  181. package/src/visibility/index.ts +6 -0
  182. package/src/visibility/react-navigation/index.ts +2 -0
  183. package/src/visibility/react-navigation/useIsFocusedSafely.tsx +58 -0
  184. package/src/visibility/react-navigation/useNavigationSafely.tsx +30 -0
  185. package/src/visibility/useIsAppForeground.tsx +73 -0
  186. package/src/visibility/useVisibility.tsx +54 -0
  187. package/src/visibility/useVisibilityChange.ts +69 -0
  188. package/src/visibility/useVisibilityChanged.tsx +69 -0
  189. package/src/visibility/utils/usePrevious.tsx +24 -0
@@ -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,92 @@
1
+ {
2
+ "name": "@granite-js/react-native",
3
+ "version": "0.0.1",
4
+ "description": "The Granite Framework",
5
+ "bin": {
6
+ "granite": "./bin/cli.js"
7
+ },
8
+ "scripts": {
9
+ "typecheck": "tsc --noEmit",
10
+ "test": "vitest --no-watch",
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": "0.0.1",
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
+ "esbuild": "^0.25.4",
68
+ "eslint": "^9.7.0",
69
+ "jsdom": "^25.0.1",
70
+ "react": "18.2.0",
71
+ "react-dom": "18.2.0",
72
+ "react-native": "0.72.6",
73
+ "tsup": "^8.5.0",
74
+ "typescript": "5.8.3",
75
+ "vitest": "^2.1.8"
76
+ },
77
+ "peerDependencies": {
78
+ "@granite-js/native": "*",
79
+ "@types/react": "*",
80
+ "react": "*",
81
+ "react-native": "*"
82
+ },
83
+ "dependencies": {
84
+ "@granite-js/cli": "0.0.1",
85
+ "@granite-js/image": "0.0.1",
86
+ "@granite-js/jest": "0.0.1",
87
+ "@granite-js/mpack": "0.0.1",
88
+ "@granite-js/style-utils": "0.0.1",
89
+ "es-toolkit": "^1.34.1",
90
+ "react-native-url-polyfill": "1.3.0"
91
+ }
92
+ }
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,130 @@
1
+ import { SafeAreaProvider } from '@granite-js/native/react-native-safe-area-context';
2
+ import { ComponentType, PropsWithChildren } from 'react';
3
+ import { App } from './App';
4
+ import { registerPage } from './registerPage';
5
+ import type { InitialProps } from '../initial-props';
6
+ import { Router, type RouterProps, type RequireContext } from '../router';
7
+ import { BackEventProvider, useBackEventState } from '../use-back-event';
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
+ /**
30
+ * @internal
31
+ */
32
+ interface AppRootProps extends GraniteProps {
33
+ container: ComponentType<PropsWithChildren<InitialProps>>;
34
+ initialProps: InitialProps;
35
+ }
36
+
37
+ const scheme = global.__granite.app.scheme;
38
+
39
+ function AppRoot({ appName, context, container, initialProps, router }: AppRootProps) {
40
+ const backEventState = useBackEventState();
41
+ const baseScheme = `${scheme}://${appName}`;
42
+
43
+ return (
44
+ <App {...initialProps}>
45
+ <SafeAreaProvider>
46
+ <BackEventProvider backEvent={backEventState}>
47
+ <Router
48
+ context={context}
49
+ initialProps={initialProps}
50
+ container={container}
51
+ canGoBack={!backEventState.hasBackEvent}
52
+ onBack={backEventState.onBack}
53
+ prefix={baseScheme}
54
+ {...router}
55
+ />
56
+ </BackEventProvider>
57
+ </SafeAreaProvider>
58
+ </App>
59
+ );
60
+ }
61
+
62
+ const createApp = () => {
63
+ let _appName: string | null = null;
64
+
65
+ return {
66
+ registerApp(
67
+ AppContainer: ComponentType<PropsWithChildren<InitialProps>>,
68
+ { appName, context, router }: GraniteProps
69
+ ): (initialProps: InitialProps) => JSX.Element {
70
+ function Root(initialProps: InitialProps) {
71
+ return (
72
+ <AppRoot
73
+ container={AppContainer}
74
+ initialProps={initialProps}
75
+ appName={appName}
76
+ context={context}
77
+ router={router}
78
+ />
79
+ );
80
+ }
81
+
82
+ registerPage(Root);
83
+ _appName = appName;
84
+ return Root;
85
+ },
86
+
87
+ get appName(): string {
88
+ if (_appName === null) {
89
+ throw new Error('Granite.appName can only be used after registerApp has been called.');
90
+ }
91
+ return _appName;
92
+ },
93
+ };
94
+ };
95
+
96
+ /**
97
+ * @public
98
+ * @category Core
99
+ * @name Granite
100
+ * @description
101
+ *
102
+ * @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.
103
+ *
104
+ * The features provided by the `Granite.registerApp` function are as follows:
105
+ * - 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`.
106
+ * - Query Parameters: You can easily use query parameters received through URL schemes. For example, you can receive a `referrer` parameter and log it.
107
+ * - 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.
108
+ * - 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.
109
+ *
110
+ * @example
111
+ *
112
+ * ### Example of creating with the `Granite` component
113
+ *
114
+ * ```tsx
115
+ * import { PropsWithChildren } from 'react';
116
+ * import { Granite, InitialProps } from '@granite-js/react-native';
117
+ * import { context } from '../require.context';
118
+ *
119
+ * function AppContainer({ children }: PropsWithChildren<InitialProps>) {
120
+ * return <>{children}</>;
121
+ * }
122
+ *
123
+ * export default Granite.registerApp(AppContainer, {
124
+ * appName: 'my-app',
125
+ * context,
126
+ * });
127
+ *
128
+ * ```
129
+ */
130
+ export const Granite = createApp();
@@ -0,0 +1,2 @@
1
+ export { Granite } from './Granite';
2
+ export type { GraniteProps } from './Granite';
@@ -0,0 +1,29 @@
1
+ import type { ComponentType } from 'react';
2
+
3
+ const globalThis = new Function('return this')();
4
+
5
+ /**
6
+ * @kind function
7
+ * @name registerPage
8
+ * @description
9
+ * Function to register a page component.
10
+ *
11
+ * @param {ComponentType<any>} Page - The page component to register
12
+ * @returns {ComponentType<any>} Returns the registered page component
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { registerPage } from './path/to/module';
17
+ *
18
+ * const MyPage: React.FC = () => <div>My Page</div>;
19
+ *
20
+ * registerPage(MyPage);
21
+ * ```
22
+ */
23
+ export function registerPage(Page: ComponentType<any>): ComponentType<any> {
24
+ if (globalThis.__SPLIT_CHUNK_ENABLED__) {
25
+ globalThis.Page = Page;
26
+ }
27
+
28
+ return Page;
29
+ }
@@ -0,0 +1,2 @@
1
+ export * from './native-modules/natives/closeView';
2
+ export * from './native-modules/natives/openURL';
@@ -0,0 +1 @@
1
+ export * from './native-modules/natives/getSchemeUri';
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ import type { ComponentType } from 'react';
4
+ import { AppRegistry } from 'react-native';
5
+ import { setup } from '../rn-polyfills';
6
+
7
+ setup();
8
+
9
+ let registered = false;
10
+
11
+ export function register(Component: ComponentType<any>) {
12
+ if (registered) {
13
+ throw new Error('둘 이상의 Page를 register할 수 없습니다. entrypoint에서 1회에 한해 호출해주세요.');
14
+ }
15
+ registered = true;
16
+
17
+ const component = (props: any) => <Component {...props} />;
18
+
19
+ AppRegistry.registerComponent('Page', () => component);
20
+ AppRegistry.registerComponent('shared', () => component);
21
+ }
@@ -0,0 +1,130 @@
1
+ export abstract class GraniteEventDefinition<O = undefined, R = void> {
2
+ // Event name (literal type recommended)
3
+ abstract name: string;
4
+
5
+ /**
6
+ * Method to implement event logic.
7
+ * @param options - Event options (undefined if not used)
8
+ * @param onEvent - Callback called when the event is triggered.
9
+ * @param onError - Callback called on error (error type: unknown)
10
+ */
11
+ abstract listener(options: O, onEvent: (response: R) => void, onError: (error: unknown) => void): void;
12
+
13
+ /**
14
+ * Additional logic to execute when removing the event listener.
15
+ * If needed in the plugin, override this method and it will be called
16
+ * when the listener is removed.
17
+ */
18
+ abstract remove(): void;
19
+ }
20
+
21
+ /**
22
+ * GraniteEvent class registers event definition instances passed to the constructor.
23
+ * The addEventListener method only allows registered event names, and the types of passed
24
+ * options/callbacks are automatically inferred.
25
+ *
26
+ * Each subscription is uniquely identified by (event name + options).
27
+ */
28
+ export class GraniteEvent<Defs extends GraniteEventDefinition<unknown, unknown>> {
29
+ private definitions = new Map<Defs['name'], Defs>();
30
+ private subscriptionGroups = new Map<
31
+ string,
32
+ {
33
+ eventName: Defs['name'];
34
+ options: Extract<Defs, { name: Defs['name'] }> extends GraniteEventDefinition<infer O, any> ? O : never;
35
+ callbacks: Array<{
36
+ onEvent: (response: any) => void;
37
+ onError?: (error: unknown) => void;
38
+ }>;
39
+ }
40
+ >();
41
+
42
+ constructor(defs: Defs[]) {
43
+ for (const def of defs) {
44
+ this.definitions.set(def.name, def);
45
+ }
46
+ }
47
+
48
+ addEventListener<E extends Defs['name']>(
49
+ eventName: E,
50
+ listener: Extract<Defs, { name: E }> extends GraniteEventDefinition<infer O, infer R>
51
+ ? [O] extends [undefined]
52
+ ? { onEvent: (response: R) => void; onError?: (error: unknown) => void }
53
+ : { options: O; onEvent: (response: R) => void; onError?: (error: unknown) => void }
54
+ : never
55
+ ): () => void {
56
+ const def = this.definitions.get(eventName);
57
+ if (!def) {
58
+ throw new Error(`Event "${String(eventName)}" is not registered.`);
59
+ }
60
+ const opts = (listener as any).options;
61
+ const key = this._getKey(String(eventName), opts);
62
+ let group = this.subscriptionGroups.get(key);
63
+
64
+ if (!group) {
65
+ group = {
66
+ eventName,
67
+ options: opts,
68
+ callbacks: [],
69
+ };
70
+ this.subscriptionGroups.set(key, group);
71
+
72
+ const aggregatedOnEvent = (response: any) => {
73
+ for (const cb of group!.callbacks) {
74
+ cb.onEvent(response);
75
+ }
76
+ };
77
+ const aggregatedOnError = (error: unknown) => {
78
+ for (const cb of group!.callbacks) {
79
+ if (cb.onError) {
80
+ cb.onError(error);
81
+ }
82
+ }
83
+ };
84
+
85
+ def.listener(group.options, aggregatedOnEvent, aggregatedOnError);
86
+ }
87
+
88
+ group.callbacks.push({ onEvent: listener.onEvent, onError: listener.onError });
89
+
90
+ return () => {
91
+ const grp = this.subscriptionGroups.get(key);
92
+ if (!grp) {
93
+ return;
94
+ }
95
+ grp.callbacks = grp.callbacks.filter((cb) => cb.onEvent !== listener.onEvent);
96
+ if (grp.callbacks.length === 0) {
97
+ def.remove();
98
+ this.subscriptionGroups.delete(key);
99
+ }
100
+ };
101
+ }
102
+
103
+ emit<E extends Defs['name']>(
104
+ eventName: E,
105
+ data: Extract<Defs, { name: E }> extends GraniteEventDefinition<unknown, infer R> ? R : never
106
+ ) {
107
+ const def = this.definitions.get(eventName);
108
+ if (!def) {
109
+ throw new Error(`Event "${String(eventName)}" is not registered.`);
110
+ }
111
+
112
+ for (const group of this.subscriptionGroups.values()) {
113
+ if (group.eventName === eventName) {
114
+ for (const callback of group.callbacks) {
115
+ try {
116
+ callback.onEvent(data);
117
+ } catch (error) {
118
+ if (callback.onError) {
119
+ callback.onError(error);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ private _getKey(eventName: string, options: unknown): string {
128
+ return `${eventName}:${options ? JSON.stringify(options) : ''}`;
129
+ }
130
+ }
@@ -0,0 +1,2 @@
1
+ export * from './abstract';
2
+ export * from './useGraniteEvent';
@@ -0,0 +1,34 @@
1
+ import { useMemo } from 'react';
2
+ import { GraniteEvent, GraniteEventDefinition } from './abstract';
3
+ import { BackEventControls, useBackEvent } from '../use-back-event/useBackEvent';
4
+
5
+ class BackEvent extends GraniteEventDefinition<void, void> {
6
+ name = 'backEvent' as const;
7
+
8
+ ref = {
9
+ remove: () => {},
10
+ };
11
+
12
+ constructor(private backEventControls: BackEventControls) {
13
+ super();
14
+ }
15
+
16
+ remove() {
17
+ this.ref.remove();
18
+ }
19
+
20
+ listener(_: void, onEvent: (response: void) => void): void {
21
+ this.backEventControls.addEventListener(onEvent);
22
+ this.ref.remove = () => this.backEventControls.removeEventListener(onEvent);
23
+ }
24
+ }
25
+
26
+ export function useGraniteEvent() {
27
+ const backEvent = useBackEvent();
28
+
29
+ const event = useMemo(() => {
30
+ return new GraniteEvent([new BackEvent(backEvent)]);
31
+ }, [backEvent]);
32
+
33
+ return event;
34
+ }