@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.
Files changed (33) hide show
  1. package/components/basic/bottomsheet/bottomsheet.component.js +439 -131
  2. package/components/basic/bottomsheet/bottomsheet.component.js.map +1 -1
  3. package/components/basic/bottomsheet/bottomsheet.props.js +7 -0
  4. package/components/basic/bottomsheet/bottomsheet.props.js.map +1 -1
  5. package/components/basic/bottomsheet/bottomsheet.styles.js +12 -3
  6. package/components/basic/bottomsheet/bottomsheet.styles.js.map +1 -1
  7. package/components/input/chips/chips.component.js +10 -20
  8. package/components/input/chips/chips.component.js.map +1 -1
  9. package/components/input/chips/chips.styles.js +32 -32
  10. package/components/input/chips/chips.styles.js.map +1 -1
  11. package/components/page/page.component.js +3 -1
  12. package/components/page/page.component.js.map +1 -1
  13. package/core/AppConfig.js.map +1 -1
  14. package/core/responsive.utils.js +2 -2
  15. package/core/responsive.utils.js.map +1 -1
  16. package/core/screen-capture-protection.service.js +5 -0
  17. package/core/screen-capture-protection.service.js.map +1 -0
  18. package/core/secure-storage.service.js +55 -0
  19. package/core/secure-storage.service.js.map +1 -0
  20. package/core/storage.service.js.map +1 -1
  21. package/gestures/carousel-swipe.animation.js +6 -6
  22. package/gestures/carousel-swipe.animation.js.map +1 -1
  23. package/gestures/swipe.animation.js +6 -6
  24. package/gestures/swipe.animation.js.map +1 -1
  25. package/npm-shrinkwrap.json +2803 -2134
  26. package/package-lock.json +2803 -2134
  27. package/package.json +5 -3
  28. package/runtime/App.js +32 -2
  29. package/runtime/App.js.map +1 -1
  30. package/runtime/base-page.component.js +17 -1
  31. package/runtime/base-page.component.js.map +1 -1
  32. package/styles/theme.js +3 -0
  33. 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, Animated, PanResponder, Dimensions, TouchableWithoutFeedback, Platform, StatusBar, BackHandler, KeyboardAvoidingView, Keyboard, Modal } from 'react-native';
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.2);
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.closeSheet();
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
- // Animate the sheet height adjustment
106
- Animated.timing(this.state.sheetHeight, {
107
- toValue: adjustedHeight,
108
- duration: 100,
109
- useNativeDriver: false
110
- }).start();
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
- // Restore the original sheet height when keyboard hides
117
- Animated.timing(this.state.sheetHeight, {
118
- toValue: this.state.isExpanded ? this.expandedHeight : this.calculatedHeight,
119
- duration: 100,
120
- useNativeDriver: false
121
- }).start();
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
- this.updateState({
128
- lastGestureDy: 0
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
- // Expand the bottom sheet threshold is 25% of the fully expanded height
133
- // If the user swipe distance is below the threshold, revert to the original sheet height
134
- if (gestureState.dy < this.expandedHeight / 4) {
135
- Animated.parallel([Animated.timing(this.state.translateY, {
136
- toValue: 0,
137
- // Keep sheet open
138
- duration: this.animationDuration,
139
- useNativeDriver: false
140
- }), Animated.timing(this.state.sheetHeight, {
141
- toValue: this.calculatedHeight,
142
- // Back to original height
143
- duration: this.animationDuration,
144
- useNativeDriver: false
145
- })]).start();
146
- this.updateState({
147
- isExpanded: false
148
- });
149
- } else if (gestureState.dy > this.expandedHeight / 4 || gestureState.vy > 0.5) {
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 (gestureState.dy > 100 || gestureState.vy > 0.5) {
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.state.lastGestureDy + gestureState.dy);
174
- this.state.translateY.setValue(newTranslateY);
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
- // Handle downward drag
191
- const newTranslateY = Math.max(0, this.state.lastGestureDy + gestureState.dy);
192
- this.state.translateY.setValue(newTranslateY);
193
- } else if (gestureState.dy < 0 && this.props.expand && this.props.bottomsheetheightratio !== 1) {
194
- // Handle upward drag - expand to full height
195
- // Allow expansion to full screen height
196
- const targetHeight = Math.min(this.expandedHeight, SCREEN_HEIGHT);
197
- Animated.timing(this.state.sheetHeight, {
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
- this.updateState({
221
- lastGestureDy: 0
222
- });
223
- Animated.parallel([Animated.timing(this.state.translateY, {
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
- Animated.parallel([Animated.timing(this.state.translateY, {
243
- toValue: SCREEN_HEIGHT,
244
- duration: this.animationDuration,
245
- useNativeDriver: false
246
- }), Animated.timing(this.state.backdropOpacity, {
247
- toValue: 0,
248
- duration: this.animationDuration,
249
- useNativeDriver: false
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.state.translateY.setValue(SCREEN_HEIGHT);
262
- this.state.backdropOpacity.setValue(0);
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.state.sheetHeight.setValue(this.calculatedHeight);
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
- this.topInset = (insets === null || insets === void 0 ? void 0 : insets.top) || 0;
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(TouchableWithoutFeedback, {
283
- onPress: this.closeSheet
284
- }, /*#__PURE__*/React.createElement(Animated.View, _extends({
285
- style: [this.styles.backdrop, {
286
- opacity: this.state.backdropOpacity
287
- }]
288
- }, this.getTestProps('backdrop'), getAccessibilityProps(AccessibilityWidgetType.BOTTOMSHEET, props)))), /*#__PURE__*/React.createElement(Animated.View, _extends({
289
- style: [this.styles.container, {
290
- height: this.state.sheetHeight,
291
- transform: [{
292
- translateY: this.state.translateY
293
- }]
294
- }]
295
- }, this.panResponder.panHandlers), /*#__PURE__*/React.createElement(View, _extends({
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: true
313
- }, this.getTestProps('scorllview')), props.children)));
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
- this.state.sheetHeight.setValue(this.calculatedHeight);
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
- if (this.state.isBottomsheetVisible) {
337
- this.openSheet();
338
- } else {
339
- this.closeSheetImmediate();
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.remove();
356
- this.keyboardDidHideListener.remove();
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.state.sheetHeight.setValue(this.calculatedHeight);
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: this.closeSheet,
396
- statusBarTranslucent: true
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: Platform.OS === 'ios' ? 'padding' : undefined,
709
+ behavior: 'padding',
402
710
  keyboardVerticalOffset: Platform.OS === 'ios' ? 0 : undefined
403
711
  }, this.renderContent(props)));
404
712
  } else {