@mrmeg/expo-ui 0.7.1 → 0.7.2
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.
|
@@ -40,6 +40,9 @@ import { BottomSheetKeyboardController, useBottomSheetKeyboardAnimation, } from
|
|
|
40
40
|
*/
|
|
41
41
|
// Platform-specific overlay wrapper
|
|
42
42
|
const FullWindowOverlay = Platform.OS === "ios" ? RNFullWindowOverlay : React.Fragment;
|
|
43
|
+
// Floor for the keyboard-avoiding height shrink, so a tall keyboard on a short
|
|
44
|
+
// screen can't collapse the sheet to nothing.
|
|
45
|
+
const MIN_KEYBOARD_SHEET_HEIGHT = 220;
|
|
43
46
|
// ============================================================================
|
|
44
47
|
// Context
|
|
45
48
|
// ============================================================================
|
|
@@ -52,19 +55,51 @@ function useBottomSheetContext() {
|
|
|
52
55
|
return context;
|
|
53
56
|
}
|
|
54
57
|
const DragContext = createContext(null);
|
|
55
|
-
function BottomSheetPanel({ accessibilityViewIsModal, children, panHandlers, sheetStyle, styleOverride, translateY, ...props }) {
|
|
58
|
+
function BottomSheetPanel({ accessibilityViewIsModal, animatedHeight, animatedBottom, children, panHandlers, sheetStyle, styleOverride, translateY, ...props }) {
|
|
56
59
|
return (_jsx(Animated.View, { style: [
|
|
57
60
|
sheetStyle,
|
|
61
|
+
// Layout overrides (JS-driven) must come after sheetStyle so they win.
|
|
62
|
+
animatedBottom ? { bottom: animatedBottom } : undefined,
|
|
63
|
+
animatedHeight ? { height: animatedHeight } : undefined,
|
|
64
|
+
// Open/close + drag (native-driven) live on transform, a separate node.
|
|
58
65
|
{ transform: [{ translateY }] },
|
|
59
66
|
styleOverride && typeof styleOverride !== "function"
|
|
60
67
|
? StyleSheet.flatten(styleOverride)
|
|
61
68
|
: undefined,
|
|
62
69
|
], accessibilityViewIsModal: accessibilityViewIsModal, ...panHandlers, ...props, children: children }));
|
|
63
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Lifts the sheet above the keyboard while keeping its top edge on-screen.
|
|
73
|
+
*
|
|
74
|
+
* The naive approach translates the whole rigid box up by the keyboard height,
|
|
75
|
+
* which shoves the header (and any inputs near the top) off the top of the
|
|
76
|
+
* screen on tall sheets. Instead we lift the sheet's bottom to sit just above
|
|
77
|
+
* the keyboard and shrink its height by the same amount, so the top edge holds
|
|
78
|
+
* steady. The flex Body soaks up the lost height and scrolls, leaving the
|
|
79
|
+
* header, focused input, and footer all visible.
|
|
80
|
+
*
|
|
81
|
+
* This drives layout props (`bottom`/`height`) with a JS-driven keyboard value,
|
|
82
|
+
* intentionally separate from the native-driven open/close `translateY` — a
|
|
83
|
+
* single Animated.Value can't feed both a native transform and a JS layout
|
|
84
|
+
* prop, but distinct nodes on the same view can.
|
|
85
|
+
*/
|
|
64
86
|
function KeyboardAvoidingBottomSheetPanel(props) {
|
|
65
87
|
const { height: keyboardHeight } = useBottomSheetKeyboardAnimation();
|
|
66
|
-
|
|
67
|
-
|
|
88
|
+
// sheetStyle.height is the resolved max snap height (a number, set by Content).
|
|
89
|
+
const baseHeight = typeof props.sheetStyle.height === "number" ? props.sheetStyle.height : undefined;
|
|
90
|
+
const animatedHeight = useMemo(() => {
|
|
91
|
+
if (baseHeight === undefined)
|
|
92
|
+
return undefined;
|
|
93
|
+
// keyboardHeight: 0 (closed) → keyboard px (open). Shrink the sheet by it,
|
|
94
|
+
// clamped to a usable minimum so it never collapses on short screens.
|
|
95
|
+
const shrunk = Animated.subtract(baseHeight, keyboardHeight);
|
|
96
|
+
return shrunk.interpolate({
|
|
97
|
+
inputRange: [MIN_KEYBOARD_SHEET_HEIGHT, baseHeight],
|
|
98
|
+
outputRange: [MIN_KEYBOARD_SHEET_HEIGHT, baseHeight],
|
|
99
|
+
extrapolate: "clamp",
|
|
100
|
+
});
|
|
101
|
+
}, [baseHeight, keyboardHeight]);
|
|
102
|
+
return (_jsx(BottomSheetPanel, { ...props, animatedHeight: animatedHeight, animatedBottom: keyboardHeight }));
|
|
68
103
|
}
|
|
69
104
|
// ============================================================================
|
|
70
105
|
// Utility Functions
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
2
|
import { Animated, Keyboard, Platform } from "react-native";
|
|
3
|
+
// This value drives layout props (a sheet's `bottom`/`height`), which the
|
|
4
|
+
// native animation driver can't touch — so timings here must stay on the JS
|
|
5
|
+
// driver. It also means the value is a positive keyboard height (0 when
|
|
6
|
+
// hidden), letting consumers both lift and shrink the sheet from one source.
|
|
3
7
|
function animateKeyboardOffset(value, toValue, duration = 180) {
|
|
4
8
|
Animated.timing(value, {
|
|
5
9
|
toValue,
|
|
6
10
|
duration,
|
|
7
|
-
useNativeDriver:
|
|
11
|
+
useNativeDriver: false,
|
|
8
12
|
}).start();
|
|
9
13
|
}
|
|
10
14
|
export function useBottomSheetKeyboardAnimation() {
|
|
@@ -16,7 +20,7 @@ export function useBottomSheetKeyboardAnimation() {
|
|
|
16
20
|
const showEvent = Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
|
|
17
21
|
const hideEvent = Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
|
|
18
22
|
const showSubscription = Keyboard.addListener(showEvent, (event) => {
|
|
19
|
-
animateKeyboardOffset(keyboardHeight,
|
|
23
|
+
animateKeyboardOffset(keyboardHeight, event.endCoordinates.height, event.duration || 180);
|
|
20
24
|
});
|
|
21
25
|
const hideSubscription = Keyboard.addListener(hideEvent, (event) => {
|
|
22
26
|
animateKeyboardOffset(keyboardHeight, 0, event.duration || 160);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrmeg/expo-ui",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Reusable Expo and React Native UI primitives for MrMeg projects.",
|
|
6
6
|
"keywords": [
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"homepage": "https://github.com/mrmeg/expo-template/tree/main/packages/ui",
|
|
25
25
|
"type": "module",
|
|
26
26
|
"publishConfig": {
|
|
27
|
-
"access": "public"
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org/"
|
|
28
29
|
},
|
|
29
30
|
"main": "./dist/index.js",
|
|
30
31
|
"types": "./dist/index.d.ts",
|