@momo-kits/foundation 0.161.2-beta.8 → 0.161.2-beta.9
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 +5 -4
- package/Application/BottomTab/BottomTabBar.tsx +15 -15
- package/Application/BottomTab/index.tsx +32 -56
- package/Application/Components/BackgroundImageView.tsx +22 -6
- package/Application/Components/HeaderAnimated.tsx +32 -29
- package/Application/Components/HeaderBackground.tsx +20 -26
- package/Application/Components/HeaderExtendHeader.tsx +114 -94
- package/Application/Components/HeaderTitle.tsx +39 -10
- package/Application/Components/SearchHeader.tsx +16 -21
- package/Application/types.ts +4 -4
- package/Application/utils.tsx +4 -3
- package/Badge/BadgeDotAnimation.tsx +53 -71
- package/Button/index.tsx +1 -4
- package/Input/InputOTP.tsx +38 -23
- package/Layout/FloatingButton.tsx +59 -59
- package/Layout/Screen.tsx +66 -61
- package/Loader/ProgressBar.tsx +20 -18
- package/Pagination/Dot.tsx +2 -2
- package/Pagination/PaginationScroll.tsx +31 -27
- package/Skeleton/index.tsx +32 -24
- package/package.json +1 -1
package/Input/InputOTP.tsx
CHANGED
|
@@ -8,13 +8,22 @@ import React, {
|
|
|
8
8
|
useState,
|
|
9
9
|
} from 'react';
|
|
10
10
|
import {
|
|
11
|
-
Animated,
|
|
12
11
|
PixelRatio,
|
|
13
12
|
TextInput,
|
|
14
13
|
TextInputFocusEvent,
|
|
15
14
|
TouchableOpacity,
|
|
16
15
|
View,
|
|
17
16
|
} from 'react-native';
|
|
17
|
+
import Animated, {
|
|
18
|
+
cancelAnimation,
|
|
19
|
+
Easing,
|
|
20
|
+
useAnimatedStyle,
|
|
21
|
+
useSharedValue,
|
|
22
|
+
withDelay,
|
|
23
|
+
withRepeat,
|
|
24
|
+
withSequence,
|
|
25
|
+
withTiming,
|
|
26
|
+
} from 'react-native-reanimated';
|
|
18
27
|
import { useComponentId } from '../Application';
|
|
19
28
|
import { Spacing, Styles } from '../Consts';
|
|
20
29
|
import { useScaleSize, Text } from '../Text';
|
|
@@ -32,37 +41,43 @@ import {
|
|
|
32
41
|
const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
33
42
|
const DURATION = 300;
|
|
34
43
|
const { theme } = useContext(ApplicationContext);
|
|
35
|
-
const opacity =
|
|
44
|
+
const opacity = useSharedValue(0);
|
|
36
45
|
|
|
37
46
|
useEffect(() => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
).start();
|
|
47
|
+
opacity.value = withRepeat(
|
|
48
|
+
withSequence(
|
|
49
|
+
withTiming(1, { duration: DURATION, easing: Easing.linear }),
|
|
50
|
+
withDelay(
|
|
51
|
+
DURATION * 2,
|
|
52
|
+
withTiming(0, { duration: DURATION, easing: Easing.linear }),
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
-1,
|
|
56
|
+
false,
|
|
57
|
+
);
|
|
58
|
+
return () => {
|
|
59
|
+
cancelAnimation(opacity);
|
|
60
|
+
};
|
|
53
61
|
}, [opacity]);
|
|
62
|
+
|
|
63
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
64
|
+
opacity: opacity.value,
|
|
65
|
+
}));
|
|
66
|
+
|
|
54
67
|
const spacingStyle = !isNaN(Number(length)) &&
|
|
55
68
|
index !== Number(length) - 1 && { marginRight: Spacing.L };
|
|
56
69
|
|
|
57
70
|
return (
|
|
58
71
|
<View style={[Styles.rowCenter, spacingStyle]}>
|
|
59
72
|
<Animated.View
|
|
60
|
-
style={
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
style={[
|
|
74
|
+
{
|
|
75
|
+
height: useScaleSize(12),
|
|
76
|
+
width: 1,
|
|
77
|
+
backgroundColor: theme.colors.primary,
|
|
78
|
+
},
|
|
79
|
+
animatedStyle,
|
|
80
|
+
]}
|
|
66
81
|
/>
|
|
67
82
|
<Text color={theme.colors.text.hint} typography={'body_default_regular'}>
|
|
68
83
|
-
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
1
2
|
import {
|
|
2
|
-
default as React,
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'react';
|
|
8
|
-
import {
|
|
9
|
-
Animated,
|
|
10
3
|
LayoutChangeEvent,
|
|
11
4
|
StyleSheet,
|
|
12
5
|
TouchableOpacity,
|
|
13
6
|
View,
|
|
14
7
|
} from 'react-native';
|
|
8
|
+
import Animated, {
|
|
9
|
+
useAnimatedReaction,
|
|
10
|
+
useAnimatedStyle,
|
|
11
|
+
useSharedValue,
|
|
12
|
+
withTiming,
|
|
13
|
+
runOnJS,
|
|
14
|
+
type SharedValue,
|
|
15
|
+
} from 'react-native-reanimated';
|
|
15
16
|
import { ApplicationContext } from '../Context';
|
|
16
17
|
import { Icon } from '../Icon';
|
|
17
18
|
import { useScaleSize } from '../Text';
|
|
@@ -23,7 +24,7 @@ export interface FloatingButtonProps {
|
|
|
23
24
|
icon?: string;
|
|
24
25
|
iconColor?: string;
|
|
25
26
|
size?: 'small' | 'large';
|
|
26
|
-
animatedValue?:
|
|
27
|
+
animatedValue?: SharedValue<number>;
|
|
27
28
|
bottom?: number;
|
|
28
29
|
renderComponent?: () => React.ReactNode;
|
|
29
30
|
}
|
|
@@ -42,68 +43,67 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
|
|
|
42
43
|
const { theme } = useContext(ApplicationContext);
|
|
43
44
|
const scaledFontSize = useScaleSize(16);
|
|
44
45
|
const scaledLineHeight = useScaleSize(22);
|
|
45
|
-
const maxWidth =
|
|
46
|
+
const maxWidth = useSharedValue(0);
|
|
46
47
|
const minWidth = size === 'small' ? 36 : 48;
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const lastOffset =
|
|
50
|
-
const lastDirection =
|
|
51
|
-
const [showText, setShowText] =
|
|
48
|
+
const opacityAnimated = useSharedValue(0);
|
|
49
|
+
const widthAnimated = useSharedValue<number | null>(null);
|
|
50
|
+
const lastOffset = useSharedValue(0);
|
|
51
|
+
const lastDirection = useSharedValue<string | null>(null);
|
|
52
|
+
const [showText, setShowText] = useState(true);
|
|
52
53
|
|
|
53
54
|
useEffect(() => {
|
|
54
55
|
if (!label) return;
|
|
56
|
+
opacityAnimated.value = withTiming(1, { duration: 100 });
|
|
57
|
+
}, [label, opacityAnimated]);
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (lastDirection.current !== direction) {
|
|
67
|
-
lastDirection.current = direction;
|
|
59
|
+
useAnimatedReaction(
|
|
60
|
+
() => animatedValue?.value ?? 0,
|
|
61
|
+
(value) => {
|
|
62
|
+
'worklet';
|
|
63
|
+
if (!label || !animatedValue) return;
|
|
64
|
+
if (value !== lastOffset.value && value > 0) {
|
|
65
|
+
const direction = value > lastOffset.value ? 'down' : 'up';
|
|
66
|
+
lastOffset.value = value;
|
|
67
|
+
if (lastDirection.value !== direction) {
|
|
68
|
+
lastDirection.value = direction;
|
|
68
69
|
if (direction === 'down') {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
useNativeDriver: false,
|
|
78
|
-
}).start(() => setShowText(false));
|
|
70
|
+
opacityAnimated.value = withTiming(0, { duration: 100 });
|
|
71
|
+
widthAnimated.value = withTiming(
|
|
72
|
+
minWidth,
|
|
73
|
+
{ duration: 100 },
|
|
74
|
+
(finished) => {
|
|
75
|
+
if (finished) runOnJS(setShowText)(false);
|
|
76
|
+
},
|
|
77
|
+
);
|
|
79
78
|
} else {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
useNativeDriver: false,
|
|
89
|
-
}).start(() => setShowText(true));
|
|
79
|
+
opacityAnimated.value = withTiming(1, { duration: 100 });
|
|
80
|
+
widthAnimated.value = withTiming(
|
|
81
|
+
maxWidth.value,
|
|
82
|
+
{ duration: 100 },
|
|
83
|
+
(finished) => {
|
|
84
|
+
if (finished) runOnJS(setShowText)(true);
|
|
85
|
+
},
|
|
86
|
+
);
|
|
90
87
|
}
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
|
-
}
|
|
90
|
+
},
|
|
91
|
+
[label, animatedValue, minWidth],
|
|
92
|
+
);
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
const containerStyle = useAnimatedStyle(() => ({
|
|
95
|
+
width: widthAnimated.value ?? undefined,
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
const labelStyle = useAnimatedStyle(() => ({
|
|
99
|
+
opacity: opacityAnimated.value,
|
|
100
|
+
}));
|
|
101
101
|
|
|
102
102
|
const handleLayout = (event: LayoutChangeEvent) => {
|
|
103
103
|
const layout = event.nativeEvent.layout;
|
|
104
|
-
if (widthAnimated) return;
|
|
105
|
-
maxWidth.
|
|
106
|
-
|
|
104
|
+
if (widthAnimated.value != null) return;
|
|
105
|
+
maxWidth.value = layout.width;
|
|
106
|
+
widthAnimated.value = layout.width;
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
if (renderComponent) {
|
|
@@ -132,11 +132,11 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
|
|
|
132
132
|
{
|
|
133
133
|
right: position === 'right' ? 12 : undefined,
|
|
134
134
|
alignSelf: position === 'center' ? 'center' : 'flex-end',
|
|
135
|
-
width: widthAnimated,
|
|
136
135
|
height: size === 'small' ? 36 : 48,
|
|
137
136
|
backgroundColor: theme.colors.primary,
|
|
138
137
|
bottom,
|
|
139
138
|
},
|
|
139
|
+
containerStyle,
|
|
140
140
|
]}
|
|
141
141
|
>
|
|
142
142
|
<TouchableOpacity
|
|
@@ -156,9 +156,9 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
|
|
|
156
156
|
{
|
|
157
157
|
fontSize: scaledFontSize,
|
|
158
158
|
lineHeight: scaledLineHeight,
|
|
159
|
-
opacity: opacityAnimated,
|
|
160
159
|
color: 'white',
|
|
161
160
|
},
|
|
161
|
+
labelStyle,
|
|
162
162
|
]}
|
|
163
163
|
numberOfLines={1}
|
|
164
164
|
>
|
package/Layout/Screen.tsx
CHANGED
|
@@ -12,7 +12,6 @@ import React, {
|
|
|
12
12
|
useRef,
|
|
13
13
|
} from 'react';
|
|
14
14
|
import {
|
|
15
|
-
Animated,
|
|
16
15
|
KeyboardAvoidingView,
|
|
17
16
|
NativeScrollEvent,
|
|
18
17
|
NativeSyntheticEvent,
|
|
@@ -25,6 +24,13 @@ import {
|
|
|
25
24
|
View,
|
|
26
25
|
ViewProps,
|
|
27
26
|
} from 'react-native';
|
|
27
|
+
import Animated, {
|
|
28
|
+
runOnJS,
|
|
29
|
+
useAnimatedScrollHandler,
|
|
30
|
+
useSharedValue,
|
|
31
|
+
withTiming,
|
|
32
|
+
type SharedValue,
|
|
33
|
+
} from 'react-native-reanimated';
|
|
28
34
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
29
35
|
import { ApplicationContext, ScreenContext } from '../Context';
|
|
30
36
|
import Navigation from '../Application/Navigation';
|
|
@@ -138,7 +144,7 @@ export interface ScreenProps extends ViewProps {
|
|
|
138
144
|
/**
|
|
139
145
|
* Optional. Animated value for header.
|
|
140
146
|
*/
|
|
141
|
-
animatedValue?:
|
|
147
|
+
animatedValue?: SharedValue<number>;
|
|
142
148
|
|
|
143
149
|
/**
|
|
144
150
|
* Optional. If `true`, use shadow header.
|
|
@@ -195,18 +201,18 @@ const Screen = forwardRef(
|
|
|
195
201
|
const screen: any = useContext(ScreenContext);
|
|
196
202
|
const insets = useSafeAreaInsets();
|
|
197
203
|
const heightHeader = useHeaderHeight();
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
);
|
|
204
|
+
const internalAnimatedValue = useSharedValue(0);
|
|
205
|
+
const animatedValue = customAnimatedValue ?? internalAnimatedValue;
|
|
201
206
|
const currentTint = useRef<string | undefined>(undefined);
|
|
202
207
|
const isTab = navigation?.instance?.getState?.()?.type === 'tab';
|
|
203
208
|
|
|
204
|
-
let handleScroll;
|
|
209
|
+
let handleScroll: any;
|
|
205
210
|
let Component: any = View;
|
|
206
211
|
|
|
207
|
-
|
|
212
|
+
const bottomInset = Platform.OS === 'ios' ? Math.min(insets.bottom, 21) : insets.bottom;
|
|
213
|
+
let keyboardOffset = heightHeader - bottomInset;
|
|
208
214
|
if (headerType === 'extended' || animatedHeader || inputSearchProps) {
|
|
209
|
-
keyboardOffset = -
|
|
215
|
+
keyboardOffset = -bottomInset;
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
/**
|
|
@@ -248,9 +254,8 @@ const Screen = forwardRef(
|
|
|
248
254
|
interpolate={{
|
|
249
255
|
inputRange: [0, 50],
|
|
250
256
|
outputRange: [1, 0],
|
|
251
|
-
extrapolate: 'clamp',
|
|
252
257
|
}}
|
|
253
|
-
animatedValue={animatedValue
|
|
258
|
+
animatedValue={animatedValue}
|
|
254
259
|
/>
|
|
255
260
|
),
|
|
256
261
|
};
|
|
@@ -265,7 +270,7 @@ const Screen = forwardRef(
|
|
|
265
270
|
headerBackground: (props: any) => (
|
|
266
271
|
<HeaderBackground
|
|
267
272
|
{...props}
|
|
268
|
-
animatedValue={animatedValue
|
|
273
|
+
animatedValue={animatedValue}
|
|
269
274
|
useShadowHeader={useShadowHeader}
|
|
270
275
|
headerBackground={headerBackground}
|
|
271
276
|
gradientColor={gradientColor}
|
|
@@ -284,9 +289,8 @@ const Screen = forwardRef(
|
|
|
284
289
|
interpolate={{
|
|
285
290
|
inputRange: [0, 50],
|
|
286
291
|
outputRange: [1, 0],
|
|
287
|
-
extrapolate: 'clamp',
|
|
288
292
|
}}
|
|
289
|
-
animatedValue={animatedValue
|
|
293
|
+
animatedValue={animatedValue}
|
|
290
294
|
/>
|
|
291
295
|
),
|
|
292
296
|
};
|
|
@@ -321,7 +325,7 @@ const Screen = forwardRef(
|
|
|
321
325
|
headerBackground: (props: any) => (
|
|
322
326
|
<HeaderBackground
|
|
323
327
|
{...props}
|
|
324
|
-
animatedValue={animatedValue
|
|
328
|
+
animatedValue={animatedValue}
|
|
325
329
|
useGradient={false}
|
|
326
330
|
useShadowHeader={useShadowHeader}
|
|
327
331
|
headerBackground={headerBackground}
|
|
@@ -359,9 +363,8 @@ const Screen = forwardRef(
|
|
|
359
363
|
interpolate={{
|
|
360
364
|
inputRange: [0, 50],
|
|
361
365
|
outputRange: [1, 0],
|
|
362
|
-
extrapolate: 'clamp',
|
|
363
366
|
}}
|
|
364
|
-
animatedValue={animatedValue
|
|
367
|
+
animatedValue={animatedValue}
|
|
365
368
|
/>
|
|
366
369
|
),
|
|
367
370
|
};
|
|
@@ -390,7 +393,7 @@ const Screen = forwardRef(
|
|
|
390
393
|
headerLeft: (props: any) =>
|
|
391
394
|
params?.hiddenBack ? null : <HeaderLeft {...props} />,
|
|
392
395
|
headerTitle: () => (
|
|
393
|
-
<SearchHeader {...params} animatedValue={animatedValue
|
|
396
|
+
<SearchHeader {...params} animatedValue={animatedValue} />
|
|
394
397
|
),
|
|
395
398
|
};
|
|
396
399
|
|
|
@@ -441,45 +444,51 @@ const Screen = forwardRef(
|
|
|
441
444
|
});
|
|
442
445
|
});
|
|
443
446
|
|
|
447
|
+
const onTintColorChange = useCallback(
|
|
448
|
+
(offsetY: number) => {
|
|
449
|
+
if (!animatedHeader) return;
|
|
450
|
+
let color = animatedHeader?.headerTintColor ?? Colors.black_17;
|
|
451
|
+
if (offsetY > 50) {
|
|
452
|
+
color = Colors.black_17;
|
|
453
|
+
}
|
|
454
|
+
if (color !== currentTint.current) {
|
|
455
|
+
currentTint.current = color;
|
|
456
|
+
navigation?.setOptions({
|
|
457
|
+
headerTintColor: color,
|
|
458
|
+
});
|
|
459
|
+
let barStyle: StatusBarStyle = 'dark-content';
|
|
460
|
+
if (currentTint.current === Colors.black_01) {
|
|
461
|
+
barStyle = 'light-content';
|
|
462
|
+
}
|
|
463
|
+
StatusBar.setBarStyle(barStyle, true);
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
[animatedHeader, navigation],
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const emitOnScroll = useCallback(
|
|
470
|
+
(offsetY: number) => {
|
|
471
|
+
scrollViewProps?.onScroll?.({
|
|
472
|
+
nativeEvent: { contentOffset: { x: 0, y: offsetY } },
|
|
473
|
+
} as NativeSyntheticEvent<NativeScrollEvent>);
|
|
474
|
+
},
|
|
475
|
+
[scrollViewProps],
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
const scrollHandler = useAnimatedScrollHandler({
|
|
479
|
+
onScroll: (event) => {
|
|
480
|
+
animatedValue.value = event.contentOffset.y;
|
|
481
|
+
runOnJS(emitOnScroll)(event.contentOffset.y);
|
|
482
|
+
runOnJS(onTintColorChange)(event.contentOffset.y);
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
|
|
444
486
|
/**
|
|
445
487
|
* animated when use scroll && animated value
|
|
446
488
|
*/
|
|
447
489
|
if (scrollable) {
|
|
448
490
|
Component = Animated.ScrollView;
|
|
449
|
-
handleScroll =
|
|
450
|
-
[
|
|
451
|
-
{
|
|
452
|
-
nativeEvent: {
|
|
453
|
-
contentOffset: { y: animatedValue.current as Animated.Value },
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
],
|
|
457
|
-
{
|
|
458
|
-
useNativeDriver: true,
|
|
459
|
-
listener: (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
460
|
-
scrollViewProps?.onScroll?.(e);
|
|
461
|
-
if (animatedHeader) {
|
|
462
|
-
const offsetY = e.nativeEvent.contentOffset.y;
|
|
463
|
-
let color = animatedHeader?.headerTintColor ?? Colors.black_17;
|
|
464
|
-
if (offsetY > 50) {
|
|
465
|
-
color = Colors.black_17;
|
|
466
|
-
}
|
|
467
|
-
if (color !== currentTint.current) {
|
|
468
|
-
currentTint.current = color;
|
|
469
|
-
navigation?.setOptions({
|
|
470
|
-
headerTintColor: color,
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
let barStyle: StatusBarStyle = 'dark-content';
|
|
474
|
-
if (currentTint.current === Colors.black_01) {
|
|
475
|
-
barStyle = 'light-content';
|
|
476
|
-
}
|
|
477
|
-
StatusBar.setBarStyle(barStyle, true);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
},
|
|
482
|
-
);
|
|
491
|
+
handleScroll = scrollHandler;
|
|
483
492
|
}
|
|
484
493
|
|
|
485
494
|
/**
|
|
@@ -489,11 +498,7 @@ const Screen = forwardRef(
|
|
|
489
498
|
const handleScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
490
499
|
const offsetY = e.nativeEvent.contentOffset.y;
|
|
491
500
|
if (inputSearchProps && offsetY < 100 && offsetY > 0) {
|
|
492
|
-
|
|
493
|
-
toValue: 0,
|
|
494
|
-
useNativeDriver: true,
|
|
495
|
-
duration: 300,
|
|
496
|
-
}).start();
|
|
501
|
+
animatedValue.value = withTiming(0, { duration: 300 });
|
|
497
502
|
ref?.scrollTo?.({ y: 0, animated: true });
|
|
498
503
|
}
|
|
499
504
|
scrollViewProps?.onScrollEndDrag?.(e);
|
|
@@ -509,7 +514,7 @@ const Screen = forwardRef(
|
|
|
509
514
|
style={[styles.screenBanner, { maxHeight: 210 + layoutOffset }]}
|
|
510
515
|
>
|
|
511
516
|
{animatedHeader?.component({
|
|
512
|
-
animatedValue: animatedValue
|
|
517
|
+
animatedValue: animatedValue,
|
|
513
518
|
})}
|
|
514
519
|
</View>
|
|
515
520
|
);
|
|
@@ -576,7 +581,7 @@ const Screen = forwardRef(
|
|
|
576
581
|
headerType={headerType}
|
|
577
582
|
heightHeader={heightHeader}
|
|
578
583
|
headerRightWidth={headerRightWidth}
|
|
579
|
-
animatedValue={animatedValue
|
|
584
|
+
animatedValue={animatedValue}
|
|
580
585
|
inputSearchProps={inputSearchProps}
|
|
581
586
|
navigation={navigation}
|
|
582
587
|
inputSearchRef={inputSearchRef}
|
|
@@ -614,9 +619,9 @@ const Screen = forwardRef(
|
|
|
614
619
|
<View>
|
|
615
620
|
<FloatingButton
|
|
616
621
|
{...floatingButtonProps}
|
|
617
|
-
animatedValue={animatedValue
|
|
622
|
+
animatedValue={animatedValue}
|
|
618
623
|
bottom={
|
|
619
|
-
Footer || isTab ? 12 :
|
|
624
|
+
Footer || isTab ? 12 : bottomInset + Spacing.S
|
|
620
625
|
}
|
|
621
626
|
/>
|
|
622
627
|
</View>
|
|
@@ -627,7 +632,7 @@ const Screen = forwardRef(
|
|
|
627
632
|
style={[
|
|
628
633
|
styles.shadow,
|
|
629
634
|
{
|
|
630
|
-
paddingBottom:
|
|
635
|
+
paddingBottom: bottomInset + Spacing.S,
|
|
631
636
|
backgroundColor: theme.colors.background.surface,
|
|
632
637
|
},
|
|
633
638
|
]}
|
package/Loader/ProgressBar.tsx
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import React, { FC, useContext, useEffect
|
|
2
|
-
import {
|
|
1
|
+
import React, { FC, useContext, useEffect } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import Animated, {
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
useSharedValue,
|
|
6
|
+
withTiming,
|
|
7
|
+
} from 'react-native-reanimated';
|
|
3
8
|
import styles from './styles';
|
|
4
9
|
import { ProgressBarProps } from './types';
|
|
5
10
|
import { ApplicationContext } from '../Context';
|
|
@@ -7,20 +12,15 @@ import { Radius } from '../Consts';
|
|
|
7
12
|
|
|
8
13
|
const ProgressBar: FC<ProgressBarProps> = ({ percent = 0, style }) => {
|
|
9
14
|
const { theme } = useContext(ApplicationContext);
|
|
10
|
-
const animation =
|
|
15
|
+
const animation = useSharedValue(0);
|
|
11
16
|
|
|
12
17
|
useEffect(() => {
|
|
13
|
-
|
|
14
|
-
toValue: percent,
|
|
15
|
-
duration: 200,
|
|
16
|
-
useNativeDriver: false,
|
|
17
|
-
}).start();
|
|
18
|
+
animation.value = withTiming(percent, { duration: 200 });
|
|
18
19
|
}, [percent, animation]);
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
21
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
22
|
+
width: `${Math.min(Math.max(animation.value, 0), 100)}%`,
|
|
23
|
+
}));
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<View
|
|
@@ -31,12 +31,14 @@ const ProgressBar: FC<ProgressBarProps> = ({ percent = 0, style }) => {
|
|
|
31
31
|
]}
|
|
32
32
|
>
|
|
33
33
|
<Animated.View
|
|
34
|
-
style={
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
style={[
|
|
35
|
+
{
|
|
36
|
+
height: 4,
|
|
37
|
+
borderRadius: Radius.XXS,
|
|
38
|
+
backgroundColor: theme.colors.primary,
|
|
39
|
+
},
|
|
40
|
+
animatedStyle,
|
|
41
|
+
]}
|
|
40
42
|
/>
|
|
41
43
|
</View>
|
|
42
44
|
);
|
package/Pagination/Dot.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { FC, useContext } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { View } from 'react-native';
|
|
3
3
|
import styles from './styles';
|
|
4
4
|
import { DotProps } from './types';
|
|
5
5
|
import { ApplicationContext } from '../Context';
|
|
@@ -13,7 +13,7 @@ const Dot: FC<DotProps> = ({ active, style }) => {
|
|
|
13
13
|
{ backgroundColor: theme.colors.background.pressed },
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
-
return <
|
|
16
|
+
return <View style={[style, dotStyle]} />;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export default Dot;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import React, { FC, useContext,
|
|
2
|
-
import {
|
|
1
|
+
import React, { FC, useContext, useState } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import Animated, {
|
|
4
|
+
Extrapolation,
|
|
5
|
+
interpolate,
|
|
6
|
+
useAnimatedScrollHandler,
|
|
7
|
+
useAnimatedStyle,
|
|
8
|
+
useSharedValue,
|
|
9
|
+
} from 'react-native-reanimated';
|
|
3
10
|
import { ScrollIndicatorProps } from './types';
|
|
4
11
|
import styles from './styles';
|
|
5
12
|
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
@@ -13,40 +20,37 @@ const PaginationScroll: FC<ScrollIndicatorProps> = ({
|
|
|
13
20
|
}) => {
|
|
14
21
|
const { theme } = useContext(ApplicationContext);
|
|
15
22
|
const context = useContext<any>(MiniAppContext);
|
|
16
|
-
const left =
|
|
23
|
+
const left = useSharedValue(0);
|
|
17
24
|
const [scrollViewWidth, setScrollViewWidth] = useState(0);
|
|
18
25
|
const [scrollContentWidth, setScrollContentWidth] = useState(0);
|
|
19
26
|
|
|
20
27
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
21
28
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const onScroll = useAnimatedScrollHandler({
|
|
30
|
+
onScroll: (event) => {
|
|
31
|
+
left.value = event.contentOffset.x;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const indicatorStyle = useAnimatedStyle(() => {
|
|
36
|
+
if (!scrollViewWidth || !scrollContentWidth) {
|
|
37
|
+
return {};
|
|
30
38
|
}
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
const value = interpolate(
|
|
40
|
+
left.value,
|
|
41
|
+
[0, scrollContentWidth - scrollViewWidth],
|
|
42
|
+
[0, INDICATOR_CONTAINER_WIDTH - INDICATOR_WIDTH],
|
|
43
|
+
Extrapolation.CLAMP,
|
|
44
|
+
);
|
|
45
|
+
return { transform: [{ translateX: value }] };
|
|
46
|
+
});
|
|
33
47
|
|
|
34
48
|
const renderScrollView = () => {
|
|
35
49
|
return (
|
|
36
50
|
<Animated.ScrollView
|
|
37
|
-
ref={scrollViewRef}
|
|
38
|
-
onScroll={
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
nativeEvent: {
|
|
42
|
-
contentOffset: {
|
|
43
|
-
x: left,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
{ useNativeDriver: true },
|
|
49
|
-
)}
|
|
51
|
+
ref={scrollViewRef as any}
|
|
52
|
+
onScroll={onScroll}
|
|
53
|
+
scrollEventThrottle={16}
|
|
50
54
|
alwaysBounceHorizontal={false}
|
|
51
55
|
showsHorizontalScrollIndicator={false}
|
|
52
56
|
horizontal
|
|
@@ -76,7 +80,7 @@ const PaginationScroll: FC<ScrollIndicatorProps> = ({
|
|
|
76
80
|
{
|
|
77
81
|
backgroundColor: theme.colors.primary,
|
|
78
82
|
},
|
|
79
|
-
|
|
83
|
+
indicatorStyle,
|
|
80
84
|
]}
|
|
81
85
|
/>
|
|
82
86
|
</View>
|