@momo-kits/foundation 0.162.2-sp.2 → 0.162.2-test.10
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.tsx +2 -2
- package/Application/BottomTab/BottomTabBar.tsx +15 -15
- package/Application/BottomTab/index.tsx +55 -31
- package/Application/Components/BackgroundImageView.tsx +6 -22
- package/Application/Components/HeaderAnimated.tsx +29 -29
- package/Application/Components/HeaderBackground.tsx +26 -20
- package/Application/Components/HeaderExtendHeader.tsx +94 -115
- package/Application/Components/HeaderTitle.tsx +10 -43
- package/Application/Components/SearchHeader.tsx +21 -13
- package/Application/NavigationContainer.tsx +27 -2
- package/Application/ScaleSizeProvider.tsx +5 -3
- package/Application/WidgetContainer.tsx +1 -1
- package/Application/types.ts +5 -5
- package/Application/utils.tsx +2 -42
- package/Badge/BadgeDotAnimation.tsx +71 -53
- package/Button/index.tsx +4 -1
- package/Context/index.ts +6 -3
- package/Input/InputOTP.tsx +23 -38
- package/Layout/FloatingButton.tsx +59 -64
- package/Layout/Screen.tsx +20 -66
- package/Loader/ProgressBar.tsx +18 -20
- package/Pagination/Dot.tsx +2 -2
- package/Pagination/PaginationScroll.tsx +27 -31
- package/Skeleton/index.tsx +24 -32
- package/Text/utils.ts +15 -5
- package/package.json +1 -1
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import React, { Ref, useContext } from 'react';
|
|
1
|
+
import React, { Ref, useContext, useEffect, useRef } from 'react';
|
|
2
2
|
import LinearGradient from 'react-native-linear-gradient';
|
|
3
|
-
import { Dimensions, Platform, StyleSheet, View } from 'react-native';
|
|
4
|
-
import Animated, {
|
|
5
|
-
Extrapolation,
|
|
6
|
-
interpolate,
|
|
7
|
-
useAnimatedStyle,
|
|
8
|
-
} from 'react-native-reanimated';
|
|
9
3
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
4
|
+
import { Animated, Dimensions, Platform, StyleSheet, View } from 'react-native';
|
|
10
5
|
import { HeaderType } from '../../Layout/types';
|
|
11
6
|
import { InputRef, InputSearch } from '../../Input';
|
|
12
7
|
import Navigation from '../Navigation';
|
|
@@ -14,19 +9,20 @@ import { Colors, Radius, Spacing } from '../../Consts';
|
|
|
14
9
|
import { Image } from '../../Image';
|
|
15
10
|
import { SearchHeaderProps } from '../types';
|
|
16
11
|
import BackgroundImageView from './BackgroundImageView';
|
|
17
|
-
import {
|
|
18
|
-
AnimatedCompatValue,
|
|
19
|
-
useNormalizedSharedValue,
|
|
20
|
-
} from '../utils';
|
|
21
12
|
|
|
22
13
|
const SCREEN_PADDING = 12;
|
|
23
14
|
const BACK_WIDTH = 28;
|
|
24
15
|
|
|
25
16
|
const { width: screenWidth } = Dimensions.get('window');
|
|
17
|
+
const LinearGradientAnimated = Animated.createAnimatedComponent(LinearGradient);
|
|
26
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Header extended with background image
|
|
21
|
+
* @constructor
|
|
22
|
+
*/
|
|
27
23
|
const HeaderExtendHeader: React.FC<{
|
|
28
24
|
headerType?: HeaderType;
|
|
29
|
-
animatedValue:
|
|
25
|
+
animatedValue: Animated.Value;
|
|
30
26
|
heightHeader: number;
|
|
31
27
|
headerRightWidth: number;
|
|
32
28
|
inputSearchProps?: SearchHeaderProps;
|
|
@@ -42,131 +38,118 @@ const HeaderExtendHeader: React.FC<{
|
|
|
42
38
|
headerRightWidth = 73,
|
|
43
39
|
inputSearchProps,
|
|
44
40
|
inputSearchRef,
|
|
45
|
-
useShadowHeader
|
|
41
|
+
useShadowHeader = true,
|
|
46
42
|
gradientColor: customGradientColor,
|
|
47
43
|
headerBackground: customBackground,
|
|
48
44
|
}) => {
|
|
49
45
|
const { theme } = useContext(ApplicationContext);
|
|
50
46
|
const context = useContext<any>(MiniAppContext);
|
|
51
|
-
const
|
|
47
|
+
const animated = useRef(new Animated.Value(0));
|
|
52
48
|
const gradientColor = customGradientColor ?? theme.colors.gradient;
|
|
53
49
|
const headerBackground = customBackground ?? theme.assets?.headerBackground;
|
|
54
50
|
const leftPosition = inputSearchProps?.leftPosition || BACK_WIDTH + 20;
|
|
55
51
|
|
|
56
|
-
let useShadowHeader = useShadowHeaderProp;
|
|
57
|
-
if (inputSearchProps && Platform.OS === 'android') {
|
|
58
|
-
useShadowHeader = false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
52
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
62
53
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
54
|
+
const opacityBackground = animatedValue?.interpolate({
|
|
55
|
+
inputRange: [0, 52],
|
|
56
|
+
outputRange: [0, 1],
|
|
57
|
+
extrapolate: 'clamp',
|
|
58
|
+
});
|
|
59
|
+
const opacityGradient = animatedValue?.interpolate({
|
|
60
|
+
inputRange: [0, 52],
|
|
61
|
+
outputRange: [1, 0],
|
|
62
|
+
extrapolate: 'clamp',
|
|
63
|
+
});
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const listener = animatedValue.addListener(({ value }) => {
|
|
67
|
+
animated.current.setValue(value);
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
animatedValue?.removeListener(listener);
|
|
71
|
+
};
|
|
72
|
+
}, [animatedValue]);
|
|
75
73
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
[0, 100],
|
|
82
|
-
[SCREEN_PADDING, leftPosition],
|
|
83
|
-
Extrapolation.CLAMP,
|
|
84
|
-
),
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
width: interpolate(
|
|
88
|
-
sharedValue.value,
|
|
89
|
-
[0, 100],
|
|
90
|
-
[
|
|
91
|
-
screenWidth - SCREEN_PADDING * 2,
|
|
92
|
-
screenWidth - leftPosition - 12 - headerRightWidth,
|
|
93
|
-
],
|
|
94
|
-
Extrapolation.CLAMP,
|
|
95
|
-
),
|
|
96
|
-
}));
|
|
74
|
+
const height = animated.current.interpolate({
|
|
75
|
+
inputRange: [0, 100],
|
|
76
|
+
outputRange: [heightHeader + 52, heightHeader],
|
|
77
|
+
extrapolate: 'clamp',
|
|
78
|
+
});
|
|
97
79
|
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
: theme.colors.background.default };
|
|
80
|
+
const translateX = animated.current.interpolate({
|
|
81
|
+
inputRange: [0, 100],
|
|
82
|
+
outputRange: [SCREEN_PADDING, leftPosition],
|
|
83
|
+
extrapolate: 'clamp',
|
|
103
84
|
});
|
|
104
85
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
})
|
|
86
|
+
const backgroundColor = animated.current.interpolate({
|
|
87
|
+
inputRange: [0, 100],
|
|
88
|
+
outputRange: [
|
|
89
|
+
theme.colors.background.surface,
|
|
90
|
+
theme.colors.background.default,
|
|
91
|
+
],
|
|
92
|
+
extrapolate: 'clamp',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (inputSearchProps && Platform.OS === 'android') {
|
|
96
|
+
useShadowHeader = false;
|
|
97
|
+
}
|
|
113
98
|
|
|
114
99
|
if (inputSearchProps) {
|
|
115
100
|
return (
|
|
116
101
|
<View style={[{ zIndex: 0 }, showBaseLineDebug && styles.debugBaseLine]}>
|
|
117
|
-
<Animated.View style={
|
|
102
|
+
<Animated.View style={{ height: height }} />
|
|
118
103
|
<BackgroundImageView
|
|
119
104
|
useShadowHeader={useShadowHeader}
|
|
120
105
|
heightHeader={heightHeader}
|
|
121
|
-
|
|
106
|
+
opacityBackground={opacityBackground}
|
|
122
107
|
headerBackground={headerBackground}
|
|
123
108
|
/>
|
|
124
109
|
<Animated.View
|
|
125
110
|
style={[
|
|
126
111
|
styles.headerBox,
|
|
127
|
-
headerType === 'extended'
|
|
128
|
-
? heightStyle
|
|
129
|
-
: { height: heightHeader },
|
|
112
|
+
{ height: headerType === 'extended' ? height : heightHeader },
|
|
130
113
|
]}
|
|
131
114
|
>
|
|
132
115
|
{!!gradientColor && (
|
|
133
|
-
<
|
|
134
|
-
|
|
116
|
+
<LinearGradientAnimated
|
|
117
|
+
colors={[gradientColor, gradientColor + '00']}
|
|
118
|
+
style={[styles.extendedHeader, { opacity: opacityGradient }]}
|
|
135
119
|
>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
loading={false}
|
|
145
|
-
/>
|
|
146
|
-
)}
|
|
147
|
-
</LinearGradient>
|
|
148
|
-
</Animated.View>
|
|
120
|
+
{!!theme.assets?.headerBackground && (
|
|
121
|
+
<Image
|
|
122
|
+
style={styles.headerBackground}
|
|
123
|
+
source={{ uri: theme.assets?.headerBackground }}
|
|
124
|
+
loading={false}
|
|
125
|
+
/>
|
|
126
|
+
)}
|
|
127
|
+
</LinearGradientAnimated>
|
|
149
128
|
)}
|
|
150
129
|
</Animated.View>
|
|
151
130
|
<Animated.View
|
|
152
|
-
style={
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
heightStyle,
|
|
159
|
-
]}
|
|
131
|
+
style={{
|
|
132
|
+
justifyContent: 'flex-end',
|
|
133
|
+
height,
|
|
134
|
+
position: 'absolute',
|
|
135
|
+
zIndex: 2,
|
|
136
|
+
}}
|
|
160
137
|
>
|
|
161
138
|
<Animated.View
|
|
162
|
-
style={
|
|
139
|
+
style={{
|
|
140
|
+
transform: [{ translateX }],
|
|
141
|
+
marginVertical: Spacing.S,
|
|
142
|
+
width: animated.current.interpolate({
|
|
143
|
+
inputRange: [0, 100],
|
|
144
|
+
outputRange: [
|
|
145
|
+
screenWidth - SCREEN_PADDING * 2,
|
|
146
|
+
screenWidth - leftPosition - 12 - headerRightWidth,
|
|
147
|
+
],
|
|
148
|
+
extrapolate: 'clamp',
|
|
149
|
+
}),
|
|
150
|
+
}}
|
|
163
151
|
>
|
|
164
|
-
<Animated.View
|
|
165
|
-
style={[
|
|
166
|
-
{ borderRadius: Radius.XL },
|
|
167
|
-
searchBackgroundStyle,
|
|
168
|
-
]}
|
|
169
|
-
>
|
|
152
|
+
<Animated.View style={{ backgroundColor, borderRadius: Radius.XL }}>
|
|
170
153
|
<InputSearch
|
|
171
154
|
{...inputSearchProps}
|
|
172
155
|
ref={inputSearchRef}
|
|
@@ -186,26 +169,22 @@ const HeaderExtendHeader: React.FC<{
|
|
|
186
169
|
<BackgroundImageView
|
|
187
170
|
useShadowHeader={useShadowHeader}
|
|
188
171
|
heightHeader={heightHeader}
|
|
189
|
-
|
|
172
|
+
opacityBackground={opacityBackground}
|
|
190
173
|
headerBackground={headerBackground}
|
|
191
174
|
/>
|
|
192
175
|
{!!gradientColor && (
|
|
193
|
-
<
|
|
194
|
-
|
|
176
|
+
<LinearGradientAnimated
|
|
177
|
+
colors={[gradientColor, gradientColor + '00']}
|
|
178
|
+
style={[styles.extendedHeader, { opacity: opacityGradient }]}
|
|
195
179
|
>
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
loading={false}
|
|
205
|
-
/>
|
|
206
|
-
)}
|
|
207
|
-
</LinearGradient>
|
|
208
|
-
</Animated.View>
|
|
180
|
+
{!!headerBackground && (
|
|
181
|
+
<Image
|
|
182
|
+
style={styles.headerBackground}
|
|
183
|
+
source={{ uri: headerBackground }}
|
|
184
|
+
loading={false}
|
|
185
|
+
/>
|
|
186
|
+
)}
|
|
187
|
+
</LinearGradientAnimated>
|
|
209
188
|
)}
|
|
210
189
|
<View style={{ height: heightHeader }} />
|
|
211
190
|
</View>
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import React, { useContext } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Animated,
|
|
3
4
|
Dimensions,
|
|
4
5
|
StyleSheet,
|
|
5
6
|
TouchableOpacity,
|
|
6
7
|
View,
|
|
7
8
|
} from 'react-native';
|
|
8
|
-
import Animated, {
|
|
9
|
-
Extrapolation,
|
|
10
|
-
interpolate,
|
|
11
|
-
useAnimatedStyle,
|
|
12
|
-
} from 'react-native-reanimated';
|
|
13
9
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
14
10
|
import { exportFontFamily, Text, useScaleSize } from '../../Text';
|
|
15
11
|
import { Colors, Radius, Spacing, Styles } from '../../Consts';
|
|
@@ -21,51 +17,22 @@ import {
|
|
|
21
17
|
import { Image } from '../../Image';
|
|
22
18
|
import { Icon } from '../../Icon';
|
|
23
19
|
import { Skeleton } from '../../Skeleton';
|
|
24
|
-
import {
|
|
25
|
-
AnimatedCompatValue,
|
|
26
|
-
useNormalizedSharedValue,
|
|
27
|
-
} from '../utils';
|
|
28
|
-
|
|
29
|
-
type HeaderTitleInterpolate = {
|
|
30
|
-
inputRange: number[];
|
|
31
|
-
outputRange: number[];
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
type HeaderTitleExtraProps = {
|
|
35
|
-
animatedValue?: AnimatedCompatValue;
|
|
36
|
-
interpolate?: HeaderTitleInterpolate;
|
|
37
|
-
tintColor?: string;
|
|
38
|
-
children?: React.ReactNode;
|
|
39
|
-
};
|
|
40
20
|
|
|
41
21
|
/**
|
|
42
22
|
* default header title used for nav
|
|
43
23
|
*/
|
|
44
|
-
const HeaderTitle: React.FC<
|
|
24
|
+
const HeaderTitle: React.FC<any> = props => {
|
|
45
25
|
const context = useContext<any>(MiniAppContext);
|
|
46
26
|
|
|
47
27
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
48
28
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
57
|
-
if (!hasAnimated) {
|
|
58
|
-
return { opacity: 1 };
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
opacity: interpolate(
|
|
62
|
-
sharedValue.value,
|
|
63
|
-
interpolateConfig.inputRange,
|
|
64
|
-
interpolateConfig.outputRange,
|
|
65
|
-
Extrapolation.CLAMP,
|
|
66
|
-
),
|
|
67
|
-
};
|
|
68
|
-
});
|
|
29
|
+
const opacity = props.animatedValue?.interpolate(
|
|
30
|
+
props.interpolate ?? {
|
|
31
|
+
inputRange: [0, 200],
|
|
32
|
+
outputRange: [0, 1],
|
|
33
|
+
extrapolate: 'clamp',
|
|
34
|
+
},
|
|
35
|
+
);
|
|
69
36
|
|
|
70
37
|
return (
|
|
71
38
|
<View
|
|
@@ -90,9 +57,9 @@ const HeaderTitle: React.FC<HeaderTitleExtraProps & { [key: string]: any }> = pr
|
|
|
90
57
|
},
|
|
91
58
|
{
|
|
92
59
|
fontFamily: exportFontFamily('bold', 'action_xs_bold'),
|
|
60
|
+
opacity,
|
|
93
61
|
color: props.tintColor,
|
|
94
62
|
},
|
|
95
|
-
animatedStyle,
|
|
96
63
|
]}
|
|
97
64
|
numberOfLines={1}
|
|
98
65
|
/>
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { Colors, Radius, Spacing, Styles } from '../../Consts';
|
|
2
2
|
import { InputRef, InputSearch } from '../../Input';
|
|
3
3
|
import {
|
|
4
|
+
Animated,
|
|
4
5
|
Dimensions,
|
|
5
6
|
StyleSheet,
|
|
6
7
|
TouchableOpacity,
|
|
7
8
|
View,
|
|
8
9
|
} from 'react-native';
|
|
9
|
-
import
|
|
10
|
-
import React, { useContext } from 'react';
|
|
10
|
+
import React, { useContext, useEffect, useRef } from 'react';
|
|
11
11
|
import { SearchHeaderProps } from '../types';
|
|
12
12
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
13
13
|
import { Text } from '../../Text';
|
|
14
|
-
import { useNormalizedSharedValue } from '../utils';
|
|
15
14
|
|
|
16
15
|
const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
|
|
17
16
|
(
|
|
@@ -29,17 +28,28 @@ const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
|
|
|
29
28
|
const BACK_WIDTH = 28;
|
|
30
29
|
const { width: screenWidth } = Dimensions.get('window');
|
|
31
30
|
|
|
32
|
-
const
|
|
31
|
+
const animated = useRef(new Animated.Value(0));
|
|
33
32
|
const leftPosition = props?.leftPosition ?? BACK_WIDTH + 20;
|
|
34
33
|
const headerRightWidth = props?.headerRightWidth ?? 73;
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const listener = animatedValue?.addListener(({ value }) => {
|
|
37
|
+
animated.current.setValue(value);
|
|
38
|
+
});
|
|
39
|
+
return () => {
|
|
40
|
+
if (listener) {
|
|
41
|
+
animatedValue?.removeListener(listener);
|
|
42
|
+
}
|
|
42
43
|
};
|
|
44
|
+
}, [animatedValue]);
|
|
45
|
+
|
|
46
|
+
const backgroundColor = animated.current?.interpolate({
|
|
47
|
+
inputRange: [0, 100],
|
|
48
|
+
outputRange: [
|
|
49
|
+
theme.colors.background.surface,
|
|
50
|
+
theme.colors.background.default,
|
|
51
|
+
],
|
|
52
|
+
extrapolate: 'clamp',
|
|
43
53
|
});
|
|
44
54
|
|
|
45
55
|
const goBack = () => {
|
|
@@ -81,9 +91,7 @@ const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
|
|
|
81
91
|
},
|
|
82
92
|
]}
|
|
83
93
|
>
|
|
84
|
-
<Animated.View
|
|
85
|
-
style={[{ borderRadius: Radius.XL }, backgroundStyle]}
|
|
86
|
-
>
|
|
94
|
+
<Animated.View style={{ backgroundColor, borderRadius: Radius.XL }}>
|
|
87
95
|
<InputSearch
|
|
88
96
|
ref={ref}
|
|
89
97
|
{...props}
|
|
@@ -19,7 +19,7 @@ import Navigator from './Navigator';
|
|
|
19
19
|
import ScaleSizeProvider from './ScaleSizeProvider';
|
|
20
20
|
import { getModalOptions, getStackOptions } from './utils';
|
|
21
21
|
import { NavigationContainerProps } from './types';
|
|
22
|
-
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
22
|
+
import { ApplicationContext, FontScaleConfig, MiniAppContext } from '../Context';
|
|
23
23
|
import Localize from './Localize';
|
|
24
24
|
import { Colors, defaultTheme } from '../Consts';
|
|
25
25
|
import { HeaderLeft } from './Components/HeaderLeft';
|
|
@@ -29,6 +29,9 @@ import { HeaderBackground } from './Components/HeaderBackground';
|
|
|
29
29
|
|
|
30
30
|
const Stack = createStackNavigator();
|
|
31
31
|
|
|
32
|
+
// Observer storage key the host app writes FontScaleConfig to. Lowercased natively.
|
|
33
|
+
const FONT_SCALE_OBSERVER_KEY = 'font_scale_config';
|
|
34
|
+
|
|
32
35
|
const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
33
36
|
screen,
|
|
34
37
|
theme = defaultTheme,
|
|
@@ -45,6 +48,11 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
45
48
|
}) => {
|
|
46
49
|
const context = useContext<any>(MiniAppContext);
|
|
47
50
|
const [currentContext, setCurrentContext] = useState<any>({});
|
|
51
|
+
// Default = the host-seeded fontScaleConfig from MiniAppContext, so the first frame is already
|
|
52
|
+
// scaled (no flash). The observer below overwrites it on later host writes (live rate changes).
|
|
53
|
+
const [observerFontScaleConfig, setObserverFontScaleConfig] = useState<
|
|
54
|
+
FontScaleConfig | undefined
|
|
55
|
+
>(context?.fontScaleConfig);
|
|
48
56
|
|
|
49
57
|
const mergedContext = {
|
|
50
58
|
...context,
|
|
@@ -55,10 +63,27 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
55
63
|
},
|
|
56
64
|
};
|
|
57
65
|
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
// The initial value is seeded by the host into MiniAppContext and used as this state's default
|
|
68
|
+
// above, so the first frame is already scaled (no flash). Here we only subscribe to later host
|
|
69
|
+
// writes so a rate change applies live while the miniapp is open.
|
|
70
|
+
const sub = maxApi?.observer?.(
|
|
71
|
+
FONT_SCALE_OBSERVER_KEY,
|
|
72
|
+
(data: FontScaleConfig) => {
|
|
73
|
+
setObserverFontScaleConfig(data ?? undefined);
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
return () => {
|
|
77
|
+
sub?.remove?.();
|
|
78
|
+
};
|
|
79
|
+
}, [maxApi]);
|
|
80
|
+
|
|
58
81
|
return (
|
|
59
82
|
<SafeAreaProvider>
|
|
60
83
|
<MiniAppContext.Provider value={mergedContext}>
|
|
61
|
-
<ScaleSizeProvider
|
|
84
|
+
<ScaleSizeProvider
|
|
85
|
+
fontScaleConfig={observerFontScaleConfig}
|
|
86
|
+
>
|
|
62
87
|
<Navigation
|
|
63
88
|
screen={screen}
|
|
64
89
|
theme={theme}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
1
|
+
import React, { FC, useContext } from 'react';
|
|
2
2
|
import { ScaleSizeContext } from '../Context';
|
|
3
3
|
import { ScaleSizeProviderProps } from './types';
|
|
4
4
|
|
|
5
5
|
const ScaleSizeProvider: FC<ScaleSizeProviderProps> = ({
|
|
6
|
-
|
|
6
|
+
fontScaleConfig,
|
|
7
7
|
children,
|
|
8
8
|
}) => {
|
|
9
|
+
// Inherit the config from an upper layer (e.g. app root) when the host doesn't set it via MiniAppContext.
|
|
10
|
+
const parent = useContext(ScaleSizeContext);
|
|
9
11
|
return (
|
|
10
|
-
<ScaleSizeContext.Provider value={
|
|
12
|
+
<ScaleSizeContext.Provider value={fontScaleConfig ?? parent}>
|
|
11
13
|
{children}
|
|
12
14
|
</ScaleSizeContext.Provider>
|
|
13
15
|
);
|
|
@@ -78,7 +78,7 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
78
78
|
<SafeAreaProvider>
|
|
79
79
|
<MiniAppContext.Provider value={mergedContext}>
|
|
80
80
|
<ScaleSizeProvider
|
|
81
|
-
|
|
81
|
+
fontScaleConfig={mergedContext?.fontScaleConfig}
|
|
82
82
|
>
|
|
83
83
|
<ApplicationContext.Provider
|
|
84
84
|
value={{
|
package/Application/types.ts
CHANGED
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
ViewProps,
|
|
8
8
|
ViewStyle,
|
|
9
9
|
} from 'react-native';
|
|
10
|
-
import type { SharedValue } from 'react-native-reanimated';
|
|
11
10
|
import { PopupNotifyProps } from '../Popup/types';
|
|
12
11
|
import { InputRef, InputSearchProps } from '../Input';
|
|
12
|
+
import { FontScaleConfig } from '../Context';
|
|
13
13
|
import Navigation from './Navigation';
|
|
14
14
|
|
|
15
15
|
export type NavigationProps = {
|
|
@@ -109,7 +109,7 @@ export type Theme = {
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
export type ScaleSizeProviderProps = {
|
|
112
|
-
|
|
112
|
+
fontScaleConfig?: FontScaleConfig;
|
|
113
113
|
children: ViewProps['children'];
|
|
114
114
|
};
|
|
115
115
|
|
|
@@ -259,7 +259,7 @@ export interface HeaderBackProps extends NavigationButtonProps {
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
export type HeaderBackgroundProps = {
|
|
262
|
-
animatedValue?: Animated.Value
|
|
262
|
+
animatedValue?: Animated.Value;
|
|
263
263
|
useGradient?: boolean;
|
|
264
264
|
useShadowHeader?: boolean;
|
|
265
265
|
backgroundColor?: string;
|
|
@@ -299,7 +299,7 @@ export type TitleJourneyProps = {
|
|
|
299
299
|
};
|
|
300
300
|
|
|
301
301
|
export interface HeaderAnimatedProps extends ViewProps {
|
|
302
|
-
animatedValue: Animated.Value
|
|
302
|
+
animatedValue: Animated.Value;
|
|
303
303
|
image: string;
|
|
304
304
|
useScale?: boolean;
|
|
305
305
|
}
|
|
@@ -343,7 +343,7 @@ export type AnimatedHeader = {
|
|
|
343
343
|
|
|
344
344
|
export interface SearchHeaderProps extends InputSearchProps {
|
|
345
345
|
ref?: React.RefObject<InputRef>;
|
|
346
|
-
animatedValue?: Animated.Value
|
|
346
|
+
animatedValue?: Animated.Value;
|
|
347
347
|
headerRightWidth?: 0 | 74 | 110 | number;
|
|
348
348
|
leftPosition?: 12 | 48 | number;
|
|
349
349
|
renderButtons?: () => ReactNode;
|
package/Application/utils.tsx
CHANGED
|
@@ -6,8 +6,6 @@ import {
|
|
|
6
6
|
import type { HeaderTitleProps, NavigationOptions } from './types';
|
|
7
7
|
import { Colors, Spacing } from '../Consts';
|
|
8
8
|
import { Animated, AppState, Platform } from 'react-native';
|
|
9
|
-
import type { SharedValue } from 'react-native-reanimated';
|
|
10
|
-
import { useSharedValue } from 'react-native-reanimated';
|
|
11
9
|
import {
|
|
12
10
|
MiniAppContext,
|
|
13
11
|
ScreenContext,
|
|
@@ -62,7 +60,7 @@ const getModalOptions = (): StackNavigationOptions => {
|
|
|
62
60
|
*/
|
|
63
61
|
const getOptions = (
|
|
64
62
|
params: NavigationOptions,
|
|
65
|
-
animatedValue?:
|
|
63
|
+
animatedValue?: Animated.Value,
|
|
66
64
|
) => {
|
|
67
65
|
let options: StackNavigationOptions = {};
|
|
68
66
|
|
|
@@ -133,7 +131,7 @@ const getOptions = (
|
|
|
133
131
|
|
|
134
132
|
const exportHeaderTitle = (
|
|
135
133
|
params: NavigationOptions,
|
|
136
|
-
animatedValue?:
|
|
134
|
+
animatedValue?: Animated.Value,
|
|
137
135
|
): StackNavigationOptions => {
|
|
138
136
|
if (typeof params.headerTitle === 'object') {
|
|
139
137
|
return {
|
|
@@ -230,43 +228,6 @@ const useAppState = () => {
|
|
|
230
228
|
};
|
|
231
229
|
};
|
|
232
230
|
|
|
233
|
-
/**
|
|
234
|
-
* Union of the two animation runtimes an internal foundation component might
|
|
235
|
-
* receive. Public Screen props still accept React Native Animated.Value only;
|
|
236
|
-
* this type keeps lower-level header/floating components compatible while they
|
|
237
|
-
* render with reanimated.
|
|
238
|
-
*/
|
|
239
|
-
export type AnimatedCompatValue = Animated.Value | SharedValue<number>;
|
|
240
|
-
|
|
241
|
-
const isRNAnimatedValue = (v: unknown): v is Animated.Value =>
|
|
242
|
-
!!v &&
|
|
243
|
-
typeof (v as Animated.Value).setValue === 'function' &&
|
|
244
|
-
typeof (v as Animated.Value).interpolate === 'function';
|
|
245
|
-
|
|
246
|
-
const isSharedValue = (v: unknown): v is SharedValue<number> =>
|
|
247
|
-
!!v && !isRNAnimatedValue(v) && 'value' in (v as object);
|
|
248
|
-
|
|
249
|
-
const useNormalizedSharedValue = (
|
|
250
|
-
input?: AnimatedCompatValue,
|
|
251
|
-
): SharedValue<number> => {
|
|
252
|
-
const fallback = useSharedValue(0);
|
|
253
|
-
|
|
254
|
-
useEffect(() => {
|
|
255
|
-
if (!isRNAnimatedValue(input)) {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
const id = input.addListener(({ value }) => {
|
|
259
|
-
fallback.value = value;
|
|
260
|
-
});
|
|
261
|
-
return () => input.removeListener(id);
|
|
262
|
-
}, [input, fallback]);
|
|
263
|
-
|
|
264
|
-
if (isSharedValue(input)) {
|
|
265
|
-
return input;
|
|
266
|
-
}
|
|
267
|
-
return fallback;
|
|
268
|
-
};
|
|
269
|
-
|
|
270
231
|
export {
|
|
271
232
|
getStackOptions,
|
|
272
233
|
getModalOptions,
|
|
@@ -275,5 +236,4 @@ export {
|
|
|
275
236
|
setAutomationID,
|
|
276
237
|
useComponentId,
|
|
277
238
|
useAppState,
|
|
278
|
-
useNormalizedSharedValue,
|
|
279
239
|
};
|