@momo-kits/foundation 0.163.1-beta.4 → 0.163.1-beta.5

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.
@@ -16,7 +16,7 @@ import { DeviceEventEmitter } from 'react-native';
16
16
  import StackScreen from './StackScreen';
17
17
  import ModalScreen from './ModalScreen';
18
18
  import Navigator from './Navigator';
19
- import { getModalOptions, getStackOptions } from './utils';
19
+ import { getModalOptions, getStackOptions, useNativeCanGoBack } from './utils';
20
20
  import { NavigationContainerProps } from './types';
21
21
  import { ApplicationContext, MiniAppContext } from '../Context';
22
22
  import Localize from './Localize';
@@ -93,6 +93,7 @@ const Navigation: React.FC<any> = ({
93
93
  const navigator = useRef(new Navigator(navigationRef, isReady));
94
94
  const [showGrid, setShowGrid] = useState(false);
95
95
  const insets = useSafeAreaInsets();
96
+ const syncCanGoBack = useNativeCanGoBack();
96
97
 
97
98
  let headerBackground = context?.designSystemConfig?.config?.headerBar;
98
99
  let headerGradient = theme.colors?.gradient;
@@ -192,7 +193,9 @@ const Navigation: React.FC<any> = ({
192
193
  ref={navigationRef}
193
194
  onReady={() => {
194
195
  isReady.current = true;
196
+ syncCanGoBack(navigationRef.current?.getRootState?.());
195
197
  }}
198
+ onStateChange={syncCanGoBack}
196
199
  >
197
200
  <Stack.Navigator
198
201
  initialRouteName="Stack"
@@ -1,11 +1,23 @@
1
- import React, { useContext, useEffect, useMemo, useRef } from 'react';
1
+ import React, {
2
+ useCallback,
3
+ useContext,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ } from 'react';
2
8
  import {
9
+ CardStyleInterpolators,
3
10
  StackNavigationOptions,
4
11
  TransitionPresets,
5
12
  } from '@react-navigation/stack';
13
+ import type {
14
+ StackCardInterpolatedStyle,
15
+ StackCardInterpolationProps,
16
+ } from '@react-navigation/stack';
17
+ import type { NavigationState, PartialState } from '@react-navigation/native';
6
18
  import type { HeaderTitleProps, NavigationOptions } from './types';
7
19
  import { Colors, Spacing } from '../Consts';
8
- import { Animated, AppState, Platform } from 'react-native';
20
+ import { Animated, AppState, NativeModules, Platform } from 'react-native';
9
21
  import type { SharedValue } from 'react-native-reanimated';
10
22
  import { useSharedValue } from 'react-native-reanimated';
11
23
  import {
@@ -18,6 +30,26 @@ import { HeaderBackground } from './Components/HeaderBackground';
18
30
  import { HeaderLeft } from './Components/HeaderLeft';
19
31
  import { HeaderRight } from './Components/HeaderRight';
20
32
 
33
+ const forStackTransitionWithOverlay = (
34
+ props: StackCardInterpolationProps,
35
+ ): StackCardInterpolatedStyle => {
36
+ const { cardStyle, shadowStyle } =
37
+ CardStyleInterpolators.forHorizontalIOS(props);
38
+
39
+ return {
40
+ cardStyle,
41
+ shadowStyle,
42
+ overlayStyle: {
43
+ backgroundColor: '#FDEAF4',
44
+ opacity: props.current.progress.interpolate({
45
+ inputRange: [0, 1],
46
+ outputRange: [0, 0.3],
47
+ extrapolate: 'clamp',
48
+ }),
49
+ },
50
+ };
51
+ };
52
+
21
53
  /**
22
54
  * default options for stack screen
23
55
  */
@@ -38,8 +70,10 @@ const getStackOptions = (): StackNavigationOptions => {
38
70
  headerLeft: (props: any) => <HeaderLeft {...props} />,
39
71
  headerRight: (props: any) => <HeaderRight {...props} />,
40
72
  headerTintColor: Colors.black_17,
41
- gestureEnabled: false,
73
+ gestureEnabled: Platform.OS === 'ios',
42
74
  ...TransitionPresets.SlideFromRightIOS,
75
+ cardStyleInterpolator: forStackTransitionWithOverlay,
76
+ cardOverlayEnabled: true,
43
77
  };
44
78
  };
45
79
 
@@ -54,9 +88,20 @@ const getModalOptions = (): StackNavigationOptions => {
54
88
  cardOverlayEnabled: true,
55
89
  animation: 'none',
56
90
  presentation: 'transparentModal',
91
+ gestureEnabled: false,
57
92
  };
58
93
  };
59
94
 
95
+ /**
96
+ * screen owns its back flow (guard popup, custom handler or no back button),
97
+ * so swipe back must not bypass it
98
+ */
99
+ const hasCustomBackHandling = (params: NavigationOptions) =>
100
+ params.preventBack !== undefined ||
101
+ params.hiddenBack === true ||
102
+ typeof params.onBackHandler === 'function' ||
103
+ typeof params.onPressLeftHeader === 'function';
104
+
60
105
  /**
61
106
  * build react-navigation options
62
107
  */
@@ -125,6 +170,13 @@ const getOptions = (
125
170
  };
126
171
  }
127
172
 
173
+ /**
174
+ * only ever turns swipe back off, screens opt in via gestureEnabled
175
+ */
176
+ if (params.gestureEnabled === undefined && hasCustomBackHandling(params)) {
177
+ options.gestureEnabled = false;
178
+ }
179
+
128
180
  return {
129
181
  ...params,
130
182
  ...options,
@@ -230,6 +282,55 @@ const useAppState = () => {
230
282
  };
231
283
  };
232
284
 
285
+ /**
286
+ * screens the focused navigation branch can still pop.
287
+ * only stack navigators count, switching bottom tab is not a back step
288
+ */
289
+ const getStackDepth = (
290
+ state?: NavigationState | PartialState<NavigationState>,
291
+ ): number => {
292
+ const routes = state?.routes;
293
+ if (!routes?.length) {
294
+ return 0;
295
+ }
296
+
297
+ const index = state?.index ?? routes.length - 1;
298
+ const depth = state?.type === 'stack' ? index : 0;
299
+
300
+ return depth + getStackDepth(routes[index]?.state);
301
+ };
302
+
303
+ /**
304
+ * report back ownership to the native container: `true` when the mini app sits
305
+ * on its root screen and native may dismiss the rootview, `false` while
306
+ * react-navigation still has screens (or a modal / bottom sheet) to pop.
307
+ */
308
+ const useNativeCanGoBack = () => {
309
+ const lastValue = useRef<boolean | undefined>(undefined);
310
+
311
+ return useCallback(
312
+ (state?: NavigationState | PartialState<NavigationState>) => {
313
+ const canDismiss = getStackDepth(state) === 0;
314
+ if (lastValue.current === canDismiss) {
315
+ return;
316
+ }
317
+
318
+ const setCanGoBack = NativeModules?.MiniAppModule?.setCanGoBack;
319
+ if (typeof setCanGoBack !== 'function') {
320
+ return;
321
+ }
322
+
323
+ lastValue.current = canDismiss;
324
+ try {
325
+ setCanGoBack(canDismiss);
326
+ } catch (error) {
327
+ console.warn('[NavigationContainer] setCanGoBack failed:', error);
328
+ }
329
+ },
330
+ [],
331
+ );
332
+ };
333
+
233
334
  /**
234
335
  * Union of the two animation runtimes an internal foundation component might
235
336
  * receive. Public Screen props still accept React Native Animated.Value only;
@@ -271,9 +372,11 @@ export {
271
372
  getStackOptions,
272
373
  getModalOptions,
273
374
  getOptions,
375
+ getStackDepth,
274
376
  exportHeaderTitle,
275
377
  setAutomationID,
276
378
  useComponentId,
277
379
  useAppState,
380
+ useNativeCanGoBack,
278
381
  useNormalizedSharedValue,
279
382
  };
package/package.json CHANGED
@@ -1,35 +1,35 @@
1
1
  {
2
- "name": "@momo-kits/foundation",
3
- "version": "0.163.1-beta.4",
4
- "description": "React Native Component Kits",
5
- "main": "index.ts",
6
- "scripts": {},
7
- "keywords": [
8
- "@momo-kits/foundation"
9
- ],
10
- "dependencies": {
11
- "react-native-fast-image": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-fast-image.git#v8.11.0",
12
- "@react-navigation/bottom-tabs": "7.4.2",
13
- "@react-navigation/core": "7.12.1",
14
- "@react-navigation/elements": "2.5.2",
15
- "@react-navigation/native": "7.1.14",
16
- "@react-navigation/routers": "7.4.1",
17
- "@react-navigation/stack": "7.4.2",
18
- "react-native-gesture-handler": "2.27.1",
19
- "react-native-linear-gradient": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-linear-gradient#v3.0.0",
20
- "react-native-reanimated": "4.2.2",
21
- "react-native-safe-area-context": "5.5.2",
22
- "@shopify/flash-list": "2.1.0",
23
- "lottie-react-native": "7.2.4"
24
- },
25
- "peerDependencies": {
26
- "react-native": "*"
27
- },
28
- "devDependencies": {
29
- "@types/color": "3.0.6"
30
- },
31
- "publishConfig": {
32
- "registry": "https://registry.npmjs.org/"
33
- },
34
- "license": "MoMo"
35
- }
2
+ "name": "@momo-kits/foundation",
3
+ "version": "0.163.1-beta.5",
4
+ "description": "React Native Component Kits",
5
+ "main": "index.ts",
6
+ "scripts": {},
7
+ "keywords": [
8
+ "@momo-kits/foundation"
9
+ ],
10
+ "dependencies": {
11
+ "react-native-fast-image": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-fast-image.git#v8.11.0",
12
+ "@react-navigation/bottom-tabs": "7.4.2",
13
+ "@react-navigation/core": "7.12.1",
14
+ "@react-navigation/elements": "2.5.2",
15
+ "@react-navigation/native": "7.1.14",
16
+ "@react-navigation/routers": "7.4.1",
17
+ "@react-navigation/stack": "7.4.2",
18
+ "react-native-gesture-handler": "2.27.1",
19
+ "react-native-linear-gradient": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-linear-gradient#v3.0.0",
20
+ "react-native-reanimated": "4.2.2",
21
+ "react-native-safe-area-context": "5.5.2",
22
+ "@shopify/flash-list": "2.1.0",
23
+ "lottie-react-native": "7.2.4"
24
+ },
25
+ "peerDependencies": {
26
+ "react-native": "*"
27
+ },
28
+ "devDependencies": {
29
+ "@types/color": "3.0.6"
30
+ },
31
+ "publishConfig": {
32
+ "registry": "https://registry.npmjs.org/"
33
+ },
34
+ "license": "MoMo"
35
+ }