@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,231 @@
1
+ import { PropsWithChildren, ReactElement, ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ interface Props {
4
+ onImpressionStart?: () => void;
5
+ onImpressionEnd?: () => void;
6
+ enabled?: boolean;
7
+ UNSAFE__impressFallbackOnMount?: boolean;
8
+ style?: StyleProp<ViewStyle>;
9
+ areaThreshold?: number;
10
+ timeThreshold?: number;
11
+ children?: ReactNode;
12
+ }
13
+ /**
14
+ * @public
15
+ * @category Screen Control
16
+ * @name ImpressionArea
17
+ * @description
18
+ * A component that detects whether a specific component is visible on the screen and notifies the outside. Using this component, you can easily implement features like collecting logs or running animations when a specific component becomes visible on the screen.
19
+ * The visibility is detected using the return value of `useVisibility` and the `IOScrollView` and `InView` components that indicate whether the component is displayed within the viewport. When using `ScrollView` in React, even if a view is not visible on the screen, using `ImpressionArea` allows you to trigger events only when the view is actually visible on the screen.
20
+
21
+ ::: info Note
22
+
23
+ `ImpressionArea` must be used inside `IOScrollView`. If you need to use it outside of `IOScrollView`, you can set the `UNSAFE__impressFallbackOnMount` property to `true` to detect based on when the component is mounted. If this property is set to `false` and used outside of `IOScrollView`, an `IOProviderMissingError` will occur.
24
+
25
+ :::
26
+ *
27
+ * @param {() => void} [onImpressionStart] Callback function that is executed when the child component becomes visible on the screen.
28
+ * @param {() => void} [onImpressionEnd] Callback function that is executed when the child component is hidden from the screen.
29
+ * @param {boolean} [enabled=true] Value that directly controls the condition for visibility. Default value is `true`. If passed as `false`, the `onImpressionStart` callback function will not be executed even if the component is visible.
30
+ * @param {number} [areaThreshold=0] Value that sets the ratio of the visible area. If the component appears on the screen with a ratio greater than this value, `onImpressionStart` is called.
31
+ * The value should be set between 0 and 1. Setting it to 0 triggers the event when even 1px of the component is visible. Conversely, setting it to 1 only triggers the event when the component is 100% visible on the screen.
32
+ * @param {number} [timeThreshold=0] Sets the time in milliseconds before `onImpressionStart` is called after this component becomes visible on the screen. Default value is `0` milliseconds (0 seconds).
33
+ * @param {ViewStyle} [style] `style` value to be applied to the `InView` component. Default value is `undefined`, used when you want to specify a style.
34
+ * @param {boolean} [UNSAFE__impressFallbackOnMount=false] Whether to consider the component as visible immediately when mounted. Default value is `false`.
35
+ * Useful when you cannot determine if the component is in the viewport without using `IOScrollView`. For example, a component located outside of `IOScrollView` will be considered visible at mount time if set to `true`.
36
+ *
37
+ * @returns {ReactElement} - Returns a component that can detect visibility on the screen.
38
+ * @example
39
+ *
40
+ * ### Basic Usage Example
41
+ *
42
+ * ```tsx
43
+ * import { useState } from 'react';
44
+ * import { Button, Dimensions, Text, View } from 'react-native';
45
+ * import { ImpressionArea, IOScrollView } from '@granite-js/react-native';
46
+ *
47
+ * export default function ImpressionAreaExample() {
48
+ * const [isImpressionStart, setIsImpressionStart] = useState(false);
49
+ *
50
+ * return (
51
+ * <>
52
+ * <Text>{isImpressionStart ? 'Impression Start' : 'Impression End'}</Text>
53
+ * <IOScrollView
54
+ * style={{
55
+ * flex: 1,
56
+ * margin: 16,
57
+ * backgroundColor: 'white',
58
+ * }}
59
+ * >
60
+ * <View
61
+ * style={{
62
+ * height: Dimensions.get('screen').height,
63
+ * borderWidth: 1,
64
+ * borderColor: 'black',
65
+ * }}
66
+ * >
67
+ * <Text>Scroll to here</Text>
68
+ * </View>
69
+ *
70
+ * <ImpressionArea
71
+ * onImpressionStart={() => setIsImpressionStart(true)}
72
+ * onImpressionEnd={() => setIsImpressionStart(false)}
73
+ * >
74
+ * <Button title="Button" />
75
+ * </ImpressionArea>
76
+ * </IOScrollView>
77
+ * </>
78
+ * );
79
+ * }
80
+ * ```
81
+ *
82
+ * ### Example of Detection at Mount Time
83
+ *
84
+ * When `ImpressionArea` is not located inside a component like `IOScrollView`, setting `UNSAFE__impressFallbackOnMount` to `true` will consider the component as visible when it is mounted.
85
+ *
86
+ * ```tsx
87
+ * import { useState } from 'react';
88
+ * import { Button, Dimensions, ScrollView, Text, View } from 'react-native';
89
+ * import { ImpressionArea } from '@granite-js/react-native';
90
+ *
91
+ * export default function ImpressionArea2Example() {
92
+ * const [isImpressionStart, setIsImpressionStart] = useState(false);
93
+ *
94
+ * return (
95
+ * <>
96
+ * <Text>{isImpressionStart ? 'Impression Start' : 'Impression End'}</Text>
97
+ * <ScrollView
98
+ * style={{
99
+ * flex: 1,
100
+ * margin: 16,
101
+ * backgroundColor: 'white',
102
+ * }}
103
+ * >
104
+ * <View
105
+ * style={{
106
+ * height: Dimensions.get('screen').height,
107
+ * borderWidth: 1,
108
+ * borderColor: 'black',
109
+ * }}
110
+ * >
111
+ * <Text>Scroll to here</Text>
112
+ * </View>
113
+ *
114
+ * <ImpressionArea
115
+ * UNSAFE__impressFallbackOnMount={true}
116
+ * onImpressionStart={() => setIsImpressionStart(true)}
117
+ * onImpressionEnd={() => setIsImpressionStart(false)}
118
+ * >
119
+ * <Button title="Button" />
120
+ * </ImpressionArea>
121
+ * </ScrollView>
122
+ * </>
123
+ * );
124
+ * }
125
+ * ```
126
+ */
127
+ export declare function ImpressionArea(props: Props): ReactElement;
128
+ export declare class IOProviderMissingError extends Error {
129
+ message: string;
130
+ }
131
+ /**
132
+ * @category Components
133
+ * @kind function
134
+ * @name ImpressionAreaOnMount
135
+ * @description
136
+ * A component that calls `onImpressionStart` and `onImpressionEnd` when the component is mounted on the screen.
137
+ * Used when `UNSAFE__impressFallbackOnMount` is `true` in `ImpressionArea`.
138
+ * This component can be used when `ImpressionArea` is needed outside of `IOScrollView`.
139
+ *
140
+ * @param {() => void} [onImpressionStart] - Callback function that is called when the component is mounted.
141
+ * @param {() => void} [onImpressionEnd] - Callback function that is called when the component is unmounted.
142
+ * @param {StyleProp<ViewStyle>} [style] - Sets the style of the top-level container of the `ImpressionAreaOnMount` component.
143
+ * @param {ReactNode} [children] - Sets the child components to be wrapped by `ImpressionAreaOnMount`.
144
+ * @returns {ReactElement} - Returns a component that detects mount status
145
+ * @example
146
+ * ### Example of Detection at Mount Time
147
+ * ```tsx
148
+ * import { ImpressionAreaOnMount } from '@granite-js/react-native';
149
+ *
150
+ * export default function AlwaysImpressionAreaPage() {
151
+ * // isImpressionStart is set to true when AlwaysImpressionAreaPage is mounted
152
+ * const [isImpressionStart, setIsImpressionStart] = useState(false);
153
+ *
154
+ * return (
155
+ * <ScrollView
156
+ * style={{
157
+ * flex: 1,
158
+ * padding: 16,
159
+ * backgroundColor: 'white',
160
+ * }}
161
+ * >
162
+ * <TestTitle title="ImpressionArea" description="@granite-js/impression-area" />
163
+ * <Button label={'Scroll to origin'} onPress={() => {}} />
164
+ * <Code style={{ width, height }} json={{ isImpressionStart }} />
165
+ * <ImpressionAreaOnMount
166
+ * onImpressionStart={() => setIsImpressionStart(true)}
167
+ * onImpressionEnd={() => setIsImpressionStart(false)}
168
+ * >
169
+ * <Button label={'Scroll to here'} onPress={() => {}} />
170
+ * </ImpressionArea>
171
+ * </ScrollView>
172
+ * );
173
+ * }
174
+ * ```
175
+ */
176
+ export declare function ImpressionAreaOnMount({ onImpressionStart: _onImpressionStart, onImpressionEnd: _onImpressionEnd, style, children, }: PropsWithChildren<Props>): ReactElement;
177
+ /**
178
+ * @category Components
179
+ * @kind function
180
+ * @name ImpressionAreaWithIntersectionObserver
181
+ * @description
182
+ * A component that calls `onImpressionStart` and `onImpressionEnd` based on whether the component is visible on the user's screen.
183
+ * This is a component that can be used in `IOScrollView` and can notify the outside about its visibility status.
184
+ *
185
+ * @param {() => void} [onImpressionStart] - Callback function that is called when the component becomes visible on the screen.
186
+ * @param {() => void} [onImpressionEnd] - Callback function that is called when the component disappears from the screen.
187
+ * @param {boolean} [enabled=true] - Sets whether to enable `ImpressionArea`.
188
+ * @param {StyleProp<ViewStyle>} [style] - Sets the style of the top-level container of the `ImpressionAreaWithIntersectionObserver` component.
189
+ * @param {number} [areaThreshold=0] - Considers the component visible when its visible area exceeds the set ratio.
190
+ * @param {number} [timeThreshold=0] - Sets the time in milliseconds before `onImpressionStart` and `onImpressionEnd` are called after the component becomes visible on the screen. Default value is `0` milliseconds.
191
+ * @param {ReactNode} [children] - Sets the child components to be wrapped by `ImpressionAreaWithIntersectionObserver`.
192
+ * @returns {ReactElement} - Returns a component that can detect visibility on the screen.
193
+ * @example
194
+ * ### Example using IntersectionObserver
195
+ * ```tsx
196
+ * import { ImpressionAreaWithIntersectionObserver, IOScrollView } from '@granite-js/react-native';
197
+ *
198
+ * export default function ImpressionAreaPage() {
199
+ * const [isImpressionStart, setIsImpressionStart] = useState(false);
200
+ *
201
+ * return (
202
+ * <IOScrollView
203
+ * style={{
204
+ * flex: 1,
205
+ * margin: 16,
206
+ * backgroundColor: 'white',
207
+ * }}
208
+ * >
209
+ * <TestTitle title="ImpressionArea" description="@granite-js/impression-area" />
210
+ * <Button label={'Scroll to origin'} onPress={() => {}} />
211
+ * <Code style={{ width, height }} textStyle={{ flex: 1, verticalAlign: 'middle' }} json={{ isImpressionStart }} />
212
+ * <ImpressionAreaWithIntersectionObserver
213
+ * onImpressionStart={() => setIsImpressionStart(true)}
214
+ * onImpressionEnd={() => setIsImpressionStart(false)}
215
+ * >
216
+ * <Button label={'Scroll to here'} onPress={() => {}} />
217
+ * </ImpressionArea>
218
+ * </IOScrollView>
219
+ * );
220
+ * }
221
+ * ```
222
+ */
223
+ export declare function ImpressionAreaWithIntersectionObserver({ onImpressionStart: _onImpressionStart, onImpressionEnd: _onImpressionEnd, timeThreshold, ...props }: PropsWithChildren<{
224
+ onImpressionStart?: () => void;
225
+ onImpressionEnd?: () => void;
226
+ enabled?: boolean;
227
+ style?: StyleProp<ViewStyle>;
228
+ areaThreshold?: number;
229
+ timeThreshold?: number;
230
+ }>): ReactElement;
231
+ export {};
@@ -0,0 +1 @@
1
+ export * from './ImpressionArea';
@@ -0,0 +1,17 @@
1
+ import './types/global';
2
+ export { Granite } from './app';
3
+ export * from '@granite-js/style-utils';
4
+ export * from '@granite-js/image';
5
+ export * from './dev-entrypoint';
6
+ export * from './native-modules/natives';
7
+ export * from './visibility';
8
+ export * from './use-back-event';
9
+ export * from './keyboard';
10
+ export * from './intersection-observer';
11
+ export * from './impression-area';
12
+ export * from './scroll-view-inertial-background';
13
+ export * from './react';
14
+ export * from './router/createRoute';
15
+ export * from './event';
16
+ export type { InitialProps, ColorPreference } from './initial-props';
17
+ export type { GraniteProps } from './app';
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @public
3
+ * @category UI
4
+ * @name ColorPreference
5
+ * @description
6
+ * Type representing the color mode of the current device. It is a string representing light mode and dark mode.
7
+ *
8
+ * @typedef {'light' | 'dark'} ColorPreference
9
+ */
10
+ export type ColorPreference = 'light' | 'dark';
11
+ /**
12
+ * @name NetworkStatus
13
+ * @description
14
+ * Type representing the network status.
15
+ *
16
+ * @typedef {'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE'} NetworkStatus
17
+ */
18
+ type NetworkStatus = 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE';
19
+ /**
20
+ * @category Types
21
+ * @name BaseInitialProps
22
+ * @description
23
+ * Interface representing the base initial properties.
24
+ *
25
+ * @interface
26
+ * @property {'ios' | 'android'} platform - Platform type
27
+ * @property {string} appVersion - App version
28
+ * @property {ColorPreference} initialColorPreference - Initial color
29
+ * @property {NetworkStatus} networkStatus - Network status
30
+ * @property {number} loadingStartTs - Timestamp when ReactNativeView started rendering in native
31
+ * @property {string} [scheme] - Executed scheme
32
+ */
33
+ type BaseInitialProps = {
34
+ platform: 'ios' | 'android';
35
+ appVersion: string;
36
+ initialColorPreference: ColorPreference;
37
+ networkStatus: NetworkStatus;
38
+ loadingStartTs: number;
39
+ scheme?: string;
40
+ };
41
+ /**
42
+ * @category Types
43
+ * @name AndroidInitialProps
44
+ * @description
45
+ * Values passed from Android to React Native.
46
+ *
47
+ * @interface
48
+ * @augments BaseInitialProps
49
+ * @property {'android'} platform - Platform name (Android)
50
+ * @property {string} initialFontScale - Font scale set on the device
51
+ * @property {string} distributionGroup - Distribution group
52
+ */
53
+ export type AndroidInitialProps = BaseInitialProps & {
54
+ platform: 'android';
55
+ initialFontScale: string;
56
+ distributionGroup: string;
57
+ };
58
+ /**
59
+ * @category Types
60
+ * @name IOSInitialProps
61
+ * @description
62
+ * Interface representing iOS initial properties.
63
+ *
64
+ * @interface
65
+ * @augments BaseInitialProps
66
+ * @property {'ios'} platform - Platform (iOS)
67
+ * @property {IOSFontSizeType} initialFontSize - Initial font size
68
+ * @property {boolean} isVisible - Visibility status
69
+ */
70
+ export type IOSInitialProps = BaseInitialProps & {
71
+ platform: 'ios';
72
+ initialFontSize: IOSFontSizeType;
73
+ isVisible: boolean;
74
+ };
75
+ /**
76
+ * @category Types
77
+ * @name IOSFontSizeType
78
+ * @description
79
+ * Type representing iOS font size type.
80
+ *
81
+ * @typedef {'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxLarge' | 'xxxLarge' | 'A11y_Medium' | 'A11y_Large' | 'A11y_xLarge' | 'A11y_xxLarge' | 'A11y_xxxLarge'} IOSFontSizeType
82
+ */
83
+ type IOSFontSizeType = 'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxLarge' | 'xxxLarge' | 'A11y_Medium' | 'A11y_Large' | 'A11y_xLarge' | 'A11y_xxLarge' | 'A11y_xxxLarge';
84
+ /**
85
+ * @public
86
+ * @category Core
87
+ * @name InitialProps
88
+ * @description
89
+ * Provides the initial data type that native platforms (Android/iOS) pass to the app when a user enters a specific screen in a React Native app.
90
+ * The initial data contains important information used for screen initialization, and the required data types differ by native platform.
91
+ *
92
+ * The data type provided by Android is `AndroidInitialProps`, and the data type provided by iOS is `IOSInitialProps`.
93
+ *
94
+ * @property {'ios' | 'android'} platform - The platform on which the app is currently running. Has a value of either `ios` or `android`.
95
+ * @property {ColorPreference} initialColorPreference - The initial color theme. Represents the color theme set by the user.
96
+ * @property {NetworkStatus} networkStatus - The current device's network connection status and connected network.
97
+ * @property {string} [scheme] - The URL scheme used to enter the current screen.
98
+ * @property {`xSmall` | `Small` | `Medium` | `Large` | `xLarge` | `xxLarge` | `xxxLarge` | `A11y_Medium` | `A11y_Large` | `A11y_xLarge` | `A11y_xxLarge` | `A11y_xxxLarge`} initialFontSize (iOS only) iOS system font size. Each value represents a specific font size. Default value is `Large`.
99
+ * @property {boolean} isVisible (iOS only) Whether the screen is currently visible in iOS. Initial value is passed as `true`.
100
+ * @property {string} initialFontScale (Android only) Android system font scale. The font size scale adjusted by the user in Android device's accessibility settings. This value is multiplied by the base font size to determine the final font size.
101
+ *
102
+ * @example
103
+ *
104
+ * ### Example using `InitialProps`
105
+ *
106
+ * ::: code-group
107
+ * ```tsx [_app.tsx]
108
+ * import { PropsWithChildren } from 'react';
109
+ * import { Granite, InitialProps } from '@granite-js/react-native';
110
+ * import { context } from '../require.context';
111
+ *
112
+ * const APP_NAME = 'my-app-name';
113
+ *
114
+ * function AppContainer({ children, ...initialProps }: PropsWithChildren<InitialProps>) {
115
+ * console.log({ initialProps });
116
+ * return <>{children}</>;
117
+ * }
118
+ *
119
+ * export default Granite.registerApp(AppContainer, {
120
+ * appName: APP_NAME,
121
+ * context,
122
+ * });
123
+ * :::
124
+ * ```
125
+ */
126
+ export type InitialProps = AndroidInitialProps | IOSInitialProps;
127
+ export {};
@@ -0,0 +1 @@
1
+ export * from './InitialProps';
@@ -0,0 +1,10 @@
1
+ import IOManager from './IOManager';
2
+ export interface IOContextValue {
3
+ manager: null | IOManager;
4
+ }
5
+ /**
6
+ * @name IOContext
7
+ * @description Context that shares the IOManager instance.
8
+ */
9
+ declare const IOContext: import("react").Context<IOContextValue>;
10
+ export default IOContext;
@@ -0,0 +1,55 @@
1
+ import { RefAttributes } from 'react';
2
+ import { FlatList, FlatListProps } from 'react-native';
3
+ import { IOComponentProps } from './withIO';
4
+ export type IOFlatListController = FlatList;
5
+ export type IOFlatListProps<ItemT = any> = IOComponentProps & FlatListProps<ItemT>;
6
+ /**
7
+ * @public
8
+ * @category Screen Control
9
+ * @name IOFlatList
10
+ * @description
11
+ * `IOFlatList` is a `FlatList` component with added Intersection Observer functionality to detect when specific elements become visible or disappear from the screen during scrolling. Using this component, you can easily check and handle whether each item in the list is visible on the screen.
12
+ *
13
+ * When used with `InView`, you can check the exposure status of each element. The [InView](/reference/react-native/Screen%20Control/InView) component included as a child element detects whether the element is visible on the screen through the observation functionality of `IOFlatList` and triggers events based on the exposure status.
14
+ *
15
+ * @example
16
+ *
17
+ * You can check whether each item in the list appears on the screen using `IOFlatList`.
18
+ * When each item in the list appears on the screen, the `InView` component changes to the `visible` state.
19
+ *
20
+ * ```tsx
21
+ * import { ReactNode, useState } from 'react';
22
+ * import { StyleSheet, Text, View } from 'react-native';
23
+ * import { InView, IOFlatList } from '@granite-js/react-native';
24
+ *
25
+ * const mockData = Array.from({ length: 30 }, (_, i) => ({ key: String(i) }));
26
+ *
27
+ * export default function FlatListPage() {
28
+ * return <IOFlatList data={mockData} renderItem={({ item }) => <InViewItem>{item.key}</InViewItem>} />;
29
+ * }
30
+ *
31
+ * function InViewItem({ children }: { children: ReactNode }) {
32
+ * const [visible, setVisible] = useState(false);
33
+ *
34
+ * return (
35
+ * <InView onChange={setVisible}>
36
+ * <View style={styles.item}>
37
+ * <Text>{children}</Text>
38
+ * <Text>{visible ? 'visible' : ''}</Text>
39
+ * </View>
40
+ * </InView>
41
+ * );
42
+ * }
43
+ *
44
+ * const styles = StyleSheet.create({
45
+ * item: {
46
+ * padding: 16,
47
+ * borderBottomWidth: 1,
48
+ * borderBottomColor: '#ddd',
49
+ * },
50
+ * });
51
+ * ```
52
+ */
53
+ declare const IOFlatList: typeof IOFlatListFunction;
54
+ declare function IOFlatListFunction<ItemT = any>(props: IOFlatListProps<ItemT> & RefAttributes<IOFlatListController>): JSX.Element;
55
+ export default IOFlatList;
@@ -0,0 +1,24 @@
1
+ import IntersectionObserver, { IntersectionObserverOptions, IntersectionObserverEntry, Element } from './IntersectionObserver';
2
+ export type ObserverInstanceCallback = (inView: boolean, intersectionRatio: number) => void;
3
+ export interface ObserverInstance {
4
+ readonly callback: ObserverInstanceCallback;
5
+ readonly element: Element;
6
+ readonly observerId: number;
7
+ readonly observer: IntersectionObserver;
8
+ }
9
+ /**
10
+ * @kind class
11
+ * @name IOManager
12
+ * @description A class that tracks the visibility of DOM elements using `IntersectionObserver` instances and executes callbacks when elements enter or leave the viewport.
13
+ * This class makes it easy to manage multiple elements and execute custom logic based on the visibility status of each element.
14
+ */
15
+ declare class IOManager {
16
+ io: IntersectionObserver;
17
+ observerId: number;
18
+ instanceMap: Map<Element, ObserverInstance>;
19
+ constructor(options: IntersectionObserverOptions);
20
+ handleChange: (entries: IntersectionObserverEntry[]) => void;
21
+ observe(element: Element, callback: ObserverInstanceCallback): ObserverInstance;
22
+ unobserve(element: any): void;
23
+ }
24
+ export default IOManager;
@@ -0,0 +1,59 @@
1
+ import { ForwardRefExoticComponent, RefAttributes } from 'react';
2
+ import { ScrollView, ScrollViewProps } from 'react-native';
3
+ import { IOComponentProps } from './withIO';
4
+ export type IOScrollViewController = ScrollView;
5
+ export type IOScrollViewProps = IOComponentProps & ScrollViewProps;
6
+ /**
7
+ * @public
8
+ * @category Screen Control
9
+ * @name IOScrollView
10
+ * @description
11
+ * `IOScrollView` is a [ScrollView](https://reactnative.dev/docs/scrollview) component with added `Intersection Observer` functionality. It can detect when specific elements become visible or disappear from the screen during scrolling.
12
+ * By utilizing this functionality with the `InView` component as a child element, you can easily check whether elements are exposed on the screen.
13
+ *
14
+ * @example
15
+ *
16
+ * You can check whether each item in the list appears on the screen using `IOScrollView`.
17
+ * When each item in the list appears on the screen, the `InView` component changes to the `visible` state.
18
+ *
19
+ * ```tsx
20
+ * import { ReactNode, useState } from 'react';
21
+ * import { StyleSheet, Text, View } from 'react-native';
22
+ * import { InView, IOScrollView } from '@granite-js/react-native';
23
+ *
24
+ * const mockData = Array.from({ length: 30 }, (_, i) => ({ key: String(i) }));
25
+ *
26
+ * export default function IOScrollViewPage() {
27
+ * return (
28
+ * <IOScrollView>
29
+ * {mockData.map((data) => (
30
+ * <InViewItem key={data.key}>{data.key}</InViewItem>
31
+ * ))}
32
+ * </IOScrollView>
33
+ * );
34
+ * }
35
+ *
36
+ * function InViewItem({ children }: { children: ReactNode }) {
37
+ * const [visible, setVisible] = useState(false);
38
+ *
39
+ * return (
40
+ * <InView onChange={setVisible}>
41
+ * <View style={styles.item}>
42
+ * <Text>{children}</Text>
43
+ * <Text>{visible ? 'visible' : ''}</Text>
44
+ * </View>
45
+ * </InView>
46
+ * );
47
+ * }
48
+ *
49
+ * const styles = StyleSheet.create({
50
+ * item: {
51
+ * padding: 16,
52
+ * borderBottomWidth: 1,
53
+ * borderBottomColor: '#ddd',
54
+ * },
55
+ * });
56
+ * ```
57
+ */
58
+ declare const IOScrollView: ForwardRefExoticComponent<IOScrollViewProps & RefAttributes<IOScrollViewController>>;
59
+ export default IOScrollView;
@@ -0,0 +1,107 @@
1
+ import { ComponentType, PureComponent, ReactElement, ReactNode, RefObject } from 'react';
2
+ import { LayoutChangeEvent, View, ViewProps } from 'react-native';
3
+ import { IOContextValue } from './IOContext';
4
+ import { ObserverInstance } from './IOManager';
5
+ import { Element } from './IntersectionObserver';
6
+ export interface RenderProps {
7
+ inView: boolean;
8
+ onChange: (inView: boolean) => void;
9
+ }
10
+ export interface Props {
11
+ [key: string]: any;
12
+ }
13
+ export type InViewProps<T = Props> = T & {
14
+ children: ReactNode | ((fields: RenderProps) => ReactElement<View>);
15
+ as?: ComponentType<any>;
16
+ triggerOnce?: boolean;
17
+ onLayout?: (event: LayoutChangeEvent) => void;
18
+ onChange?: (inView: boolean, areaThreshold: number) => void;
19
+ };
20
+ export type InViewWrapper = ComponentType<{
21
+ ref?: RefObject<any> | ((ref: any) => void);
22
+ onLayout?: (event: LayoutChangeEvent) => void;
23
+ }>;
24
+ /**
25
+ * @public
26
+ * @category Screen Control
27
+ * @name InView
28
+ * @description
29
+ * The `InView` component detects when an element starts to become visible on the screen or disappears from the screen.
30
+ * When an element starts to become visible on the screen, the `onChanged` handler is called with `true` as the first argument. Conversely, when the element disappears from the screen, `false` is passed.
31
+ * The second argument of the `onChanged` handler receives the exposure ratio of the element on the screen. The exposure ratio value ranges from `0` to `1.0`. For example, if `0.2` is passed, it means the component is 20% exposed on the screen.
32
+ *
33
+ ::: warning Note
34
+
35
+ `InView` must be used inside [IOScrollView](/reference/react-native/Screen%20Control/InView.md) or [IOFlatList](/reference/react-native/Screen%20Control/IOFlatList.md) that includes `IOContext`.
36
+ If used outside of `IOContext`, an `IOProviderMissingError` will occur.
37
+
38
+ :::
39
+
40
+ * @param {Object} props - Props object passed to the component.
41
+ * @param {React.ReactNode} props.children - Child components to be rendered under the component.
42
+ * @param {React.ComponentType} [prop.as=View] - Specifies the component to actually render. Default is the [View](https://reactnative.dev/docs/view) component.
43
+ * @param {boolean} [triggerOnce=false] - Use this option if you want to call the `onChange` callback only once when the element first becomes visible.
44
+ * @param {(event: LayoutChangeEvent) => void} [onLayout] - Callback function called when there is a change in the layout.
45
+ * @param {(inView: boolean, areaThreshold: number) => void} [onChange] - Callback function called when an element appears or disappears from the screen. The first argument receives the visibility status, and the second argument receives the exposure ratio.
46
+ *
47
+ * @example
48
+ *
49
+ * ### Detecting the `10%` point of an element using the `InView` component
50
+ *
51
+ * ```tsx
52
+ * import { LayoutChangeEvent, View, Text, Dimensions } from 'react-native';
53
+ * import { InView, IOScrollView } from '@granite-js/react-native';
54
+ *
55
+ * export function InViewExample() {
56
+ * const handleLayout = (event: LayoutChangeEvent) => {
57
+ * console.log('Layout changed', event.nativeEvent.layout);
58
+ * };
59
+ *
60
+ * const handleChange = (inView: boolean, areaThreshold: number) => {
61
+ * if (inView) {
62
+ * console.log(`Element is visible at ${areaThreshold * 100}% ratio`);
63
+ * } else {
64
+ * console.log('Element is not visible');
65
+ * }
66
+ * };
67
+ *
68
+ * return (
69
+ * <IOScrollView>
70
+ * <View style={{ height: HEIGHT, width: '100%', backgroundColor: 'blue' }}>
71
+ * <Text style={{ color: 'white' }}>Please scroll down</Text>
72
+ * </View>
73
+ * <InView onLayout={handleLayout} onChange={handleChange}>
74
+ * <View style={{ width: 100, height: 300, backgroundColor: 'yellow' }}>
75
+ * <View style={{ position: 'absolute', top: 30, width: 100, height: 1, borderWidth: 1 }}>
76
+ * <Text style={{ position: 'absolute', top: 0 }}>10% point</Text>
77
+ * </View>
78
+ * </View>
79
+ * </InView>
80
+ * </IOScrollView>
81
+ * );
82
+ * }
83
+ * ```
84
+ */
85
+ declare class InView<T = ViewProps> extends PureComponent<InViewProps<T>> {
86
+ static contextType: import("react").Context<IOContextValue>;
87
+ static defaultProps: Partial<InViewProps>;
88
+ context: undefined | IOContextValue;
89
+ mounted: boolean;
90
+ protected element: Element;
91
+ protected instance: undefined | ObserverInstance;
92
+ protected view: any;
93
+ constructor(props: InViewProps<T>);
94
+ componentDidMount(): void;
95
+ componentWillUnmount(): void;
96
+ protected handleChange: (inView: boolean, areaThreshold: number) => void;
97
+ protected handleRef: (ref: any) => void;
98
+ protected handleLayout: (event: LayoutChangeEvent) => void;
99
+ measure: (...args: any) => void;
100
+ measureInWindow: (...args: any) => void;
101
+ measureLayout: (...args: any) => void;
102
+ setNativeProps: (...args: any) => void;
103
+ focus: (...args: any) => void;
104
+ blur: (...args: any) => void;
105
+ render(): import("react/jsx-runtime").JSX.Element | null;
106
+ }
107
+ export default InView;