@momo-kits/foundation 0.163.1-beta.13 → 0.163.1-beta.14

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.
Files changed (2) hide show
  1. package/Layout/Screen.tsx +50 -28
  2. package/package.json +1 -1
package/Layout/Screen.tsx CHANGED
@@ -25,7 +25,12 @@ import {
25
25
  View,
26
26
  ViewProps,
27
27
  } from 'react-native';
28
- import { useSharedValue, withTiming } from 'react-native-reanimated';
28
+ import Reanimated, {
29
+ useAnimatedKeyboard,
30
+ useAnimatedStyle,
31
+ useSharedValue,
32
+ withTiming,
33
+ } from 'react-native-reanimated';
29
34
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
30
35
  import { ApplicationContext, ScreenContext } from '../Context';
31
36
  import Navigation from '../Application/Navigation';
@@ -51,13 +56,6 @@ import {
51
56
  SearchHeader,
52
57
  } from '../Application';
53
58
 
54
- /**
55
- * Scroll distance (px) over which the animated search header collapses from its
56
- * expanded to its docked state — the input range consumed by `HeaderExtendHeader`
57
- * and the settle threshold in `handleScrollEnd`.
58
- */
59
- const SEARCH_HEADER_COLLAPSE_DISTANCE = 100;
60
-
61
59
  export interface ScreenProps extends ViewProps {
62
60
  /**
63
61
  * ReactNode representing the content of the screen.
@@ -199,12 +197,30 @@ const Screen = forwardRef(
199
197
  ref: any,
200
198
  ) => {
201
199
  const screenRef = useRef<View | ScrollView>(null);
202
- const { width: widthDevice, height: heightDevice } = useWindowDimensions();
203
- const { theme } = useContext(ApplicationContext);
200
+ const { width: widthDevice } = useWindowDimensions();
201
+ const { theme, navigator } = useContext(ApplicationContext);
204
202
  const screen: any = useContext(ScreenContext);
205
203
  const insets = useSafeAreaInsets();
206
204
  const heightHeader = useHeaderHeight();
207
205
 
206
+ /**
207
+ * On Android, the native root view already pads for the full IME inset
208
+ * (which itself includes the navigation bar's height) as soon as the
209
+ * keyboard shows. `useSafeAreaInsets()`'s own bottom recompute is JS-thread
210
+ * work (its own native listener, then a bridge crossing, then a React
211
+ * re-render) and always lands at least one frame after that native padding
212
+ * change, so any JS-driven correction (state + re-render, regardless of
213
+ * which event triggers it) has the same lag — the nav bar height gets
214
+ * counted twice for that window, visible as the footer overshooting
215
+ * before settling back down.
216
+ * `useAnimatedKeyboard()` sidesteps this: its worklet callback updates a
217
+ * shared value directly from the same native WindowInsetsAnimation
218
+ * callback driving the keyboard's own motion, on the UI thread, with no
219
+ * bridge crossing — so the footer's compensating style below can react
220
+ * in the same frame instead of a JS tick later.
221
+ */
222
+ const keyboard = useAnimatedKeyboard();
223
+
208
224
  /**
209
225
  * Dual animation source:
210
226
  * - `animatedValue` is a react-native `Animated.Value` driven natively by the
@@ -239,7 +255,7 @@ const Screen = forwardRef(
239
255
  }, [customAnimatedValue, internalShared]);
240
256
 
241
257
  const currentTint = useRef<string | undefined>(undefined);
242
-
258
+
243
259
  const isTab = !!screen?.bottomTab;
244
260
 
245
261
  let handleScroll;
@@ -251,6 +267,25 @@ const Screen = forwardRef(
251
267
  keyboardOffset = -bottomInset;
252
268
  }
253
269
 
270
+ /**
271
+ * Android only: while the keyboard is up, MainActivity's own native inset
272
+ * listener already accounts for the full space it needs (keyboard height
273
+ * plus nav bar) on the root view, so the footer here should only add its
274
+ * usual Spacing.S gap — not `bottomInset` on top, which would double-count
275
+ * the nav bar for as long as the keyboard is visible.
276
+ *
277
+ * `isAndroid` is read here (not inside the worklet) because referencing
278
+ * `Platform.OS` directly inside `useAnimatedStyle` captures the whole
279
+ * `Platform` module into the worklet closure — Reanimated then fails
280
+ * trying to serialize that module object for the UI thread.
281
+ */
282
+ const isAndroid = Platform.OS === 'android';
283
+ const footerAnimatedStyle = useAnimatedStyle(() => {
284
+ const paddingBottom =
285
+ isAndroid && keyboard.height.value > 0 ? Spacing.S : bottomInset + Spacing.S;
286
+ return { paddingBottom };
287
+ });
288
+
254
289
  /**
255
290
  * inject params for screen tracking
256
291
  */
@@ -658,17 +693,6 @@ const Screen = forwardRef(
658
693
  style={[Styles.flex]}
659
694
  contentContainerStyle={[
660
695
  scrollable && !Footer && !isTab && { paddingBottom: bottomInset },
661
- // The animated search header collapses as the body scrolls. When the
662
- // body is short (e.g. no search history) the ScrollView is barely
663
- // scrollable, so overscroll bounce feeds the scroll-driven animation
664
- // and the input jitters on its way up to the header. A ScrollView
665
- // frame can never exceed the window, so forcing the content to be at
666
- // least one screen plus the collapse distance guarantees the animation
667
- // always has room to complete smoothly, independent of body content.
668
- scrollable &&
669
- inputSearchProps && {
670
- minHeight: heightDevice + SEARCH_HEADER_COLLAPSE_DISTANCE,
671
- },
672
696
  scrollViewProps?.contentContainerStyle,
673
697
  ]}
674
698
  >
@@ -688,17 +712,15 @@ const Screen = forwardRef(
688
712
  )}
689
713
 
690
714
  {Footer && (
691
- <View
715
+ <Reanimated.View
692
716
  style={[
693
717
  styles.shadow,
694
- {
695
- paddingBottom: bottomInset + Spacing.S,
696
- backgroundColor: theme.colors.background.surface,
697
- },
718
+ { backgroundColor: theme.colors.background.surface },
719
+ footerAnimatedStyle,
698
720
  ]}
699
721
  >
700
722
  <Section>{Footer}</Section>
701
- </View>
723
+ </Reanimated.View>
702
724
  )}
703
725
  </KeyboardAvoidingView>
704
726
  </View>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.163.1-beta.13",
3
+ "version": "0.163.1-beta.14",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},