@wavemaker/app-rn-runtime 11.12.1-rc.221 → 11.13.0-2.647474
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 +439 -131
- package/components/basic/bottomsheet/bottomsheet.component.js.map +1 -1
- package/components/basic/bottomsheet/bottomsheet.props.js +7 -0
- package/components/basic/bottomsheet/bottomsheet.props.js.map +1 -1
- package/components/basic/bottomsheet/bottomsheet.styles.js +12 -3
- package/components/basic/bottomsheet/bottomsheet.styles.js.map +1 -1
- package/components/input/chips/chips.component.js +10 -20
- package/components/input/chips/chips.component.js.map +1 -1
- package/components/input/chips/chips.styles.js +32 -32
- package/components/input/chips/chips.styles.js.map +1 -1
- package/components/page/page.component.js +3 -1
- package/components/page/page.component.js.map +1 -1
- package/core/AppConfig.js.map +1 -1
- package/core/responsive.utils.js +2 -2
- package/core/responsive.utils.js.map +1 -1
- package/core/screen-capture-protection.service.js +5 -0
- package/core/screen-capture-protection.service.js.map +1 -0
- package/core/secure-storage.service.js +55 -0
- package/core/secure-storage.service.js.map +1 -0
- package/core/storage.service.js.map +1 -1
- package/gestures/carousel-swipe.animation.js +6 -6
- package/gestures/carousel-swipe.animation.js.map +1 -1
- package/gestures/swipe.animation.js +6 -6
- package/gestures/swipe.animation.js.map +1 -1
- package/npm-shrinkwrap.json +2803 -2134
- package/package-lock.json +2803 -2134
- package/package.json +5 -3
- package/runtime/App.js +32 -2
- package/runtime/App.js.map +1 -1
- package/runtime/base-page.component.js +17 -1
- package/runtime/base-page.component.js.map +1 -1
- package/styles/theme.js +3 -0
- package/styles/theme.js.map +1 -1
|
@@ -4,12 +4,14 @@ 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';
|
|
12
13
|
import { AccessibilityWidgetType, getAccessibilityProps } from '@wavemaker/app-rn-runtime/core/accessibility';
|
|
14
|
+
import { ModalProvider } from '@wavemaker/app-rn-runtime/core/modal.service';
|
|
13
15
|
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
|
|
14
16
|
const {
|
|
15
17
|
height: SCREEN_HEIGHT
|
|
@@ -17,25 +19,78 @@ const {
|
|
|
17
19
|
export class WmBottomsheetState extends BaseComponentState {
|
|
18
20
|
constructor(...args) {
|
|
19
21
|
super(...args);
|
|
20
|
-
_defineProperty(this, "translateY", new Animated.Value(SCREEN_HEIGHT));
|
|
21
|
-
_defineProperty(this, "backdropOpacity", new Animated.Value(0));
|
|
22
|
-
_defineProperty(this, "sheetHeight", new Animated.Value(0));
|
|
23
|
-
_defineProperty(this, "lastGestureDy", 0);
|
|
24
22
|
_defineProperty(this, "scrollViewRef", /*#__PURE__*/createRef());
|
|
25
23
|
_defineProperty(this, "isScrolling", false);
|
|
26
24
|
_defineProperty(this, "scrollOffset", 0);
|
|
27
25
|
_defineProperty(this, "isExpanded", false);
|
|
28
26
|
_defineProperty(this, "isBottomsheetVisible", false);
|
|
29
27
|
_defineProperty(this, "keyboardHeight", 0);
|
|
28
|
+
_defineProperty(this, "localModalsOpened", []);
|
|
29
|
+
_defineProperty(this, "lastGestureDy", 0);
|
|
30
30
|
}
|
|
31
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
|
+
};
|
|
32
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
|
+
}
|
|
33
89
|
calculateSheetHeight(bottomsheetheightratio) {
|
|
34
90
|
// Use default height if ratio not provided, but ensure it's not below minimum
|
|
35
91
|
const effectiveRatio = bottomsheetheightratio || this.defaultHeight;
|
|
36
92
|
this.maxHeightRatio = Math.max(this.minimumHeight, Math.min(effectiveRatio, this.maxHeight));
|
|
37
93
|
const screenHeight = Dimensions.get('screen').height;
|
|
38
|
-
const windowHeight = Dimensions.get('window').height;
|
|
39
94
|
let calculatedHeight = screenHeight * this.maxHeightRatio;
|
|
40
95
|
if (Platform.OS === 'ios') {
|
|
41
96
|
// Subtract top inset bar height for ios only if bottomsheetheightratio is 0.9
|
|
@@ -67,11 +122,11 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
67
122
|
_defineProperty(this, "expandedHeight", void 0);
|
|
68
123
|
_defineProperty(this, "defaultHeight", 0.5);
|
|
69
124
|
_defineProperty(this, "expandedDefaultHeight", 0.8);
|
|
70
|
-
_defineProperty(this, "minimumHeight", 0.
|
|
125
|
+
_defineProperty(this, "minimumHeight", 0.01);
|
|
71
126
|
_defineProperty(this, "minimumExpandedHeight", 0.5);
|
|
72
127
|
_defineProperty(this, "maxHeight", 1.0);
|
|
73
|
-
// Allow full screen height
|
|
74
128
|
_defineProperty(this, "animationDuration", 400);
|
|
129
|
+
_defineProperty(this, "keyboardAnimationDuration", Platform.OS === 'ios' ? 250 : 275);
|
|
75
130
|
_defineProperty(this, "statusBarHeight", StatusBar.currentHeight || 0);
|
|
76
131
|
_defineProperty(this, "defaultTopInset", 44);
|
|
77
132
|
_defineProperty(this, "maxHeightRatio", 0);
|
|
@@ -80,9 +135,89 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
80
135
|
_defineProperty(this, "topInset", 0);
|
|
81
136
|
_defineProperty(this, "iosKeyboardHeight", 0);
|
|
82
137
|
_defineProperty(this, "isIosKeyboardHeightSet", false);
|
|
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);
|
|
145
|
+
_defineProperty(this, "isSheetExpanded", () => {
|
|
146
|
+
return this.state.isExpanded;
|
|
147
|
+
});
|
|
148
|
+
_defineProperty(this, "expandBottomSheet", () => {
|
|
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
|
+
};
|
|
157
|
+
|
|
158
|
+
// Reset drag settle value immediately on UI thread
|
|
159
|
+
this.lastGestureDyShared.value = 0;
|
|
160
|
+
if (this.props.enabledragsettle) {
|
|
161
|
+
// Synchronize both animations to complete together
|
|
162
|
+
this.sheetHeight.value = withTiming(targetHeight, {
|
|
163
|
+
duration: this.animationDuration,
|
|
164
|
+
easing: Easing.out(Easing.ease)
|
|
165
|
+
});
|
|
166
|
+
this.translateY.value = withTiming(0, {
|
|
167
|
+
duration: this.animationDuration,
|
|
168
|
+
easing: Easing.out(Easing.ease)
|
|
169
|
+
}, finished => {
|
|
170
|
+
if (finished) {
|
|
171
|
+
runOnJS(callback)();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
} else {
|
|
175
|
+
// Only animate height for non-drag-settle mode
|
|
176
|
+
this.sheetHeight.value = withTiming(targetHeight, {
|
|
177
|
+
duration: this.animationDuration,
|
|
178
|
+
easing: Easing.out(Easing.ease)
|
|
179
|
+
}, finished => {
|
|
180
|
+
if (finished) {
|
|
181
|
+
runOnJS(callback)();
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
_defineProperty(this, "collapseBottomSheet", () => {
|
|
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, {
|
|
198
|
+
duration: this.animationDuration,
|
|
199
|
+
easing: Easing.out(Easing.ease)
|
|
200
|
+
});
|
|
201
|
+
this.sheetHeight.value = withTiming(this.calculatedHeight, {
|
|
202
|
+
duration: this.animationDuration,
|
|
203
|
+
easing: Easing.out(Easing.ease)
|
|
204
|
+
}, finished => {
|
|
205
|
+
if (finished) {
|
|
206
|
+
runOnJS(callback)();
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
83
210
|
_defineProperty(this, "handleBackPress", () => {
|
|
211
|
+
// Close top-most local modal first, if any
|
|
212
|
+
if (this.state.localModalsOpened && this.state.localModalsOpened.length > 0) {
|
|
213
|
+
const top = this.state.localModalsOpened[this.state.localModalsOpened.length - 1];
|
|
214
|
+
this.sheetModalService.hideModal(top);
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
84
217
|
if (this.state.isBottomsheetVisible) {
|
|
85
|
-
this.
|
|
218
|
+
if (!this.props.disableswipedownclose && this.props.autoclose !== 'disabled') {
|
|
219
|
+
this.closeSheet();
|
|
220
|
+
}
|
|
86
221
|
return true; // Prevent default back action
|
|
87
222
|
}
|
|
88
223
|
return false;
|
|
@@ -102,55 +237,94 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
102
237
|
// Leave some buffer space for the drag handle and safe area
|
|
103
238
|
const bufferSpace = (Platform.OS === 'ios' ? this.topInset : this.statusBarHeight) + 20;
|
|
104
239
|
const adjustedHeight = availableHeight - bufferSpace;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
+
}
|
|
111
247
|
this.updateState({
|
|
112
248
|
keyboardHeight: keyboardHeight
|
|
113
249
|
});
|
|
114
250
|
});
|
|
115
251
|
_defineProperty(this, "onKeyboardHide", () => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
+
}
|
|
122
259
|
this.updateState({
|
|
123
260
|
keyboardHeight: 0
|
|
124
261
|
});
|
|
125
262
|
});
|
|
126
263
|
_defineProperty(this, "handleSwipeGesture", gestureState => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
264
|
+
// Only reset lastGestureDy for traditional behavior, not for drag and settle
|
|
265
|
+
if (!this.props.enabledragsettle) {
|
|
266
|
+
this.updateState({
|
|
267
|
+
lastGestureDy: 0
|
|
268
|
+
});
|
|
269
|
+
if (this.lastGestureDyShared) {
|
|
270
|
+
this.lastGestureDyShared.value = 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (this.props.enabledragsettle && gestureState.dy > 0) {
|
|
274
|
+
var _this$translateY;
|
|
275
|
+
const currentTranslateY = ((_this$translateY = this.translateY) === null || _this$translateY === void 0 ? void 0 : _this$translateY.value) || 0;
|
|
276
|
+
if (gestureState.vy > 0.5 && !this.props.disableswipedownclose) {
|
|
277
|
+
this.closeSheet();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (this.translateY && this.lastGestureDyShared) {
|
|
281
|
+
this.translateY.value = currentTranslateY;
|
|
282
|
+
this.lastGestureDyShared.value = currentTranslateY;
|
|
283
|
+
}
|
|
284
|
+
this.updateState({
|
|
285
|
+
isExpanded: false,
|
|
286
|
+
lastGestureDy: currentTranslateY
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
130
290
|
if (gestureState.dy > 0) {
|
|
131
|
-
if (this.state.isExpanded) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
291
|
+
if (this.state.isExpanded || this.props.disableswipedownclose) {
|
|
292
|
+
if (gestureState.dy < this.expandedHeight / 4 || this.props.disableswipedownclose) {
|
|
293
|
+
var _this$sheetHeight;
|
|
294
|
+
let sheetMinimumHeight = this.props.bottomsheetminimumheight || 0.1;
|
|
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
|
+
}
|
|
319
|
+
} else if ((gestureState.dy > this.expandedHeight / 4 || gestureState.vy > 0.5) && !this.props.disableswipedownclose) {
|
|
150
320
|
this.closeSheet();
|
|
151
321
|
}
|
|
152
322
|
} else {
|
|
153
|
-
if (
|
|
323
|
+
if (this.props.disableswipedownclose) {
|
|
324
|
+
this.openSheet();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if ((gestureState.dy > 100 || gestureState.vy > 0.5) && !this.props.disableswipedownclose) {
|
|
154
328
|
this.closeSheet();
|
|
155
329
|
} else {
|
|
156
330
|
this.openSheet();
|
|
@@ -161,17 +335,35 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
161
335
|
// panResponder for bottom sheet scroll view
|
|
162
336
|
_defineProperty(this, "panResponder", PanResponder.create({
|
|
163
337
|
onStartShouldSetPanResponder: (_, gestureState) => {
|
|
338
|
+
if (this.props.disablescrollonrest && !this.state.isExpanded) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
164
341
|
// Only handle the gesture if we're at the top and swiping down
|
|
165
342
|
return gestureState.dy > 0 && this.state.scrollOffset <= 0;
|
|
166
343
|
},
|
|
167
344
|
onMoveShouldSetPanResponder: (_, gestureState) => {
|
|
345
|
+
if (this.props.disablescrollonrest && !this.state.isExpanded) {
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
168
348
|
// Only handle the gesture if we're at the top and swiping down
|
|
169
349
|
return gestureState.dy > 0 && this.state.scrollOffset <= 0;
|
|
170
350
|
},
|
|
351
|
+
onPanResponderGrant: () => {
|
|
352
|
+
// Cancel any ongoing animations when user starts dragging
|
|
353
|
+
if (this.translateY) {
|
|
354
|
+
cancelAnimation(this.translateY);
|
|
355
|
+
}
|
|
356
|
+
},
|
|
171
357
|
onPanResponderMove: (_, gestureState) => {
|
|
172
|
-
if (gestureState.dy > 0) {
|
|
173
|
-
const newTranslateY = Math.max(0, this.
|
|
174
|
-
this.
|
|
358
|
+
if (gestureState.dy > 0 && this.translateY && this.lastGestureDyShared) {
|
|
359
|
+
const newTranslateY = Math.max(0, this.lastGestureDyShared.value + gestureState.dy);
|
|
360
|
+
this.translateY.value = newTranslateY;
|
|
361
|
+
// Reset expand flag if dragging down
|
|
362
|
+
this.isDragHandleExpanding = false;
|
|
363
|
+
} else if (gestureState.dy < 0 && this.props.expand && this.props.bottomsheetheightratio !== 1 && !this.isDragHandleExpanding && !this.state.isExpanded) {
|
|
364
|
+
// Only trigger expand once with threshold of -50px upward drag
|
|
365
|
+
this.isDragHandleExpanding = true;
|
|
366
|
+
this.expandBottomSheet();
|
|
175
367
|
}
|
|
176
368
|
},
|
|
177
369
|
onPanResponderRelease: (_, gestureState) => {
|
|
@@ -185,26 +377,28 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
185
377
|
_defineProperty(this, "dragHandlePanResponder", PanResponder.create({
|
|
186
378
|
onStartShouldSetPanResponder: () => true,
|
|
187
379
|
onMoveShouldSetPanResponder: () => true,
|
|
380
|
+
onPanResponderGrant: () => {
|
|
381
|
+
// Cancel any ongoing animations when user starts dragging
|
|
382
|
+
if (this.translateY) {
|
|
383
|
+
cancelAnimation(this.translateY);
|
|
384
|
+
}
|
|
385
|
+
// Reset the expand flag
|
|
386
|
+
this.isDragHandleExpanding = false;
|
|
387
|
+
},
|
|
188
388
|
onPanResponderMove: (_, gestureState) => {
|
|
189
|
-
if (gestureState.dy > 0) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
toValue: targetHeight,
|
|
199
|
-
duration: this.animationDuration,
|
|
200
|
-
useNativeDriver: false
|
|
201
|
-
}).start();
|
|
202
|
-
this.updateState({
|
|
203
|
-
isExpanded: true
|
|
204
|
-
});
|
|
389
|
+
if (gestureState.dy > 0 && this.translateY && this.lastGestureDyShared) {
|
|
390
|
+
const newTranslateY = Math.max(0, this.lastGestureDyShared.value + gestureState.dy);
|
|
391
|
+
this.translateY.value = newTranslateY;
|
|
392
|
+
// Reset expand flag if dragging down
|
|
393
|
+
this.isDragHandleExpanding = false;
|
|
394
|
+
} else if (gestureState.dy < -50 && this.props.expand && this.props.bottomsheetheightratio !== 1 && !this.isDragHandleExpanding && !this.state.isExpanded) {
|
|
395
|
+
// Only trigger expand once with threshold of -50px upward drag
|
|
396
|
+
this.isDragHandleExpanding = true;
|
|
397
|
+
this.expandBottomSheet();
|
|
205
398
|
}
|
|
206
399
|
},
|
|
207
400
|
onPanResponderRelease: (_, gestureState) => {
|
|
401
|
+
this.isDragHandleExpanding = false;
|
|
208
402
|
this.handleSwipeGesture(gestureState);
|
|
209
403
|
}
|
|
210
404
|
}));
|
|
@@ -217,20 +411,32 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
217
411
|
});
|
|
218
412
|
});
|
|
219
413
|
_defineProperty(this, "openSheet", () => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
toValue: 0,
|
|
225
|
-
duration: this.animationDuration,
|
|
226
|
-
useNativeDriver: false
|
|
227
|
-
}), Animated.timing(this.state.backdropOpacity, {
|
|
228
|
-
toValue: 1,
|
|
229
|
-
duration: this.animationDuration,
|
|
230
|
-
useNativeDriver: false
|
|
231
|
-
})]).start(() => {
|
|
414
|
+
const callback = () => {
|
|
415
|
+
this.updateState({
|
|
416
|
+
lastGestureDy: 0
|
|
417
|
+
});
|
|
232
418
|
this.invokeEventCallback('onOpened', [null, this]);
|
|
233
|
-
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// Reset drag settle value immediately on UI thread
|
|
422
|
+
if (this.lastGestureDyShared) {
|
|
423
|
+
this.lastGestureDyShared.value = 0;
|
|
424
|
+
}
|
|
425
|
+
if (this.translateY && this.backdropOpacity) {
|
|
426
|
+
this.translateY.value = withTiming(0, {
|
|
427
|
+
duration: this.animationDuration,
|
|
428
|
+
easing: Easing.out(Easing.ease)
|
|
429
|
+
}, finished => {
|
|
430
|
+
if (finished) {
|
|
431
|
+
runOnJS(callback)();
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
// Backdrop animation synchronized with sheet animation
|
|
435
|
+
this.backdropOpacity.value = withTiming(1, {
|
|
436
|
+
duration: this.animationDuration,
|
|
437
|
+
easing: Easing.out(Easing.ease)
|
|
438
|
+
});
|
|
439
|
+
}
|
|
234
440
|
});
|
|
235
441
|
_defineProperty(this, "handleClose", () => {
|
|
236
442
|
this.updateState({
|
|
@@ -239,69 +445,98 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
239
445
|
this.invokeEventCallback('onClose', [null, this]);
|
|
240
446
|
});
|
|
241
447
|
_defineProperty(this, "closeSheet", () => {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
})]).start(() => {
|
|
251
|
-
requestAnimationFrame(() => {
|
|
252
|
-
this.state.sheetHeight.setValue(this.calculatedHeight);
|
|
253
|
-
this.updateState({
|
|
254
|
-
isExpanded: false
|
|
255
|
-
});
|
|
256
|
-
this.handleClose();
|
|
448
|
+
const callback = () => {
|
|
449
|
+
// Reset sheet height after close
|
|
450
|
+
if (this.sheetHeight) {
|
|
451
|
+
this.sheetHeight.value = this.calculatedHeight;
|
|
452
|
+
}
|
|
453
|
+
this.updateState({
|
|
454
|
+
isExpanded: false,
|
|
455
|
+
localModalsOpened: []
|
|
257
456
|
});
|
|
258
|
-
|
|
457
|
+
this.handleClose();
|
|
458
|
+
};
|
|
459
|
+
if (this.translateY && this.backdropOpacity) {
|
|
460
|
+
this.translateY.value = withTiming(SCREEN_HEIGHT, {
|
|
461
|
+
duration: this.animationDuration,
|
|
462
|
+
easing: Easing.out(Easing.ease)
|
|
463
|
+
}, finished => {
|
|
464
|
+
if (finished) {
|
|
465
|
+
runOnJS(callback)();
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
// Backdrop animation synchronized with sheet animation
|
|
469
|
+
this.backdropOpacity.value = withTiming(0, {
|
|
470
|
+
duration: this.animationDuration,
|
|
471
|
+
easing: Easing.out(Easing.ease)
|
|
472
|
+
});
|
|
473
|
+
}
|
|
259
474
|
});
|
|
260
475
|
_defineProperty(this, "closeSheetImmediate", () => {
|
|
261
|
-
this.
|
|
262
|
-
|
|
476
|
+
if (this.translateY && this.backdropOpacity && this.lastGestureDyShared) {
|
|
477
|
+
this.translateY.value = SCREEN_HEIGHT;
|
|
478
|
+
this.backdropOpacity.value = 0;
|
|
479
|
+
this.lastGestureDyShared.value = 0;
|
|
480
|
+
}
|
|
263
481
|
this.updateState({
|
|
264
482
|
lastGestureDy: 0,
|
|
265
483
|
isExpanded: false,
|
|
266
|
-
isBottomsheetVisible: false
|
|
484
|
+
isBottomsheetVisible: false,
|
|
485
|
+
localModalsOpened: []
|
|
267
486
|
});
|
|
268
487
|
requestAnimationFrame(() => {
|
|
269
|
-
this.
|
|
488
|
+
if (this.sheetHeight) {
|
|
489
|
+
this.sheetHeight.value = this.calculatedHeight;
|
|
490
|
+
}
|
|
270
491
|
});
|
|
271
492
|
});
|
|
493
|
+
// Class methods to prevent recreation on every render
|
|
494
|
+
_defineProperty(this, "handleBackdropPress", () => {
|
|
495
|
+
if (this.props.autoclose !== 'disabled') {
|
|
496
|
+
this.closeSheet();
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
_defineProperty(this, "handleDragHandlePress", () => {
|
|
500
|
+
this.invokeEventCallback('onDraghandleiconclick', [null, this]);
|
|
501
|
+
});
|
|
272
502
|
_defineProperty(this, "renderContent", props => {
|
|
503
|
+
// Don't render if shared values aren't initialized yet
|
|
504
|
+
if (!this.translateY || !this.backdropOpacity || !this.sheetHeight || !this.lastGestureDyShared) {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
273
507
|
return /*#__PURE__*/React.createElement(SafeAreaInsetsContext.Consumer, null, (insets = {
|
|
274
508
|
top: 0,
|
|
275
509
|
bottom: 0,
|
|
276
510
|
left: 0,
|
|
277
511
|
right: 0
|
|
278
512
|
}) => {
|
|
279
|
-
|
|
513
|
+
// Store topInset for later use (avoid mutation during render)
|
|
514
|
+
const topInset = (insets === null || insets === void 0 ? void 0 : insets.top) || 0;
|
|
515
|
+
// Update the instance variable outside of render cycle
|
|
516
|
+
if (this.topInset !== topInset) {
|
|
517
|
+
requestAnimationFrame(() => {
|
|
518
|
+
this.topInset = topInset;
|
|
519
|
+
});
|
|
520
|
+
}
|
|
280
521
|
return /*#__PURE__*/React.createElement(View, _extends({
|
|
281
522
|
style: this.styles.root
|
|
282
|
-
}, this.getTestProps('keyboardview')), this._background, /*#__PURE__*/React.createElement(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
},
|
|
296
|
-
style: this.styles.dragHandleContainer
|
|
297
|
-
}, this.dragHandlePanResponder.panHandlers), /*#__PURE__*/React.createElement(TouchableWithoutFeedback, {
|
|
298
|
-
onPress: this.closeSheet
|
|
299
|
-
}, /*#__PURE__*/React.createElement(View, _extends({
|
|
300
|
-
style: this.styles.dragIconHandle
|
|
301
|
-
}, this.getTestProps('draghandle'))))), /*#__PURE__*/React.createElement(ScrollView, _extends({
|
|
523
|
+
}, this.getTestProps('keyboardview')), this._background, /*#__PURE__*/React.createElement(AnimatedBottomsheetContent, {
|
|
524
|
+
translateY: this.translateY,
|
|
525
|
+
backdropOpacity: this.backdropOpacity,
|
|
526
|
+
sheetHeight: this.sheetHeight,
|
|
527
|
+
lastGestureDy: this.lastGestureDyShared,
|
|
528
|
+
styles: this.styles,
|
|
529
|
+
props: props,
|
|
530
|
+
panHandlers: this.panResponder.panHandlers,
|
|
531
|
+
dragHandlePanHandlers: this.dragHandlePanResponder.panHandlers,
|
|
532
|
+
onBackdropPress: this.handleBackdropPress,
|
|
533
|
+
onDragHandlePress: this.handleDragHandlePress,
|
|
534
|
+
getTestProps: this.getTestProps.bind(this),
|
|
535
|
+
enabledragsettle: props.enabledragsettle
|
|
536
|
+
}, contentStyle => /*#__PURE__*/React.createElement(ScrollView, _extends({
|
|
302
537
|
ref: this.state.scrollViewRef,
|
|
303
538
|
style: this.styles.sheetContentContainer,
|
|
304
|
-
contentContainerStyle: this.styles.sheetScrollContent,
|
|
539
|
+
contentContainerStyle: [this.styles.sheetScrollContent],
|
|
305
540
|
alwaysBounceVertical: false,
|
|
306
541
|
alwaysBounceHorizontal: false,
|
|
307
542
|
bounces: false,
|
|
@@ -309,8 +544,26 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
309
544
|
scrollEventThrottle: 16,
|
|
310
545
|
onScroll: this.handleScroll,
|
|
311
546
|
nestedScrollEnabled: true,
|
|
312
|
-
scrollEnabled:
|
|
313
|
-
}, this.getTestProps('scorllview')), props.
|
|
547
|
+
scrollEnabled: !props.issticky && (!props.disablescrollonrest || this.state.isExpanded)
|
|
548
|
+
}, this.getTestProps('scorllview')), props.enablemodalsupport ? /*#__PURE__*/React.createElement(ModalProvider, {
|
|
549
|
+
value: this.sheetModalService
|
|
550
|
+
}, /*#__PURE__*/React.createElement(Animated.View, {
|
|
551
|
+
style: contentStyle
|
|
552
|
+
}, props.children)) : /*#__PURE__*/React.createElement(Animated.View, {
|
|
553
|
+
style: contentStyle
|
|
554
|
+
}, props.children))), props.enablemodalsupport && this.state.localModalsOpened && this.state.localModalsOpened.map((o, i) => /*#__PURE__*/React.createElement(View, {
|
|
555
|
+
key: (o.name || '') + i,
|
|
556
|
+
onStartShouldSetResponder: () => true,
|
|
557
|
+
onResponderEnd: () => o.isModal && this.sheetModalService.hideModal(o),
|
|
558
|
+
style: [this.styles.modalOverlay, o.centered ? this.styles.centeredOverlay : null, {
|
|
559
|
+
zIndex: o.elevationIndex || 9999,
|
|
560
|
+
elevation: o.elevationIndex || 9999
|
|
561
|
+
}, o.modalStyle || {}]
|
|
562
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
563
|
+
style: [o.contentStyle || {}],
|
|
564
|
+
onStartShouldSetResponder: () => true,
|
|
565
|
+
onResponderEnd: e => e.stopPropagation()
|
|
566
|
+
}, o.content))));
|
|
314
567
|
});
|
|
315
568
|
});
|
|
316
569
|
this.calculatedHeight = this.calculateSheetHeight(_props.bottomsheetheightratio);
|
|
@@ -329,18 +582,63 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
329
582
|
this.expandedHeight -= this.defaultTopInset;
|
|
330
583
|
}
|
|
331
584
|
}
|
|
332
|
-
|
|
585
|
+
|
|
586
|
+
// Initialize shared values in constructor using makeMutable (not hooks)
|
|
587
|
+
// makeMutable can be called outside of React components
|
|
588
|
+
this.translateY = makeMutable(SCREEN_HEIGHT);
|
|
589
|
+
this.backdropOpacity = makeMutable(0);
|
|
590
|
+
this.sheetHeight = makeMutable(this.calculatedHeight);
|
|
591
|
+
this.lastGestureDyShared = makeMutable(0);
|
|
333
592
|
this.updateState({
|
|
334
593
|
isBottomsheetVisible: this.props.showonrender || false
|
|
335
594
|
});
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
this.
|
|
595
|
+
|
|
596
|
+
// Initialize values immediately to prevent flicker
|
|
597
|
+
if (this.props.showonrender) {
|
|
598
|
+
this.translateY.value = 0;
|
|
599
|
+
this.backdropOpacity.value = 1;
|
|
340
600
|
}
|
|
601
|
+
|
|
602
|
+
// Local ModalService for content rendered inside Bottomsheet
|
|
603
|
+
this.sheetModalService = {
|
|
604
|
+
refresh: () => this.forceUpdate(),
|
|
605
|
+
showModal: options => {
|
|
606
|
+
const exists = this.state.localModalsOpened.find(o => o === options);
|
|
607
|
+
if (!exists) {
|
|
608
|
+
// ensure high z-index within sheet
|
|
609
|
+
options.elevationIndex = 9999 + this.state.localModalsOpened.length + 1;
|
|
610
|
+
const list = [...this.state.localModalsOpened, options];
|
|
611
|
+
this.updateState({
|
|
612
|
+
localModalsOpened: list
|
|
613
|
+
}, () => {
|
|
614
|
+
setTimeout(() => options.onOpen && options.onOpen(), 0);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
hideModal: options => {
|
|
619
|
+
const list = [...this.state.localModalsOpened];
|
|
620
|
+
const idx = options ? list.findIndex(o => o === options) : list.length - 1;
|
|
621
|
+
if (idx >= 0) {
|
|
622
|
+
const o = list[idx];
|
|
623
|
+
o && o.onClose && o.onClose();
|
|
624
|
+
list.splice(idx, 1);
|
|
625
|
+
this.updateState({
|
|
626
|
+
localModalsOpened: list
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
};
|
|
341
631
|
}
|
|
342
632
|
componentDidMount() {
|
|
343
633
|
super.componentDidMount();
|
|
634
|
+
|
|
635
|
+
// Trigger animation after mount if showonrender is true
|
|
636
|
+
if (this.state.isBottomsheetVisible) {
|
|
637
|
+
// Use requestAnimationFrame to ensure animation happens after initial render
|
|
638
|
+
requestAnimationFrame(() => {
|
|
639
|
+
this.openSheet();
|
|
640
|
+
});
|
|
641
|
+
}
|
|
344
642
|
if (Platform.OS === 'android') {
|
|
345
643
|
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
|
346
644
|
}
|
|
@@ -352,13 +650,19 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
352
650
|
if (Platform.OS === 'android') {
|
|
353
651
|
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
|
354
652
|
}
|
|
355
|
-
this.keyboardDidShowListener
|
|
356
|
-
|
|
653
|
+
if (this.keyboardDidShowListener) {
|
|
654
|
+
this.keyboardDidShowListener.remove();
|
|
655
|
+
}
|
|
656
|
+
if (this.keyboardDidHideListener) {
|
|
657
|
+
this.keyboardDidHideListener.remove();
|
|
658
|
+
}
|
|
357
659
|
}
|
|
358
660
|
componentDidUpdate(prevProps) {
|
|
359
661
|
if (prevProps.bottomsheetheightratio !== this.props.bottomsheetheightratio) {
|
|
360
662
|
this.calculatedHeight = this.calculateSheetHeight(this.props.bottomsheetheightratio);
|
|
361
|
-
this.
|
|
663
|
+
if (this.sheetHeight) {
|
|
664
|
+
this.sheetHeight.value = this.calculatedHeight;
|
|
665
|
+
}
|
|
362
666
|
}
|
|
363
667
|
}
|
|
364
668
|
onPropertyChange(name, $new, $old) {
|
|
@@ -392,13 +696,17 @@ export default class WmBottomsheet extends BaseComponent {
|
|
|
392
696
|
visible: this.state.isBottomsheetVisible,
|
|
393
697
|
transparent: true,
|
|
394
698
|
animationType: "none",
|
|
395
|
-
onRequestClose:
|
|
396
|
-
|
|
699
|
+
onRequestClose: () => {
|
|
700
|
+
if (!this.props.disableswipedownclose && this.props.autoclose !== 'disabled') {
|
|
701
|
+
this.closeSheet();
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
statusBarTranslucent: false
|
|
397
705
|
}, /*#__PURE__*/React.createElement(KeyboardAvoidingView, {
|
|
398
706
|
style: {
|
|
399
707
|
flex: 1
|
|
400
708
|
},
|
|
401
|
-
behavior:
|
|
709
|
+
behavior: 'padding',
|
|
402
710
|
keyboardVerticalOffset: Platform.OS === 'ios' ? 0 : undefined
|
|
403
711
|
}, this.renderContent(props)));
|
|
404
712
|
} else {
|