@momo-kits/foundation 0.169.7-beta.3 → 0.169.7-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Application/BottomSheet.hooks.ts +8 -8
- package/Application/BottomSheet.parts.tsx +34 -44
- package/Application/BottomSheet.tsx +37 -40
- package/Application/BottomTab/ActiveIndicator.tsx +14 -15
- package/Application/BottomTab/BottomTabBar.tsx +62 -49
- package/Application/BottomTab/BottomTabInset.tsx +4 -8
- package/Application/BottomTab/CurvedContainer.tsx +12 -14
- package/Application/BottomTab/CustomBottomTabItem.tsx +13 -13
- package/Application/BottomTab/DuoBarCompression.tsx +19 -13
- package/Application/BottomTab/DuoRailTabBar.tsx +24 -20
- package/Application/BottomTab/DuoTabBar.tsx +10 -8
- package/Application/BottomTab/TabBarIcon.tsx +29 -15
- package/Application/BottomTab/TabScreen.tsx +5 -1
- package/Application/BottomTab/index.tsx +30 -33
- package/Application/BottomTab/metrics.ts +23 -23
- package/Application/BottomTab/tabItems.ts +1 -1
- package/Application/BottomTab/usePressLift.ts +2 -2
- package/Application/Components/BackgroundImageView.tsx +0 -4
- package/Application/Components/DuoGlassBackground.tsx +4 -5
- package/Application/Components/HeaderAnimated.tsx +0 -4
- package/Application/Components/HeaderBackground.tsx +0 -4
- package/Application/Components/HeaderExtendHeader.tsx +10 -11
- package/Application/Components/HeaderLeft.tsx +1 -2
- package/Application/Components/HeaderRight.tsx +1 -2
- package/Application/Components/HeaderTitle.shared.ts +9 -11
- package/Application/Components/HeaderTitle.tsx +3 -4
- package/Application/Components/HeaderToolkitAction.tsx +20 -17
- package/Application/Components/NavigationButton.tsx +1 -2
- package/Application/Components/SearchHeader.tsx +10 -17
- package/Application/Components/TitleJourney.tsx +2 -2
- package/Application/Components/TitleLocation.tsx +2 -2
- package/Application/Components/TitleUser.tsx +2 -2
- package/Application/Components/useToolkitActions.tsx +32 -17
- package/Application/KitAdoption/AdoptionBadge.tsx +119 -0
- package/Application/KitAdoption/AdoptionProbe.tsx +166 -0
- package/Application/KitAdoption/AdoptionStore.ts +80 -0
- package/Application/KitAdoption/Authorship/utils.ts +137 -0
- package/Application/KitAdoption/Slots/utils.ts +68 -0
- package/Application/KitAdoption/constants.ts +120 -0
- package/Application/KitAdoption/index.ts +12 -0
- package/Application/KitAdoption/styles.ts +55 -0
- package/Application/KitAdoption/types.ts +61 -0
- package/Application/KitAdoption/utils.ts +376 -0
- package/Application/Localize.ts +0 -7
- package/Application/ModalScreen.tsx +10 -10
- package/Application/Navigation.ts +16 -14
- package/Application/NavigationContainer.tsx +18 -19
- package/Application/Navigator.ts +48 -20
- package/Application/ScaleSizeProvider.tsx +6 -13
- package/Application/StackScreen.tracking.ts +33 -11
- package/Application/StackScreen.tsx +54 -10
- package/Application/TooltipPortal.tsx +5 -12
- package/Application/WidgetContainer.tsx +4 -10
- package/Application/__tests__/KitAdoption.integration.test.tsx +253 -0
- package/Application/__tests__/KitAdoption.test.ts +283 -0
- package/Application/__tests__/KitAdoptionAuthorship.test.ts +132 -0
- package/Application/__tests__/KitAdoptionStore.test.ts +110 -0
- package/Application/__tests__/KitAdoptionStructural.test.ts +193 -0
- package/Application/__tests__/modalLayout.test.ts +128 -0
- package/Application/modalLayout.ts +14 -16
- package/Application/navigationOptions.tsx +17 -21
- package/Badge/Badge.tsx +0 -5
- package/Badge/BadgeDot.tsx +0 -1
- package/Badge/BadgeDotAnimation.tsx +7 -15
- package/Badge/BadgeRibbon.tsx +38 -46
- package/Badge/Shape.tsx +0 -2
- package/Badge/types.ts +2 -2
- package/Button/index.tsx +16 -5
- package/Button/utils.ts +15 -9
- package/CheckBox/index.tsx +0 -4
- package/Consts/theme.ts +10 -10
- package/Context/index.ts +1 -5
- package/Divider/DashDivider.tsx +0 -1
- package/Divider/index.tsx +0 -4
- package/FoundationList/index.tsx +0 -4
- package/Icon/index.tsx +6 -6
- package/Icon/types.ts +1 -1
- package/IconButton/index.tsx +12 -4
- package/Image/index.tsx +7 -9
- package/Input/Input.tsx +9 -8
- package/Input/InputDropDown.tsx +12 -10
- package/Input/InputMoney.tsx +8 -12
- package/Input/InputMoneyView.tsx +7 -14
- package/Input/InputOTP.tsx +33 -35
- package/Input/InputPhoneNumber.tsx +9 -8
- package/Input/InputSearch.tsx +6 -4
- package/Input/InputTextArea.tsx +0 -4
- package/Input/SearchTextTyping.tsx +0 -4
- package/Input/SystemTextInput.tsx +2 -7
- package/Input/TextTyping.tsx +0 -4
- package/Input/common.tsx +12 -26
- package/Input/index.tsx +20 -17
- package/Input/moneyUtils.ts +4 -10
- package/Input/styles.ts +5 -0
- package/Input/utils.ts +12 -14
- package/Layout/Card.tsx +4 -7
- package/Layout/FloatingButton.tsx +0 -4
- package/Layout/Item.tsx +2 -6
- package/Layout/ItemList.tsx +7 -9
- package/Layout/ItemSectionList.tsx +1 -2
- package/Layout/ReservedRegions.tsx +25 -25
- package/Layout/Screen.tsx +58 -56
- package/Layout/Section.tsx +5 -8
- package/Layout/TrackingScope.tsx +0 -1
- package/Layout/screenContent.tsx +2 -4
- package/Layout/screenFooter.tsx +18 -28
- package/Layout/screenHeader.tsx +31 -34
- package/Layout/screenQuickReturn.tsx +20 -17
- package/Layout/screenScroll.ts +7 -4
- package/Layout/screenTypes.ts +2 -3
- package/Layout/types.ts +4 -2
- package/Layout/utils.ts +37 -31
- package/Loader/DotLoader.tsx +0 -4
- package/Loader/Loader.tsx +0 -4
- package/Loader/ProgressBar.tsx +0 -1
- package/Loader/Spinner.tsx +0 -4
- package/Loader/utils.ts +7 -11
- package/Pagination/Dot.tsx +0 -4
- package/Pagination/PaginationDot.tsx +0 -1
- package/Pagination/PaginationNumber.tsx +3 -5
- package/Pagination/PaginationScroll.tsx +0 -5
- package/Pagination/PaginationWhiteDot.tsx +0 -1
- package/Pagination/index.tsx +0 -4
- package/Pagination/types.ts +2 -2
- package/Popup/PopupNotify.tsx +49 -45
- package/Popup/PopupPromotion.tsx +7 -4
- package/Popup/types.ts +4 -4
- package/Popup/utils.ts +4 -11
- package/Radio/index.tsx +0 -4
- package/Skeleton/index.tsx +0 -8
- package/Switch/index.tsx +0 -1
- package/Tag/index.tsx +1 -5
- package/Tag/types.ts +3 -3
- package/Text/index.tsx +3 -14
- package/Text/styles.ts +1 -1
- package/Text/types.ts +6 -1
- package/Text/utils.ts +4 -20
- package/Title/index.tsx +32 -41
- package/ViewBoundary/index.tsx +2 -4
- package/index.ts +6 -0
- package/package.json +1 -1
package/Application/Navigator.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import {CommonActions, StackActions} from '@react-navigation/native';
|
|
2
2
|
import {BottomSheetParams, ModalParams, ScreenParams} from './types';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Imperative navigation API exposed to features through `ApplicationContext`.
|
|
6
|
-
* Every action is a no-op until the container reports ready.
|
|
7
|
-
*/
|
|
8
4
|
class Navigator {
|
|
9
5
|
ref?: any;
|
|
10
6
|
isReady?: any;
|
|
@@ -18,28 +14,40 @@ class Navigator {
|
|
|
18
14
|
this.isWidget = isWidget;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* push new stack screen
|
|
19
|
+
* @param params
|
|
20
|
+
*/
|
|
22
21
|
push = (params: ScreenParams) => {
|
|
23
22
|
if (this.isReady.current) {
|
|
24
23
|
this.ref.current?.dispatch?.(StackActions.push('Stack', params));
|
|
25
24
|
}
|
|
26
25
|
};
|
|
27
26
|
|
|
28
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* replace current screen with new screen
|
|
29
|
+
* @param params
|
|
30
|
+
*/
|
|
29
31
|
replace = (params: ScreenParams) => {
|
|
30
32
|
if (this.isReady.current) {
|
|
31
33
|
this.ref.current?.dispatch?.(StackActions.replace('Stack', params));
|
|
32
34
|
}
|
|
33
35
|
};
|
|
34
36
|
|
|
35
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* pop to dismiss a screen
|
|
39
|
+
* @param count
|
|
40
|
+
*/
|
|
36
41
|
pop = (count?: number) => {
|
|
37
42
|
if (this.isReady.current) {
|
|
38
43
|
this.ref.current?.dispatch?.(StackActions.pop(count ?? 1));
|
|
39
44
|
}
|
|
40
45
|
};
|
|
41
46
|
|
|
42
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* present a new screen, show from bottom iOS
|
|
49
|
+
* @param params
|
|
50
|
+
*/
|
|
43
51
|
present = (params: ScreenParams) => {
|
|
44
52
|
if (this.isReady.current) {
|
|
45
53
|
this.ref.current?.dispatch?.(StackActions.push('Dialog', params));
|
|
@@ -47,8 +55,9 @@ class Navigator {
|
|
|
47
55
|
};
|
|
48
56
|
|
|
49
57
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
58
|
+
* show a modal popup
|
|
59
|
+
* @param params
|
|
60
|
+
* @param onError
|
|
52
61
|
*/
|
|
53
62
|
showModal = (params: ModalParams, onError?: (error: string) => void) => {
|
|
54
63
|
try {
|
|
@@ -67,7 +76,11 @@ class Navigator {
|
|
|
67
76
|
}
|
|
68
77
|
};
|
|
69
78
|
|
|
70
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* show a bottom sheet
|
|
81
|
+
* @param params
|
|
82
|
+
* @param onError
|
|
83
|
+
*/
|
|
71
84
|
showBottomSheet = (
|
|
72
85
|
params: BottomSheetParams,
|
|
73
86
|
onError?: (error: string) => void
|
|
@@ -89,21 +102,31 @@ class Navigator {
|
|
|
89
102
|
}
|
|
90
103
|
};
|
|
91
104
|
|
|
92
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* pop all screen route
|
|
107
|
+
*/
|
|
93
108
|
popToTop = () => {
|
|
94
109
|
if (this.isReady.current) {
|
|
95
110
|
this.ref.current?.dispatch?.(StackActions.popToTop());
|
|
96
111
|
}
|
|
97
112
|
};
|
|
98
113
|
|
|
99
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* navigate route name bottom tab only
|
|
116
|
+
* @param name
|
|
117
|
+
*/
|
|
100
118
|
navigate = (name: string) => {
|
|
101
119
|
if (this.isReady.current) {
|
|
102
|
-
this.ref.current?.dispatch?.(
|
|
120
|
+
this.ref.current?.dispatch?.(
|
|
121
|
+
CommonActions.navigate(name)
|
|
122
|
+
);
|
|
103
123
|
}
|
|
104
124
|
};
|
|
105
125
|
|
|
106
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* reset a navigation flow with new screen
|
|
128
|
+
* @param params
|
|
129
|
+
*/
|
|
107
130
|
reset = (params: ScreenParams) => {
|
|
108
131
|
if (this.isReady.current) {
|
|
109
132
|
this.ref.current?.dispatch?.(
|
|
@@ -121,21 +144,26 @@ class Navigator {
|
|
|
121
144
|
}
|
|
122
145
|
};
|
|
123
146
|
|
|
124
|
-
/**
|
|
147
|
+
/**
|
|
148
|
+
* dismiss a feature data
|
|
149
|
+
* @param data
|
|
150
|
+
*/
|
|
125
151
|
setDismissData = (data: any) => {
|
|
126
152
|
this.dismissData = data;
|
|
127
153
|
};
|
|
128
154
|
|
|
129
155
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
156
|
+
* set app context using for features of kit
|
|
157
|
+
* @param context
|
|
132
158
|
*/
|
|
133
|
-
setCurrentContext = (
|
|
159
|
+
setCurrentContext = (context: {
|
|
134
160
|
code?: string;
|
|
135
161
|
name?: {vi: string; en: string};
|
|
136
162
|
description?: {vi: string; en: string};
|
|
137
163
|
icon?: string;
|
|
138
|
-
}) => {
|
|
164
|
+
}) => {
|
|
165
|
+
console.log(context);
|
|
166
|
+
};
|
|
139
167
|
}
|
|
140
168
|
|
|
141
169
|
export default Navigator;
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import React, { FC
|
|
2
|
-
import {
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { ScaleSizeContext } from '../Context';
|
|
3
3
|
import { ScaleSizeProviderProps } from './types';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Caps the font scale of its subtree at `scaleSizeMaxRate` × the design size
|
|
7
|
-
* (`useScaleSize`), passed down in MiniAppContext. The nearest provider wins;
|
|
8
|
-
* an undefined rate lifts an outer cap.
|
|
9
|
-
*/
|
|
5
|
+
/** @deprecated Max font scale is fixed at 1.5; this provider no longer affects scaling. */
|
|
10
6
|
const ScaleSizeProvider: FC<ScaleSizeProviderProps> = ({
|
|
11
7
|
scaleSizeMaxRate,
|
|
12
8
|
children,
|
|
13
9
|
}) => {
|
|
14
|
-
const context = useContext<object | undefined>(MiniAppContext);
|
|
15
|
-
const value = useMemo(() => {
|
|
16
|
-
return { ...context, scaleSizeMaxRate };
|
|
17
|
-
}, [context, scaleSizeMaxRate]);
|
|
18
|
-
|
|
19
10
|
return (
|
|
20
|
-
<
|
|
11
|
+
<ScaleSizeContext.Provider value={{ scaleSizeMaxRate }}>
|
|
12
|
+
{children}
|
|
13
|
+
</ScaleSizeContext.Provider>
|
|
21
14
|
);
|
|
22
15
|
};
|
|
23
16
|
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import { Alert } from 'react-native';
|
|
2
2
|
import { version } from '../package.json';
|
|
3
|
+
import { getAdoptionTrackingParams } from './KitAdoption';
|
|
4
|
+
import type { AdoptionMeasureRef } from './KitAdoption/types';
|
|
3
5
|
|
|
4
6
|
type ScreenTrackingDeps = {
|
|
5
7
|
tracking: { current: any };
|
|
6
8
|
context: any;
|
|
7
9
|
navigator: any;
|
|
8
10
|
screenName: string;
|
|
11
|
+
adoptionMeasure?: AdoptionMeasureRef;
|
|
9
12
|
};
|
|
10
13
|
|
|
11
|
-
/**
|
|
12
|
-
* Auto-tracking reporters of a stack screen. Each event fires at most once per
|
|
13
|
-
* screen, guarded by the `release*` flags on `tracking.current`.
|
|
14
|
-
*/
|
|
15
14
|
export const createScreenTracking = ({
|
|
16
15
|
tracking,
|
|
17
16
|
context,
|
|
18
17
|
navigator,
|
|
19
18
|
screenName,
|
|
19
|
+
adoptionMeasure,
|
|
20
20
|
}: ScreenTrackingDeps) => {
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* tracking for screen load
|
|
23
|
+
*/
|
|
22
24
|
const onScreenLoad = () => {
|
|
23
25
|
if (!tracking.current?.releaseLoad) {
|
|
24
26
|
let timeLoad = tracking.current.timeLoad;
|
|
@@ -26,6 +28,8 @@ export const createScreenTracking = ({
|
|
|
26
28
|
timeLoad = tracking.current.endTime - tracking.current.startTime;
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
const adoption = getAdoptionTrackingParams(adoptionMeasure?.current?.());
|
|
32
|
+
|
|
29
33
|
context?.autoTracking?.({
|
|
30
34
|
...context,
|
|
31
35
|
screenName,
|
|
@@ -36,6 +40,7 @@ export const createScreenTracking = ({
|
|
|
36
40
|
params: tracking.current.params,
|
|
37
41
|
version: version,
|
|
38
42
|
lastElement: tracking.current.lastElement,
|
|
43
|
+
adoption,
|
|
39
44
|
});
|
|
40
45
|
navigator?.maxApi?.stopTrace?.(
|
|
41
46
|
tracking.current.traceIdLoad,
|
|
@@ -44,22 +49,29 @@ export const createScreenTracking = ({
|
|
|
44
49
|
);
|
|
45
50
|
tracking.current.releaseLoad = true;
|
|
46
51
|
|
|
52
|
+
/**
|
|
53
|
+
* debug
|
|
54
|
+
*/
|
|
47
55
|
navigator?.maxApi?.showToastDebug?.({
|
|
48
56
|
appId: context.appId,
|
|
49
57
|
message: `${screenName} screen_load_time ${timeLoad}`,
|
|
50
58
|
type: 'ERROR',
|
|
51
59
|
});
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
if (
|
|
61
|
+
__DEV__ &&
|
|
62
|
+
tracking.current.lastElement?.children?.current?.length > 0
|
|
63
|
+
) {
|
|
54
64
|
Alert.alert(
|
|
55
65
|
`${screenName}- load ${timeLoad}ms`,
|
|
56
|
-
JSON.stringify(
|
|
66
|
+
JSON.stringify(tracking.current.lastElement?.children?.current),
|
|
57
67
|
);
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
70
|
};
|
|
61
71
|
|
|
62
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* tracking for screen load
|
|
74
|
+
*/
|
|
63
75
|
const onScreenInteraction = () => {
|
|
64
76
|
if (!tracking.current?.releaseInteraction) {
|
|
65
77
|
let timeLoad = tracking.current.timeLoad;
|
|
@@ -87,6 +99,9 @@ export const createScreenTracking = ({
|
|
|
87
99
|
);
|
|
88
100
|
tracking.current.releaseInteraction = true;
|
|
89
101
|
|
|
102
|
+
/**
|
|
103
|
+
* debug toast
|
|
104
|
+
*/
|
|
90
105
|
navigator?.maxApi?.showToastDebug?.({
|
|
91
106
|
appId: context.appId,
|
|
92
107
|
message: `${screenName} screen_interaction_time ${tracking.current.timeInteraction}`,
|
|
@@ -95,7 +110,9 @@ export const createScreenTracking = ({
|
|
|
95
110
|
}
|
|
96
111
|
};
|
|
97
112
|
|
|
98
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* tracking for first interaction by user
|
|
115
|
+
*/
|
|
99
116
|
const onFirstInteraction = (action: string) => {
|
|
100
117
|
if (!tracking.current?.releaseUserInteraction) {
|
|
101
118
|
const timeLoad = tracking.current.endTime - tracking.current.startTime;
|
|
@@ -109,6 +126,9 @@ export const createScreenTracking = ({
|
|
|
109
126
|
});
|
|
110
127
|
tracking.current.releaseUserInteraction = true;
|
|
111
128
|
|
|
129
|
+
/**
|
|
130
|
+
* debug
|
|
131
|
+
*/
|
|
112
132
|
navigator?.maxApi?.showToastDebug?.({
|
|
113
133
|
appId: context.appId,
|
|
114
134
|
message: `${screenName} user_interaction ${timeLoad}`,
|
|
@@ -117,7 +137,9 @@ export const createScreenTracking = ({
|
|
|
117
137
|
}
|
|
118
138
|
};
|
|
119
139
|
|
|
120
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* tracking for loading screen
|
|
142
|
+
*/
|
|
121
143
|
const onScreenLoading = () => {
|
|
122
144
|
const start = tracking.current.timeStartLoading;
|
|
123
145
|
const end = tracking.current.timeEndLoading;
|
|
@@ -8,12 +8,15 @@ import { SwipeBackHaptic } from './Components/SwipeBackHaptic';
|
|
|
8
8
|
import { useAppState } from './hooks';
|
|
9
9
|
import { createScreenTracking } from './StackScreen.tracking';
|
|
10
10
|
import { TooltipPortalHost, TooltipPortalProvider } from './TooltipPortal';
|
|
11
|
+
import { AdoptionProbe } from './KitAdoption';
|
|
12
|
+
import type { WalkResult } from './KitAdoption/types';
|
|
11
13
|
|
|
12
14
|
const runAfterInteractions = InteractionManager.runAfterInteractions;
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
+
* container for stack screen
|
|
18
|
+
* @param props
|
|
19
|
+
* @constructor
|
|
17
20
|
*/
|
|
18
21
|
const StackScreen: React.FC<any> = props => {
|
|
19
22
|
const { navigator } = useContext(ApplicationContext);
|
|
@@ -40,6 +43,9 @@ const StackScreen: React.FC<any> = props => {
|
|
|
40
43
|
lastElement: undefined,
|
|
41
44
|
});
|
|
42
45
|
const widgets = useRef<any>([]);
|
|
46
|
+
const adoptionMeasure = useRef<(() => WalkResult | undefined) | undefined>(
|
|
47
|
+
undefined,
|
|
48
|
+
);
|
|
43
49
|
const context = useContext<any>(MiniAppContext);
|
|
44
50
|
|
|
45
51
|
const {
|
|
@@ -63,12 +69,18 @@ const StackScreen: React.FC<any> = props => {
|
|
|
63
69
|
|
|
64
70
|
const screenName = Component?.name || Component?.type?.name || 'Invalid';
|
|
65
71
|
|
|
72
|
+
/**
|
|
73
|
+
* set options for screen
|
|
74
|
+
*/
|
|
66
75
|
useLayoutEffect(() => {
|
|
67
76
|
if (options) {
|
|
68
77
|
navigation.setOptions(options);
|
|
69
78
|
}
|
|
70
79
|
}, [navigation, options]);
|
|
71
80
|
|
|
81
|
+
/**
|
|
82
|
+
* tracking for screen
|
|
83
|
+
*/
|
|
72
84
|
useEffect(() => {
|
|
73
85
|
let focusScreen: any;
|
|
74
86
|
let onFocusApp: any;
|
|
@@ -142,7 +154,6 @@ const StackScreen: React.FC<any> = props => {
|
|
|
142
154
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
143
155
|
}, []);
|
|
144
156
|
|
|
145
|
-
/** Reports a navigation to this screen: `back` if it was shown before. */
|
|
146
157
|
const onScreenNavigated = (pre: string, current: string) => {
|
|
147
158
|
if (!isBackgroundToForeground) {
|
|
148
159
|
const item: any = {
|
|
@@ -160,6 +171,9 @@ const StackScreen: React.FC<any> = props => {
|
|
|
160
171
|
|
|
161
172
|
tracking.current.mounted = true;
|
|
162
173
|
|
|
174
|
+
/**
|
|
175
|
+
* debug toast
|
|
176
|
+
*/
|
|
163
177
|
navigator?.maxApi?.showToastDebug?.({
|
|
164
178
|
appId: context.appId,
|
|
165
179
|
message: `${screenName} screen_navigated`,
|
|
@@ -173,7 +187,13 @@ const StackScreen: React.FC<any> = props => {
|
|
|
173
187
|
onScreenInteraction,
|
|
174
188
|
onFirstInteraction,
|
|
175
189
|
onScreenLoading,
|
|
176
|
-
} = createScreenTracking({
|
|
190
|
+
} = createScreenTracking({
|
|
191
|
+
tracking,
|
|
192
|
+
context,
|
|
193
|
+
navigator,
|
|
194
|
+
screenName,
|
|
195
|
+
adoptionMeasure,
|
|
196
|
+
});
|
|
177
197
|
|
|
178
198
|
return (
|
|
179
199
|
<ScreenContext.Provider
|
|
@@ -181,7 +201,9 @@ const StackScreen: React.FC<any> = props => {
|
|
|
181
201
|
screenName,
|
|
182
202
|
bottomTab: !!bottomTab,
|
|
183
203
|
onElementLoad: (item: any) => {
|
|
184
|
-
|
|
204
|
+
/**
|
|
205
|
+
* widget handle
|
|
206
|
+
*/
|
|
185
207
|
if (item?.componentName === 'Widget') {
|
|
186
208
|
const index = widgets.current.findIndex(
|
|
187
209
|
(element: any) => element.componentId === item.componentId,
|
|
@@ -205,25 +227,35 @@ const StackScreen: React.FC<any> = props => {
|
|
|
205
227
|
return;
|
|
206
228
|
}
|
|
207
229
|
|
|
230
|
+
/**
|
|
231
|
+
* tracking for element screen load
|
|
232
|
+
*/
|
|
208
233
|
clearTimeout(tracking.current.timeoutLoad);
|
|
209
234
|
tracking.current.endTime = Date.now();
|
|
210
235
|
tracking.current.timeoutInteraction?.cancel?.();
|
|
211
236
|
tracking.current.timeoutInteraction = runAfterInteractions(() => {
|
|
212
|
-
|
|
213
|
-
|
|
237
|
+
tracking.current.timeInteraction =
|
|
238
|
+
Date.now() - tracking.current.startTime;
|
|
214
239
|
});
|
|
215
240
|
|
|
241
|
+
/**
|
|
242
|
+
* support for debug last element
|
|
243
|
+
*/
|
|
216
244
|
if (item?.componentName) {
|
|
217
245
|
tracking.current.lastElement = item;
|
|
218
246
|
}
|
|
219
247
|
|
|
220
|
-
|
|
248
|
+
/**
|
|
249
|
+
* for stop tracking when user interaction
|
|
250
|
+
*/
|
|
221
251
|
if (item?.interaction) {
|
|
222
252
|
onScreenLoad();
|
|
223
253
|
onScreenInteraction();
|
|
224
254
|
onFirstInteraction(item?.action);
|
|
225
255
|
}
|
|
226
|
-
|
|
256
|
+
/**
|
|
257
|
+
* timeout for handle tracking screen
|
|
258
|
+
*/
|
|
227
259
|
tracking.current.timeoutLoad = setTimeout(() => {
|
|
228
260
|
const time = tracking.current.endTime - tracking.current.startTime;
|
|
229
261
|
tracking.current.widgets = widgets.current;
|
|
@@ -241,10 +273,16 @@ const StackScreen: React.FC<any> = props => {
|
|
|
241
273
|
tracking.current.timeStartLoading = Date.now();
|
|
242
274
|
}
|
|
243
275
|
|
|
276
|
+
/**
|
|
277
|
+
* tracking for loading screen
|
|
278
|
+
*/
|
|
244
279
|
if (!loading) {
|
|
245
280
|
tracking.current.timeEndLoading = Date.now();
|
|
246
281
|
}
|
|
247
282
|
|
|
283
|
+
/**
|
|
284
|
+
* timeout for handle tracking screen
|
|
285
|
+
*/
|
|
248
286
|
clearTimeout(tracking.current.timeoutLoading);
|
|
249
287
|
tracking.current.timeoutLoading = setTimeout(() => {
|
|
250
288
|
onScreenLoading();
|
|
@@ -256,7 +294,13 @@ const StackScreen: React.FC<any> = props => {
|
|
|
256
294
|
}}
|
|
257
295
|
>
|
|
258
296
|
<TooltipPortalProvider>
|
|
259
|
-
<
|
|
297
|
+
<AdoptionProbe
|
|
298
|
+
screenName={screenName}
|
|
299
|
+
navigation={props.navigation}
|
|
300
|
+
measureRef={adoptionMeasure}
|
|
301
|
+
>
|
|
302
|
+
<Component heightHeader={heightHeader} {...data} />
|
|
303
|
+
</AdoptionProbe>
|
|
260
304
|
<TooltipPortalHost />
|
|
261
305
|
<SwipeBackHaptic />
|
|
262
306
|
</TooltipPortalProvider>
|
|
@@ -21,14 +21,10 @@ const TooltipPortalContext = createContext<TooltipPortalContextValue | null>(
|
|
|
21
21
|
null,
|
|
22
22
|
);
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Registry of tooltip contents that `TooltipPortalHost` renders in one layer
|
|
26
|
-
* above the screen, so tooltips aren't clipped by their anchor's parents.
|
|
27
|
-
*/
|
|
28
24
|
export const TooltipPortalProvider: React.FC<{ children: ReactNode }> = ({
|
|
29
25
|
children,
|
|
30
26
|
}) => {
|
|
31
|
-
//
|
|
27
|
+
// Use ref for synchronous updates + reducer for manual re-renders
|
|
32
28
|
const portalsRef = useRef<Map<string, ReactNode>>(new Map());
|
|
33
29
|
const hostRef = useRef<View>(null);
|
|
34
30
|
const [updateCounter, forceUpdate] = useReducer((x: number) => x + 1, 0);
|
|
@@ -36,15 +32,16 @@ export const TooltipPortalProvider: React.FC<{ children: ReactNode }> = ({
|
|
|
36
32
|
|
|
37
33
|
const register = useCallback((id: string, content: ReactNode) => {
|
|
38
34
|
portalsRef.current.set(id, content);
|
|
39
|
-
forceUpdate();
|
|
35
|
+
forceUpdate(); // Trigger re-render to show new content
|
|
40
36
|
}, []);
|
|
41
37
|
|
|
42
38
|
const unregister = useCallback((id: string, immediate = false) => {
|
|
43
39
|
const hasItem = portalsRef.current.has(id);
|
|
44
|
-
if (!hasItem) return;
|
|
40
|
+
if (!hasItem) return; // Already removed
|
|
45
41
|
|
|
46
42
|
portalsRef.current.delete(id);
|
|
47
43
|
|
|
44
|
+
// Clear any pending updates
|
|
48
45
|
if (pendingUpdateRef.current) {
|
|
49
46
|
clearTimeout(pendingUpdateRef.current);
|
|
50
47
|
pendingUpdateRef.current = null;
|
|
@@ -75,7 +72,6 @@ export const TooltipPortalProvider: React.FC<{ children: ReactNode }> = ({
|
|
|
75
72
|
);
|
|
76
73
|
};
|
|
77
74
|
|
|
78
|
-
/** Full-screen, touch-through layer that renders every registered tooltip. */
|
|
79
75
|
export const TooltipPortalHost: React.FC = () => {
|
|
80
76
|
const context = useContext(TooltipPortalContext);
|
|
81
77
|
|
|
@@ -99,10 +95,6 @@ export const TooltipPortalHost: React.FC = () => {
|
|
|
99
95
|
);
|
|
100
96
|
};
|
|
101
97
|
|
|
102
|
-
/**
|
|
103
|
-
* Tooltip portal API. Outside a provider it returns no-ops (and warns in dev)
|
|
104
|
-
* so a tooltip degrades instead of crashing.
|
|
105
|
-
*/
|
|
106
98
|
export const useTooltipPortal = () => {
|
|
107
99
|
const context = useContext(TooltipPortalContext);
|
|
108
100
|
|
|
@@ -112,6 +104,7 @@ export const useTooltipPortal = () => {
|
|
|
112
104
|
'useTooltipPortal must be used within TooltipPortalProvider. Tooltips may not appear correctly.',
|
|
113
105
|
);
|
|
114
106
|
}
|
|
107
|
+
// Return no-op functions if context is missing
|
|
115
108
|
return {
|
|
116
109
|
register: () => { },
|
|
117
110
|
unregister: () => { },
|
|
@@ -18,7 +18,6 @@ import { StyleSheet, View } from 'react-native';
|
|
|
18
18
|
|
|
19
19
|
const Stack = createStackNavigator();
|
|
20
20
|
|
|
21
|
-
/** Widget screen that reports its laid-out height to size the container. */
|
|
22
21
|
const WidgetContent: React.FC = ({ route }: any) => {
|
|
23
22
|
const Component = route?.params?.screen;
|
|
24
23
|
return (
|
|
@@ -32,10 +31,6 @@ const WidgetContent: React.FC = ({ route }: any) => {
|
|
|
32
31
|
);
|
|
33
32
|
};
|
|
34
33
|
|
|
35
|
-
/**
|
|
36
|
-
* Root of an embedded widget: its own navigator with the widget screen and the
|
|
37
|
-
* `Modal` route, sized to the widget's content height.
|
|
38
|
-
*/
|
|
39
34
|
const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
40
35
|
widget,
|
|
41
36
|
theme = defaultTheme,
|
|
@@ -66,9 +61,11 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
66
61
|
headerGradient = context?.designConfig?.headerGradient;
|
|
67
62
|
}
|
|
68
63
|
|
|
64
|
+
/**
|
|
65
|
+
* inject data for navigator
|
|
66
|
+
*/
|
|
69
67
|
navigator.current.maxApi = maxApi;
|
|
70
68
|
|
|
71
|
-
/** Text for a localization key, or the current-language side of `{ vi, en }`. */
|
|
72
69
|
const translate = (data?: string | { vi: string; en: string }) => {
|
|
73
70
|
if (data && typeof data !== 'string') {
|
|
74
71
|
return localize?.translateData(data);
|
|
@@ -84,10 +81,7 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
84
81
|
};
|
|
85
82
|
const isWhiteList = isWhiteListDesignSystem(mergedContext);
|
|
86
83
|
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
87
|
-
|
|
88
|
-
if (isWhiteList) {
|
|
89
|
-
navigationFontFamily = 'MomoTrustSans-Regular';
|
|
90
|
-
}
|
|
84
|
+
const navigationFontFamily = isWhiteList ? 'MomoTrustSans-Regular' : 'SFProText';
|
|
91
85
|
|
|
92
86
|
return (
|
|
93
87
|
<View style={[styles.container, { height: height ?? '100%' }]}>
|