@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.
- package/Layout/Screen.tsx +50 -28
- 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
|
|
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
|
|
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
|
-
|
|
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>
|