@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.
@@ -1,75 +1,93 @@
1
- import React, { useEffect } from 'react';
2
- import { View } from 'react-native';
3
- import Animated, {
4
- cancelAnimation,
5
- useAnimatedStyle,
6
- useSharedValue,
7
- withRepeat,
8
- withSequence,
9
- withSpring,
10
- withTiming,
11
- } from 'react-native-reanimated';
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Animated, View } from 'react-native';
12
3
  import { BadgeDotProps } from './types';
13
4
  import styles from './styles';
14
5
 
15
6
  const DURATION = 500;
16
7
 
17
8
  const BadgeDotAnimation = ({ size, style }: BadgeDotProps) => {
18
- const scaleAnim = useSharedValue(1);
19
- const waveScaleAnim = useSharedValue(1);
20
- const waveOpacityAnim = useSharedValue(0);
9
+ // Refs for animated values
10
+ const scaleAnim = useRef(new Animated.Value(1)).current;
11
+ const waveScaleAnim = useRef(new Animated.Value(1)).current;
12
+ const waveOpacityAnim = useRef(new Animated.Value(0)).current;
21
13
 
22
14
  const dotStyle =
23
15
  size === 'small' ? styles.dotAnimationSmall : styles.dotAnimation;
24
16
  const waveStyle = size === 'small' ? styles.waveSmall : styles.wave;
25
17
 
26
18
  useEffect(() => {
27
- const springCfg = { damping: 5, stiffness: 30, mass: 1 };
28
-
29
- scaleAnim.value = withRepeat(
30
- withSequence(
31
- withSpring(1, springCfg),
32
- withSpring(1.1, springCfg),
33
- ),
34
- -1,
35
- false,
36
- );
37
- waveScaleAnim.value = withRepeat(
38
- withSequence(
39
- withTiming(2.5, { duration: DURATION * 3 }),
40
- withTiming(1, { duration: 0 }),
41
- ),
42
- -1,
43
- false,
44
- );
45
- waveOpacityAnim.value = withRepeat(
46
- withSequence(
47
- withTiming(0.3, { duration: DURATION * 2 }),
48
- withTiming(0, { duration: DURATION }),
49
- ),
50
- -1,
51
- false,
19
+ // Infinite loop animation for the scale and wave effect
20
+ const animation = Animated.loop(
21
+ Animated.parallel([
22
+ // Dot pulse animation
23
+ Animated.sequence([
24
+ Animated.spring(scaleAnim, {
25
+ toValue: 1, // Scale up slightly
26
+ friction: 5, // Controls the "bounciness" of the spring
27
+ tension: 30, // Controls the "stiffness" of the spring
28
+ useNativeDriver: true,
29
+ }),
30
+ Animated.spring(scaleAnim, {
31
+ toValue: 1.1,
32
+ friction: 5,
33
+ tension: 30,
34
+ useNativeDriver: true,
35
+ }),
36
+ ]), // Wave animation
37
+ Animated.sequence([
38
+ Animated.timing(waveScaleAnim, {
39
+ toValue: 2.5,
40
+ duration: DURATION * 3,
41
+ useNativeDriver: true,
42
+ }),
43
+ Animated.timing(waveScaleAnim, {
44
+ toValue: 1, // Reset wave size
45
+ duration: 0,
46
+ useNativeDriver: true,
47
+ }),
48
+ ]), // Wave opacity animation
49
+ Animated.sequence([
50
+ Animated.timing(waveOpacityAnim, {
51
+ toValue: 0.3, // Wave becomes visible
52
+ duration: DURATION * 2,
53
+ useNativeDriver: true,
54
+ }),
55
+ Animated.timing(waveOpacityAnim, {
56
+ toValue: 0, // Wave fades out
57
+ duration: DURATION,
58
+ useNativeDriver: true,
59
+ }),
60
+ ]),
61
+ ]),
52
62
  );
63
+ animation.start();
64
+
53
65
  return () => {
54
- cancelAnimation(scaleAnim);
55
- cancelAnimation(waveScaleAnim);
56
- cancelAnimation(waveOpacityAnim);
66
+ animation.stop();
57
67
  };
58
68
  }, [scaleAnim, waveOpacityAnim, waveScaleAnim]);
59
69
 
60
- const waveAnimatedStyle = useAnimatedStyle(() => ({
61
- transform: [{ scale: waveScaleAnim.value }],
62
- opacity: waveOpacityAnim.value,
63
- }));
64
-
65
- const dotAnimatedStyle = useAnimatedStyle(() => ({
66
- transform: [{ scale: scaleAnim.value }],
67
- }));
68
-
69
70
  return (
70
71
  <View style={[styles.dotAnimationContainer, style]}>
71
- <Animated.View style={[waveStyle, waveAnimatedStyle]} />
72
- <Animated.View style={[dotStyle, dotAnimatedStyle]} />
72
+ {/* Wave Animation */}
73
+ <Animated.View
74
+ style={[
75
+ waveStyle,
76
+ {
77
+ transform: [{ scale: waveScaleAnim }],
78
+ opacity: waveOpacityAnim,
79
+ },
80
+ ]}
81
+ />
82
+ {/* Dot Animation */}
83
+ <Animated.View
84
+ style={[
85
+ dotStyle,
86
+ {
87
+ transform: [{ scale: scaleAnim }],
88
+ },
89
+ ]}
90
+ />
73
91
  </View>
74
92
  );
75
93
  };
package/Button/index.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import React, { FC, useContext, useRef } from 'react';
2
2
  import {
3
+ Animated,
3
4
  StyleSheet,
4
5
  TouchableOpacity,
5
6
  TouchableOpacityProps,
@@ -28,6 +29,8 @@ import Reanimated, {
28
29
  withTiming,
29
30
  } from 'react-native-reanimated';
30
31
 
32
+ const AnimationLinear = Animated.createAnimatedComponent(LinearGradient);
33
+
31
34
  export interface ButtonProps extends TouchableOpacityProps {
32
35
  /**
33
36
  * Defines the visual style of the button.
@@ -356,7 +359,7 @@ const Button: FC<ButtonProps> = ({
356
359
  {renderTitle()}
357
360
  {renderIcon('right')}
358
361
  {gradientPros && (
359
- <LinearGradient {...gradientPros} style={styles.gradientView} />
362
+ <AnimationLinear {...gradientPros} style={styles.gradientView} />
360
363
  )}
361
364
  {gradientPros && <View style={styles.strokeView} />}
362
365
  </Reanimated.View>
package/Context/index.ts CHANGED
@@ -9,9 +9,12 @@ const MiniAppContext = (Platform as any).MiniAppContext ?? Context;
9
9
  const ScreenContext = (Platform as any).ScreenContext ?? Context;
10
10
  const ComponentContext = (Platform as any).ComponentContext ?? Context;
11
11
  const SkeletonContext = createContext({ loading: false });
12
- const ScaleSizeContext = createContext<{ scaleSizeMaxRate?: number }>({
13
- scaleSizeMaxRate: undefined,
14
- });
12
+ // Single source of truth: holds both the OS flag and the user-adjusted rate.
13
+ export type FontScaleConfig = {
14
+ useOSFontScale?: boolean;
15
+ userScaleRate?: number;
16
+ };
17
+ const ScaleSizeContext = createContext<FontScaleConfig>({});
15
18
  const TrackingScopeContext = createContext<{ scopeName?: string }>({
16
19
  scopeName: undefined,
17
20
  });
@@ -8,22 +8,13 @@ import React, {
8
8
  useState,
9
9
  } from 'react';
10
10
  import {
11
+ Animated,
11
12
  PixelRatio,
12
13
  TextInput,
13
14
  TextInputFocusEvent,
14
15
  TouchableOpacity,
15
16
  View,
16
17
  } 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';
27
18
  import { useComponentId } from '../Application';
28
19
  import { Spacing, Styles } from '../Consts';
29
20
  import { useScaleSize, Text } from '../Text';
@@ -41,43 +32,37 @@ import {
41
32
  const OTPCaret: FC<CaretProps> = ({ index, length }) => {
42
33
  const DURATION = 300;
43
34
  const { theme } = useContext(ApplicationContext);
44
- const opacity = useSharedValue(0);
35
+ const opacity = useRef(new Animated.Value(0)).current;
45
36
 
46
37
  useEffect(() => {
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
- };
38
+ Animated.loop(
39
+ Animated.sequence([
40
+ Animated.timing(opacity, {
41
+ toValue: 1,
42
+ duration: DURATION,
43
+ useNativeDriver: true,
44
+ }),
45
+ Animated.delay(DURATION * 2),
46
+ Animated.timing(opacity, {
47
+ toValue: 0,
48
+ duration: DURATION,
49
+ useNativeDriver: true,
50
+ }),
51
+ ]),
52
+ ).start();
61
53
  }, [opacity]);
62
-
63
- const animatedStyle = useAnimatedStyle(() => ({
64
- opacity: opacity.value,
65
- }));
66
-
67
54
  const spacingStyle = !isNaN(Number(length)) &&
68
55
  index !== Number(length) - 1 && { marginRight: Spacing.L };
69
56
 
70
57
  return (
71
58
  <View style={[Styles.rowCenter, spacingStyle]}>
72
59
  <Animated.View
73
- style={[
74
- {
75
- height: useScaleSize(12),
76
- width: 1,
77
- backgroundColor: theme.colors.primary,
78
- },
79
- animatedStyle,
80
- ]}
60
+ style={{
61
+ height: useScaleSize(12),
62
+ width: 1,
63
+ backgroundColor: theme.colors.primary,
64
+ opacity,
65
+ }}
81
66
  />
82
67
  <Text color={theme.colors.text.hint} typography={'body_default_regular'}>
83
68
  -
@@ -1,24 +1,20 @@
1
- import React, { useContext, useEffect, useState } from 'react';
2
1
  import {
2
+ default as React,
3
+ useContext,
4
+ useEffect,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
8
+ import {
9
+ Animated,
3
10
  LayoutChangeEvent,
4
11
  StyleSheet,
5
12
  TouchableOpacity,
6
13
  View,
7
14
  } from 'react-native';
8
- import Animated, {
9
- useAnimatedReaction,
10
- useAnimatedStyle,
11
- useSharedValue,
12
- withTiming,
13
- runOnJS,
14
- } from 'react-native-reanimated';
15
15
  import { ApplicationContext } from '../Context';
16
16
  import { Icon } from '../Icon';
17
17
  import { useScaleSize } from '../Text';
18
- import {
19
- AnimatedCompatValue,
20
- useNormalizedSharedValue,
21
- } from '../Application/utils';
22
18
 
23
19
  export interface FloatingButtonProps {
24
20
  label?: string;
@@ -27,7 +23,7 @@ export interface FloatingButtonProps {
27
23
  icon?: string;
28
24
  iconColor?: string;
29
25
  size?: 'small' | 'large';
30
- animatedValue?: AnimatedCompatValue;
26
+ animatedValue?: Animated.Value;
31
27
  bottom?: number;
32
28
  renderComponent?: () => React.ReactNode;
33
29
  }
@@ -44,71 +40,70 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
44
40
  bottom = 12,
45
41
  }: FloatingButtonProps) => {
46
42
  const { theme } = useContext(ApplicationContext);
47
- const enabled = animatedValue != null;
48
- const sharedValue = useNormalizedSharedValue(animatedValue);
49
43
  const scaledFontSize = useScaleSize(16);
50
44
  const scaledLineHeight = useScaleSize(22);
51
- const maxWidth = useSharedValue(0);
45
+ const maxWidth = useRef(0);
52
46
  const minWidth = size === 'small' ? 36 : 48;
53
- const opacityAnimated = useSharedValue(0);
54
- const widthAnimated = useSharedValue<number | null>(null);
55
- const lastOffset = useSharedValue(0);
56
- const lastDirection = useSharedValue<string | null>(null);
57
- const [showText, setShowText] = useState(true);
47
+ const [opacityAnimated] = useState(new Animated.Value(0)); // Initial opacity set to 0
48
+ const [widthAnimated, setWidthAnimated] = useState<Animated.Value>();
49
+ const lastOffset = useRef(0);
50
+ const lastDirection = useRef<string>(null);
51
+ const [showText, setShowText] = React.useState(true);
58
52
 
59
53
  useEffect(() => {
60
54
  if (!label) return;
61
- opacityAnimated.value = withTiming(1, { duration: 100 });
62
- }, [label, opacityAnimated]);
63
55
 
64
- useAnimatedReaction(
65
- () => sharedValue.value,
66
- (value) => {
67
- 'worklet';
68
- if (!label || !enabled) return;
69
- if (value !== lastOffset.value && value > 0) {
70
- const direction = value > lastOffset.value ? 'down' : 'up';
71
- lastOffset.value = value;
72
- if (lastDirection.value !== direction) {
73
- lastDirection.value = direction;
56
+ Animated.timing(opacityAnimated, {
57
+ toValue: 1,
58
+ duration: 100,
59
+ useNativeDriver: true,
60
+ }).start();
61
+
62
+ const listener = animatedValue?.addListener(({ value }) => {
63
+ if (value !== lastOffset.current && value > 0) {
64
+ const direction = value > lastOffset.current ? 'down' : 'up';
65
+ lastOffset.current = value;
66
+ if (lastDirection.current !== direction) {
67
+ lastDirection.current = direction;
74
68
  if (direction === 'down') {
75
- opacityAnimated.value = withTiming(0, { duration: 100 });
76
- widthAnimated.value = withTiming(
77
- minWidth,
78
- { duration: 100 },
79
- (finished) => {
80
- if (finished) runOnJS(setShowText)(false);
81
- },
82
- );
69
+ Animated.timing(opacityAnimated, {
70
+ toValue: 0,
71
+ duration: 100,
72
+ useNativeDriver: true,
73
+ }).start();
74
+ Animated.timing(widthAnimated!, {
75
+ toValue: minWidth,
76
+ duration: 100,
77
+ useNativeDriver: false,
78
+ }).start(() => setShowText(false));
83
79
  } else {
84
- opacityAnimated.value = withTiming(1, { duration: 100 });
85
- widthAnimated.value = withTiming(
86
- maxWidth.value,
87
- { duration: 100 },
88
- (finished) => {
89
- if (finished) runOnJS(setShowText)(true);
90
- },
91
- );
80
+ Animated.timing(opacityAnimated, {
81
+ toValue: 1,
82
+ duration: 100,
83
+ useNativeDriver: true,
84
+ }).start();
85
+ Animated.timing(widthAnimated!, {
86
+ toValue: maxWidth.current,
87
+ duration: 100,
88
+ useNativeDriver: false,
89
+ }).start(() => setShowText(true));
92
90
  }
93
91
  }
94
92
  }
95
- },
96
- [label, enabled, minWidth],
97
- );
93
+ });
98
94
 
99
- const containerStyle = useAnimatedStyle(() => ({
100
- width: widthAnimated.value ?? undefined,
101
- }));
102
-
103
- const labelStyle = useAnimatedStyle(() => ({
104
- opacity: opacityAnimated.value,
105
- }));
95
+ return () => {
96
+ if (listener) {
97
+ animatedValue?.removeListener(listener);
98
+ }
99
+ };
100
+ }, [animatedValue, label, minWidth, opacityAnimated, widthAnimated]);
106
101
 
107
102
  const handleLayout = (event: LayoutChangeEvent) => {
108
103
  const layout = event.nativeEvent.layout;
109
- if (widthAnimated.value != null) return;
110
- maxWidth.value = layout.width;
111
- widthAnimated.value = layout.width;
104
+ if (widthAnimated) return;
105
+ maxWidth.current = layout.width;
106
+ setWidthAnimated(new Animated.Value(layout.width));
112
107
  };
113
108
 
114
109
  if (renderComponent) {
@@ -137,11 +132,11 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
137
132
  {
138
133
  right: position === 'right' ? 12 : undefined,
139
134
  alignSelf: position === 'center' ? 'center' : 'flex-end',
135
+ width: widthAnimated,
140
136
  height: size === 'small' ? 36 : 48,
141
137
  backgroundColor: theme.colors.primary,
142
138
  bottom,
143
139
  },
144
- containerStyle,
145
140
  ]}
146
141
  >
147
142
  <TouchableOpacity
@@ -161,9 +156,9 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
161
156
  {
162
157
  fontSize: scaledFontSize,
163
158
  lineHeight: scaledLineHeight,
159
+ opacity: opacityAnimated,
164
160
  color: 'white',
165
161
  },
166
- labelStyle,
167
162
  ]}
168
163
  numberOfLines={1}
169
164
  >
package/Layout/Screen.tsx CHANGED
@@ -25,10 +25,6 @@ import {
25
25
  View,
26
26
  ViewProps,
27
27
  } from 'react-native';
28
- import {
29
- useSharedValue,
30
- withTiming,
31
- } from 'react-native-reanimated';
32
28
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
33
29
  import { ApplicationContext, ScreenContext } from '../Context';
34
30
  import Navigation from '../Application/Navigation';
@@ -140,8 +136,7 @@ export interface ScreenProps extends ViewProps {
140
136
  inputSearchRef?: Ref<InputRef>;
141
137
 
142
138
  /**
143
- * Optional. React Native animated value for header.
144
- * Internally, Screen mirrors it into a reanimated shared value.
139
+ * Optional. Animated value for header.
145
140
  */
146
141
  animatedValue?: Animated.Value;
147
142
 
@@ -200,40 +195,9 @@ const Screen = forwardRef(
200
195
  const screen: any = useContext(ScreenContext);
201
196
  const insets = useSafeAreaInsets();
202
197
  const heightHeader = useHeaderHeight();
203
-
204
- /**
205
- * Dual animation source:
206
- * - `rnValue` is a react-native `Animated.Value` driven natively by the
207
- * scroll event. It is what legacy consumers receive (`animatedValue`).
208
- * - `sharedValue` is a reanimated `SharedValue` consumed by every internal
209
- * foundation component (and offered to modern consumers). It is kept in
210
- * sync from the scroll `listener` (see below), which fires on the JS
211
- * thread even when the scroll uses the native driver.
212
- * If a legacy value is driven outside of Screen, its listener also
213
- * mirrors JS-driven updates into the shared value.
214
- * Consumers pass only `Animated.Value`; the reanimated shared value stays
215
- * an internal implementation detail.
216
- */
217
- const rnValue = useRef<Animated.Value>(
218
- customAnimatedValue ?? new Animated.Value(0),
198
+ const animatedValue = useRef<Animated.Value>(
199
+ customAnimatedValue || new Animated.Value(0),
219
200
  );
220
- const internalShared = useSharedValue(0);
221
- const sharedValue = internalShared;
222
-
223
- useEffect(() => {
224
- if (!customAnimatedValue) {
225
- return;
226
- }
227
-
228
- const listenerId = customAnimatedValue.addListener(({ value }) => {
229
- internalShared.value = value;
230
- });
231
-
232
- return () => {
233
- customAnimatedValue.removeListener(listenerId);
234
- };
235
- }, [customAnimatedValue, internalShared]);
236
-
237
201
  const currentTint = useRef<string | undefined>(undefined);
238
202
  const isTab = navigation?.instance?.getState?.()?.type === 'tab';
239
203
 
@@ -284,8 +248,9 @@ const Screen = forwardRef(
284
248
  interpolate={{
285
249
  inputRange: [0, 50],
286
250
  outputRange: [1, 0],
251
+ extrapolate: 'clamp',
287
252
  }}
288
- animatedValue={sharedValue}
253
+ animatedValue={animatedValue.current}
289
254
  />
290
255
  ),
291
256
  };
@@ -300,7 +265,7 @@ const Screen = forwardRef(
300
265
  headerBackground: (props: any) => (
301
266
  <HeaderBackground
302
267
  {...props}
303
- animatedValue={sharedValue}
268
+ animatedValue={animatedValue.current}
304
269
  useShadowHeader={useShadowHeader}
305
270
  headerBackground={headerBackground}
306
271
  gradientColor={gradientColor}
@@ -319,8 +284,9 @@ const Screen = forwardRef(
319
284
  interpolate={{
320
285
  inputRange: [0, 50],
321
286
  outputRange: [1, 0],
287
+ extrapolate: 'clamp',
322
288
  }}
323
- animatedValue={sharedValue}
289
+ animatedValue={animatedValue.current}
324
290
  />
325
291
  ),
326
292
  };
@@ -334,7 +300,6 @@ const Screen = forwardRef(
334
300
  headerBackground,
335
301
  inputSearchProps,
336
302
  navigation?.instance,
337
- sharedValue,
338
303
  useShadowHeader,
339
304
  ],
340
305
  );
@@ -356,7 +321,7 @@ const Screen = forwardRef(
356
321
  headerBackground: (props: any) => (
357
322
  <HeaderBackground
358
323
  {...props}
359
- animatedValue={sharedValue}
324
+ animatedValue={animatedValue.current}
360
325
  useGradient={false}
361
326
  useShadowHeader={useShadowHeader}
362
327
  headerBackground={headerBackground}
@@ -377,13 +342,7 @@ const Screen = forwardRef(
377
342
 
378
343
  navigation?.instance?.setOptions(options);
379
344
  },
380
- [
381
- gradientColor,
382
- headerBackground,
383
- navigation?.instance,
384
- sharedValue,
385
- useShadowHeader,
386
- ],
345
+ [gradientColor, headerBackground, navigation?.instance, useShadowHeader],
387
346
  );
388
347
 
389
348
  /**
@@ -400,14 +359,15 @@ const Screen = forwardRef(
400
359
  interpolate={{
401
360
  inputRange: [0, 50],
402
361
  outputRange: [1, 0],
362
+ extrapolate: 'clamp',
403
363
  }}
404
- animatedValue={sharedValue}
364
+ animatedValue={animatedValue.current}
405
365
  />
406
366
  ),
407
367
  };
408
368
 
409
369
  navigation?.instance?.setOptions(options);
410
- }, [navigation?.instance, sharedValue]);
370
+ }, [navigation?.instance]);
411
371
 
412
372
  /**
413
373
  * export search header
@@ -430,7 +390,7 @@ const Screen = forwardRef(
430
390
  headerLeft: (props: any) =>
431
391
  params?.hiddenBack ? null : <HeaderLeft {...props} />,
432
392
  headerTitle: () => (
433
- <SearchHeader {...params} animatedValue={sharedValue} />
393
+ <SearchHeader {...params} animatedValue={animatedValue.current} />
434
394
  ),
435
395
  };
436
396
 
@@ -490,18 +450,16 @@ const Screen = forwardRef(
490
450
  [
491
451
  {
492
452
  nativeEvent: {
493
- contentOffset: { y: rnValue.current as Animated.Value },
453
+ contentOffset: { y: animatedValue.current as Animated.Value },
494
454
  },
495
455
  },
496
456
  ],
497
457
  {
498
458
  useNativeDriver: true,
499
459
  listener: (e: NativeSyntheticEvent<NativeScrollEvent>) => {
500
- const offsetY = e.nativeEvent.contentOffset.y;
501
- // keep the reanimated source in sync for the internal components.
502
- sharedValue.value = offsetY;
503
460
  scrollViewProps?.onScroll?.(e);
504
461
  if (animatedHeader) {
462
+ const offsetY = e.nativeEvent.contentOffset.y;
505
463
  let color = animatedHeader?.headerTintColor ?? Colors.black_17;
506
464
  if (offsetY > 50) {
507
465
  color = Colors.black_17;
@@ -531,12 +489,11 @@ const Screen = forwardRef(
531
489
  const handleScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
532
490
  const offsetY = e.nativeEvent.contentOffset.y;
533
491
  if (inputSearchProps && offsetY < 100 && offsetY > 0) {
534
- Animated.timing(rnValue.current, {
492
+ Animated.timing(animatedValue.current, {
535
493
  toValue: 0,
536
494
  useNativeDriver: true,
537
495
  duration: 300,
538
496
  }).start();
539
- sharedValue.value = withTiming(0, { duration: 300 });
540
497
  ref?.scrollTo?.({ y: 0, animated: true });
541
498
  }
542
499
  scrollViewProps?.onScrollEndDrag?.(e);
@@ -552,10 +509,7 @@ const Screen = forwardRef(
552
509
  style={[styles.screenBanner, { maxHeight: 210 + layoutOffset }]}
553
510
  >
554
511
  {animatedHeader?.component({
555
- // legacy consumers read `animatedValue` (Animated.Value),
556
- // modern consumers read `sharedValue` (SharedValue).
557
- animatedValue: rnValue.current,
558
- sharedValue: sharedValue,
512
+ animatedValue: animatedValue.current,
559
513
  })}
560
514
  </View>
561
515
  );
@@ -622,7 +576,7 @@ const Screen = forwardRef(
622
576
  headerType={headerType}
623
577
  heightHeader={heightHeader}
624
578
  headerRightWidth={headerRightWidth}
625
- animatedValue={sharedValue}
579
+ animatedValue={animatedValue.current}
626
580
  inputSearchProps={inputSearchProps}
627
581
  navigation={navigation}
628
582
  inputSearchRef={inputSearchRef}
@@ -660,7 +614,7 @@ const Screen = forwardRef(
660
614
  <View>
661
615
  <FloatingButton
662
616
  {...floatingButtonProps}
663
- animatedValue={sharedValue}
617
+ animatedValue={animatedValue.current}
664
618
  bottom={
665
619
  Footer || isTab ? 12 : Math.min(insets.bottom, 21) + Spacing.S
666
620
  }