Skip to content

Commit 239ed8c

Browse files
author
Srirang.Kalantri
committed
fix: improve bottom sheet issues and performance
1 parent 87146e0 commit 239ed8c

5 files changed

Lines changed: 349 additions & 174 deletions

File tree

packages/pluggableWidgets/bottom-sheet-native/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
88

99
### Fixed
1010

11-
- Fixed the "non‑worklet function called on the UI thread” error in bottom sheet coming from @gorhom/bottom-sheet usage.
11+
- Fixed the “non‑worklet function called on the UI thread” error in bottom sheet coming from @gorhom/bottom-sheet usage.
12+
- Fixed ExpandingDrawer to open correctly and show all elements.
13+
14+
### Changed
15+
16+
- Improved performance by memoizing all callbacks with useCallback and useMemo across all components.
17+
- BottomSheet now uses BottomSheetScrollView instead of BottomSheetView, enabling proper scrolling in expanded states.
18+
- NativeBottomSheet now explicitly calculates snapPoints with 90% screen height cap for predictable sizing.
19+
- CustomModalSheet now measures content height dynamically with 90% screen height cap, removing offscreen SafeAreaView measurement.
1220

1321
## [5.0.3] - 2025-12-15
1422

packages/pluggableWidgets/bottom-sheet-native/src/__tests__/__snapshots__/BottomSheet.spec.tsx.snap

Lines changed: 90 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,104 +2,159 @@
22

33
exports[`Bottom sheet renders a custom bottom action sheet for ios (Basic modal) with custom style 1`] = `null`;
44

5-
exports[`Bottom sheet renders a custom modal 1`] = `
5+
exports[`Bottom sheet renders a custom modal 1`] = `null`;
6+
7+
exports[`Bottom sheet renders a expanding 1`] = `
68
<View
9+
pointerEvents="box-none"
710
style={
811
{
912
"bottom": 0,
1013
"left": 0,
11-
"opacity": 0,
1214
"position": "absolute",
1315
"right": 0,
1416
"top": 0,
1517
}
1618
}
1719
>
18-
<RCTSafeAreaView
19-
onLayout={[Function]}
20+
<View
2021
style={
2122
{
22-
"flex": 1,
23+
"bottom": 0,
24+
"left": 0,
25+
"opacity": 0,
26+
"pointerEvents": "none",
27+
"position": "absolute",
28+
"right": 0,
29+
"zIndex": -1,
2330
}
2431
}
25-
/>
26-
</View>
27-
`;
28-
29-
exports[`Bottom sheet renders a expanding 1`] = `
30-
<View
31-
style={
32-
{
33-
"bottom": -1334,
34-
"position": "absolute",
35-
}
36-
}
37-
>
38-
<View
39-
onLayout={[Function]}
40-
pointerEvents="box-none"
4132
>
4233
<View
4334
onLayout={[Function]}
4435
pointerEvents="box-none"
45-
style={{}}
4636
>
4737
<Text>
4838
Header
4939
</Text>
5040
</View>
51-
<Text>
52-
Content
53-
</Text>
41+
<View
42+
onLayout={[Function]}
43+
pointerEvents="box-none"
44+
>
45+
<Text>
46+
Content
47+
</Text>
48+
</View>
5449
</View>
5550
</View>
5651
`;
5752

5853
exports[`Bottom sheet renders a expanding fullscreen 1`] = `
5954
<View
55+
pointerEvents="box-none"
6056
style={
6157
{
6258
"bottom": 0,
6359
"left": 0,
64-
"opacity": 0,
6560
"position": "absolute",
6661
"right": 0,
6762
"top": 0,
6863
}
6964
}
7065
>
71-
<RCTSafeAreaView
72-
onLayout={[Function]}
66+
<View
7367
style={
7468
{
75-
"flex": 1,
69+
"bottom": 0,
70+
"left": 0,
71+
"opacity": 0,
72+
"pointerEvents": "none",
73+
"position": "absolute",
74+
"right": 0,
75+
"zIndex": -1,
7676
}
7777
}
78-
/>
78+
>
79+
<View
80+
onLayout={[Function]}
81+
pointerEvents="box-none"
82+
>
83+
<Text>
84+
Header
85+
</Text>
86+
</View>
87+
<View
88+
onLayout={[Function]}
89+
pointerEvents="box-none"
90+
>
91+
<Text>
92+
Content
93+
</Text>
94+
</View>
95+
<View
96+
onLayout={[Function]}
97+
pointerEvents="box-none"
98+
>
99+
<Text>
100+
Full screen content
101+
</Text>
102+
</View>
103+
</View>
79104
</View>
80105
`;
81106

82107
exports[`Bottom sheet renders a expanding fullscreen with custom styles 1`] = `
83108
<View
109+
pointerEvents="box-none"
84110
style={
85111
{
86112
"bottom": 0,
87113
"left": 0,
88-
"opacity": 0,
89114
"position": "absolute",
90115
"right": 0,
91116
"top": 0,
92117
}
93118
}
94119
>
95-
<RCTSafeAreaView
96-
onLayout={[Function]}
120+
<View
97121
style={
98122
{
99-
"flex": 1,
123+
"bottom": 0,
124+
"left": 0,
125+
"opacity": 0,
126+
"pointerEvents": "none",
127+
"position": "absolute",
128+
"right": 0,
129+
"zIndex": -1,
100130
}
101131
}
102-
/>
132+
>
133+
<View
134+
onLayout={[Function]}
135+
pointerEvents="box-none"
136+
>
137+
<Text>
138+
Header
139+
</Text>
140+
</View>
141+
<View
142+
onLayout={[Function]}
143+
pointerEvents="box-none"
144+
>
145+
<Text>
146+
Content
147+
</Text>
148+
</View>
149+
<View
150+
onLayout={[Function]}
151+
pointerEvents="box-none"
152+
>
153+
<Text>
154+
Full screen content
155+
</Text>
156+
</View>
157+
</View>
103158
</View>
104159
`;
105160

packages/pluggableWidgets/bottom-sheet-native/src/components/CustomModalSheet.tsx

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { ReactElement, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
2-
import { InteractionManager, LayoutChangeEvent, Modal, Pressable, SafeAreaView, StyleSheet, View } from "react-native";
3-
import BottomSheet, { BottomSheetBackdrop, BottomSheetBackdropProps, BottomSheetView } from "@gorhom/bottom-sheet";
2+
import { Dimensions, InteractionManager, LayoutChangeEvent, Modal, Pressable } from "react-native";
3+
import BottomSheet, {
4+
BottomSheetBackdrop,
5+
BottomSheetBackdropProps,
6+
BottomSheetScrollView
7+
} from "@gorhom/bottom-sheet";
48
import { EditableValue, ValueStatus } from "mendix";
5-
import { BottomSheetStyle, defaultPaddings } from "../ui/Styles";
9+
import { BottomSheetStyle } from "../ui/Styles";
610

711
interface CustomModalSheetProps {
812
triggerAttribute?: EditableValue<boolean>;
@@ -14,7 +18,7 @@ let lastIndexRef = -1;
1418

1519
export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement => {
1620
const bottomSheetRef = useRef<BottomSheet>(null);
17-
const [height, setHeight] = useState(0);
21+
const [contentHeight, setContentHeight] = useState(0);
1822
const [currentStatus, setCurrentStatus] = useState(false);
1923

2024
const isAvailable = props.triggerAttribute && props.triggerAttribute.status === ValueStatus.Available;
@@ -24,12 +28,15 @@ export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement =>
2428
props.triggerAttribute.status === ValueStatus.Available &&
2529
props.triggerAttribute.value;
2630

27-
const onLayoutFullscreenHandler = (event: LayoutChangeEvent): void => {
28-
const layoutHeight = event.nativeEvent.layout.height;
29-
if (layoutHeight > 0 && layoutHeight !== height) {
30-
setHeight(layoutHeight);
31-
}
32-
};
31+
const onContentLayoutHandler = useCallback(
32+
(event: LayoutChangeEvent): void => {
33+
const layoutHeight = event.nativeEvent.layout.height;
34+
if (layoutHeight > 0 && layoutHeight !== contentHeight) {
35+
setContentHeight(layoutHeight);
36+
}
37+
},
38+
[contentHeight]
39+
);
3340

3441
const close = useCallback(() => {
3542
bottomSheetRef.current?.close();
@@ -51,11 +58,15 @@ export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement =>
5158
);
5259

5360
const snapPoints = useMemo(() => {
54-
if (height === 0) {
55-
return [0];
61+
if (contentHeight === 0) {
62+
return [1]; // During measurement
5663
}
57-
return [height - Number(defaultPaddings.paddingBottom)];
58-
}, [height]);
64+
65+
// Use actual measured content height, cap at 90% screen
66+
const maxHeight = Dimensions.get("screen").height * 0.9;
67+
const snapHeight = Math.min(contentHeight, maxHeight);
68+
return [snapHeight];
69+
}, [contentHeight]);
5970

6071
const handleSheetChanges = useCallback(
6172
(index: number) => {
@@ -89,14 +100,6 @@ export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement =>
89100
}
90101
}, [props.triggerAttribute, currentStatus, isAvailable]);
91102

92-
if (height === 0) {
93-
return (
94-
<View style={{ ...StyleSheet.absoluteFillObject, opacity: 0 }}>
95-
<SafeAreaView style={{ flex: 1 }} onLayout={onLayoutFullscreenHandler} />
96-
</View>
97-
);
98-
}
99-
100103
return (
101104
<Modal onRequestClose={close} transparent visible={!!isOpen}>
102105
<BottomSheet
@@ -112,7 +115,13 @@ export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement =>
112115
handleComponent={null}
113116
handleStyle={{ display: "none" }}
114117
>
115-
<BottomSheetView style={[props.styles.container, defaultPaddings]}>{props.content}</BottomSheetView>
118+
<BottomSheetScrollView
119+
style={[{ flex: 1 }]}
120+
contentContainerStyle={{ paddingBottom: 16 }}
121+
onLayout={onContentLayoutHandler}
122+
>
123+
{props.content}
124+
</BottomSheetScrollView>
116125
</BottomSheet>
117126
</Modal>
118127
);

0 commit comments

Comments
 (0)