@wavemaker/app-rn-runtime 11.13.0-rc.222 → 11.13.0-rc.6277
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/components/basic/bottomsheet/bottomsheet.component.js +318 -152
- package/components/basic/bottomsheet/bottomsheet.component.js.map +1 -1
- package/components/basic/bottomsheet/bottomsheet.props.js +2 -0
- package/components/basic/bottomsheet/bottomsheet.props.js.map +1 -1
- package/npm-shrinkwrap.json +466 -434
- package/package-lock.json +466 -434
- package/package.json +2 -2
- package/styles/theme.js +3 -0
- package/styles/theme.js.map +1 -1
|
@@ -4,8 +4,9 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
|
|
|
4
4
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
5
|
import React, { createRef } from 'react';
|
|
6
6
|
import { BaseComponent, BaseComponentState } from '@wavemaker/app-rn-runtime/core/base.component';
|
|
7
|
-
import { View,
|
|
7
|
+
import { View, PanResponder, Dimensions, TouchableWithoutFeedback, Platform, StatusBar, BackHandler, KeyboardAvoidingView, Keyboard, Modal, Pressable } from 'react-native';
|
|
8
8
|
import { ScrollView } from 'react-native-gesture-handler';
|
|
9
|
+
import Animated, { useAnimatedStyle, withTiming, runOnJS, Easing, makeMutable, cancelAnimation } from 'react-native-reanimated';
|
|
9
10
|
import WmBottomsheetProps from './bottomsheet.props';
|
|
10
11
|
import { DEFAULT_CLASS } from './bottomsheet.styles';
|
|
11
12
|
import { createSkeleton } from '../skeleton/skeleton.component';
|
|
@@ -18,10 +19,6 @@ const {
|
|
|
18
19
|
export class WmBottomsheetState extends BaseComponentState {
|
|
19
20
|
constructor(...args) {
|
|
20
21
|
super(...args);
|
|
21
|
-
_defineProperty(this, "translateY", new Animated.Value(SCREEN_HEIGHT));
|
|
22
|
-
_defineProperty(this, "backdropOpacity", new Animated.Value(0));
|
|
23
|
-
_defineProperty(this, "sheetHeight", new Animated.Value(0));
|
|
24
|
-
_defineProperty(this, "lastGestureDy", 0);
|
|
25
22
|
_defineProperty(this, "scrollViewRef", /*#__PURE__*/createRef());
|
|
26
23
|
_defineProperty(this, "isScrolling", false);
|
|
27
24
|
_defineProperty(this, "scrollOffset", 0);
|
|
@@ -29,15 +26,71 @@ export class WmBottomsheetState extends BaseComponentState {
|
|
|
29
26
|
_defineProperty(this, "isBottomsheetVisible", false);
|
|
30
27
|
_defineProperty(this, "keyboardHeight", 0);
|
|
31
28
|
_defineProperty(this, "localModalsOpened", []);
|
|
29
|
+
_defineProperty(this, "lastGestureDy", 0);
|
|
32
30
|
}
|
|
33
31
|
}
|
|
32
|
+
|
|
33
|
+
// Animated wrapper component that uses hooks
|
|
34
|
+
const AnimatedBottomsheetContent = ({
|
|
35
|
+
translateY,
|
|
36
|
+
backdropOpacity,
|
|
37
|
+
sheetHeight,
|
|
38
|
+
lastGestureDy,
|
|
39
|
+
styles,
|
|
40
|
+
props,
|
|
41
|
+
children,
|
|
42
|
+
panHandlers,
|
|
43
|
+
dragHandlePanHandlers,
|
|
44
|
+
onBackdropPress,
|
|
45
|
+
onDragHandlePress,
|
|
46
|
+
getTestProps,
|
|
47
|
+
enabledragsettle
|
|
48
|
+
}) => {
|
|
49
|
+
const backdropAnimatedStyle = useAnimatedStyle(() => ({
|
|
50
|
+
opacity: backdropOpacity.value
|
|
51
|
+
}));
|
|
52
|
+
const containerAnimatedStyle = useAnimatedStyle(() => ({
|
|
53
|
+
height: sheetHeight.value,
|
|
54
|
+
transform: [{
|
|
55
|
+
translateY: translateY.value
|
|
56
|
+
}]
|
|
57
|
+
}));
|
|
58
|
+
const contentStyle = useAnimatedStyle(() => {
|
|
59
|
+
if (enabledragsettle && lastGestureDy.value > 0) {
|
|
60
|
+
return {
|
|
61
|
+
paddingBottom: lastGestureDy.value
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {};
|
|
65
|
+
});
|
|
66
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TouchableWithoutFeedback, {
|
|
67
|
+
onPress: onBackdropPress
|
|
68
|
+
}, /*#__PURE__*/React.createElement(Animated.View, _extends({
|
|
69
|
+
style: [styles.backdrop, backdropAnimatedStyle]
|
|
70
|
+
}, getTestProps('backdrop'), getAccessibilityProps(AccessibilityWidgetType.BOTTOMSHEET, props)))), /*#__PURE__*/React.createElement(Animated.View, _extends({
|
|
71
|
+
style: [styles.container, containerAnimatedStyle]
|
|
72
|
+
}, panHandlers), /*#__PURE__*/React.createElement(View, _extends({
|
|
73
|
+
style: styles.dragHandleContainer
|
|
74
|
+
}, dragHandlePanHandlers), /*#__PURE__*/React.createElement(Pressable, {
|
|
75
|
+
onPress: onDragHandlePress
|
|
76
|
+
}, /*#__PURE__*/React.createElement(View, _extends({
|
|
77
|
+
style: styles.dragIconHandle
|
|
78
|
+
}, getTestProps('draghandle'))))), children(contentStyle)));
|
|
79
|
+
};
|
|
34
80
|
export default class WmBottomsheet extends BaseComponent {
|
|
81
|
+
// Helper method to calculate animation duration based on distance and velocity
|
|
82
|
+
getAnimationDuration(distance, velocity) {
|
|
83
|
+
// Base duration on distance, but cap it between 200-500ms
|
|
84
|
+
// Higher velocity = shorter duration for snappier feel
|
|
85
|
+
const velocityFactor = Math.max(0.3, Math.min(1, 1 - Math.abs(velocity) / 2));
|
|
86
|
+
const calculatedDuration = Math.abs(distance) * velocityFactor;
|
|
87
|
+
return Math.min(500, Math.max(200, calculatedDuration));
|
|
88
|
+
}
|
|
35
89
|
calculateSheetHeight(bottomsheetheightratio) {
|
|
36
90
|
// Use default height if ratio not provided, but ensure it's not below minimum
|
|
37
91
|
const effectiveRatio = bottomsheetheightratio || this.defaultHeight;
|
|
38
92
|
this.maxHeightRatio = Math.max(this.minimumHeight, Math.min(effectiveRatio, this.maxHeight));
|
|
39
93
|
const screenHeight = Dimensions.get('screen').height;
|
|
40
|
-
const windowHeight = Dimensions.get('window').height;
|
|
41
94
|
let calculatedHeight = screenHeight * this.maxHeightRatio;
|
|
42
95
|
if (Platform.OS === 'ios') {
|
|
43
96
|
// Subtract top inset bar height for ios only if bottomsheetheightratio is 0.9
|
|
@@ -72,8 +125,8 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
72
125
|
_defineProperty(this, "minimumHeight", 0.01);
|
|
73
126
|
_defineProperty(this, "minimumExpandedHeight", 0.5);
|
|
74
127
|
_defineProperty(this, "maxHeight", 1.0);
|
|
75
|
-
// Allow full screen height
|
|
76
128
|
_defineProperty(this, "animationDuration", 400);
|
|
129
|
+
_defineProperty(this, "keyboardAnimationDuration", Platform.OS === 'ios' ? 250 : 275);
|
|
77
130
|
_defineProperty(this, "statusBarHeight", StatusBar.currentHeight || 0);
|
|
78
131
|
_defineProperty(this, "defaultTopInset", 44);
|
|
79
132
|
_defineProperty(this, "maxHeightRatio", 0);
|
|
@@ -83,51 +136,75 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
83
136
|
_defineProperty(this, "iosKeyboardHeight", 0);
|
|
84
137
|
_defineProperty(this, "isIosKeyboardHeightSet", false);
|
|
85
138
|
_defineProperty(this, "sheetModalService", void 0);
|
|
139
|
+
_defineProperty(this, "isDragHandleExpanding", false);
|
|
140
|
+
// Reanimated shared values - created once and reused
|
|
141
|
+
_defineProperty(this, "translateY", void 0);
|
|
142
|
+
_defineProperty(this, "backdropOpacity", void 0);
|
|
143
|
+
_defineProperty(this, "sheetHeight", void 0);
|
|
144
|
+
_defineProperty(this, "lastGestureDyShared", void 0);
|
|
86
145
|
_defineProperty(this, "isSheetExpanded", () => {
|
|
87
146
|
return this.state.isExpanded;
|
|
88
147
|
});
|
|
89
148
|
_defineProperty(this, "expandBottomSheet", () => {
|
|
90
149
|
const targetHeight = Math.min(this.expandedHeight, SCREEN_HEIGHT);
|
|
150
|
+
const callback = () => {
|
|
151
|
+
this.updateState({
|
|
152
|
+
isExpanded: true,
|
|
153
|
+
lastGestureDy: 0
|
|
154
|
+
});
|
|
155
|
+
this.invokeEventCallback('onExpand', [null, this]);
|
|
156
|
+
};
|
|
91
157
|
|
|
92
|
-
//
|
|
158
|
+
// Reset drag settle value immediately on UI thread
|
|
159
|
+
this.lastGestureDyShared.value = 0;
|
|
93
160
|
if (this.props.enabledragsettle) {
|
|
94
|
-
|
|
95
|
-
|
|
161
|
+
// Synchronize both animations to complete together
|
|
162
|
+
this.sheetHeight.value = withTiming(targetHeight, {
|
|
96
163
|
duration: this.animationDuration,
|
|
97
|
-
|
|
98
|
-
})
|
|
99
|
-
|
|
164
|
+
easing: Easing.out(Easing.ease)
|
|
165
|
+
});
|
|
166
|
+
this.translateY.value = withTiming(0, {
|
|
100
167
|
duration: this.animationDuration,
|
|
101
|
-
|
|
102
|
-
}
|
|
168
|
+
easing: Easing.out(Easing.ease)
|
|
169
|
+
}, finished => {
|
|
170
|
+
if (finished) {
|
|
171
|
+
runOnJS(callback)();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
103
174
|
} else {
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
toValue: targetHeight,
|
|
175
|
+
// Only animate height for non-drag-settle mode
|
|
176
|
+
this.sheetHeight.value = withTiming(targetHeight, {
|
|
107
177
|
duration: this.animationDuration,
|
|
108
|
-
|
|
109
|
-
}
|
|
178
|
+
easing: Easing.out(Easing.ease)
|
|
179
|
+
}, finished => {
|
|
180
|
+
if (finished) {
|
|
181
|
+
runOnJS(callback)();
|
|
182
|
+
}
|
|
183
|
+
});
|
|
110
184
|
}
|
|
111
|
-
this.updateState({
|
|
112
|
-
isExpanded: true,
|
|
113
|
-
lastGestureDy: 0 // Reset to start from top when expanded
|
|
114
|
-
});
|
|
115
185
|
});
|
|
116
186
|
_defineProperty(this, "collapseBottomSheet", () => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
187
|
+
const callback = () => {
|
|
188
|
+
this.updateState({
|
|
189
|
+
isExpanded: false,
|
|
190
|
+
lastGestureDy: 0
|
|
191
|
+
});
|
|
192
|
+
this.invokeEventCallback('onCollapse', [null, this]);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Reset drag settle value immediately on UI thread
|
|
196
|
+
this.lastGestureDyShared.value = 0;
|
|
197
|
+
this.translateY.value = withTiming(0, {
|
|
120
198
|
duration: this.animationDuration,
|
|
121
|
-
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
toValue: this.calculatedHeight,
|
|
199
|
+
easing: Easing.out(Easing.ease)
|
|
200
|
+
});
|
|
201
|
+
this.sheetHeight.value = withTiming(this.calculatedHeight, {
|
|
125
202
|
duration: this.animationDuration,
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
203
|
+
easing: Easing.out(Easing.ease)
|
|
204
|
+
}, finished => {
|
|
205
|
+
if (finished) {
|
|
206
|
+
runOnJS(callback)();
|
|
207
|
+
}
|
|
131
208
|
});
|
|
132
209
|
});
|
|
133
210
|
_defineProperty(this, "handleBackPress", () => {
|
|
@@ -160,23 +237,25 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
160
237
|
// Leave some buffer space for the drag handle and safe area
|
|
161
238
|
const bufferSpace = (Platform.OS === 'ios' ? this.topInset : this.statusBarHeight) + 20;
|
|
162
239
|
const adjustedHeight = availableHeight - bufferSpace;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
240
|
+
if (this.sheetHeight && Platform.OS == 'android' && this.props.modal) {
|
|
241
|
+
// Use platform-specific keyboard animation duration for smooth synchronization
|
|
242
|
+
this.sheetHeight.value = withTiming(adjustedHeight, {
|
|
243
|
+
duration: this.keyboardAnimationDuration,
|
|
244
|
+
easing: Easing.out(Easing.ease)
|
|
245
|
+
});
|
|
246
|
+
}
|
|
169
247
|
this.updateState({
|
|
170
248
|
keyboardHeight: keyboardHeight
|
|
171
249
|
});
|
|
172
250
|
});
|
|
173
251
|
_defineProperty(this, "onKeyboardHide", () => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
252
|
+
if (this.sheetHeight && Platform.OS == 'android' && this.props.modal) {
|
|
253
|
+
// Use platform-specific keyboard animation duration for smooth synchronization
|
|
254
|
+
this.sheetHeight.value = withTiming(this.state.isExpanded ? this.expandedHeight : this.calculatedHeight, {
|
|
255
|
+
duration: this.keyboardAnimationDuration,
|
|
256
|
+
easing: Easing.out(Easing.ease)
|
|
257
|
+
});
|
|
258
|
+
}
|
|
180
259
|
this.updateState({
|
|
181
260
|
keyboardHeight: 0
|
|
182
261
|
});
|
|
@@ -187,21 +266,21 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
187
266
|
this.updateState({
|
|
188
267
|
lastGestureDy: 0
|
|
189
268
|
});
|
|
269
|
+
if (this.lastGestureDyShared) {
|
|
270
|
+
this.lastGestureDyShared.value = 0;
|
|
271
|
+
}
|
|
190
272
|
}
|
|
191
|
-
|
|
192
|
-
// New drag and settle behavior
|
|
193
273
|
if (this.props.enabledragsettle && gestureState.dy > 0) {
|
|
194
|
-
|
|
195
|
-
const currentTranslateY = this.
|
|
196
|
-
// If dragged too far down, close the sheet
|
|
274
|
+
var _this$translateY;
|
|
275
|
+
const currentTranslateY = ((_this$translateY = this.translateY) === null || _this$translateY === void 0 ? void 0 : _this$translateY.value) || 0;
|
|
197
276
|
if (gestureState.vy > 0.5 && !this.props.disableswipedownclose) {
|
|
198
277
|
this.closeSheet();
|
|
199
278
|
return;
|
|
200
279
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
280
|
+
if (this.translateY && this.lastGestureDyShared) {
|
|
281
|
+
this.translateY.value = currentTranslateY;
|
|
282
|
+
this.lastGestureDyShared.value = currentTranslateY;
|
|
283
|
+
}
|
|
205
284
|
this.updateState({
|
|
206
285
|
isExpanded: false,
|
|
207
286
|
lastGestureDy: currentTranslateY
|
|
@@ -210,24 +289,33 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
210
289
|
}
|
|
211
290
|
if (gestureState.dy > 0) {
|
|
212
291
|
if (this.state.isExpanded || this.props.disableswipedownclose) {
|
|
213
|
-
// Expand the bottom sheet threshold is 25% of the fully expanded height
|
|
214
|
-
// If the user swipe distance is below the threshold, revert to the original sheet height
|
|
215
292
|
if (gestureState.dy < this.expandedHeight / 4 || this.props.disableswipedownclose) {
|
|
293
|
+
var _this$sheetHeight;
|
|
216
294
|
let sheetMinimumHeight = this.props.bottomsheetminimumheight || 0.1;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
295
|
+
const targetHeight = this.props.disableswipedownclose ? sheetMinimumHeight * SCREEN_HEIGHT : this.calculatedHeight;
|
|
296
|
+
const currentHeight = ((_this$sheetHeight = this.sheetHeight) === null || _this$sheetHeight === void 0 ? void 0 : _this$sheetHeight.value) || this.expandedHeight;
|
|
297
|
+
const distance = Math.abs(currentHeight - targetHeight);
|
|
298
|
+
const duration = this.getAnimationDuration(distance, gestureState.vy);
|
|
299
|
+
const callback = () => {
|
|
300
|
+
this.updateState({
|
|
301
|
+
isExpanded: false
|
|
302
|
+
});
|
|
303
|
+
this.invokeEventCallback('onCollapse', [null, this]);
|
|
304
|
+
};
|
|
305
|
+
if (this.translateY && this.sheetHeight) {
|
|
306
|
+
this.translateY.value = withTiming(0, {
|
|
307
|
+
duration: duration,
|
|
308
|
+
easing: Easing.out(Easing.ease)
|
|
309
|
+
});
|
|
310
|
+
this.sheetHeight.value = withTiming(targetHeight, {
|
|
311
|
+
duration: duration,
|
|
312
|
+
easing: Easing.out(Easing.ease)
|
|
313
|
+
}, finished => {
|
|
314
|
+
if (finished) {
|
|
315
|
+
runOnJS(callback)();
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
231
319
|
} else if ((gestureState.dy > this.expandedHeight / 4 || gestureState.vy > 0.5) && !this.props.disableswipedownclose) {
|
|
232
320
|
this.closeSheet();
|
|
233
321
|
}
|
|
@@ -254,10 +342,16 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
254
342
|
// Only handle the gesture if we're at the top and swiping down
|
|
255
343
|
return gestureState.dy > 0 && this.state.scrollOffset <= 0;
|
|
256
344
|
},
|
|
345
|
+
onPanResponderGrant: () => {
|
|
346
|
+
// Cancel any ongoing animations when user starts dragging
|
|
347
|
+
if (this.translateY) {
|
|
348
|
+
cancelAnimation(this.translateY);
|
|
349
|
+
}
|
|
350
|
+
},
|
|
257
351
|
onPanResponderMove: (_, gestureState) => {
|
|
258
|
-
if (gestureState.dy > 0) {
|
|
259
|
-
const newTranslateY = Math.max(0, this.
|
|
260
|
-
this.
|
|
352
|
+
if (gestureState.dy > 0 && this.translateY && this.lastGestureDyShared) {
|
|
353
|
+
const newTranslateY = Math.max(0, this.lastGestureDyShared.value + gestureState.dy);
|
|
354
|
+
this.translateY.value = newTranslateY;
|
|
261
355
|
}
|
|
262
356
|
},
|
|
263
357
|
onPanResponderRelease: (_, gestureState) => {
|
|
@@ -271,18 +365,28 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
271
365
|
_defineProperty(this, "dragHandlePanResponder", PanResponder.create({
|
|
272
366
|
onStartShouldSetPanResponder: () => true,
|
|
273
367
|
onMoveShouldSetPanResponder: () => true,
|
|
368
|
+
onPanResponderGrant: () => {
|
|
369
|
+
// Cancel any ongoing animations when user starts dragging
|
|
370
|
+
if (this.translateY) {
|
|
371
|
+
cancelAnimation(this.translateY);
|
|
372
|
+
}
|
|
373
|
+
// Reset the expand flag
|
|
374
|
+
this.isDragHandleExpanding = false;
|
|
375
|
+
},
|
|
274
376
|
onPanResponderMove: (_, gestureState) => {
|
|
275
|
-
if (gestureState.dy > 0) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
//
|
|
377
|
+
if (gestureState.dy > 0 && this.translateY && this.lastGestureDyShared) {
|
|
378
|
+
const newTranslateY = Math.max(0, this.lastGestureDyShared.value + gestureState.dy);
|
|
379
|
+
this.translateY.value = newTranslateY;
|
|
380
|
+
// Reset expand flag if dragging down
|
|
381
|
+
this.isDragHandleExpanding = false;
|
|
382
|
+
} else if (gestureState.dy < -50 && this.props.expand && this.props.bottomsheetheightratio !== 1 && !this.isDragHandleExpanding && !this.state.isExpanded) {
|
|
383
|
+
// Only trigger expand once with threshold of -50px upward drag
|
|
384
|
+
this.isDragHandleExpanding = true;
|
|
282
385
|
this.expandBottomSheet();
|
|
283
386
|
}
|
|
284
387
|
},
|
|
285
388
|
onPanResponderRelease: (_, gestureState) => {
|
|
389
|
+
this.isDragHandleExpanding = false;
|
|
286
390
|
this.handleSwipeGesture(gestureState);
|
|
287
391
|
}
|
|
288
392
|
}));
|
|
@@ -295,20 +399,32 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
295
399
|
});
|
|
296
400
|
});
|
|
297
401
|
_defineProperty(this, "openSheet", () => {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
toValue: 0,
|
|
303
|
-
duration: this.animationDuration,
|
|
304
|
-
useNativeDriver: false
|
|
305
|
-
}), Animated.timing(this.state.backdropOpacity, {
|
|
306
|
-
toValue: 1,
|
|
307
|
-
duration: this.animationDuration,
|
|
308
|
-
useNativeDriver: false
|
|
309
|
-
})]).start(() => {
|
|
402
|
+
const callback = () => {
|
|
403
|
+
this.updateState({
|
|
404
|
+
lastGestureDy: 0
|
|
405
|
+
});
|
|
310
406
|
this.invokeEventCallback('onOpened', [null, this]);
|
|
311
|
-
}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// Reset drag settle value immediately on UI thread
|
|
410
|
+
if (this.lastGestureDyShared) {
|
|
411
|
+
this.lastGestureDyShared.value = 0;
|
|
412
|
+
}
|
|
413
|
+
if (this.translateY && this.backdropOpacity) {
|
|
414
|
+
this.translateY.value = withTiming(0, {
|
|
415
|
+
duration: this.animationDuration,
|
|
416
|
+
easing: Easing.out(Easing.ease)
|
|
417
|
+
}, finished => {
|
|
418
|
+
if (finished) {
|
|
419
|
+
runOnJS(callback)();
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
// Backdrop animation synchronized with sheet animation
|
|
423
|
+
this.backdropOpacity.value = withTiming(1, {
|
|
424
|
+
duration: this.animationDuration,
|
|
425
|
+
easing: Easing.out(Easing.ease)
|
|
426
|
+
});
|
|
427
|
+
}
|
|
312
428
|
});
|
|
313
429
|
_defineProperty(this, "handleClose", () => {
|
|
314
430
|
this.updateState({
|
|
@@ -317,28 +433,39 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
317
433
|
this.invokeEventCallback('onClose', [null, this]);
|
|
318
434
|
});
|
|
319
435
|
_defineProperty(this, "closeSheet", () => {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
})]).start(() => {
|
|
329
|
-
requestAnimationFrame(() => {
|
|
330
|
-
this.state.sheetHeight.setValue(this.calculatedHeight);
|
|
331
|
-
this.updateState({
|
|
332
|
-
isExpanded: false,
|
|
333
|
-
localModalsOpened: []
|
|
334
|
-
});
|
|
335
|
-
this.handleClose();
|
|
436
|
+
const callback = () => {
|
|
437
|
+
// Reset sheet height after close
|
|
438
|
+
if (this.sheetHeight) {
|
|
439
|
+
this.sheetHeight.value = this.calculatedHeight;
|
|
440
|
+
}
|
|
441
|
+
this.updateState({
|
|
442
|
+
isExpanded: false,
|
|
443
|
+
localModalsOpened: []
|
|
336
444
|
});
|
|
337
|
-
|
|
445
|
+
this.handleClose();
|
|
446
|
+
};
|
|
447
|
+
if (this.translateY && this.backdropOpacity) {
|
|
448
|
+
this.translateY.value = withTiming(SCREEN_HEIGHT, {
|
|
449
|
+
duration: this.animationDuration,
|
|
450
|
+
easing: Easing.out(Easing.ease)
|
|
451
|
+
}, finished => {
|
|
452
|
+
if (finished) {
|
|
453
|
+
runOnJS(callback)();
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
// Backdrop animation synchronized with sheet animation
|
|
457
|
+
this.backdropOpacity.value = withTiming(0, {
|
|
458
|
+
duration: this.animationDuration,
|
|
459
|
+
easing: Easing.out(Easing.ease)
|
|
460
|
+
});
|
|
461
|
+
}
|
|
338
462
|
});
|
|
339
463
|
_defineProperty(this, "closeSheetImmediate", () => {
|
|
340
|
-
this.
|
|
341
|
-
|
|
464
|
+
if (this.translateY && this.backdropOpacity && this.lastGestureDyShared) {
|
|
465
|
+
this.translateY.value = SCREEN_HEIGHT;
|
|
466
|
+
this.backdropOpacity.value = 0;
|
|
467
|
+
this.lastGestureDyShared.value = 0;
|
|
468
|
+
}
|
|
342
469
|
this.updateState({
|
|
343
470
|
lastGestureDy: 0,
|
|
344
471
|
isExpanded: false,
|
|
@@ -346,44 +473,58 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
346
473
|
localModalsOpened: []
|
|
347
474
|
});
|
|
348
475
|
requestAnimationFrame(() => {
|
|
349
|
-
this.
|
|
476
|
+
if (this.sheetHeight) {
|
|
477
|
+
this.sheetHeight.value = this.calculatedHeight;
|
|
478
|
+
}
|
|
350
479
|
});
|
|
351
480
|
});
|
|
481
|
+
// Class methods to prevent recreation on every render
|
|
482
|
+
_defineProperty(this, "handleBackdropPress", () => {
|
|
483
|
+
if (this.props.autoclose !== 'disabled') {
|
|
484
|
+
this.closeSheet();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
_defineProperty(this, "handleDragHandlePress", () => {
|
|
488
|
+
this.invokeEventCallback('onDraghandleiconclick', [null, this]);
|
|
489
|
+
});
|
|
352
490
|
_defineProperty(this, "renderContent", props => {
|
|
491
|
+
// Don't render if shared values aren't initialized yet
|
|
492
|
+
if (!this.translateY || !this.backdropOpacity || !this.sheetHeight || !this.lastGestureDyShared) {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
353
495
|
return /*#__PURE__*/React.createElement(SafeAreaInsetsContext.Consumer, null, (insets = {
|
|
354
496
|
top: 0,
|
|
355
497
|
bottom: 0,
|
|
356
498
|
left: 0,
|
|
357
499
|
right: 0
|
|
358
500
|
}) => {
|
|
359
|
-
|
|
501
|
+
// Store topInset for later use (avoid mutation during render)
|
|
502
|
+
const topInset = (insets === null || insets === void 0 ? void 0 : insets.top) || 0;
|
|
503
|
+
// Update the instance variable outside of render cycle
|
|
504
|
+
if (this.topInset !== topInset) {
|
|
505
|
+
requestAnimationFrame(() => {
|
|
506
|
+
this.topInset = topInset;
|
|
507
|
+
});
|
|
508
|
+
}
|
|
360
509
|
return /*#__PURE__*/React.createElement(View, _extends({
|
|
361
510
|
style: this.styles.root
|
|
362
|
-
}, this.getTestProps('keyboardview')), this._background, /*#__PURE__*/React.createElement(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
},
|
|
376
|
-
style: this.styles.dragHandleContainer
|
|
377
|
-
}, this.dragHandlePanResponder.panHandlers), /*#__PURE__*/React.createElement(Pressable, {
|
|
378
|
-
onPress: () => this.invokeEventCallback('onDraghandleiconclick', [null, this])
|
|
379
|
-
}, /*#__PURE__*/React.createElement(View, _extends({
|
|
380
|
-
style: this.styles.dragIconHandle
|
|
381
|
-
}, this.getTestProps('draghandle'))))), /*#__PURE__*/React.createElement(ScrollView, _extends({
|
|
511
|
+
}, this.getTestProps('keyboardview')), this._background, /*#__PURE__*/React.createElement(AnimatedBottomsheetContent, {
|
|
512
|
+
translateY: this.translateY,
|
|
513
|
+
backdropOpacity: this.backdropOpacity,
|
|
514
|
+
sheetHeight: this.sheetHeight,
|
|
515
|
+
lastGestureDy: this.lastGestureDyShared,
|
|
516
|
+
styles: this.styles,
|
|
517
|
+
props: props,
|
|
518
|
+
panHandlers: this.panResponder.panHandlers,
|
|
519
|
+
dragHandlePanHandlers: this.dragHandlePanResponder.panHandlers,
|
|
520
|
+
onBackdropPress: this.handleBackdropPress,
|
|
521
|
+
onDragHandlePress: this.handleDragHandlePress,
|
|
522
|
+
getTestProps: this.getTestProps.bind(this),
|
|
523
|
+
enabledragsettle: props.enabledragsettle
|
|
524
|
+
}, contentStyle => /*#__PURE__*/React.createElement(ScrollView, _extends({
|
|
382
525
|
ref: this.state.scrollViewRef,
|
|
383
526
|
style: this.styles.sheetContentContainer,
|
|
384
|
-
contentContainerStyle: [this.styles.sheetScrollContent,
|
|
385
|
-
paddingBottom: this.state.lastGestureDy
|
|
386
|
-
}],
|
|
527
|
+
contentContainerStyle: [this.styles.sheetScrollContent],
|
|
387
528
|
alwaysBounceVertical: false,
|
|
388
529
|
alwaysBounceHorizontal: false,
|
|
389
530
|
bounces: false,
|
|
@@ -391,10 +532,14 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
391
532
|
scrollEventThrottle: 16,
|
|
392
533
|
onScroll: this.handleScroll,
|
|
393
534
|
nestedScrollEnabled: true,
|
|
394
|
-
scrollEnabled:
|
|
535
|
+
scrollEnabled: !props.issticky && (!props.disablescrollonrest || this.state.isExpanded)
|
|
395
536
|
}, this.getTestProps('scorllview')), props.enablemodalsupport ? /*#__PURE__*/React.createElement(ModalProvider, {
|
|
396
537
|
value: this.sheetModalService
|
|
397
|
-
},
|
|
538
|
+
}, /*#__PURE__*/React.createElement(Animated.View, {
|
|
539
|
+
style: contentStyle
|
|
540
|
+
}, props.children)) : /*#__PURE__*/React.createElement(Animated.View, {
|
|
541
|
+
style: contentStyle
|
|
542
|
+
}, props.children))), props.enablemodalsupport && this.state.localModalsOpened && this.state.localModalsOpened.map((o, i) => /*#__PURE__*/React.createElement(View, {
|
|
398
543
|
key: (o.name || '') + i,
|
|
399
544
|
onStartShouldSetResponder: () => true,
|
|
400
545
|
onResponderEnd: () => o.isModal && this.sheetModalService.hideModal(o),
|
|
@@ -425,14 +570,21 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
425
570
|
this.expandedHeight -= this.defaultTopInset;
|
|
426
571
|
}
|
|
427
572
|
}
|
|
428
|
-
|
|
573
|
+
|
|
574
|
+
// Initialize shared values in constructor using makeMutable (not hooks)
|
|
575
|
+
// makeMutable can be called outside of React components
|
|
576
|
+
this.translateY = makeMutable(SCREEN_HEIGHT);
|
|
577
|
+
this.backdropOpacity = makeMutable(0);
|
|
578
|
+
this.sheetHeight = makeMutable(this.calculatedHeight);
|
|
579
|
+
this.lastGestureDyShared = makeMutable(0);
|
|
429
580
|
this.updateState({
|
|
430
581
|
isBottomsheetVisible: this.props.showonrender || false
|
|
431
582
|
});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
this.
|
|
583
|
+
|
|
584
|
+
// Initialize values immediately to prevent flicker
|
|
585
|
+
if (this.props.showonrender) {
|
|
586
|
+
this.translateY.value = 0;
|
|
587
|
+
this.backdropOpacity.value = 1;
|
|
436
588
|
}
|
|
437
589
|
|
|
438
590
|
// Local ModalService for content rendered inside Bottomsheet
|
|
@@ -467,6 +619,14 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
467
619
|
}
|
|
468
620
|
componentDidMount() {
|
|
469
621
|
super.componentDidMount();
|
|
622
|
+
|
|
623
|
+
// Trigger animation after mount if showonrender is true
|
|
624
|
+
if (this.state.isBottomsheetVisible) {
|
|
625
|
+
// Use requestAnimationFrame to ensure animation happens after initial render
|
|
626
|
+
requestAnimationFrame(() => {
|
|
627
|
+
this.openSheet();
|
|
628
|
+
});
|
|
629
|
+
}
|
|
470
630
|
if (Platform.OS === 'android') {
|
|
471
631
|
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
|
472
632
|
}
|
|
@@ -478,13 +638,19 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
478
638
|
if (Platform.OS === 'android') {
|
|
479
639
|
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
|
480
640
|
}
|
|
481
|
-
this.keyboardDidShowListener
|
|
482
|
-
|
|
641
|
+
if (this.keyboardDidShowListener) {
|
|
642
|
+
this.keyboardDidShowListener.remove();
|
|
643
|
+
}
|
|
644
|
+
if (this.keyboardDidHideListener) {
|
|
645
|
+
this.keyboardDidHideListener.remove();
|
|
646
|
+
}
|
|
483
647
|
}
|
|
484
648
|
componentDidUpdate(prevProps) {
|
|
485
649
|
if (prevProps.bottomsheetheightratio !== this.props.bottomsheetheightratio) {
|
|
486
650
|
this.calculatedHeight = this.calculateSheetHeight(this.props.bottomsheetheightratio);
|
|
487
|
-
this.
|
|
651
|
+
if (this.sheetHeight) {
|
|
652
|
+
this.sheetHeight.value = this.calculatedHeight;
|
|
653
|
+
}
|
|
488
654
|
}
|
|
489
655
|
}
|
|
490
656
|
onPropertyChange(name, $new, $old) {
|
|
@@ -523,12 +689,12 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
523
689
|
this.closeSheet();
|
|
524
690
|
}
|
|
525
691
|
},
|
|
526
|
-
statusBarTranslucent:
|
|
692
|
+
statusBarTranslucent: false
|
|
527
693
|
}, /*#__PURE__*/React.createElement(KeyboardAvoidingView, {
|
|
528
694
|
style: {
|
|
529
695
|
flex: 1
|
|
530
696
|
},
|
|
531
|
-
behavior:
|
|
697
|
+
behavior: 'padding',
|
|
532
698
|
keyboardVerticalOffset: Platform.OS === 'ios' ? 0 : undefined
|
|
533
699
|
}, this.renderContent(props)));
|
|
534
700
|
} else {
|